diff options
Diffstat (limited to 'src/org/junit/internal/runners')
22 files changed, 1349 insertions, 0 deletions
diff --git a/src/org/junit/internal/runners/ClassRoadie.java b/src/org/junit/internal/runners/ClassRoadie.java new file mode 100644 index 0000000..1f77d37 --- /dev/null +++ b/src/org/junit/internal/runners/ClassRoadie.java @@ -0,0 +1,79 @@ +package org.junit.internal.runners; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; + +import org.junit.runner.Description; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.BlockJUnit4ClassRunner; + +/** + * @deprecated Included for backwards compatibility with JUnit 4.4. Will be + * removed in the next release. Please use + * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}. + */ +@Deprecated +public +class ClassRoadie { + private RunNotifier fNotifier; + private TestClass fTestClass; + private Description fDescription; + private final Runnable fRunnable; + + public ClassRoadie(RunNotifier notifier, TestClass testClass, + Description description, Runnable runnable) { + fNotifier= notifier; + fTestClass= testClass; + fDescription= description; + fRunnable= runnable; + } + + protected void runUnprotected() { + fRunnable.run(); + }; + + protected void addFailure(Throwable targetException) { + fNotifier.fireTestFailure(new Failure(fDescription, targetException)); + } + + public void runProtected() { + try { + runBefores(); + runUnprotected(); + } catch (FailedBefore e) { + } finally { + runAfters(); + } + } + + private void runBefores() throws FailedBefore { + try { + try { + List<Method> befores= fTestClass.getBefores(); + for (Method before : befores) + before.invoke(null); + } catch (InvocationTargetException e) { + throw e.getTargetException(); + } + } catch (org.junit.internal.AssumptionViolatedException e) { + throw new FailedBefore(); + } catch (Throwable e) { + addFailure(e); + throw new FailedBefore(); + } + } + + private void runAfters() { + List<Method> afters= fTestClass.getAfters(); + for (Method after : afters) + try { + after.invoke(null); + } catch (InvocationTargetException e) { + addFailure(e.getTargetException()); + } catch (Throwable e) { + addFailure(e); // Untested, but seems impossible + } + } +}
\ No newline at end of file diff --git a/src/org/junit/internal/runners/ErrorReportingRunner.java b/src/org/junit/internal/runners/ErrorReportingRunner.java new file mode 100644 index 0000000..200b6f0 --- /dev/null +++ b/src/org/junit/internal/runners/ErrorReportingRunner.java @@ -0,0 +1,60 @@ +package org.junit.internal.runners; + +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.List; + +import org.junit.runner.Description; +import org.junit.runner.Runner; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.model.InitializationError; + +public class ErrorReportingRunner extends Runner { + private final List<Throwable> fCauses; + + private final Class<?> fTestClass; + + public ErrorReportingRunner(Class<?> testClass, Throwable cause) { + fTestClass= testClass; + fCauses= getCauses(cause); + } + + @Override + public Description getDescription() { + Description description= Description.createSuiteDescription(fTestClass); + for (Throwable each : fCauses) + description.addChild(describeCause(each)); + return description; + } + + @Override + public void run(RunNotifier notifier) { + for (Throwable each : fCauses) + runCause(each, notifier); + } + + @SuppressWarnings("deprecation") + private List<Throwable> getCauses(Throwable cause) { + if (cause instanceof InvocationTargetException) + return getCauses(cause.getCause()); + if (cause instanceof InitializationError) + return ((InitializationError) cause).getCauses(); + if (cause instanceof org.junit.internal.runners.InitializationError) + return ((org.junit.internal.runners.InitializationError) cause) + .getCauses(); + return Arrays.asList(cause); + } + + private Description describeCause(Throwable child) { + return Description.createTestDescription(fTestClass, + "initializationError"); + } + + private void runCause(Throwable child, RunNotifier notifier) { + Description description= describeCause(child); + notifier.fireTestStarted(description); + notifier.fireTestFailure(new Failure(description, child)); + notifier.fireTestFinished(description); + } +}
\ No newline at end of file diff --git a/src/org/junit/internal/runners/FailedBefore.java b/src/org/junit/internal/runners/FailedBefore.java new file mode 100644 index 0000000..29dcba4 --- /dev/null +++ b/src/org/junit/internal/runners/FailedBefore.java @@ -0,0 +1,14 @@ +package org.junit.internal.runners; + +import org.junit.runners.BlockJUnit4ClassRunner; + + +/** + * @deprecated Included for backwards compatibility with JUnit 4.4. Will be + * removed in the next release. Please use + * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}. + */ +@Deprecated +class FailedBefore extends Exception { + private static final long serialVersionUID= 1L; +}
\ No newline at end of file diff --git a/src/org/junit/internal/runners/InitializationError.java b/src/org/junit/internal/runners/InitializationError.java new file mode 100644 index 0000000..5715ec5 --- /dev/null +++ b/src/org/junit/internal/runners/InitializationError.java @@ -0,0 +1,30 @@ +package org.junit.internal.runners; + +import java.util.Arrays; +import java.util.List; + +@Deprecated +/** + * Use the published version: {@link org.junit.runners.InitializationError} + * This may disappear as soon as 1 April 2009 + */ +public class InitializationError extends Exception { + private static final long serialVersionUID= 1L; + private final List<Throwable> fErrors; + + public InitializationError(List<Throwable> errors) { + fErrors= errors; + } + + public InitializationError(Throwable... errors) { + this(Arrays.asList(errors)); + } + + public InitializationError(String string) { + this(new Exception(string)); + } + + public List<Throwable> getCauses() { + return fErrors; + } +} diff --git a/src/org/junit/internal/runners/JUnit38ClassRunner.java b/src/org/junit/internal/runners/JUnit38ClassRunner.java new file mode 100644 index 0000000..0028d0c --- /dev/null +++ b/src/org/junit/internal/runners/JUnit38ClassRunner.java @@ -0,0 +1,158 @@ +package org.junit.internal.runners; + +import junit.extensions.TestDecorator; +import junit.framework.AssertionFailedError; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestListener; +import junit.framework.TestResult; +import junit.framework.TestSuite; +import org.junit.runner.Describable; +import org.junit.runner.Description; +import org.junit.runner.Runner; +import org.junit.runner.manipulation.Filter; +import org.junit.runner.manipulation.Filterable; +import org.junit.runner.manipulation.NoTestsRemainException; +import org.junit.runner.manipulation.Sortable; +import org.junit.runner.manipulation.Sorter; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunNotifier; + +public class JUnit38ClassRunner extends Runner implements Filterable, Sortable { + private final class OldTestClassAdaptingListener implements + TestListener { + private final RunNotifier fNotifier; + + private OldTestClassAdaptingListener(RunNotifier notifier) { + fNotifier= notifier; + } + + public void endTest(Test test) { + fNotifier.fireTestFinished(asDescription(test)); + } + + public void startTest(Test test) { + fNotifier.fireTestStarted(asDescription(test)); + } + + // Implement junit.framework.TestListener + public void addError(Test test, Throwable t) { + Failure failure= new Failure(asDescription(test), t); + fNotifier.fireTestFailure(failure); + } + + private Description asDescription(Test test) { + if (test instanceof Describable) { + Describable facade= (Describable) test; + return facade.getDescription(); + } + return Description.createTestDescription(getEffectiveClass(test), getName(test)); + } + + private Class<? extends Test> getEffectiveClass(Test test) { + return test.getClass(); + } + + private String getName(Test test) { + if (test instanceof TestCase) + return ((TestCase) test).getName(); + else + return test.toString(); + } + + public void addFailure(Test test, AssertionFailedError t) { + addError(test, t); + } + } + + private Test fTest; + + public JUnit38ClassRunner(Class<?> klass) { + this(new TestSuite(klass.asSubclass(TestCase.class))); + } + + public JUnit38ClassRunner(Test test) { + super(); + setTest(test); + } + + @Override + public void run(RunNotifier notifier) { + TestResult result= new TestResult(); + result.addListener(createAdaptingListener(notifier)); + getTest().run(result); + } + + public TestListener createAdaptingListener(final RunNotifier notifier) { + return new OldTestClassAdaptingListener(notifier); + } + + @Override + public Description getDescription() { + return makeDescription(getTest()); + } + + private static Description makeDescription(Test test) { + if (test instanceof TestCase) { + TestCase tc= (TestCase) test; + return Description.createTestDescription(tc.getClass(), tc.getName()); + } else if (test instanceof TestSuite) { + TestSuite ts= (TestSuite) test; + String name= ts.getName() == null ? createSuiteDescription(ts) : ts.getName(); + Description description= Description.createSuiteDescription(name); + int n= ts.testCount(); + for (int i= 0; i < n; i++) { + Description made= makeDescription(ts.testAt(i)); + description.addChild(made); + } + return description; + } else if (test instanceof Describable) { + Describable adapter= (Describable) test; + return adapter.getDescription(); + } else if (test instanceof TestDecorator) { + TestDecorator decorator= (TestDecorator) test; + return makeDescription(decorator.getTest()); + } else { + // This is the best we can do in this case + return Description.createSuiteDescription(test.getClass()); + } + } + + private static String createSuiteDescription(TestSuite ts) { + int count= ts.countTestCases(); + String example = count == 0 ? "" : String.format(" [example: %s]", ts.testAt(0)); + return String.format("TestSuite with %s tests%s", count, example); + } + + public void filter(Filter filter) throws NoTestsRemainException { + if (getTest() instanceof Filterable) { + Filterable adapter= (Filterable) getTest(); + adapter.filter(filter); + } else if (getTest() instanceof TestSuite) { + TestSuite suite= (TestSuite) getTest(); + TestSuite filtered= new TestSuite(suite.getName()); + int n= suite.testCount(); + for (int i= 0; i < n; i++) { + Test test= suite.testAt(i); + if (filter.shouldRun(makeDescription(test))) + filtered.addTest(test); + } + setTest(filtered); + } + } + + public void sort(Sorter sorter) { + if (getTest() instanceof Sortable) { + Sortable adapter= (Sortable) getTest(); + adapter.sort(sorter); + } + } + + private void setTest(Test test) { + fTest = test; + } + + private Test getTest() { + return fTest; + } +} diff --git a/src/org/junit/internal/runners/JUnit4ClassRunner.java b/src/org/junit/internal/runners/JUnit4ClassRunner.java new file mode 100644 index 0000000..d732880 --- /dev/null +++ b/src/org/junit/internal/runners/JUnit4ClassRunner.java @@ -0,0 +1,145 @@ +package org.junit.internal.runners; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +import org.junit.runner.Description; +import org.junit.runner.Runner; +import org.junit.runner.manipulation.Filter; +import org.junit.runner.manipulation.Filterable; +import org.junit.runner.manipulation.NoTestsRemainException; +import org.junit.runner.manipulation.Sortable; +import org.junit.runner.manipulation.Sorter; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.BlockJUnit4ClassRunner; + +/** + * @deprecated Included for backwards compatibility with JUnit 4.4. Will be + * removed in the next release. Please use + * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}. + * + * This may disappear as soon as 1 April 2009 + */ +@Deprecated +public class JUnit4ClassRunner extends Runner implements Filterable, Sortable { + private final List<Method> fTestMethods; + private TestClass fTestClass; + + public JUnit4ClassRunner(Class<?> klass) throws InitializationError { + fTestClass= new TestClass(klass); + fTestMethods= getTestMethods(); + validate(); + } + + protected List<Method> getTestMethods() { + return fTestClass.getTestMethods(); + } + + protected void validate() throws InitializationError { + MethodValidator methodValidator= new MethodValidator(fTestClass); + methodValidator.validateMethodsForDefaultRunner(); + methodValidator.assertValid(); + } + + @Override + public void run(final RunNotifier notifier) { + new ClassRoadie(notifier, fTestClass, getDescription(), new Runnable() { + public void run() { + runMethods(notifier); + } + }).runProtected(); + } + + protected void runMethods(final RunNotifier notifier) { + for (Method method : fTestMethods) + invokeTestMethod(method, notifier); + } + + @Override + public Description getDescription() { + Description spec= Description.createSuiteDescription(getName(), classAnnotations()); + List<Method> testMethods= fTestMethods; + for (Method method : testMethods) + spec.addChild(methodDescription(method)); + return spec; + } + + protected Annotation[] classAnnotations() { + return fTestClass.getJavaClass().getAnnotations(); + } + + protected String getName() { + return getTestClass().getName(); + } + + protected Object createTest() throws Exception { + return getTestClass().getConstructor().newInstance(); + } + + protected void invokeTestMethod(Method method, RunNotifier notifier) { + Description description= methodDescription(method); + Object test; + try { + test= createTest(); + } catch (InvocationTargetException e) { + testAborted(notifier, description, e.getCause()); + return; + } catch (Exception e) { + testAborted(notifier, description, e); + return; + } + TestMethod testMethod= wrapMethod(method); + new MethodRoadie(test, testMethod, notifier, description).run(); + } + + private void testAborted(RunNotifier notifier, Description description, + Throwable e) { + notifier.fireTestStarted(description); + notifier.fireTestFailure(new Failure(description, e)); + notifier.fireTestFinished(description); + } + + protected TestMethod wrapMethod(Method method) { + return new TestMethod(method, fTestClass); + } + + protected String testName(Method method) { + return method.getName(); + } + + protected Description methodDescription(Method method) { + return Description.createTestDescription(getTestClass().getJavaClass(), testName(method), testAnnotations(method)); + } + + protected Annotation[] testAnnotations(Method method) { + return method.getAnnotations(); + } + + public void filter(Filter filter) throws NoTestsRemainException { + for (Iterator<Method> iter= fTestMethods.iterator(); iter.hasNext();) { + Method method= iter.next(); + if (!filter.shouldRun(methodDescription(method))) + iter.remove(); + } + if (fTestMethods.isEmpty()) + throw new NoTestsRemainException(); + } + + public void sort(final Sorter sorter) { + Collections.sort(fTestMethods, new Comparator<Method>() { + public int compare(Method o1, Method o2) { + return sorter.compare(methodDescription(o1), methodDescription(o2)); + } + }); + } + + protected TestClass getTestClass() { + return fTestClass; + } +}
\ No newline at end of file diff --git a/src/org/junit/internal/runners/MethodRoadie.java b/src/org/junit/internal/runners/MethodRoadie.java new file mode 100644 index 0000000..4407821 --- /dev/null +++ b/src/org/junit/internal/runners/MethodRoadie.java @@ -0,0 +1,157 @@ +package org.junit.internal.runners; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.junit.internal.AssumptionViolatedException; +import org.junit.runner.Description; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.BlockJUnit4ClassRunner; + +/** + * @deprecated Included for backwards compatibility with JUnit 4.4. Will be + * removed in the next release. Please use + * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}. + */ +@Deprecated +public class MethodRoadie { + private final Object fTest; + private final RunNotifier fNotifier; + private final Description fDescription; + private TestMethod fTestMethod; + + public MethodRoadie(Object test, TestMethod method, RunNotifier notifier, Description description) { + fTest= test; + fNotifier= notifier; + fDescription= description; + fTestMethod= method; + } + + public void run() { + if (fTestMethod.isIgnored()) { + fNotifier.fireTestIgnored(fDescription); + return; + } + fNotifier.fireTestStarted(fDescription); + try { + long timeout= fTestMethod.getTimeout(); + if (timeout > 0) + runWithTimeout(timeout); + else + runTest(); + } finally { + fNotifier.fireTestFinished(fDescription); + } + } + + private void runWithTimeout(final long timeout) { + runBeforesThenTestThenAfters(new Runnable() { + + public void run() { + ExecutorService service= Executors.newSingleThreadExecutor(); + Callable<Object> callable= new Callable<Object>() { + public Object call() throws Exception { + runTestMethod(); + return null; + } + }; + Future<Object> result= service.submit(callable); + service.shutdown(); + try { + boolean terminated= service.awaitTermination(timeout, + TimeUnit.MILLISECONDS); + if (!terminated) + service.shutdownNow(); + result.get(0, TimeUnit.MILLISECONDS); // throws the exception if one occurred during the invocation + } catch (TimeoutException e) { + addFailure(new Exception(String.format("test timed out after %d milliseconds", timeout))); + } catch (Exception e) { + addFailure(e); + } + } + }); + } + + public void runTest() { + runBeforesThenTestThenAfters(new Runnable() { + public void run() { + runTestMethod(); + } + }); + } + + public void runBeforesThenTestThenAfters(Runnable test) { + try { + runBefores(); + test.run(); + } catch (FailedBefore e) { + } catch (Exception e) { + throw new RuntimeException("test should never throw an exception to this level"); + } finally { + runAfters(); + } + } + + protected void runTestMethod() { + try { + fTestMethod.invoke(fTest); + if (fTestMethod.expectsException()) + addFailure(new AssertionError("Expected exception: " + fTestMethod.getExpectedException().getName())); + } catch (InvocationTargetException e) { + Throwable actual= e.getTargetException(); + if (actual instanceof AssumptionViolatedException) + return; + else if (!fTestMethod.expectsException()) + addFailure(actual); + else if (fTestMethod.isUnexpected(actual)) { + String message= "Unexpected exception, expected<" + fTestMethod.getExpectedException().getName() + "> but was<" + + actual.getClass().getName() + ">"; + addFailure(new Exception(message, actual)); + } + } catch (Throwable e) { + addFailure(e); + } + } + + private void runBefores() throws FailedBefore { + try { + try { + List<Method> befores= fTestMethod.getBefores(); + for (Method before : befores) + before.invoke(fTest); + } catch (InvocationTargetException e) { + throw e.getTargetException(); + } + } catch (AssumptionViolatedException e) { + throw new FailedBefore(); + } catch (Throwable e) { + addFailure(e); + throw new FailedBefore(); + } + } + + private void runAfters() { + List<Method> afters= fTestMethod.getAfters(); + for (Method after : afters) + try { + after.invoke(fTest); + } catch (InvocationTargetException e) { + addFailure(e.getTargetException()); + } catch (Throwable e) { + addFailure(e); // Untested, but seems impossible + } + } + + protected void addFailure(Throwable e) { + fNotifier.fireTestFailure(new Failure(fDescription, e)); + } +} + diff --git a/src/org/junit/internal/runners/MethodValidator.java b/src/org/junit/internal/runners/MethodValidator.java new file mode 100644 index 0000000..cadc93f --- /dev/null +++ b/src/org/junit/internal/runners/MethodValidator.java @@ -0,0 +1,91 @@ +package org.junit.internal.runners; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runners.BlockJUnit4ClassRunner; + +/** + * @deprecated Included for backwards compatibility with JUnit 4.4. Will be + * removed in the next release. Please use + * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}. + */ +@Deprecated +public class MethodValidator { + + private final List<Throwable> fErrors= new ArrayList<Throwable>(); + + private TestClass fTestClass; + + public MethodValidator(TestClass testClass) { + fTestClass = testClass; + } + + public void validateInstanceMethods() { + validateTestMethods(After.class, false); + validateTestMethods(Before.class, false); + validateTestMethods(Test.class, false); + + List<Method> methods= fTestClass.getAnnotatedMethods(Test.class); + if (methods.size() == 0) + fErrors.add(new Exception("No runnable methods")); + } + + public void validateStaticMethods() { + validateTestMethods(BeforeClass.class, true); + validateTestMethods(AfterClass.class, true); + } + + public List<Throwable> validateMethodsForDefaultRunner() { + validateNoArgConstructor(); + validateStaticMethods(); + validateInstanceMethods(); + return fErrors; + } + + public void assertValid() throws InitializationError { + if (!fErrors.isEmpty()) + throw new InitializationError(fErrors); + } + + public void validateNoArgConstructor() { + try { + fTestClass.getConstructor(); + } catch (Exception e) { + fErrors.add(new Exception("Test class should have public zero-argument constructor", e)); + } + } + + private void validateTestMethods(Class<? extends Annotation> annotation, + boolean isStatic) { + List<Method> methods= fTestClass.getAnnotatedMethods(annotation); + + for (Method each : methods) { + if (Modifier.isStatic(each.getModifiers()) != isStatic) { + String state= isStatic ? "should" : "should not"; + fErrors.add(new Exception("Method " + each.getName() + "() " + + state + " be static")); + } + if (!Modifier.isPublic(each.getDeclaringClass().getModifiers())) + fErrors.add(new Exception("Class " + each.getDeclaringClass().getName() + + " should be public")); + if (!Modifier.isPublic(each.getModifiers())) + fErrors.add(new Exception("Method " + each.getName() + + " should be public")); + if (each.getReturnType() != Void.TYPE) + fErrors.add(new Exception("Method " + each.getName() + + " should be void")); + if (each.getParameterTypes().length != 0) + fErrors.add(new Exception("Method " + each.getName() + + " should have no parameters")); + } + } +} diff --git a/src/org/junit/internal/runners/SuiteMethod.java b/src/org/junit/internal/runners/SuiteMethod.java new file mode 100644 index 0000000..4e8bebc --- /dev/null +++ b/src/org/junit/internal/runners/SuiteMethod.java @@ -0,0 +1,40 @@ +package org.junit.internal.runners; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import junit.framework.Test; + +/** Runner for use with JUnit 3.8.x-style AllTests classes + * (those that only implement a static <code>suite()</code> + * method). For example: + * <pre> + * @RunWith(AllTests.class) + * public class ProductTests { + * public static junit.framework.Test suite() { + * ... + * } + * } + * </pre> + */ +public class SuiteMethod extends JUnit38ClassRunner { + public SuiteMethod(Class<?> klass) throws Throwable { + super(testFromSuiteMethod(klass)); + } + + public static Test testFromSuiteMethod(Class<?> klass) throws Throwable { + Method suiteMethod= null; + Test suite= null; + try { + suiteMethod= klass.getMethod("suite"); + if (! Modifier.isStatic(suiteMethod.getModifiers())) { + throw new Exception(klass.getName() + ".suite() must be static"); + } + suite= (Test) suiteMethod.invoke(null); // static method + } catch (InvocationTargetException e) { + throw e.getCause(); + } + return suite; + } +} diff --git a/src/org/junit/internal/runners/TestClass.java b/src/org/junit/internal/runners/TestClass.java new file mode 100644 index 0000000..1ca2b9d --- /dev/null +++ b/src/org/junit/internal/runners/TestClass.java @@ -0,0 +1,102 @@ +package org.junit.internal.runners; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runners.BlockJUnit4ClassRunner; + +/** + * @deprecated Included for backwards compatibility with JUnit 4.4. Will be + * removed in the next release. Please use + * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}. + */ +@Deprecated +public class TestClass { + private final Class<?> fClass; + + public TestClass(Class<?> klass) { + fClass= klass; + } + + public List<Method> getTestMethods() { + return getAnnotatedMethods(Test.class); + } + + List<Method> getBefores() { + return getAnnotatedMethods(BeforeClass.class); + } + + List<Method> getAfters() { + return getAnnotatedMethods(AfterClass.class); + } + + public List<Method> getAnnotatedMethods(Class<? extends Annotation> annotationClass) { + List<Method> results= new ArrayList<Method>(); + for (Class<?> eachClass : getSuperClasses(fClass)) { + Method[] methods= eachClass.getDeclaredMethods(); + for (Method eachMethod : methods) { + Annotation annotation= eachMethod.getAnnotation(annotationClass); + if (annotation != null && ! isShadowed(eachMethod, results)) + results.add(eachMethod); + } + } + if (runsTopToBottom(annotationClass)) + Collections.reverse(results); + return results; + } + + private boolean runsTopToBottom(Class< ? extends Annotation> annotation) { + return annotation.equals(Before.class) || annotation.equals(BeforeClass.class); + } + + private boolean isShadowed(Method method, List<Method> results) { + for (Method each : results) { + if (isShadowed(method, each)) + return true; + } + return false; + } + + private boolean isShadowed(Method current, Method previous) { + if (! previous.getName().equals(current.getName())) + return false; + if (previous.getParameterTypes().length != current.getParameterTypes().length) + return false; + for (int i= 0; i < previous.getParameterTypes().length; i++) { + if (! previous.getParameterTypes()[i].equals(current.getParameterTypes()[i])) + return false; + } + return true; + } + + private List<Class<?>> getSuperClasses(Class< ?> testClass) { + ArrayList<Class<?>> results= new ArrayList<Class<?>>(); + Class<?> current= testClass; + while (current != null) { + results.add(current); + current= current.getSuperclass(); + } + return results; + } + + public Constructor<?> getConstructor() throws SecurityException, NoSuchMethodException { + return fClass.getConstructor(); + } + + public Class<?> getJavaClass() { + return fClass; + } + + public String getName() { + return fClass.getName(); + } + +} diff --git a/src/org/junit/internal/runners/TestMethod.java b/src/org/junit/internal/runners/TestMethod.java new file mode 100644 index 0000000..a06213c --- /dev/null +++ b/src/org/junit/internal/runners/TestMethod.java @@ -0,0 +1,69 @@ +package org.junit.internal.runners; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.Test.None; +import org.junit.runners.BlockJUnit4ClassRunner; + +/** + * @deprecated Included for backwards compatibility with JUnit 4.4. Will be + * removed in the next release. Please use + * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}. + */ +@Deprecated +public class TestMethod { + private final Method fMethod; + private TestClass fTestClass; + + public TestMethod(Method method, TestClass testClass) { + fMethod= method; + fTestClass= testClass; + } + + public boolean isIgnored() { + return fMethod.getAnnotation(Ignore.class) != null; + } + + public long getTimeout() { + Test annotation= fMethod.getAnnotation(Test.class); + if (annotation == null) + return 0; + long timeout= annotation.timeout(); + return timeout; + } + + protected Class<? extends Throwable> getExpectedException() { + Test annotation= fMethod.getAnnotation(Test.class); + if (annotation == null || annotation.expected() == None.class) + return null; + else + return annotation.expected(); + } + + boolean isUnexpected(Throwable exception) { + return ! getExpectedException().isAssignableFrom(exception.getClass()); + } + + boolean expectsException() { + return getExpectedException() != null; + } + + List<Method> getBefores() { + return fTestClass.getAnnotatedMethods(Before.class); + } + + List<Method> getAfters() { + return fTestClass.getAnnotatedMethods(After.class); + } + + public void invoke(Object test) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + fMethod.invoke(test); + } + +} diff --git a/src/org/junit/internal/runners/model/EachTestNotifier.java b/src/org/junit/internal/runners/model/EachTestNotifier.java new file mode 100644 index 0000000..a7d534c --- /dev/null +++ b/src/org/junit/internal/runners/model/EachTestNotifier.java @@ -0,0 +1,51 @@ +/** + * + */ +package org.junit.internal.runners.model; + +import org.junit.internal.AssumptionViolatedException; +import org.junit.runner.Description; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.model.MultipleFailureException; + +public class EachTestNotifier { + private final RunNotifier fNotifier; + + private final Description fDescription; + + public EachTestNotifier(RunNotifier notifier, Description description) { + fNotifier= notifier; + fDescription= description; + } + + public void addFailure(Throwable targetException) { + if (targetException instanceof MultipleFailureException) { + addMultipleFailureException((MultipleFailureException) targetException); + } else { + fNotifier + .fireTestFailure(new Failure(fDescription, targetException)); + } + } + + private void addMultipleFailureException(MultipleFailureException mfe) { + for (Throwable each : mfe.getFailures()) + addFailure(each); + } + + public void addFailedAssumption(AssumptionViolatedException e) { + fNotifier.fireTestAssumptionFailed(new Failure(fDescription, e)); + } + + public void fireTestFinished() { + fNotifier.fireTestFinished(fDescription); + } + + public void fireTestStarted() { + fNotifier.fireTestStarted(fDescription); + } + + public void fireTestIgnored() { + fNotifier.fireTestIgnored(fDescription); + } +}
\ No newline at end of file diff --git a/src/org/junit/internal/runners/model/MultipleFailureException.java b/src/org/junit/internal/runners/model/MultipleFailureException.java new file mode 100644 index 0000000..3316806 --- /dev/null +++ b/src/org/junit/internal/runners/model/MultipleFailureException.java @@ -0,0 +1,12 @@ +package org.junit.internal.runners.model; + +import java.util.List; + +@Deprecated +public class MultipleFailureException extends org.junit.runners.model.MultipleFailureException { + private static final long serialVersionUID= 1L; + + public MultipleFailureException(List<Throwable> errors) { + super(errors); + } +} diff --git a/src/org/junit/internal/runners/model/ReflectiveCallable.java b/src/org/junit/internal/runners/model/ReflectiveCallable.java new file mode 100644 index 0000000..9150d90 --- /dev/null +++ b/src/org/junit/internal/runners/model/ReflectiveCallable.java @@ -0,0 +1,22 @@ +/** + * + */ +package org.junit.internal.runners.model; + +import java.lang.reflect.InvocationTargetException; + +/** + * When invoked, throws the exception from the reflected method, rather than + * wrapping it in an InvocationTargetException. + */ +public abstract class ReflectiveCallable { + public Object run() throws Throwable { + try { + return runReflectiveCall(); + } catch (InvocationTargetException e) { + throw e.getTargetException(); + } + } + + protected abstract Object runReflectiveCall() throws Throwable; +}
\ No newline at end of file diff --git a/src/org/junit/internal/runners/package-info.java b/src/org/junit/internal/runners/package-info.java new file mode 100644 index 0000000..5ab7e7b --- /dev/null +++ b/src/org/junit/internal/runners/package-info.java @@ -0,0 +1,6 @@ +/** + * Provides implementations of {@link org.junit.runner.Runner} + * + * @since 4.0 + */ +package org.junit.internal.runners;
\ No newline at end of file diff --git a/src/org/junit/internal/runners/rules/RuleFieldValidator.java b/src/org/junit/internal/runners/rules/RuleFieldValidator.java new file mode 100644 index 0000000..e7df8bf --- /dev/null +++ b/src/org/junit/internal/runners/rules/RuleFieldValidator.java @@ -0,0 +1,92 @@ +package org.junit.internal.runners.rules; + +import java.lang.annotation.Annotation; +import java.util.List; + +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.rules.TestRule; +import org.junit.runners.model.FrameworkField; +import org.junit.runners.model.TestClass; + +/** + * A RuleFieldValidator validates the rule fields of a + * {@link org.junit.runners.model.TestClass}. All reasons for rejecting the + * {@code TestClass} are written to a list of errors. + * + * There are two slightly different validators. The {@link #CLASS_RULE_VALIDATOR} + * validates fields with a {@link ClassRule} annotation and the + * {@link #RULE_VALIDATOR} validates fields with a {@link Rule} annotation. + */ +public enum RuleFieldValidator { + /** + * Validates fields with a {@link ClassRule} annotation. + */ + CLASS_RULE_VALIDATOR(ClassRule.class, true), + /** + * Validates fields with a {@link Rule} annotation. + */ + RULE_VALIDATOR(Rule.class, false); + + private final Class<? extends Annotation> fAnnotation; + + private final boolean fOnlyStaticFields; + + private RuleFieldValidator(Class<? extends Annotation> annotation, + boolean onlyStaticFields) { + this.fAnnotation= annotation; + this.fOnlyStaticFields= onlyStaticFields; + } + + /** + * Validate the {@link org.junit.runners.model.TestClass} and adds reasons + * for rejecting the class to a list of errors. + * @param target the {@code TestClass} to validate. + * @param errors the list of errors. + */ + public void validate(TestClass target, List<Throwable> errors) { + List<FrameworkField> fields= target.getAnnotatedFields(fAnnotation); + for (FrameworkField each : fields) + validateField(each, errors); + } + + private void validateField(FrameworkField field, List<Throwable> errors) { + optionallyValidateStatic(field, errors); + validatePublic(field, errors); + validateTestRuleOrMethodRule(field, errors); + } + + private void optionallyValidateStatic(FrameworkField field, + List<Throwable> errors) { + if (fOnlyStaticFields && !field.isStatic()) + addError(errors, field, "must be static."); + } + + private void validatePublic(FrameworkField field, List<Throwable> errors) { + if (!field.isPublic()) + addError(errors, field, "must be public."); + } + + private void validateTestRuleOrMethodRule(FrameworkField field, + List<Throwable> errors) { + if (!isMethodRule(field) && !isTestRule(field)) + addError(errors, field, "must implement MethodRule or TestRule."); + } + + private boolean isTestRule(FrameworkField target) { + return TestRule.class.isAssignableFrom(target.getType()); + } + + @SuppressWarnings("deprecation") + private boolean isMethodRule(FrameworkField target) { + return org.junit.rules.MethodRule.class.isAssignableFrom(target + .getType()); + } + + private void addError(List<Throwable> errors, FrameworkField field, + String suffix) { + String message= "The @" + fAnnotation.getSimpleName() + " '" + + field.getName() + "' " + suffix; + errors.add(new Exception(message)); + } +} diff --git a/src/org/junit/internal/runners/statements/ExpectException.java b/src/org/junit/internal/runners/statements/ExpectException.java new file mode 100644 index 0000000..ddfef07 --- /dev/null +++ b/src/org/junit/internal/runners/statements/ExpectException.java @@ -0,0 +1,38 @@ +/** + * + */ +package org.junit.internal.runners.statements; + +import org.junit.internal.AssumptionViolatedException; +import org.junit.runners.model.Statement; + +public class ExpectException extends Statement { + private Statement fNext; + private final Class<? extends Throwable> fExpected; + + public ExpectException(Statement next, Class<? extends Throwable> expected) { + fNext= next; + fExpected= expected; + } + + @Override + public void evaluate() throws Exception { + boolean complete = false; + try { + fNext.evaluate(); + complete = true; + } catch (AssumptionViolatedException e) { + throw e; + } catch (Throwable e) { + if (!fExpected.isAssignableFrom(e.getClass())) { + String message= "Unexpected exception, expected<" + + fExpected.getName() + "> but was<" + + e.getClass().getName() + ">"; + throw new Exception(message, e); + } + } + if (complete) + throw new AssertionError("Expected exception: " + + fExpected.getName()); + } +}
\ No newline at end of file diff --git a/src/org/junit/internal/runners/statements/Fail.java b/src/org/junit/internal/runners/statements/Fail.java new file mode 100644 index 0000000..e7d0d5c --- /dev/null +++ b/src/org/junit/internal/runners/statements/Fail.java @@ -0,0 +1,17 @@ +package org.junit.internal.runners.statements; + +import org.junit.runners.model.Statement; + + +public class Fail extends Statement { + private final Throwable fError; + + public Fail(Throwable e) { + fError= e; + } + + @Override + public void evaluate() throws Throwable { + throw fError; + } +} diff --git a/src/org/junit/internal/runners/statements/FailOnTimeout.java b/src/org/junit/internal/runners/statements/FailOnTimeout.java new file mode 100644 index 0000000..bff7c72 --- /dev/null +++ b/src/org/junit/internal/runners/statements/FailOnTimeout.java @@ -0,0 +1,71 @@ +/** + * + */ +package org.junit.internal.runners.statements; + +import org.junit.runners.model.Statement; + +public class FailOnTimeout extends Statement { + private final Statement fOriginalStatement; + + private final long fTimeout; + + public FailOnTimeout(Statement originalStatement, long timeout) { + fOriginalStatement= originalStatement; + fTimeout= timeout; + } + + @Override + public void evaluate() throws Throwable { + StatementThread thread= evaluateStatement(); + if (!thread.fFinished) + throwExceptionForUnfinishedThread(thread); + } + + private StatementThread evaluateStatement() throws InterruptedException { + StatementThread thread= new StatementThread(fOriginalStatement); + thread.start(); + thread.join(fTimeout); + thread.interrupt(); + return thread; + } + + private void throwExceptionForUnfinishedThread(StatementThread thread) + throws Throwable { + if (thread.fExceptionThrownByOriginalStatement != null) + throw thread.fExceptionThrownByOriginalStatement; + else + throwTimeoutException(thread); + } + + private void throwTimeoutException(StatementThread thread) throws Exception { + Exception exception= new Exception(String.format( + "test timed out after %d milliseconds", fTimeout)); + exception.setStackTrace(thread.getStackTrace()); + throw exception; + } + + private static class StatementThread extends Thread { + private final Statement fStatement; + + private boolean fFinished= false; + + private Throwable fExceptionThrownByOriginalStatement= null; + + public StatementThread(Statement statement) { + fStatement= statement; + } + + @Override + public void run() { + try { + fStatement.evaluate(); + fFinished= true; + } catch (InterruptedException e) { + //don't log the InterruptedException + } catch (Throwable e) { + fExceptionThrownByOriginalStatement= e; + } + } + } +}
\ No newline at end of file diff --git a/src/org/junit/internal/runners/statements/InvokeMethod.java b/src/org/junit/internal/runners/statements/InvokeMethod.java new file mode 100644 index 0000000..e2e81e1 --- /dev/null +++ b/src/org/junit/internal/runners/statements/InvokeMethod.java @@ -0,0 +1,22 @@ +/** + * + */ +package org.junit.internal.runners.statements; + +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.Statement; + +public class InvokeMethod extends Statement { + private final FrameworkMethod fTestMethod; + private Object fTarget; + + public InvokeMethod(FrameworkMethod testMethod, Object target) { + fTestMethod= testMethod; + fTarget= target; + } + + @Override + public void evaluate() throws Throwable { + fTestMethod.invokeExplosively(fTarget); + } +}
\ No newline at end of file diff --git a/src/org/junit/internal/runners/statements/RunAfters.java b/src/org/junit/internal/runners/statements/RunAfters.java new file mode 100644 index 0000000..475ec72 --- /dev/null +++ b/src/org/junit/internal/runners/statements/RunAfters.java @@ -0,0 +1,43 @@ +/** + * + */ +package org.junit.internal.runners.statements; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.MultipleFailureException; +import org.junit.runners.model.Statement; + +public class RunAfters extends Statement { + private final Statement fNext; + + private final Object fTarget; + + private final List<FrameworkMethod> fAfters; + + public RunAfters(Statement next, List<FrameworkMethod> afters, Object target) { + fNext= next; + fAfters= afters; + fTarget= target; + } + + @Override + public void evaluate() throws Throwable { + List<Throwable> errors = new ArrayList<Throwable>(); + try { + fNext.evaluate(); + } catch (Throwable e) { + errors.add(e); + } finally { + for (FrameworkMethod each : fAfters) + try { + each.invokeExplosively(fTarget); + } catch (Throwable e) { + errors.add(e); + } + } + MultipleFailureException.assertEmpty(errors); + } +}
\ No newline at end of file diff --git a/src/org/junit/internal/runners/statements/RunBefores.java b/src/org/junit/internal/runners/statements/RunBefores.java new file mode 100644 index 0000000..66a34e1 --- /dev/null +++ b/src/org/junit/internal/runners/statements/RunBefores.java @@ -0,0 +1,30 @@ +/** + * + */ +package org.junit.internal.runners.statements; + +import java.util.List; + +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.Statement; + +public class RunBefores extends Statement { + private final Statement fNext; + + private final Object fTarget; + + private final List<FrameworkMethod> fBefores; + + public RunBefores(Statement next, List<FrameworkMethod> befores, Object target) { + fNext= next; + fBefores= befores; + fTarget= target; + } + + @Override + public void evaluate() throws Throwable { + for (FrameworkMethod before : fBefores) + before.invokeExplosively(fTarget); + fNext.evaluate(); + } +}
\ No newline at end of file |