aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/junit/runners
diff options
context:
space:
mode:
authorPaul Duffin <paulduffin@google.com>2016-12-14 11:13:37 +0000
committerPaul Duffin <paulduffin@google.com>2016-12-15 18:53:12 +0000
commit4dd042caba6f0ee54f604a409df7152b3e8205bb (patch)
treefd9aa7f11b8c8f927c9e98fd828e60086895ca5e /src/main/java/org/junit/runners
parent50db5f5810104e1dd0b0294145e9d3e602bb2627 (diff)
downloadjunit-4dd042caba6f0ee54f604a409df7152b3e8205bb.tar.gz
Moved source to match upstream file structure
Will make it simpler to update JUnit source. Bug: 33613916 Test: make checkbuild Change-Id: I76984a6defd3e40f34eea995e6ed865d32d53da3
Diffstat (limited to 'src/main/java/org/junit/runners')
-rw-r--r--src/main/java/org/junit/runners/AllTests.java24
-rw-r--r--src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java407
-rw-r--r--src/main/java/org/junit/runners/JUnit4.java22
-rw-r--r--src/main/java/org/junit/runners/Parameterized.java167
-rw-r--r--src/main/java/org/junit/runners/ParentRunner.java378
-rw-r--r--src/main/java/org/junit/runners/Suite.java130
-rw-r--r--src/main/java/org/junit/runners/model/FrameworkField.java65
-rw-r--r--src/main/java/org/junit/runners/model/FrameworkMember.java20
-rw-r--r--src/main/java/org/junit/runners/model/FrameworkMethod.java156
-rw-r--r--src/main/java/org/junit/runners/model/InitializationError.java39
-rw-r--r--src/main/java/org/junit/runners/model/MultipleFailureException.java60
-rw-r--r--src/main/java/org/junit/runners/model/NoGenericTypeParametersValidator.java53
-rw-r--r--src/main/java/org/junit/runners/model/RunnerBuilder.java104
-rw-r--r--src/main/java/org/junit/runners/model/RunnerScheduler.java21
-rw-r--r--src/main/java/org/junit/runners/model/Statement.java16
-rw-r--r--src/main/java/org/junit/runners/model/TestClass.java159
-rw-r--r--src/main/java/org/junit/runners/package-info.java8
17 files changed, 1829 insertions, 0 deletions
diff --git a/src/main/java/org/junit/runners/AllTests.java b/src/main/java/org/junit/runners/AllTests.java
new file mode 100644
index 0000000..50c02db
--- /dev/null
+++ b/src/main/java/org/junit/runners/AllTests.java
@@ -0,0 +1,24 @@
+package org.junit.runners;
+
+import org.junit.internal.runners.SuiteMethod;
+
+/** Runner for use with JUnit 3.8.x-style AllTests classes
+ * (those that only implement a static <code>suite()</code>
+ * method). For example:
+ * <pre>
+ * &#064;RunWith(AllTests.class)
+ * public class ProductTests {
+ * public static junit.framework.Test suite() {
+ * ...
+ * }
+ * }
+ * </pre>
+ */
+public class AllTests extends SuiteMethod {
+ /**
+ * Only called reflectively. Do not use programmatically.
+ */
+ public AllTests(Class<?> klass) throws Throwable {
+ super(klass);
+ }
+}
diff --git a/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java b/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java
new file mode 100644
index 0000000..92e0d07
--- /dev/null
+++ b/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java
@@ -0,0 +1,407 @@
+package org.junit.runners;
+
+import static org.junit.internal.runners.rules.RuleFieldValidator.RULE_VALIDATOR;
+
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.Test.None;
+import org.junit.internal.runners.model.ReflectiveCallable;
+import org.junit.internal.runners.statements.ExpectException;
+import org.junit.internal.runners.statements.Fail;
+import org.junit.internal.runners.statements.FailOnTimeout;
+import org.junit.internal.runners.statements.InvokeMethod;
+import org.junit.internal.runners.statements.RunAfters;
+import org.junit.internal.runners.statements.RunBefores;
+import org.junit.rules.RunRules;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.MultipleFailureException;
+import org.junit.runners.model.Statement;
+
+/**
+ * Implements the JUnit 4 standard test case class model, as defined by the
+ * annotations in the org.junit package. Many users will never notice this
+ * class: it is now the default test class runner, but it should have exactly
+ * the same behavior as the old test class runner ({@code JUnit4ClassRunner}).
+ *
+ * BlockJUnit4ClassRunner has advantages for writers of custom JUnit runners
+ * that are slight changes to the default behavior, however:
+ *
+ * <ul>
+ * <li>It has a much simpler implementation based on {@link Statement}s,
+ * allowing new operations to be inserted into the appropriate point in the
+ * execution flow.
+ *
+ * <li>It is published, and extension and reuse are encouraged, whereas {@code
+ * JUnit4ClassRunner} was in an internal package, and is now deprecated.
+ * </ul>
+ */
+public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> {
+ /**
+ * Creates a BlockJUnit4ClassRunner to run {@code klass}
+ *
+ * @throws InitializationError
+ * if the test class is malformed.
+ */
+ public BlockJUnit4ClassRunner(Class<?> klass) throws InitializationError {
+ super(klass);
+ }
+
+ //
+ // Implementation of ParentRunner
+ //
+
+ @Override
+ protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
+ Description description= describeChild(method);
+ if (method.getAnnotation(Ignore.class) != null) {
+ notifier.fireTestIgnored(description);
+ } else {
+ runLeaf(methodBlock(method), description, notifier);
+ }
+ }
+
+ @Override
+ protected Description describeChild(FrameworkMethod method) {
+ return Description.createTestDescription(getTestClass().getJavaClass(),
+ testName(method), method.getAnnotations());
+ }
+
+ @Override
+ protected List<FrameworkMethod> getChildren() {
+ return computeTestMethods();
+ }
+
+ //
+ // Override in subclasses
+ //
+
+ /**
+ * Returns the methods that run tests. Default implementation returns all
+ * methods annotated with {@code @Test} on this class and superclasses that
+ * are not overridden.
+ */
+ protected List<FrameworkMethod> computeTestMethods() {
+ return getTestClass().getAnnotatedMethods(Test.class);
+ }
+
+ @Override
+ protected void collectInitializationErrors(List<Throwable> errors) {
+ super.collectInitializationErrors(errors);
+
+ validateNoNonStaticInnerClass(errors);
+ validateConstructor(errors);
+ validateInstanceMethods(errors);
+ validateFields(errors);
+ }
+
+ protected void validateNoNonStaticInnerClass(List<Throwable> errors) {
+ if (getTestClass().isANonStaticInnerClass()) {
+ String gripe= "The inner class " + getTestClass().getName()
+ + " is not static.";
+ errors.add(new Exception(gripe));
+ }
+ }
+
+ /**
+ * Adds to {@code errors} if the test class has more than one constructor,
+ * or if the constructor takes parameters. Override if a subclass requires
+ * different validation rules.
+ */
+ protected void validateConstructor(List<Throwable> errors) {
+ validateOnlyOneConstructor(errors);
+ validateZeroArgConstructor(errors);
+ }
+
+ /**
+ * Adds to {@code errors} if the test class has more than one constructor
+ * (do not override)
+ */
+ protected void validateOnlyOneConstructor(List<Throwable> errors) {
+ if (!hasOneConstructor()) {
+ String gripe= "Test class should have exactly one public constructor";
+ errors.add(new Exception(gripe));
+ }
+ }
+
+ /**
+ * Adds to {@code errors} if the test class's single constructor takes
+ * parameters (do not override)
+ */
+ protected void validateZeroArgConstructor(List<Throwable> errors) {
+ if (!getTestClass().isANonStaticInnerClass()
+ && hasOneConstructor()
+ && (getTestClass().getOnlyConstructor().getParameterTypes().length != 0)) {
+ String gripe= "Test class should have exactly one public zero-argument constructor";
+ errors.add(new Exception(gripe));
+ }
+ }
+
+ private boolean hasOneConstructor() {
+ return getTestClass().getJavaClass().getConstructors().length == 1;
+ }
+
+ /**
+ * Adds to {@code errors} for each method annotated with {@code @Test},
+ * {@code @Before}, or {@code @After} that is not a public, void instance
+ * method with no arguments.
+ *
+ * @deprecated unused API, will go away in future version
+ */
+ @Deprecated
+ protected void validateInstanceMethods(List<Throwable> errors) {
+ validatePublicVoidNoArgMethods(After.class, false, errors);
+ validatePublicVoidNoArgMethods(Before.class, false, errors);
+ validateTestMethods(errors);
+
+ if (computeTestMethods().size() == 0)
+ errors.add(new Exception("No runnable methods"));
+ }
+
+ private void validateFields(List<Throwable> errors) {
+ RULE_VALIDATOR.validate(getTestClass(), errors);
+ }
+
+ /**
+ * Adds to {@code errors} for each method annotated with {@code @Test}that
+ * is not a public, void instance method with no arguments.
+ */
+ protected void validateTestMethods(List<Throwable> errors) {
+ validatePublicVoidNoArgMethods(Test.class, false, errors);
+ }
+
+ /**
+ * Returns a new fixture for running a test. Default implementation executes
+ * the test class's no-argument constructor (validation should have ensured
+ * one exists).
+ */
+ protected Object createTest() throws Exception {
+ return getTestClass().getOnlyConstructor().newInstance();
+ }
+
+ /**
+ * Returns the name that describes {@code method} for {@link Description}s.
+ * Default implementation is the method's name
+ */
+ protected String testName(FrameworkMethod method) {
+ return method.getName();
+ }
+
+ /**
+ * Returns a Statement that, when executed, either returns normally if
+ * {@code method} passes, or throws an exception if {@code method} fails.
+ *
+ * Here is an outline of the default implementation:
+ *
+ * <ul>
+ * <li>Invoke {@code method} on the result of {@code createTest()}, and
+ * throw any exceptions thrown by either operation.
+ * <li>HOWEVER, if {@code method}'s {@code @Test} annotation has the {@code
+ * expecting} attribute, return normally only if the previous step threw an
+ * exception of the correct type, and throw an exception otherwise.
+ * <li>HOWEVER, if {@code method}'s {@code @Test} annotation has the {@code
+ * timeout} attribute, throw an exception if the previous step takes more
+ * than the specified number of milliseconds.
+ * <li>ALWAYS run all non-overridden {@code @Before} methods on this class
+ * and superclasses before any of the previous steps; if any throws an
+ * Exception, stop execution and pass the exception on.
+ * <li>ALWAYS run all non-overridden {@code @After} methods on this class
+ * and superclasses after any of the previous steps; all After methods are
+ * always executed: exceptions thrown by previous steps are combined, if
+ * necessary, with exceptions from After methods into a
+ * {@link MultipleFailureException}.
+ * <li>ALWAYS allow {@code @Rule} fields to modify the execution of the
+ * above steps. A {@code Rule} may prevent all execution of the above steps,
+ * or add additional behavior before and after, or modify thrown exceptions.
+ * For more information, see {@link TestRule}
+ * </ul>
+ *
+ * This can be overridden in subclasses, either by overriding this method,
+ * or the implementations creating each sub-statement.
+ */
+ protected Statement methodBlock(FrameworkMethod method) {
+ Object test;
+ try {
+ test= new ReflectiveCallable() {
+ @Override
+ protected Object runReflectiveCall() throws Throwable {
+ return createTest();
+ }
+ }.run();
+ } catch (Throwable e) {
+ return new Fail(e);
+ }
+
+ Statement statement= methodInvoker(method, test);
+ statement= possiblyExpectingExceptions(method, test, statement);
+ statement= withPotentialTimeout(method, test, statement);
+ statement= withBefores(method, test, statement);
+ statement= withAfters(method, test, statement);
+ statement= withRules(method, test, statement);
+ return statement;
+ }
+
+ //
+ // Statement builders
+ //
+
+ /**
+ * Returns a {@link Statement} that invokes {@code method} on {@code test}
+ */
+ protected Statement methodInvoker(FrameworkMethod method, Object test) {
+ return new InvokeMethod(method, test);
+ }
+
+ /**
+ * Returns a {@link Statement}: if {@code method}'s {@code @Test} annotation
+ * has the {@code expecting} attribute, return normally only if {@code next}
+ * throws an exception of the correct type, and throw an exception
+ * otherwise.
+ *
+ * @deprecated Will be private soon: use Rules instead
+ */
+ @Deprecated
+ protected Statement possiblyExpectingExceptions(FrameworkMethod method,
+ Object test, Statement next) {
+ Test annotation= method.getAnnotation(Test.class);
+ return expectsException(annotation) ? new ExpectException(next,
+ getExpectedException(annotation)) : next;
+ }
+
+ /**
+ * Returns a {@link Statement}: if {@code method}'s {@code @Test} annotation
+ * has the {@code timeout} attribute, throw an exception if {@code next}
+ * takes more than the specified number of milliseconds.
+ *
+ * @deprecated Will be private soon: use Rules instead
+ */
+ @Deprecated
+ protected Statement withPotentialTimeout(FrameworkMethod method,
+ Object test, Statement next) {
+ long timeout= getTimeout(method.getAnnotation(Test.class));
+ return timeout > 0 ? new FailOnTimeout(next, timeout) : next;
+ }
+
+ /**
+ * Returns a {@link Statement}: run all non-overridden {@code @Before}
+ * methods on this class and superclasses before running {@code next}; if
+ * any throws an Exception, stop execution and pass the exception on.
+ *
+ * @deprecated Will be private soon: use Rules instead
+ */
+ @Deprecated
+ protected Statement withBefores(FrameworkMethod method, Object target,
+ Statement statement) {
+ List<FrameworkMethod> befores= getTestClass().getAnnotatedMethods(
+ Before.class);
+ return befores.isEmpty() ? statement : new RunBefores(statement,
+ befores, target);
+ }
+
+ /**
+ * Returns a {@link Statement}: run all non-overridden {@code @After}
+ * methods on this class and superclasses before running {@code next}; all
+ * After methods are always executed: exceptions thrown by previous steps
+ * are combined, if necessary, with exceptions from After methods into a
+ * {@link MultipleFailureException}.
+ *
+ * @deprecated Will be private soon: use Rules instead
+ */
+ @Deprecated
+ protected Statement withAfters(FrameworkMethod method, Object target,
+ Statement statement) {
+ List<FrameworkMethod> afters= getTestClass().getAnnotatedMethods(
+ After.class);
+ return afters.isEmpty() ? statement : new RunAfters(statement, afters,
+ target);
+ }
+
+ private Statement withRules(FrameworkMethod method, Object target,
+ Statement statement) {
+ Statement result= statement;
+ result= withMethodRules(method, target, result);
+ result= withTestRules(method, target, result);
+ return result;
+ }
+
+ @SuppressWarnings("deprecation")
+ private Statement withMethodRules(FrameworkMethod method, Object target,
+ Statement result) {
+ List<TestRule> testRules= getTestRules(target);
+ for (org.junit.rules.MethodRule each : getMethodRules(target))
+ if (! testRules.contains(each))
+ result= each.apply(result, method, target);
+ return result;
+ }
+
+ @SuppressWarnings("deprecation")
+ private List<org.junit.rules.MethodRule> getMethodRules(Object target) {
+ return rules(target);
+ }
+
+ /**
+ * @param target
+ * the test case instance
+ * @return a list of MethodRules that should be applied when executing this
+ * test
+ * @deprecated {@link org.junit.rules.MethodRule} is a deprecated interface. Port to
+ * {@link TestRule} and
+ * {@link BlockJUnit4ClassRunner#getTestRules(Object)}
+ */
+ @Deprecated
+ protected List<org.junit.rules.MethodRule> rules(Object target) {
+ return getTestClass().getAnnotatedFieldValues(target, Rule.class,
+ org.junit.rules.MethodRule.class);
+ }
+
+ /**
+ * Returns a {@link Statement}: apply all non-static {@link Value} fields
+ * annotated with {@link Rule}.
+ *
+ * @param statement The base statement
+ * @return a RunRules statement if any class-level {@link Rule}s are
+ * found, or the base statement
+ */
+ private Statement withTestRules(FrameworkMethod method, Object target,
+ Statement statement) {
+ List<TestRule> testRules= getTestRules(target);
+ return testRules.isEmpty() ? statement :
+ new RunRules(statement, testRules, describeChild(method));
+ }
+
+ /**
+ * @param target
+ * the test case instance
+ * @return a list of TestRules that should be applied when executing this
+ * test
+ */
+ protected List<TestRule> getTestRules(Object target) {
+ return getTestClass().getAnnotatedFieldValues(target,
+ Rule.class, TestRule.class);
+ }
+
+ private Class<? extends Throwable> getExpectedException(Test annotation) {
+ if (annotation == null || annotation.expected() == None.class)
+ return null;
+ else
+ return annotation.expected();
+ }
+
+ private boolean expectsException(Test annotation) {
+ return getExpectedException(annotation) != null;
+ }
+
+ private long getTimeout(Test annotation) {
+ if (annotation == null)
+ return 0;
+ return annotation.timeout();
+ }
+}
diff --git a/src/main/java/org/junit/runners/JUnit4.java b/src/main/java/org/junit/runners/JUnit4.java
new file mode 100644
index 0000000..1e1f347
--- /dev/null
+++ b/src/main/java/org/junit/runners/JUnit4.java
@@ -0,0 +1,22 @@
+package org.junit.runners;
+
+import org.junit.runners.model.InitializationError;
+
+/**
+ * Aliases the current default JUnit 4 class runner, for future-proofing. If
+ * future versions of JUnit change the default Runner class, they will also
+ * change the definition of this class. Developers wanting to explicitly tag a
+ * class as a JUnit 4 class should use {@code @RunWith(JUnit4.class)}, not,
+ * for example in JUnit 4.5, {@code @RunWith(BlockJUnit4ClassRunner.class)}.
+ * This is the only way this class should be used--any extension that
+ * depends on the implementation details of this class is likely to break
+ * in future versions.
+ */
+public final class JUnit4 extends BlockJUnit4ClassRunner {
+ /**
+ * Constructs a new instance of the default runner
+ */
+ public JUnit4(Class<?> klass) throws InitializationError {
+ super(klass);
+ }
+}
diff --git a/src/main/java/org/junit/runners/Parameterized.java b/src/main/java/org/junit/runners/Parameterized.java
new file mode 100644
index 0000000..3ebfead
--- /dev/null
+++ b/src/main/java/org/junit/runners/Parameterized.java
@@ -0,0 +1,167 @@
+package org.junit.runners;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.runner.Runner;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.Statement;
+import org.junit.runners.model.TestClass;
+
+/**
+ * <p>
+ * The custom runner <code>Parameterized</code> implements parameterized tests.
+ * When running a parameterized test class, instances are created for the
+ * cross-product of the test methods and the test data elements.
+ * </p>
+ *
+ * For example, to test a Fibonacci function, write:
+ *
+ * <pre>
+ * &#064;RunWith(Parameterized.class)
+ * public class FibonacciTest {
+ * &#064;Parameters
+ * public static List&lt;Object[]&gt; data() {
+ * return Arrays.asList(new Object[][] {
+ * { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 }
+ * });
+ * }
+ *
+ * private int fInput;
+ *
+ * private int fExpected;
+ *
+ * public FibonacciTest(int input, int expected) {
+ * fInput= input;
+ * fExpected= expected;
+ * }
+ *
+ * &#064;Test
+ * public void test() {
+ * assertEquals(fExpected, Fibonacci.compute(fInput));
+ * }
+ * }
+ * </pre>
+ *
+ * <p>
+ * Each instance of <code>FibonacciTest</code> will be constructed using the
+ * two-argument constructor and the data values in the
+ * <code>&#064;Parameters</code> method.
+ * </p>
+ */
+public class Parameterized extends Suite {
+ /**
+ * Annotation for a method which provides parameters to be injected into the
+ * test class constructor by <code>Parameterized</code>
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.METHOD)
+ public static @interface Parameters {
+ }
+
+ private class TestClassRunnerForParameters extends
+ BlockJUnit4ClassRunner {
+ private final int fParameterSetNumber;
+
+ private final List<Object[]> fParameterList;
+
+ TestClassRunnerForParameters(Class<?> type,
+ List<Object[]> parameterList, int i) throws InitializationError {
+ super(type);
+ fParameterList= parameterList;
+ fParameterSetNumber= i;
+ }
+
+ @Override
+ public Object createTest() throws Exception {
+ return getTestClass().getOnlyConstructor().newInstance(
+ computeParams());
+ }
+
+ private Object[] computeParams() throws Exception {
+ try {
+ return fParameterList.get(fParameterSetNumber);
+ } catch (ClassCastException e) {
+ throw new Exception(String.format(
+ "%s.%s() must return a Collection of arrays.",
+ getTestClass().getName(), getParametersMethod(
+ getTestClass()).getName()));
+ }
+ }
+
+ @Override
+ protected String getName() {
+ return String.format("[%s]", fParameterSetNumber);
+ }
+
+ @Override
+ protected String testName(final FrameworkMethod method) {
+ return String.format("%s[%s]", method.getName(),
+ fParameterSetNumber);
+ }
+
+ @Override
+ protected void validateConstructor(List<Throwable> errors) {
+ validateOnlyOneConstructor(errors);
+ }
+
+ @Override
+ protected Statement classBlock(RunNotifier notifier) {
+ return childrenInvoker(notifier);
+ }
+
+ @Override
+ protected Annotation[] getRunnerAnnotations() {
+ return new Annotation[0];
+ }
+ }
+
+ private final ArrayList<Runner> runners= new ArrayList<Runner>();
+
+ /**
+ * Only called reflectively. Do not use programmatically.
+ */
+ public Parameterized(Class<?> klass) throws Throwable {
+ super(klass, Collections.<Runner>emptyList());
+ List<Object[]> parametersList= getParametersList(getTestClass());
+ for (int i= 0; i < parametersList.size(); i++)
+ runners.add(new TestClassRunnerForParameters(getTestClass().getJavaClass(),
+ parametersList, i));
+ }
+
+ @Override
+ protected List<Runner> getChildren() {
+ return runners;
+ }
+
+ @SuppressWarnings("unchecked")
+ private List<Object[]> getParametersList(TestClass klass)
+ throws Throwable {
+ return (List<Object[]>) getParametersMethod(klass).invokeExplosively(
+ null);
+ }
+
+ private FrameworkMethod getParametersMethod(TestClass testClass)
+ throws Exception {
+ List<FrameworkMethod> methods= testClass
+ .getAnnotatedMethods(Parameters.class);
+ for (FrameworkMethod each : methods) {
+ int modifiers= each.getMethod().getModifiers();
+ if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))
+ return each;
+ }
+
+ throw new Exception("No public static parameters method on class "
+ + testClass.getName());
+ }
+
+}
diff --git a/src/main/java/org/junit/runners/ParentRunner.java b/src/main/java/org/junit/runners/ParentRunner.java
new file mode 100644
index 0000000..a41aad3
--- /dev/null
+++ b/src/main/java/org/junit/runners/ParentRunner.java
@@ -0,0 +1,378 @@
+package org.junit.runners;
+
+import static org.junit.internal.runners.rules.RuleFieldValidator.CLASS_RULE_VALIDATOR;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.internal.AssumptionViolatedException;
+import org.junit.internal.runners.model.EachTestNotifier;
+import org.junit.internal.runners.statements.RunAfters;
+import org.junit.internal.runners.statements.RunBefores;
+import org.junit.rules.RunRules;
+import org.junit.rules.TestRule;
+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.RunNotifier;
+import org.junit.runner.notification.StoppedByUserException;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.MultipleFailureException;
+import org.junit.runners.model.RunnerScheduler;
+import org.junit.runners.model.Statement;
+import org.junit.runners.model.TestClass;
+
+/**
+ * Provides most of the functionality specific to a Runner that implements a
+ * "parent node" in the test tree, with children defined by objects of some data
+ * type {@code T}. (For {@link BlockJUnit4ClassRunner}, {@code T} is
+ * {@link Method} . For {@link Suite}, {@code T} is {@link Class}.) Subclasses
+ * must implement finding the children of the node, describing each child, and
+ * running each child. ParentRunner will filter and sort children, handle
+ * {@code @BeforeClass} and {@code @AfterClass} methods,
+ * handle annotated {@link ClassRule}s, create a composite
+ * {@link Description}, and run children sequentially.
+ */
+public abstract class ParentRunner<T> extends Runner implements Filterable,
+ Sortable {
+ private final TestClass fTestClass;
+
+ private Sorter fSorter= Sorter.NULL;
+
+ private List<T> fFilteredChildren= null;
+
+ private RunnerScheduler fScheduler= new RunnerScheduler() {
+ public void schedule(Runnable childStatement) {
+ childStatement.run();
+ }
+
+ public void finished() {
+ // do nothing
+ }
+ };
+
+ /**
+ * Constructs a new {@code ParentRunner} that will run {@code @TestClass}
+ * @throws InitializationError
+ */
+ protected ParentRunner(Class<?> testClass) throws InitializationError {
+ fTestClass= new TestClass(testClass);
+ validate();
+ }
+
+ //
+ // Must be overridden
+ //
+
+ /**
+ * Returns a list of objects that define the children of this Runner.
+ */
+ protected abstract List<T> getChildren();
+
+ /**
+ * Returns a {@link Description} for {@code child}, which can be assumed to
+ * be an element of the list returned by {@link ParentRunner#getChildren()}
+ */
+ protected abstract Description describeChild(T child);
+
+ /**
+ * Runs the test corresponding to {@code child}, which can be assumed to be
+ * an element of the list returned by {@link ParentRunner#getChildren()}.
+ * Subclasses are responsible for making sure that relevant test events are
+ * reported through {@code notifier}
+ */
+ protected abstract void runChild(T child, RunNotifier notifier);
+
+ //
+ // May be overridden
+ //
+
+ /**
+ * Adds to {@code errors} a throwable for each problem noted with the test class (available from {@link #getTestClass()}).
+ * Default implementation adds an error for each method annotated with
+ * {@code @BeforeClass} or {@code @AfterClass} that is not
+ * {@code public static void} with no arguments.
+ */
+ protected void collectInitializationErrors(List<Throwable> errors) {
+ validatePublicVoidNoArgMethods(BeforeClass.class, true, errors);
+ validatePublicVoidNoArgMethods(AfterClass.class, true, errors);
+ validateClassRules(errors);
+ }
+
+ /**
+ * Adds to {@code errors} if any method in this class is annotated with
+ * {@code annotation}, but:
+ * <ul>
+ * <li>is not public, or
+ * <li>takes parameters, or
+ * <li>returns something other than void, or
+ * <li>is static (given {@code isStatic is false}), or
+ * <li>is not static (given {@code isStatic is true}).
+ */
+ protected void validatePublicVoidNoArgMethods(Class<? extends Annotation> annotation,
+ boolean isStatic, List<Throwable> errors) {
+ List<FrameworkMethod> methods= getTestClass().getAnnotatedMethods(annotation);
+
+ for (FrameworkMethod eachTestMethod : methods)
+ eachTestMethod.validatePublicVoidNoArg(isStatic, errors);
+ }
+
+ private void validateClassRules(List<Throwable> errors) {
+ CLASS_RULE_VALIDATOR.validate(getTestClass(), errors);
+ }
+
+ /**
+ * Constructs a {@code Statement} to run all of the tests in the test class. Override to add pre-/post-processing.
+ * Here is an outline of the implementation:
+ * <ul>
+ * <li>Call {@link #runChild(Object, RunNotifier)} on each object returned by {@link #getChildren()} (subject to any imposed filter and sort).</li>
+ * <li>ALWAYS run all non-overridden {@code @BeforeClass} methods on this class
+ * and superclasses before the previous step; if any throws an
+ * Exception, stop execution and pass the exception on.
+ * <li>ALWAYS run all non-overridden {@code @AfterClass} methods on this class
+ * and superclasses before any of the previous steps; all AfterClass methods are
+ * always executed: exceptions thrown by previous steps are combined, if
+ * necessary, with exceptions from AfterClass methods into a
+ * {@link MultipleFailureException}.
+ * </ul>
+ * @param notifier
+ * @return {@code Statement}
+ */
+ protected Statement classBlock(final RunNotifier notifier) {
+ Statement statement= childrenInvoker(notifier);
+ statement= withBeforeClasses(statement);
+ statement= withAfterClasses(statement);
+ statement= withClassRules(statement);
+ return statement;
+ }
+
+ /**
+ * Returns a {@link Statement}: run all non-overridden {@code @BeforeClass} methods on this class
+ * and superclasses before executing {@code statement}; if any throws an
+ * Exception, stop execution and pass the exception on.
+ */
+ protected Statement withBeforeClasses(Statement statement) {
+ List<FrameworkMethod> befores= fTestClass
+ .getAnnotatedMethods(BeforeClass.class);
+ return befores.isEmpty() ? statement :
+ new RunBefores(statement, befores, null);
+ }
+
+ /**
+ * Returns a {@link Statement}: run all non-overridden {@code @AfterClass} methods on this class
+ * and superclasses before executing {@code statement}; all AfterClass methods are
+ * always executed: exceptions thrown by previous steps are combined, if
+ * necessary, with exceptions from AfterClass methods into a
+ * {@link MultipleFailureException}.
+ */
+ protected Statement withAfterClasses(Statement statement) {
+ List<FrameworkMethod> afters= fTestClass
+ .getAnnotatedMethods(AfterClass.class);
+ return afters.isEmpty() ? statement :
+ new RunAfters(statement, afters, null);
+ }
+
+ /**
+ * Returns a {@link Statement}: apply all
+ * static fields assignable to {@link TestRule}
+ * annotated with {@link ClassRule}.
+ *
+ * @param statement
+ * the base statement
+ * @return a RunRules statement if any class-level {@link Rule}s are
+ * found, or the base statement
+ */
+ private Statement withClassRules(Statement statement) {
+ List<TestRule> classRules= classRules();
+ return classRules.isEmpty() ? statement :
+ new RunRules(statement, classRules, getDescription());
+ }
+
+ /**
+ * @return the {@code ClassRule}s that can transform the block that runs
+ * each method in the tested class.
+ */
+ protected List<TestRule> classRules() {
+ return fTestClass.getAnnotatedFieldValues(null, ClassRule.class, TestRule.class);
+ }
+
+ /**
+ * Returns a {@link Statement}: Call {@link #runChild(Object, RunNotifier)}
+ * on each object returned by {@link #getChildren()} (subject to any imposed
+ * filter and sort)
+ */
+ protected Statement childrenInvoker(final RunNotifier notifier) {
+ return new Statement() {
+ @Override
+ public void evaluate() {
+ runChildren(notifier);
+ }
+ };
+ }
+
+ private void runChildren(final RunNotifier notifier) {
+ for (final T each : getFilteredChildren())
+ fScheduler.schedule(new Runnable() {
+ public void run() {
+ ParentRunner.this.runChild(each, notifier);
+ }
+ });
+ fScheduler.finished();
+ }
+
+ /**
+ * Returns a name used to describe this Runner
+ */
+ protected String getName() {
+ return fTestClass.getName();
+ }
+
+ //
+ // Available for subclasses
+ //
+
+ /**
+ * Returns a {@link TestClass} object wrapping the class to be executed.
+ */
+ public final TestClass getTestClass() {
+ return fTestClass;
+ }
+
+ /**
+ * Runs a {@link Statement} that represents a leaf (aka atomic) test.
+ */
+ protected final void runLeaf(Statement statement, Description description,
+ RunNotifier notifier) {
+ EachTestNotifier eachNotifier= new EachTestNotifier(notifier, description);
+ eachNotifier.fireTestStarted();
+ try {
+ statement.evaluate();
+ } catch (AssumptionViolatedException e) {
+ eachNotifier.addFailedAssumption(e);
+ } catch (Throwable e) {
+ eachNotifier.addFailure(e);
+ } finally {
+ eachNotifier.fireTestFinished();
+ }
+ }
+
+ /**
+ * @return the annotations that should be attached to this runner's
+ * description.
+ */
+ protected Annotation[] getRunnerAnnotations() {
+ return fTestClass.getAnnotations();
+ }
+
+ //
+ // Implementation of Runner
+ //
+
+ @Override
+ public Description getDescription() {
+ Description description= Description.createSuiteDescription(getName(),
+ getRunnerAnnotations());
+ for (T child : getFilteredChildren())
+ description.addChild(describeChild(child));
+ return description;
+ }
+
+ @Override
+ public void run(final RunNotifier notifier) {
+ EachTestNotifier testNotifier= new EachTestNotifier(notifier,
+ getDescription());
+ try {
+ Statement statement= classBlock(notifier);
+ statement.evaluate();
+ } catch (AssumptionViolatedException e) {
+ testNotifier.fireTestIgnored();
+ } catch (StoppedByUserException e) {
+ throw e;
+ } catch (Throwable e) {
+ testNotifier.addFailure(e);
+ }
+ }
+
+ //
+ // Implementation of Filterable and Sortable
+ //
+
+ public void filter(Filter filter) throws NoTestsRemainException {
+ for (Iterator<T> iter = getFilteredChildren().iterator(); iter.hasNext(); ) {
+ T each = iter.next();
+ if (shouldRun(filter, each))
+ try {
+ filter.apply(each);
+ } catch (NoTestsRemainException e) {
+ iter.remove();
+ }
+ else
+ iter.remove();
+ }
+ if (getFilteredChildren().isEmpty()) {
+ throw new NoTestsRemainException();
+ }
+ }
+
+ public void sort(Sorter sorter) {
+ fSorter= sorter;
+ for (T each : getFilteredChildren())
+ sortChild(each);
+ Collections.sort(getFilteredChildren(), comparator());
+ }
+
+ //
+ // Private implementation
+ //
+
+ private void validate() throws InitializationError {
+ List<Throwable> errors= new ArrayList<Throwable>();
+ collectInitializationErrors(errors);
+ if (!errors.isEmpty())
+ throw new InitializationError(errors);
+ }
+
+ private List<T> getFilteredChildren() {
+ if (fFilteredChildren == null)
+ fFilteredChildren = new ArrayList<T>(getChildren());
+ return fFilteredChildren;
+ }
+
+ private void sortChild(T child) {
+ fSorter.apply(child);
+ }
+
+ private boolean shouldRun(Filter filter, T each) {
+ return filter.shouldRun(describeChild(each));
+ }
+
+ private Comparator<? super T> comparator() {
+ return new Comparator<T>() {
+ public int compare(T o1, T o2) {
+ return fSorter.compare(describeChild(o1), describeChild(o2));
+ }
+ };
+ }
+
+ /**
+ * Sets a scheduler that determines the order and parallelization
+ * of children. Highly experimental feature that may change.
+ */
+ public void setScheduler(RunnerScheduler scheduler) {
+ this.fScheduler = scheduler;
+ }
+}
diff --git a/src/main/java/org/junit/runners/Suite.java b/src/main/java/org/junit/runners/Suite.java
new file mode 100644
index 0000000..1b3bb48
--- /dev/null
+++ b/src/main/java/org/junit/runners/Suite.java
@@ -0,0 +1,130 @@
+package org.junit.runners;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.List;
+
+import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
+import org.junit.runner.Description;
+import org.junit.runner.Runner;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.RunnerBuilder;
+
+/**
+ * Using <code>Suite</code> as a runner allows you to manually
+ * build a suite containing tests from many classes. It is the JUnit 4 equivalent of the JUnit 3.8.x
+ * static {@link junit.framework.Test} <code>suite()</code> method. To use it, annotate a class
+ * with <code>@RunWith(Suite.class)</code> and <code>@SuiteClasses({TestClass1.class, ...})</code>.
+ * When you run this class, it will run all the tests in all the suite classes.
+ */
+public class Suite extends ParentRunner<Runner> {
+ /**
+ * Returns an empty suite.
+ */
+ public static Runner emptySuite() {
+ try {
+ return new Suite((Class<?>)null, new Class<?>[0]);
+ } catch (InitializationError e) {
+ throw new RuntimeException("This shouldn't be possible");
+ }
+ }
+
+ /**
+ * The <code>SuiteClasses</code> annotation specifies the classes to be run when a class
+ * annotated with <code>@RunWith(Suite.class)</code> is run.
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.TYPE)
+ @Inherited
+ public @interface SuiteClasses {
+ /**
+ * @return the classes to be run
+ */
+ public Class<?>[] value();
+ }
+
+ private static Class<?>[] getAnnotatedClasses(Class<?> klass) throws InitializationError {
+ SuiteClasses annotation= klass.getAnnotation(SuiteClasses.class);
+ if (annotation == null)
+ throw new InitializationError(String.format("class '%s' must have a SuiteClasses annotation", klass.getName()));
+ return annotation.value();
+ }
+
+ private final List<Runner> fRunners;
+
+ /**
+ * Called reflectively on classes annotated with <code>@RunWith(Suite.class)</code>
+ *
+ * @param klass the root class
+ * @param builder builds runners for classes in the suite
+ * @throws InitializationError
+ */
+ public Suite(Class<?> klass, RunnerBuilder builder) throws InitializationError {
+ this(builder, klass, getAnnotatedClasses(klass));
+ }
+
+ /**
+ * Call this when there is no single root class (for example, multiple class names
+ * passed on the command line to {@link org.junit.runner.JUnitCore}
+ *
+ * @param builder builds runners for classes in the suite
+ * @param classes the classes in the suite
+ * @throws InitializationError
+ */
+ public Suite(RunnerBuilder builder, Class<?>[] classes) throws InitializationError {
+ this(null, builder.runners(null, classes));
+ }
+
+ /**
+ * Call this when the default builder is good enough. Left in for compatibility with JUnit 4.4.
+ * @param klass the root of the suite
+ * @param suiteClasses the classes in the suite
+ * @throws InitializationError
+ */
+ protected Suite(Class<?> klass, Class<?>[] suiteClasses) throws InitializationError {
+ this(new AllDefaultPossibilitiesBuilder(true), klass, suiteClasses);
+ }
+
+ /**
+ * Called by this class and subclasses once the classes making up the suite have been determined
+ *
+ * @param builder builds runners for classes in the suite
+ * @param klass the root of the suite
+ * @param suiteClasses the classes in the suite
+ * @throws InitializationError
+ */
+ protected Suite(RunnerBuilder builder, Class<?> klass, Class<?>[] suiteClasses) throws InitializationError {
+ this(klass, builder.runners(klass, suiteClasses));
+ }
+
+ /**
+ * Called by this class and subclasses once the runners making up the suite have been determined
+ *
+ * @param klass root of the suite
+ * @param runners for each class in the suite, a {@link Runner}
+ * @throws InitializationError
+ */
+ protected Suite(Class<?> klass, List<Runner> runners) throws InitializationError {
+ super(klass);
+ fRunners = runners;
+ }
+
+ @Override
+ protected List<Runner> getChildren() {
+ return fRunners;
+ }
+
+ @Override
+ protected Description describeChild(Runner child) {
+ return child.getDescription();
+ }
+
+ @Override
+ protected void runChild(Runner runner, final RunNotifier notifier) {
+ runner.run(notifier);
+ }
+}
diff --git a/src/main/java/org/junit/runners/model/FrameworkField.java b/src/main/java/org/junit/runners/model/FrameworkField.java
new file mode 100644
index 0000000..4a4d4a4
--- /dev/null
+++ b/src/main/java/org/junit/runners/model/FrameworkField.java
@@ -0,0 +1,65 @@
+package org.junit.runners.model;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+/**
+ * Represents a field on a test class (currently used only for Rules in
+ * {@link BlockJUnit4ClassRunner}, but custom runners can make other uses)
+ */
+public class FrameworkField extends FrameworkMember<FrameworkField> {
+ private final Field fField;
+
+ FrameworkField(Field field) {
+ fField= field;
+ }
+
+ public String getName() {
+ return getField().getName();
+ }
+
+ @Override
+ public Annotation[] getAnnotations() {
+ return fField.getAnnotations();
+ }
+
+ public boolean isPublic() {
+ int modifiers= fField.getModifiers();
+ return Modifier.isPublic(modifiers);
+ }
+
+ @Override
+ public boolean isShadowedBy(FrameworkField otherMember) {
+ return otherMember.getName().equals(getName());
+ }
+
+ public boolean isStatic() {
+ int modifiers= fField.getModifiers();
+ return Modifier.isStatic(modifiers);
+ }
+
+ /**
+ * @return the underlying java Field
+ */
+ public Field getField() {
+ return fField;
+ }
+
+ /**
+ * @return the underlying Java Field type
+ * @see java.lang.reflect.Field#getType()
+ */
+ public Class<?> getType() {
+ return fField.getType();
+ }
+
+ /**
+ * Attempts to retrieve the value of this field on {@code target}
+ */
+ public Object get(Object target) throws IllegalArgumentException, IllegalAccessException {
+ return fField.get(target);
+ }
+}
diff --git a/src/main/java/org/junit/runners/model/FrameworkMember.java b/src/main/java/org/junit/runners/model/FrameworkMember.java
new file mode 100644
index 0000000..9cccd4b
--- /dev/null
+++ b/src/main/java/org/junit/runners/model/FrameworkMember.java
@@ -0,0 +1,20 @@
+package org.junit.runners.model;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+
+abstract class FrameworkMember<T extends FrameworkMember<T>> {
+ /**
+ * Returns the annotations on this method
+ */
+ abstract Annotation[] getAnnotations();
+
+ abstract boolean isShadowedBy(T otherMember);
+
+ boolean isShadowedBy(List<T> members) {
+ for (T each : members)
+ if (isShadowedBy(each))
+ return true;
+ return false;
+ }
+}
diff --git a/src/main/java/org/junit/runners/model/FrameworkMethod.java b/src/main/java/org/junit/runners/model/FrameworkMethod.java
new file mode 100644
index 0000000..81c8963
--- /dev/null
+++ b/src/main/java/org/junit/runners/model/FrameworkMethod.java
@@ -0,0 +1,156 @@
+package org.junit.runners.model;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.util.List;
+
+import org.junit.internal.runners.model.ReflectiveCallable;
+
+/**
+ * Represents a method on a test class to be invoked at the appropriate point in
+ * test execution. These methods are usually marked with an annotation (such as
+ * {@code @Test}, {@code @Before}, {@code @After}, {@code @BeforeClass},
+ * {@code @AfterClass}, etc.)
+ */
+public class FrameworkMethod extends FrameworkMember<FrameworkMethod> {
+ final Method fMethod;
+
+ /**
+ * Returns a new {@code FrameworkMethod} for {@code method}
+ */
+ public FrameworkMethod(Method method) {
+ fMethod= method;
+ }
+
+ /**
+ * Returns the underlying Java method
+ */
+ public Method getMethod() {
+ return fMethod;
+ }
+
+ /**
+ * Returns the result of invoking this method on {@code target} with
+ * parameters {@code params}. {@link InvocationTargetException}s thrown are
+ * unwrapped, and their causes rethrown.
+ */
+ public Object invokeExplosively(final Object target, final Object... params)
+ throws Throwable {
+ return new ReflectiveCallable() {
+ @Override
+ protected Object runReflectiveCall() throws Throwable {
+ return fMethod.invoke(target, params);
+ }
+ }.run();
+ }
+
+ /**
+ * Returns the method's name
+ */
+ public String getName() {
+ return fMethod.getName();
+ }
+
+ /**
+ * Adds to {@code errors} if this method:
+ * <ul>
+ * <li>is not public, or
+ * <li>takes parameters, or
+ * <li>returns something other than void, or
+ * <li>is static (given {@code isStatic is false}), or
+ * <li>is not static (given {@code isStatic is true}).
+ */
+ public void validatePublicVoidNoArg(boolean isStatic, List<Throwable> errors) {
+ validatePublicVoid(isStatic, errors);
+ if (fMethod.getParameterTypes().length != 0)
+ errors.add(new Exception("Method " + fMethod.getName() + " should have no parameters"));
+ }
+
+
+ /**
+ * Adds to {@code errors} if this method:
+ * <ul>
+ * <li>is not public, or
+ * <li>returns something other than void, or
+ * <li>is static (given {@code isStatic is false}), or
+ * <li>is not static (given {@code isStatic is true}).
+ */
+ public void validatePublicVoid(boolean isStatic, List<Throwable> errors) {
+ if (Modifier.isStatic(fMethod.getModifiers()) != isStatic) {
+ String state= isStatic ? "should" : "should not";
+ errors.add(new Exception("Method " + fMethod.getName() + "() " + state + " be static"));
+ }
+ if (!Modifier.isPublic(fMethod.getDeclaringClass().getModifiers()))
+ errors.add(new Exception("Class " + fMethod.getDeclaringClass().getName() + " should be public"));
+ if (!Modifier.isPublic(fMethod.getModifiers()))
+ errors.add(new Exception("Method " + fMethod.getName() + "() should be public"));
+ if (fMethod.getReturnType() != Void.TYPE)
+ errors.add(new Exception("Method " + fMethod.getName() + "() should be void"));
+ }
+
+ public void validateNoTypeParametersOnArgs(List<Throwable> errors) {
+ new NoGenericTypeParametersValidator(fMethod).validate(errors);
+ }
+
+ @Override
+ public boolean isShadowedBy(FrameworkMethod other) {
+ if (!other.getName().equals(getName()))
+ return false;
+ if (other.getParameterTypes().length != getParameterTypes().length)
+ return false;
+ for (int i= 0; i < other.getParameterTypes().length; i++)
+ if (!other.getParameterTypes()[i].equals(getParameterTypes()[i]))
+ return false;
+ return true;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!FrameworkMethod.class.isInstance(obj))
+ return false;
+ return ((FrameworkMethod) obj).fMethod.equals(fMethod);
+ }
+
+ @Override
+ public int hashCode() {
+ return fMethod.hashCode();
+ }
+
+ /**
+ * Returns true iff this is a no-arg method that returns a value assignable
+ * to {@code type}
+ *
+ * @deprecated This is used only by the Theories runner, and does not
+ * use all the generic type info that it ought to. It will be replaced
+ * with a forthcoming ParameterSignature#canAcceptResultOf(FrameworkMethod)
+ * once Theories moves to junit-contrib.
+ */
+ @Deprecated
+ public boolean producesType(Type type) {
+ return getParameterTypes().length == 0 && type instanceof Class<?>
+ && ((Class<?>) type).isAssignableFrom(fMethod.getReturnType());
+ }
+
+ private Class<?>[] getParameterTypes() {
+ return fMethod.getParameterTypes();
+ }
+
+ /**
+ * Returns the annotations on this method
+ */
+ @Override
+ public Annotation[] getAnnotations() {
+ return fMethod.getAnnotations();
+ }
+
+ /**
+ * Returns the annotation of type {@code annotationType} on this method, if
+ * one exists.
+ */
+ public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
+ return fMethod.getAnnotation(annotationType);
+ }
+}
diff --git a/src/main/java/org/junit/runners/model/InitializationError.java b/src/main/java/org/junit/runners/model/InitializationError.java
new file mode 100644
index 0000000..4de9ea7
--- /dev/null
+++ b/src/main/java/org/junit/runners/model/InitializationError.java
@@ -0,0 +1,39 @@
+package org.junit.runners.model;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Represents one or more problems encountered while initializing a Runner
+ */
+public class InitializationError extends Exception {
+ private static final long serialVersionUID= 1L;
+ private final List<Throwable> fErrors;
+
+ /**
+ * Construct a new {@code InitializationError} with one or more
+ * errors {@code errors} as causes
+ */
+ public InitializationError(List<Throwable> errors) {
+ fErrors= errors;
+ }
+
+ public InitializationError(Throwable error) {
+ this(Arrays.asList(error));
+ }
+
+ /**
+ * Construct a new {@code InitializationError} with one cause
+ * with message {@code string}
+ */
+ public InitializationError(String string) {
+ this(new Exception(string));
+ }
+
+ /**
+ * Returns one or more Throwables that led to this initialization error.
+ */
+ public List<Throwable> getCauses() {
+ return fErrors;
+ }
+}
diff --git a/src/main/java/org/junit/runners/model/MultipleFailureException.java b/src/main/java/org/junit/runners/model/MultipleFailureException.java
new file mode 100644
index 0000000..6d70ca0
--- /dev/null
+++ b/src/main/java/org/junit/runners/model/MultipleFailureException.java
@@ -0,0 +1,60 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+
+package org.junit.runners.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Collects multiple {@code Throwable}s into one exception.
+ */
+public class MultipleFailureException extends Exception {
+ private static final long serialVersionUID= 1L;
+
+ private final List<Throwable> fErrors;
+
+ public MultipleFailureException(List<Throwable> errors) {
+ fErrors= new ArrayList<Throwable>(errors);
+ }
+
+ public List<Throwable> getFailures() {
+ return Collections.unmodifiableList(fErrors);
+ }
+
+ @Override
+ public String getMessage() {
+ StringBuilder sb = new StringBuilder(
+ String.format("There were %d errors:", fErrors.size()));
+ for (Throwable e : fErrors) {
+ sb.append(String.format("\n %s(%s)", e.getClass().getName(), e.getMessage()));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Asserts that a list of throwables is empty. If it isn't empty,
+ * will throw {@link MultipleFailureException} (if there are
+ * multiple throwables in the list) or the first element in the list
+ * (if there is only one element).
+ *
+ * @param errors list to check
+ * @throws Throwable if the list is not empty
+ */
+ @SuppressWarnings("deprecation")
+ public static void assertEmpty(List<Throwable> errors) throws Throwable {
+ if (errors.isEmpty())
+ return;
+ if (errors.size() == 1)
+ throw errors.get(0);
+
+ /*
+ * Many places in the code are documented to throw
+ * org.junit.internal.runners.model.MultipleFailureException.
+ * That class now extends this one, so we throw the internal
+ * exception in case developers have tests that catch
+ * MultipleFailureException.
+ */
+ throw new org.junit.internal.runners.model.MultipleFailureException(errors);
+ }
+}
diff --git a/src/main/java/org/junit/runners/model/NoGenericTypeParametersValidator.java b/src/main/java/org/junit/runners/model/NoGenericTypeParametersValidator.java
new file mode 100644
index 0000000..77662b8
--- /dev/null
+++ b/src/main/java/org/junit/runners/model/NoGenericTypeParametersValidator.java
@@ -0,0 +1,53 @@
+package org.junit.runners.model;
+
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.List;
+
+class NoGenericTypeParametersValidator {
+ private final Method fMethod;
+
+ NoGenericTypeParametersValidator(Method method) {
+ this.fMethod = method;
+ }
+
+ void validate(List<Throwable> errors) {
+ for (Type each : fMethod.getGenericParameterTypes())
+ validateNoTypeParameterOnType(each, errors);
+ }
+
+ private void validateNoTypeParameterOnType(Type type, List<Throwable> errors) {
+ if (type instanceof TypeVariable<?>) {
+ errors.add(new Exception("Method " + fMethod.getName()
+ + "() contains unresolved type variable " + type));
+ } else if (type instanceof ParameterizedType)
+ validateNoTypeParameterOnParameterizedType((ParameterizedType) type, errors);
+ else if (type instanceof WildcardType)
+ validateNoTypeParameterOnWildcardType((WildcardType) type, errors);
+ else if (type instanceof GenericArrayType)
+ validateNoTypeParameterOnGenericArrayType((GenericArrayType) type, errors);
+ }
+
+ private void validateNoTypeParameterOnParameterizedType(ParameterizedType parameterized,
+ List<Throwable> errors) {
+ for (Type each : parameterized.getActualTypeArguments())
+ validateNoTypeParameterOnType(each, errors);
+ }
+
+ private void validateNoTypeParameterOnWildcardType(WildcardType wildcard,
+ List<Throwable> errors) {
+ for (Type each : wildcard.getUpperBounds())
+ validateNoTypeParameterOnType(each, errors);
+ for (Type each : wildcard.getLowerBounds())
+ validateNoTypeParameterOnType(each, errors);
+ }
+
+ private void validateNoTypeParameterOnGenericArrayType(
+ GenericArrayType arrayType, List<Throwable> errors) {
+ validateNoTypeParameterOnType(arrayType.getGenericComponentType(), errors);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/junit/runners/model/RunnerBuilder.java b/src/main/java/org/junit/runners/model/RunnerBuilder.java
new file mode 100644
index 0000000..3a334be
--- /dev/null
+++ b/src/main/java/org/junit/runners/model/RunnerBuilder.java
@@ -0,0 +1,104 @@
+package org.junit.runners.model;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.internal.runners.ErrorReportingRunner;
+import org.junit.runner.Runner;
+
+/**
+ * A RunnerBuilder is a strategy for constructing runners for classes.
+ *
+ * Only writers of custom runners should use <code>RunnerBuilder</code>s. A custom runner class with a constructor taking
+ * a <code>RunnerBuilder</code> parameter will be passed the instance of <code>RunnerBuilder</code> used to build that runner itself.
+ * For example,
+ * imagine a custom runner that builds suites based on a list of classes in a text file:
+ *
+ * <pre>
+ * \@RunWith(TextFileSuite.class)
+ * \@SuiteSpecFile("mysuite.txt")
+ * class MySuite {}
+ * </pre>
+ *
+ * The implementation of TextFileSuite might include:
+ *
+ * <pre>
+ * public TextFileSuite(Class testClass, RunnerBuilder builder) {
+ * // ...
+ * for (String className : readClassNames())
+ * addRunner(builder.runnerForClass(Class.forName(className)));
+ * // ...
+ * }
+ * </pre>
+ *
+ * @see org.junit.runners.Suite
+ */
+public abstract class RunnerBuilder {
+ private final Set<Class<?>> parents= new HashSet<Class<?>>();
+
+ /**
+ * Override to calculate the correct runner for a test class at runtime.
+ *
+ * @param testClass class to be run
+ * @return a Runner
+ * @throws Throwable if a runner cannot be constructed
+ */
+ public abstract Runner runnerForClass(Class<?> testClass) throws Throwable;
+
+ /**
+ * Always returns a runner, even if it is just one that prints an error instead of running tests.
+ * @param testClass class to be run
+ * @return a Runner
+ */
+ public Runner safeRunnerForClass(Class<?> testClass) {
+ try {
+ return runnerForClass(testClass);
+ } catch (Throwable e) {
+ return new ErrorReportingRunner(testClass, e);
+ }
+ }
+
+ Class<?> addParent(Class<?> parent) throws InitializationError {
+ if (!parents.add(parent))
+ throw new InitializationError(String.format("class '%s' (possibly indirectly) contains itself as a SuiteClass", parent.getName()));
+ return parent;
+ }
+
+ void removeParent(Class<?> klass) {
+ parents.remove(klass);
+ }
+
+ /**
+ * Constructs and returns a list of Runners, one for each child class in
+ * {@code children}. Care is taken to avoid infinite recursion:
+ * this builder will throw an exception if it is requested for another
+ * runner for {@code parent} before this call completes.
+ */
+ public List<Runner> runners(Class<?> parent, Class<?>[] children)
+ throws InitializationError {
+ addParent(parent);
+
+ try {
+ return runners(children);
+ } finally {
+ removeParent(parent);
+ }
+ }
+
+ public List<Runner> runners(Class<?> parent, List<Class<?>> children)
+ throws InitializationError {
+ return runners(parent, children.toArray(new Class<?>[0]));
+ }
+
+ private List<Runner> runners(Class<?>[] children) {
+ ArrayList<Runner> runners= new ArrayList<Runner>();
+ for (Class<?> each : children) {
+ Runner childRunner= safeRunnerForClass(each);
+ if (childRunner != null)
+ runners.add(childRunner);
+ }
+ return runners;
+ }
+}
diff --git a/src/main/java/org/junit/runners/model/RunnerScheduler.java b/src/main/java/org/junit/runners/model/RunnerScheduler.java
new file mode 100644
index 0000000..fbc25a4
--- /dev/null
+++ b/src/main/java/org/junit/runners/model/RunnerScheduler.java
@@ -0,0 +1,21 @@
+package org.junit.runners.model;
+
+/**
+ * Represents a strategy for scheduling when individual test methods
+ * should be run (in serial or parallel)
+ *
+ * WARNING: still experimental, may go away.
+ */
+public interface RunnerScheduler {
+ /**
+ * Schedule a child statement to run
+ */
+ void schedule(Runnable childStatement);
+
+ /**
+ * Override to implement any behavior that must occur
+ * after all children have been scheduled (for example,
+ * waiting for them all to finish)
+ */
+ void finished();
+}
diff --git a/src/main/java/org/junit/runners/model/Statement.java b/src/main/java/org/junit/runners/model/Statement.java
new file mode 100644
index 0000000..a7c5478
--- /dev/null
+++ b/src/main/java/org/junit/runners/model/Statement.java
@@ -0,0 +1,16 @@
+/**
+ *
+ */
+package org.junit.runners.model;
+
+
+/**
+ * Represents one or more actions to be taken at runtime in the course
+ * of running a JUnit test suite.
+ */
+public abstract class Statement {
+ /**
+ * Run the action, throwing a {@code Throwable} if anything goes wrong.
+ */
+ public abstract void evaluate() throws Throwable;
+} \ No newline at end of file
diff --git a/src/main/java/org/junit/runners/model/TestClass.java b/src/main/java/org/junit/runners/model/TestClass.java
new file mode 100644
index 0000000..362a13a
--- /dev/null
+++ b/src/main/java/org/junit/runners/model/TestClass.java
@@ -0,0 +1,159 @@
+package org.junit.runners.model;
+
+import static java.lang.reflect.Modifier.isStatic;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+
+/**
+ * Wraps a class to be run, providing method validation and annotation searching
+ */
+public class TestClass {
+ private final Class<?> fClass;
+
+ private Map<Class<?>, List<FrameworkMethod>> fMethodsForAnnotations= new HashMap<Class<?>, List<FrameworkMethod>>();
+
+ private Map<Class<?>, List<FrameworkField>> fFieldsForAnnotations= new HashMap<Class<?>, List<FrameworkField>>();
+
+ /**
+ * Creates a {@code TestClass} wrapping {@code klass}. Each time this
+ * constructor executes, the class is scanned for annotations, which can be
+ * an expensive process (we hope in future JDK's it will not be.) Therefore,
+ * try to share instances of {@code TestClass} where possible.
+ */
+ public TestClass(Class<?> klass) {
+ fClass= klass;
+ if (klass != null && klass.getConstructors().length > 1)
+ throw new IllegalArgumentException(
+ "Test class can only have one constructor");
+
+ for (Class<?> eachClass : getSuperClasses(fClass)) {
+ for (Method eachMethod : eachClass.getDeclaredMethods())
+ addToAnnotationLists(new FrameworkMethod(eachMethod),
+ fMethodsForAnnotations);
+ for (Field eachField : eachClass.getDeclaredFields())
+ addToAnnotationLists(new FrameworkField(eachField),
+ fFieldsForAnnotations);
+ }
+ }
+
+ private <T extends FrameworkMember<T>> void addToAnnotationLists(T member,
+ Map<Class<?>, List<T>> map) {
+ for (Annotation each : member.getAnnotations()) {
+ Class<? extends Annotation> type= each.annotationType();
+ List<T> members= getAnnotatedMembers(map, type);
+ if (member.isShadowedBy(members))
+ return;
+ if (runsTopToBottom(type))
+ members.add(0, member);
+ else
+ members.add(member);
+ }
+ }
+
+ /**
+ * Returns, efficiently, all the non-overridden methods in this class and
+ * its superclasses that are annotated with {@code annotationClass}.
+ */
+ public List<FrameworkMethod> getAnnotatedMethods(
+ Class<? extends Annotation> annotationClass) {
+ return getAnnotatedMembers(fMethodsForAnnotations, annotationClass);
+ }
+
+ /**
+ * Returns, efficiently, all the non-overridden fields in this class and its
+ * superclasses that are annotated with {@code annotationClass}.
+ */
+ public List<FrameworkField> getAnnotatedFields(
+ Class<? extends Annotation> annotationClass) {
+ return getAnnotatedMembers(fFieldsForAnnotations, annotationClass);
+ }
+
+ private <T> List<T> getAnnotatedMembers(Map<Class<?>, List<T>> map,
+ Class<? extends Annotation> type) {
+ if (!map.containsKey(type))
+ map.put(type, new ArrayList<T>());
+ return map.get(type);
+ }
+
+ private boolean runsTopToBottom(Class<? extends Annotation> annotation) {
+ return annotation.equals(Before.class)
+ || annotation.equals(BeforeClass.class);
+ }
+
+ 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;
+ }
+
+ /**
+ * Returns the underlying Java class.
+ */
+ public Class<?> getJavaClass() {
+ return fClass;
+ }
+
+ /**
+ * Returns the class's name.
+ */
+ public String getName() {
+ if (fClass == null)
+ return "null";
+ return fClass.getName();
+ }
+
+ /**
+ * Returns the only public constructor in the class, or throws an {@code
+ * AssertionError} if there are more or less than one.
+ */
+
+ public Constructor<?> getOnlyConstructor() {
+ Constructor<?>[] constructors= fClass.getConstructors();
+ Assert.assertEquals(1, constructors.length);
+ return constructors[0];
+ }
+
+ /**
+ * Returns the annotations on this class
+ */
+ public Annotation[] getAnnotations() {
+ if (fClass == null)
+ return new Annotation[0];
+ return fClass.getAnnotations();
+ }
+
+ public <T> List<T> getAnnotatedFieldValues(Object test,
+ Class<? extends Annotation> annotationClass, Class<T> valueClass) {
+ List<T> results= new ArrayList<T>();
+ for (FrameworkField each : getAnnotatedFields(annotationClass)) {
+ try {
+ Object fieldValue= each.get(test);
+ if (valueClass.isInstance(fieldValue))
+ results.add(valueClass.cast(fieldValue));
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(
+ "How did getFields return a field we couldn't access?", e);
+ }
+ }
+ return results;
+ }
+
+ public boolean isANonStaticInnerClass() {
+ return fClass.isMemberClass() && !isStatic(fClass.getModifiers());
+ }
+}
diff --git a/src/main/java/org/junit/runners/package-info.java b/src/main/java/org/junit/runners/package-info.java
new file mode 100644
index 0000000..418acaf
--- /dev/null
+++ b/src/main/java/org/junit/runners/package-info.java
@@ -0,0 +1,8 @@
+/**
+ * Provides standard {@link org.junit.runner.Runner Runner} implementations.
+ *
+ * @since 4.0
+ * @see org.junit.runner.Runner
+ * @see org.junit.runners.BlockJUnit4ClassRunner
+ */
+package org.junit.runners; \ No newline at end of file