| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.jackrabbit.test; |
| |
| import junit.framework.TestFailure; |
| import junit.framework.TestResult; |
| import junit.framework.Test; |
| import junit.framework.AssertionFailedError; |
| import junit.framework.TestListener; |
| import junit.framework.TestCase; |
| |
| import java.util.Enumeration; |
| import java.util.HashSet; |
| import java.util.Set; |
| import java.util.StringTokenizer; |
| |
| /** |
| * Extends the standard JUnit TestResult class. This class ignores test errors |
| * that originated in throwing a {@link NotExecutableException}. |
| */ |
| public class JCRTestResult extends TestResult { |
| |
| /** The original TestResult we delegate to */ |
| private final TestResult orig; |
| |
| /** The log writer of the test classes */ |
| private final LogPrintWriter log; |
| |
| /** |
| * Set of Strings that identify the test methods that currently fails but |
| * are recognized as known issues. Those will not be reported as errors. |
| */ |
| private final Set<String> knownIssues; |
| |
| /** |
| * Set of Strings that identify the test methods that are listed as known |
| * issues but whose test failures should still be reported. |
| */ |
| private final Set<String> knownIssuesOverride; |
| |
| /** |
| * Creates a new JCRTestResult that delegates to <code>orig</code>. |
| * @param orig the original TestResult this result wraps. |
| * @param log the logger |
| */ |
| public JCRTestResult(TestResult orig, LogPrintWriter log) { |
| this.orig = orig; |
| this.log = log; |
| this.knownIssues = JCRTestResult.tokenize("known.issues"); |
| this.knownIssuesOverride = JCRTestResult.tokenize("known.issues.override"); |
| } |
| |
| @Override |
| protected void run(TestCase test) { |
| if (isKnownIssue(test)) { |
| // notify listeners but not actually run the test |
| startTest(test); |
| log.println("Known issue: " + test + " (skipped)"); |
| endTest(test); |
| } else { |
| super.run(test); |
| } |
| } |
| |
| /** |
| * Only add an error if <code>throwable</code> is not of type |
| * {@link NotExecutableException} and the test case is not a known issue. |
| * @param test the test. |
| * @param throwable the exception thrown by the test. |
| */ |
| public synchronized void addError(Test test, Throwable throwable) { |
| if (throwable instanceof NotExecutableException) { |
| log.println("Test case: " + test.toString() + " not executable: " + throwable.getMessage()); |
| } else if (isKnownIssue(test)) { |
| log.println("Known issue: " + test + ": " + throwable.getMessage()); |
| } else { |
| orig.addError(test, throwable); |
| } |
| } |
| |
| /** |
| * Only adds a failure if <code>test</code> is not a known issue. |
| * @param test the test case that failed. |
| * @param assertionFailedError the assertion error. |
| */ |
| public synchronized void addFailure(Test test, |
| AssertionFailedError assertionFailedError) { |
| if (isKnownIssue(test)) { |
| log.println("Known issue: " + test + ": " + assertionFailedError.getMessage()); |
| } else { |
| orig.addFailure(test, assertionFailedError); |
| } |
| } |
| |
| //-----------------------< default overwrites >----------------------------- |
| |
| public synchronized void addListener(TestListener testListener) { |
| orig.addListener(testListener); |
| } |
| |
| public synchronized void removeListener(TestListener testListener) { |
| orig.removeListener(testListener); |
| } |
| |
| public void endTest(Test test) { |
| orig.endTest(test); |
| } |
| |
| public synchronized int errorCount() { |
| return orig.errorCount(); |
| } |
| |
| public synchronized Enumeration<TestFailure> errors() { |
| return orig.errors(); |
| } |
| |
| public synchronized int failureCount() { |
| return orig.failureCount(); |
| } |
| |
| public synchronized Enumeration<TestFailure> failures() { |
| return orig.failures(); |
| } |
| |
| public synchronized int runCount() { |
| return orig.runCount(); |
| } |
| |
| public synchronized boolean shouldStop() { |
| return orig.shouldStop(); |
| } |
| |
| public void startTest(Test test) { |
| orig.startTest(test); |
| } |
| |
| public synchronized void stop() { |
| orig.stop(); |
| } |
| |
| public synchronized boolean wasSuccessful() { |
| return orig.wasSuccessful(); |
| } |
| |
| //------------------------------< internal >-------------------------------- |
| |
| /** |
| * Takes the named system property and returns the set of string tokens |
| * in the property value. Returns an empty set if the named property does |
| * not exist. |
| * |
| * @param name name of the system property |
| * @return set of string tokens |
| */ |
| private static Set<String> tokenize(String name) { |
| Set<String> tokens = new HashSet<String>(); |
| StringTokenizer tokenizer = |
| new StringTokenizer(System.getProperty(name, "")); |
| while (tokenizer.hasMoreTokens()) { |
| tokens.add(tokenizer.nextToken()); |
| } |
| return tokens; |
| } |
| |
| /** |
| * Checks if a variation of the name of the given test case is included |
| * in the given set of token. The tested variations are: |
| * <ul> |
| * <li>package name</li> |
| * <li>non-qualified class name</li> |
| * <li>fully qualified class name</li> |
| * <li>non-qualified method name</li> |
| * <li>class-qualified method name</li> |
| * <li>fully-qualified method name</li> |
| * </ul> |
| * |
| * @param tokens set of string tokens |
| * @param test test case |
| * @return <code>true</code> if the test case name is included, |
| * <code>false</code> otherwise |
| */ |
| private static boolean contains(Set<String> tokens, TestCase test) { |
| String className = test.getClass().getName(); |
| String methodName = test.getName(); |
| |
| int i = className.lastIndexOf('.'); |
| if (i >= 0) { |
| String packageName = className.substring(0, i); |
| String shortName = className.substring(i + 1); |
| return tokens.contains(packageName) |
| || tokens.contains(shortName) |
| || tokens.contains(className) |
| || tokens.contains(methodName) |
| || tokens.contains(shortName + "#" + methodName) |
| || tokens.contains(className + "#" + methodName); |
| } else { |
| return tokens.contains(className) |
| || tokens.contains(methodName) |
| || tokens.contains(className + "#" + methodName); |
| } |
| } |
| |
| /** |
| * Returns <code>true</code> if <code>test</code> is a known issue |
| * whose test result should be ignored; <code>false</code> otherwise. |
| * |
| * @param test the test case to check. |
| * @return <code>true</code> if <code>test</code> result should be ignored |
| */ |
| private boolean isKnownIssue(Test test) { |
| if (test instanceof TestCase) { |
| return contains(knownIssues, (TestCase) test) |
| && !contains(knownIssuesOverride, (TestCase) test); |
| } else { |
| return false; |
| } |
| } |
| |
| } |