diff options
Diffstat (limited to 'src/main/java/org/junit/runners')
18 files changed, 260 insertions, 962 deletions
diff --git a/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java b/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java index 455341a..4d06199 100644 --- a/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java +++ b/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java @@ -3,10 +3,8 @@ package org.junit.runners; import static org.junit.internal.runners.rules.RuleMemberValidator.RULE_METHOD_VALIDATOR; import static org.junit.internal.runners.rules.RuleMemberValidator.RULE_VALIDATOR; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import org.junit.After; @@ -23,18 +21,14 @@ 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.MethodRule; +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.FrameworkMember; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; -import org.junit.runners.model.MemberValueConsumer; import org.junit.runners.model.MultipleFailureException; import org.junit.runners.model.Statement; -import org.junit.runners.model.TestClass; -import org.junit.validator.PublicClassValidator; -import org.junit.validator.TestClassValidator; /** * Implements the JUnit 4 standard test case class model, as defined by the @@ -61,27 +55,14 @@ import org.junit.validator.TestClassValidator; * @since 4.5 */ public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> { - private static TestClassValidator PUBLIC_CLASS_VALIDATOR = new PublicClassValidator(); - - private final ConcurrentMap<FrameworkMethod, Description> methodDescriptions = new ConcurrentHashMap<FrameworkMethod, Description>(); - - /** - * Creates a BlockJUnit4ClassRunner to run {@code testClass} - * - * @throws InitializationError if the test class is malformed. - */ - public BlockJUnit4ClassRunner(Class<?> testClass) throws InitializationError { - super(testClass); - } - + private final ConcurrentHashMap<FrameworkMethod, Description> methodDescriptions = new ConcurrentHashMap<FrameworkMethod, Description>(); /** - * Creates a BlockJUnit4ClassRunner to run {@code testClass}. + * Creates a BlockJUnit4ClassRunner to run {@code klass} * * @throws InitializationError if the test class is malformed. - * @since 4.13 */ - protected BlockJUnit4ClassRunner(TestClass testClass) throws InitializationError { - super(testClass); + public BlockJUnit4ClassRunner(Class<?> klass) throws InitializationError { + super(klass); } // @@ -94,16 +75,10 @@ public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> { if (isIgnored(method)) { notifier.fireTestIgnored(description); } else { - Statement statement = new Statement() { - @Override - public void evaluate() throws Throwable { - methodBlock(method).evaluate(); - } - }; - runLeaf(statement, description, notifier); + runLeaf(methodBlock(method), description, notifier); } } - + /** * Evaluates whether {@link FrameworkMethod}s are ignored based on the * {@link Ignore} annotation. @@ -148,7 +123,6 @@ public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> { protected void collectInitializationErrors(List<Throwable> errors) { super.collectInitializationErrors(errors); - validatePublicConstructor(errors); validateNoNonStaticInnerClass(errors); validateConstructor(errors); validateInstanceMethods(errors); @@ -156,12 +130,6 @@ public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> { validateMethods(errors); } - private void validatePublicConstructor(List<Throwable> errors) { - if (getTestClass().getJavaClass() != null) { - errors.addAll(PUBLIC_CLASS_VALIDATOR.validateTestClass(getTestClass())); - } - } - protected void validateNoNonStaticInnerClass(List<Throwable> errors) { if (getTestClass().isANonStaticInnerClass()) { String gripe = "The inner class " + getTestClass().getName() @@ -212,7 +180,6 @@ public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> { * 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 */ @Deprecated protected void validateInstanceMethods(List<Throwable> errors) { @@ -220,7 +187,7 @@ public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> { validatePublicVoidNoArgMethods(Before.class, false, errors); validateTestMethods(errors); - if (computeTestMethods().isEmpty()) { + if (computeTestMethods().size() == 0) { errors.add(new Exception("No runnable methods")); } } @@ -251,16 +218,6 @@ public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> { } /** - * Returns a new fixture to run a particular test {@code method} against. - * Default implementation executes the no-argument {@link #createTest()} method. - * - * @since 4.13 - */ - protected Object createTest(FrameworkMethod method) throws Exception { - return createTest(); - } - - /** * Returns the name that describes {@code method} for {@link Description}s. * Default implementation is the method's name */ @@ -275,10 +232,10 @@ public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> { * Here is an outline of the default implementation: * * <ul> - * <li>Invoke {@code method} on the result of {@link #createTest(org.junit.runners.model.FrameworkMethod)}, and + * <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 {@link Test#expected()} - * attribute, return normally only if the previous step threw an + * <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 @@ -300,13 +257,13 @@ public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> { * This can be overridden in subclasses, either by overriding this method, * or the implementations creating each sub-statement. */ - protected Statement methodBlock(final FrameworkMethod method) { + protected Statement methodBlock(FrameworkMethod method) { Object test; try { test = new ReflectiveCallable() { @Override protected Object runReflectiveCall() throws Throwable { - return createTest(method); + return createTest(); } }.run(); } catch (Throwable e) { @@ -319,7 +276,6 @@ public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> { statement = withBefores(method, test, statement); statement = withAfters(method, test, statement); statement = withRules(method, test, statement); - statement = withInterruptIsolation(statement); return statement; } @@ -336,22 +292,21 @@ public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> { /** * Returns a {@link Statement}: if {@code method}'s {@code @Test} annotation - * has the {@link Test#expected()} attribute, return normally only if {@code next} + * has the {@code expecting} attribute, return normally only if {@code next} * throws an exception of the correct type, and throw an exception * otherwise. */ protected Statement possiblyExpectingExceptions(FrameworkMethod method, Object test, Statement next) { Test annotation = method.getAnnotation(Test.class); - Class<? extends Throwable> expectedExceptionClass = getExpectedException(annotation); - return expectedExceptionClass != null ? new ExpectException(next, expectedExceptionClass) : next; + 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 */ @Deprecated protected Statement withPotentialTimeout(FrameworkMethod method, @@ -393,23 +348,28 @@ public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> { target); } - private Statement withRules(FrameworkMethod method, Object target, Statement statement) { - RuleContainer ruleContainer = new RuleContainer(); - CURRENT_RULE_CONTAINER.set(ruleContainer); - try { - List<TestRule> testRules = getTestRules(target); - for (MethodRule each : rules(target)) { - if (!(each instanceof TestRule && testRules.contains(each))) { - ruleContainer.add(each); - } - } - for (TestRule rule : testRules) { - ruleContainer.add(rule); + private Statement withRules(FrameworkMethod method, Object target, + Statement statement) { + List<TestRule> testRules = getTestRules(target); + Statement result = statement; + result = withMethodRules(method, testRules, target, result); + result = withTestRules(method, testRules, result); + + return result; + } + + private Statement withMethodRules(FrameworkMethod method, List<TestRule> testRules, + Object target, Statement result) { + for (org.junit.rules.MethodRule each : getMethodRules(target)) { + if (!testRules.contains(each)) { + result = each.apply(result, method, target); } - } finally { - CURRENT_RULE_CONTAINER.remove(); } - return ruleContainer.apply(method, describeChild(method), target, statement); + return result; + } + + private List<org.junit.rules.MethodRule> getMethodRules(Object target) { + return rules(target); } /** @@ -418,12 +378,27 @@ public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> { * test */ protected List<MethodRule> rules(Object target) { - RuleCollector<MethodRule> collector = new RuleCollector<MethodRule>(); - getTestClass().collectAnnotatedMethodValues(target, Rule.class, MethodRule.class, - collector); - getTestClass().collectAnnotatedFieldValues(target, Rule.class, MethodRule.class, - collector); - return collector.result; + List<MethodRule> rules = getTestClass().getAnnotatedMethodValues(target, + Rule.class, MethodRule.class); + + rules.addAll(getTestClass().getAnnotatedFieldValues(target, + Rule.class, MethodRule.class)); + + return rules; + } + + /** + * Returns a {@link Statement}: apply all non-static 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, List<TestRule> testRules, + Statement statement) { + return testRules.isEmpty() ? statement : + new RunRules(statement, testRules, describeChild(method)); } /** @@ -432,10 +407,13 @@ public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> { * test */ protected List<TestRule> getTestRules(Object target) { - RuleCollector<TestRule> collector = new RuleCollector<TestRule>(); - getTestClass().collectAnnotatedMethodValues(target, Rule.class, TestRule.class, collector); - getTestClass().collectAnnotatedFieldValues(target, Rule.class, TestRule.class, collector); - return collector.result; + List<TestRule> result = getTestClass().getAnnotatedMethodValues(target, + Rule.class, TestRule.class); + + result.addAll(getTestClass().getAnnotatedFieldValues(target, + Rule.class, TestRule.class)); + + return result; } private Class<? extends Throwable> getExpectedException(Test annotation) { @@ -446,28 +424,14 @@ public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> { } } + private boolean expectsException(Test annotation) { + return getExpectedException(annotation) != null; + } + private long getTimeout(Test annotation) { if (annotation == null) { return 0; } return annotation.timeout(); } - - private static final ThreadLocal<RuleContainer> CURRENT_RULE_CONTAINER = - new ThreadLocal<RuleContainer>(); - - private static class RuleCollector<T> implements MemberValueConsumer<T> { - final List<T> result = new ArrayList<T>(); - - public void accept(FrameworkMember<?> member, T value) { - Rule rule = member.getAnnotation(Rule.class); - if (rule != null) { - RuleContainer container = CURRENT_RULE_CONTAINER.get(); - if (container != null) { - container.setOrder(value, rule.order()); - } - } - result.add(value); - } - } } diff --git a/src/main/java/org/junit/runners/JUnit4.java b/src/main/java/org/junit/runners/JUnit4.java index 28eafb3..6ba28c2 100644 --- a/src/main/java/org/junit/runners/JUnit4.java +++ b/src/main/java/org/junit/runners/JUnit4.java @@ -1,7 +1,6 @@ package org.junit.runners; import org.junit.runners.model.InitializationError; -import org.junit.runners.model.TestClass; /** * Aliases the current default JUnit 4 class runner, for future-proofing. If @@ -20,6 +19,6 @@ public final class JUnit4 extends BlockJUnit4ClassRunner { * Constructs a new instance of the default runner */ public JUnit4(Class<?> klass) throws InitializationError { - super(new TestClass(klass)); + super(klass); } } diff --git a/src/main/java/org/junit/runners/Parameterized.java b/src/main/java/org/junit/runners/Parameterized.java index d11b66a..829c8f0 100644 --- a/src/main/java/org/junit/runners/Parameterized.java +++ b/src/main/java/org/junit/runners/Parameterized.java @@ -1,6 +1,5 @@ package org.junit.runners; -import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; @@ -9,18 +8,12 @@ import java.lang.annotation.Target; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.List; -import org.junit.internal.AssumptionViolatedException; -import org.junit.runner.Description; -import org.junit.runner.Result; import org.junit.runner.Runner; -import org.junit.runner.notification.Failure; -import org.junit.runner.notification.RunNotifier; import org.junit.runners.model.FrameworkMethod; -import org.junit.runners.model.InvalidTestClassError; +import org.junit.runners.model.InitializationError; import org.junit.runners.model.TestClass; import org.junit.runners.parameterized.BlockJUnit4ClassRunnerWithParametersFactory; import org.junit.runners.parameterized.ParametersRunnerFactory; @@ -31,37 +24,34 @@ import org.junit.runners.parameterized.TestWithParameters; * 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 the <code>+</code> operator, write: + * For example, to test a Fibonacci function, write: * <pre> * @RunWith(Parameterized.class) - * public class AdditionTest { - * @Parameters(name = "{index}: {0} + {1} = {2}") + * public class FibonacciTest { + * @Parameters(name= "{index}: fib[{0}]={1}") * public static Iterable<Object[]> data() { - * return Arrays.asList(new Object[][] { { 0, 0, 0 }, { 1, 1, 2 }, - * { 3, 2, 5 }, { 4, 3, 7 } }); + * return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 }, + * { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } }); * } * - * private int firstSummand; + * private int fInput; * - * private int secondSummand; + * private int fExpected; * - * private int sum; - * - * public AdditionTest(int firstSummand, int secondSummand, int sum) { - * this.firstSummand = firstSummand; - * this.secondSummand = secondSummand; - * this.sum = sum; + * public FibonacciTest(int input, int expected) { + * fInput= input; + * fExpected= expected; * } * * @Test * public void test() { - * assertEquals(sum, firstSummand + secondSummand); + * assertEquals(fExpected, Fibonacci.compute(fInput)); * } * } * </pre> * <p> - * Each instance of <code>AdditionTest</code> will be constructed using the - * three-argument constructor and the data values in the + * Each instance of <code>FibonacciTest</code> will be constructed using the + * two-argument constructor and the data values in the * <code>@Parameters</code> method. * <p> * In order that you can easily identify the individual tests, you may provide a @@ -79,36 +69,33 @@ import org.junit.runners.parameterized.TestWithParameters; * </dl> * <p> * In the example given above, the <code>Parameterized</code> runner creates - * names like <code>[2: 3 + 2 = 5]</code>. If you don't use the name parameter, + * names like <code>[1: fib(3)=2]</code>. If you don't use the name parameter, * then the current parameter index is used as name. * <p> * You can also write: * <pre> * @RunWith(Parameterized.class) - * public class AdditionTest { - * @Parameters(name = "{index}: {0} + {1} = {2}") - * public static Iterable<Object[]> data() { - * return Arrays.asList(new Object[][] { { 0, 0, 0 }, { 1, 1, 2 }, - * { 3, 2, 5 }, { 4, 3, 7 } }); - * } - * - * @Parameter(0) - * public int firstSummand; + * public class FibonacciTest { + * @Parameters + * public static Iterable<Object[]> data() { + * return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 }, + * { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } }); + * } + * + * @Parameter(0) + * public int fInput; * - * @Parameter(1) - * public int secondSummand; + * @Parameter(1) + * public int fExpected; * - * @Parameter(2) - * public int sum; - * - * @Test - * public void test() { - * assertEquals(sum, firstSummand + secondSummand); - * } + * @Test + * public void test() { + * assertEquals(fExpected, Fibonacci.compute(fInput)); + * } * } * </pre> * <p> - * Each instance of <code>AdditionTest</code> will be constructed with the default constructor + * Each instance of <code>FibonacciTest</code> will be constructed with the default constructor * and fields annotated by <code>@Parameter</code> will be initialized * with the data values in the <code>@Parameters</code> method. * @@ -118,7 +105,8 @@ import org.junit.runners.parameterized.TestWithParameters; * <pre> * @Parameters * public static Object[][] data() { - * return new Object[][] { { 0, 0, 0 }, { 1, 1, 2 }, { 3, 2, 5 }, { 4, 3, 7 } } }; + * return new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, + * { 5, 5 }, { 6, 8 } }; * } * </pre> * @@ -142,19 +130,6 @@ import org.junit.runners.parameterized.TestWithParameters; * } * </pre> * - * <h3>Executing code before/after executing tests for specific parameters</h3> - * <p> - * If your test needs to perform some preparation or cleanup based on the - * parameters, this can be done by adding public static methods annotated with - * {@code @BeforeParam}/{@code @AfterParam}. Such methods should either have no - * parameters or the same parameters as the test. - * <pre> - * @BeforeParam - * public static void beforeTestsForParameter(String onlyParameter) { - * System.out.println("Testing " + onlyParameter); - * } - * </pre> - * * <h3>Create different runners</h3> * <p> * By default the {@code Parameterized} runner creates a slightly modified @@ -166,7 +141,7 @@ import org.junit.runners.parameterized.TestWithParameters; * The factory must have a public zero-arg constructor. * * <pre> - * public class YourRunnerFactory implements ParametersRunnerFactory { + * public class YourRunnerFactory implements ParameterizedRunnerFactory { * public Runner createRunnerForTestWithParameters(TestWithParameters test) * throws InitializationError { * return YourRunner(test); @@ -185,21 +160,6 @@ import org.junit.runners.parameterized.TestWithParameters; * } * </pre> * - * <h3>Avoid creating parameters</h3> - * <p>With {@link org.junit.Assume assumptions} you can dynamically skip tests. - * Assumptions are also supported by the <code>@Parameters</code> method. - * Creating parameters is stopped when the assumption fails and none of the - * tests in the test class is executed. JUnit reports a - * {@link Result#getAssumptionFailureCount() single assumption failure} for the - * whole test class in this case. - * <pre> - * @Parameters - * public static Iterable<? extends Object> data() { - * String os = System.getProperty("os.name").toLowerCase() - * Assume.assumeTrue(os.contains("win")); - * return Arrays.asList("first test", "second test"); - * } - * </pre> * @since 4.0 */ public class Parameterized extends Suite { @@ -210,7 +170,7 @@ public class Parameterized extends Suite { */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) - public @interface Parameters { + public static @interface Parameters { /** * Optional pattern to derive the test's name from the parameters. Use * numbers in braces to refer to the parameters or the additional data @@ -241,7 +201,7 @@ public class Parameterized extends Suite { */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) - public @interface Parameter { + public static @interface Parameter { /** * Method that returns the index of the parameter in the array * returned by the method annotated by <code>Parameters</code>. @@ -270,235 +230,122 @@ public class Parameterized extends Suite { Class<? extends ParametersRunnerFactory> value() default BlockJUnit4ClassRunnerWithParametersFactory.class; } - /** - * Annotation for {@code public static void} methods which should be executed before - * evaluating tests with particular parameters. - * - * @see org.junit.BeforeClass - * @see org.junit.Before - * @since 4.13 - */ - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.METHOD) - public @interface BeforeParam { - } + private static final ParametersRunnerFactory DEFAULT_FACTORY = new BlockJUnit4ClassRunnerWithParametersFactory(); - /** - * Annotation for {@code public static void} methods which should be executed after - * evaluating tests with particular parameters. - * - * @see org.junit.AfterClass - * @see org.junit.After - * @since 4.13 - */ - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.METHOD) - public @interface AfterParam { - } + private static final List<Runner> NO_RUNNERS = Collections.<Runner>emptyList(); + + private final List<Runner> runners; /** * Only called reflectively. Do not use programmatically. */ public Parameterized(Class<?> klass) throws Throwable { - this(klass, new RunnersFactory(klass)); - } - - private Parameterized(Class<?> klass, RunnersFactory runnersFactory) throws Exception { - super(klass, runnersFactory.createRunners()); - validateBeforeParamAndAfterParamMethods(runnersFactory.parameterCount); + super(klass, NO_RUNNERS); + ParametersRunnerFactory runnerFactory = getParametersRunnerFactory( + klass); + Parameters parameters = getParametersMethod().getAnnotation( + Parameters.class); + runners = Collections.unmodifiableList(createRunnersForParameters( + allParameters(), parameters.name(), runnerFactory)); } - private void validateBeforeParamAndAfterParamMethods(Integer parameterCount) - throws InvalidTestClassError { - List<Throwable> errors = new ArrayList<Throwable>(); - validatePublicStaticVoidMethods(Parameterized.BeforeParam.class, parameterCount, errors); - validatePublicStaticVoidMethods(Parameterized.AfterParam.class, parameterCount, errors); - if (!errors.isEmpty()) { - throw new InvalidTestClassError(getTestClass().getJavaClass(), errors); + private ParametersRunnerFactory getParametersRunnerFactory(Class<?> klass) + throws InstantiationException, IllegalAccessException { + UseParametersRunnerFactory annotation = klass + .getAnnotation(UseParametersRunnerFactory.class); + if (annotation == null) { + return DEFAULT_FACTORY; + } else { + Class<? extends ParametersRunnerFactory> factoryClass = annotation + .value(); + return factoryClass.newInstance(); } } - private void validatePublicStaticVoidMethods( - Class<? extends Annotation> annotation, Integer parameterCount, - List<Throwable> errors) { - List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(annotation); - for (FrameworkMethod fm : methods) { - fm.validatePublicVoid(true, errors); - if (parameterCount != null) { - int methodParameterCount = fm.getMethod().getParameterTypes().length; - if (methodParameterCount != 0 && methodParameterCount != parameterCount) { - errors.add(new Exception("Method " + fm.getName() - + "() should have 0 or " + parameterCount + " parameter(s)")); - } - } - } + @Override + protected List<Runner> getChildren() { + return runners; } - private static class AssumptionViolationRunner extends Runner { - private final Description description; - private final AssumptionViolatedException exception; - - AssumptionViolationRunner(TestClass testClass, String methodName, - AssumptionViolatedException exception) { - this.description = Description - .createTestDescription(testClass.getJavaClass(), - methodName + "() assumption violation"); - this.exception = exception; - } - - @Override - public Description getDescription() { - return description; - } - - @Override - public void run(RunNotifier notifier) { - notifier.fireTestAssumptionFailed(new Failure(description, exception)); - } + private TestWithParameters createTestWithNotNormalizedParameters( + String pattern, int index, Object parametersOrSingleParameter) { + Object[] parameters= (parametersOrSingleParameter instanceof Object[]) ? (Object[]) parametersOrSingleParameter + : new Object[] { parametersOrSingleParameter }; + return createTestWithParameters(getTestClass(), pattern, index, + parameters); } - private static class RunnersFactory { - private static final ParametersRunnerFactory DEFAULT_FACTORY = new BlockJUnit4ClassRunnerWithParametersFactory(); - - private final TestClass testClass; - private final FrameworkMethod parametersMethod; - private final List<Object> allParameters; - private final int parameterCount; - private final Runner runnerOverride; - - private RunnersFactory(Class<?> klass) throws Throwable { - testClass = new TestClass(klass); - parametersMethod = getParametersMethod(testClass); - List<Object> allParametersResult; - AssumptionViolationRunner assumptionViolationRunner = null; - try { - allParametersResult = allParameters(testClass, parametersMethod); - } catch (AssumptionViolatedException e) { - allParametersResult = Collections.emptyList(); - assumptionViolationRunner = new AssumptionViolationRunner(testClass, - parametersMethod.getName(), e); - } - allParameters = allParametersResult; - runnerOverride = assumptionViolationRunner; - parameterCount = - allParameters.isEmpty() ? 0 : normalizeParameters(allParameters.get(0)).length; - } - - private List<Runner> createRunners() throws Exception { - if (runnerOverride != null) { - return Collections.singletonList(runnerOverride); - } - Parameters parameters = parametersMethod.getAnnotation(Parameters.class); - return Collections.unmodifiableList(createRunnersForParameters( - allParameters, parameters.name(), - getParametersRunnerFactory())); - } - - private ParametersRunnerFactory getParametersRunnerFactory() - throws InstantiationException, IllegalAccessException { - UseParametersRunnerFactory annotation = testClass - .getAnnotation(UseParametersRunnerFactory.class); - if (annotation == null) { - return DEFAULT_FACTORY; - } else { - Class<? extends ParametersRunnerFactory> factoryClass = annotation - .value(); - return factoryClass.newInstance(); - } - } - - private TestWithParameters createTestWithNotNormalizedParameters( - String pattern, int index, Object parametersOrSingleParameter) { - Object[] parameters = normalizeParameters(parametersOrSingleParameter); - return createTestWithParameters(testClass, pattern, index, parameters); - } - - private static Object[] normalizeParameters(Object parametersOrSingleParameter) { - return (parametersOrSingleParameter instanceof Object[]) ? (Object[]) parametersOrSingleParameter - : new Object[] { parametersOrSingleParameter }; + @SuppressWarnings("unchecked") + private Iterable<Object> allParameters() throws Throwable { + Object parameters = getParametersMethod().invokeExplosively(null); + if (parameters instanceof Iterable) { + return (Iterable<Object>) parameters; + } else if (parameters instanceof Object[]) { + return Arrays.asList((Object[]) parameters); + } else { + throw parametersMethodReturnedWrongType(); } + } - @SuppressWarnings("unchecked") - private static List<Object> allParameters( - TestClass testClass, FrameworkMethod parametersMethod) throws Throwable { - Object parameters = parametersMethod.invokeExplosively(null); - if (parameters instanceof List) { - return (List<Object>) parameters; - } else if (parameters instanceof Collection) { - return new ArrayList<Object>((Collection<Object>) parameters); - } else if (parameters instanceof Iterable) { - List<Object> result = new ArrayList<Object>(); - for (Object entry : ((Iterable<Object>) parameters)) { - result.add(entry); - } - return result; - } else if (parameters instanceof Object[]) { - return Arrays.asList((Object[]) parameters); - } else { - throw parametersMethodReturnedWrongType(testClass, parametersMethod); + private FrameworkMethod getParametersMethod() throws Exception { + List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods( + Parameters.class); + for (FrameworkMethod each : methods) { + if (each.isStatic() && each.isPublic()) { + return each; } } - private static FrameworkMethod getParametersMethod(TestClass testClass) throws Exception { - List<FrameworkMethod> methods = testClass - .getAnnotatedMethods(Parameters.class); - for (FrameworkMethod each : methods) { - if (each.isStatic() && each.isPublic()) { - return each; - } - } - - throw new Exception("No public static parameters method on class " - + testClass.getName()); - } + throw new Exception("No public static parameters method on class " + + getTestClass().getName()); + } - private List<Runner> createRunnersForParameters( - Iterable<Object> allParameters, String namePattern, - ParametersRunnerFactory runnerFactory) throws Exception { - try { - List<TestWithParameters> tests = createTestsForParameters( - allParameters, namePattern); - List<Runner> runners = new ArrayList<Runner>(); - for (TestWithParameters test : tests) { - runners.add(runnerFactory - .createRunnerForTestWithParameters(test)); - } - return runners; - } catch (ClassCastException e) { - throw parametersMethodReturnedWrongType(testClass, parametersMethod); + private List<Runner> createRunnersForParameters( + Iterable<Object> allParameters, String namePattern, + ParametersRunnerFactory runnerFactory) + throws InitializationError, + Exception { + try { + List<TestWithParameters> tests = createTestsForParameters( + allParameters, namePattern); + List<Runner> runners = new ArrayList<Runner>(); + for (TestWithParameters test : tests) { + runners.add(runnerFactory + .createRunnerForTestWithParameters(test)); } + return runners; + } catch (ClassCastException e) { + throw parametersMethodReturnedWrongType(); } + } - private List<TestWithParameters> createTestsForParameters( - Iterable<Object> allParameters, String namePattern) - throws Exception { - int i = 0; - List<TestWithParameters> children = new ArrayList<TestWithParameters>(); - for (Object parametersOfSingleTest : allParameters) { - children.add(createTestWithNotNormalizedParameters(namePattern, - i++, parametersOfSingleTest)); - } - return children; + private List<TestWithParameters> createTestsForParameters( + Iterable<Object> allParameters, String namePattern) + throws Exception { + int i = 0; + List<TestWithParameters> children = new ArrayList<TestWithParameters>(); + for (Object parametersOfSingleTest : allParameters) { + children.add(createTestWithNotNormalizedParameters(namePattern, + i++, parametersOfSingleTest)); } + return children; + } - private static Exception parametersMethodReturnedWrongType( - TestClass testClass, FrameworkMethod parametersMethod) throws Exception { - String className = testClass.getName(); - String methodName = parametersMethod.getName(); - String message = MessageFormat.format( - "{0}.{1}() must return an Iterable of arrays.", className, - methodName); - return new Exception(message); - } + private Exception parametersMethodReturnedWrongType() throws Exception { + String className = getTestClass().getName(); + String methodName = getParametersMethod().getName(); + String message = MessageFormat.format( + "{0}.{1}() must return an Iterable of arrays.", + className, methodName); + return new Exception(message); + } - private TestWithParameters createTestWithParameters( - TestClass testClass, String pattern, int index, - Object[] parameters) { - String finalPattern = pattern.replaceAll("\\{index\\}", - Integer.toString(index)); - String name = MessageFormat.format(finalPattern, parameters); - return new TestWithParameters("[" + name + "]", testClass, - Arrays.asList(parameters)); - } + private static TestWithParameters createTestWithParameters( + TestClass testClass, String pattern, int index, Object[] parameters) { + String finalPattern = pattern.replaceAll("\\{index\\}", + Integer.toString(index)); + String name = MessageFormat.format(finalPattern, parameters); + return new TestWithParameters("[" + name + "]", testClass, + Arrays.asList(parameters)); } } diff --git a/src/main/java/org/junit/runners/ParentRunner.java b/src/main/java/org/junit/runners/ParentRunner.java index 0a0e7cb..92641bf 100644..100755 --- a/src/main/java/org/junit/runners/ParentRunner.java +++ b/src/main/java/org/junit/runners/ParentRunner.java @@ -1,25 +1,21 @@ package org.junit.runners; -import static org.junit.internal.Checks.notNull; import static org.junit.internal.runners.rules.RuleMemberValidator.CLASS_RULE_METHOD_VALIDATOR; import static org.junit.internal.runners.rules.RuleMemberValidator.CLASS_RULE_VALIDATOR; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.ClassRule; -import org.junit.FixMethodOrder; import org.junit.Ignore; import org.junit.Rule; import org.junit.internal.AssumptionViolatedException; @@ -32,22 +28,18 @@ 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.Orderer; -import org.junit.runner.manipulation.InvalidOrderingException; import org.junit.runner.manipulation.NoTestsRemainException; -import org.junit.runner.manipulation.Orderable; +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.FrameworkMember; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; -import org.junit.runners.model.InvalidTestClassError; -import org.junit.runners.model.MemberValueConsumer; import org.junit.runners.model.RunnerScheduler; import org.junit.runners.model.Statement; import org.junit.runners.model.TestClass; import org.junit.validator.AnnotationsValidator; +import org.junit.validator.PublicClassValidator; import org.junit.validator.TestClassValidator; /** @@ -64,15 +56,15 @@ import org.junit.validator.TestClassValidator; * @since 4.5 */ public abstract class ParentRunner<T> extends Runner implements Filterable, - Orderable { - private static final List<TestClassValidator> VALIDATORS = Collections.<TestClassValidator>singletonList( - new AnnotationsValidator()); + Sortable { + private static final List<TestClassValidator> VALIDATORS = Arrays.asList( + new AnnotationsValidator(), new PublicClassValidator()); - private final Lock childrenLock = new ReentrantLock(); + private final Object childrenLock = new Object(); private final TestClass testClass; // Guarded by childrenLock - private volatile List<T> filteredChildren = null; + private volatile Collection<T> filteredChildren = null; private volatile RunnerScheduler scheduler = new RunnerScheduler() { public void schedule(Runnable childStatement) { @@ -92,21 +84,6 @@ public abstract class ParentRunner<T> extends Runner implements Filterable, validate(); } - /** - * Constructs a new {@code ParentRunner} that will run the {@code TestClass}. - * - * @since 4.13 - */ - protected ParentRunner(TestClass testClass) throws InitializationError { - this.testClass = notNull(testClass); - validate(); - } - - /** - * @deprecated Please use {@link #ParentRunner(org.junit.runners.model.TestClass)}. - * @since 4.12 - */ - @Deprecated protected TestClass createTestClass(Class<?> testClass) { return new TestClass(testClass); } @@ -215,7 +192,6 @@ public abstract class ParentRunner<T> extends Runner implements Filterable, statement = withBeforeClasses(statement); statement = withAfterClasses(statement); statement = withClassRules(statement); - statement = withInterruptIsolation(statement); } return statement; } @@ -243,7 +219,7 @@ public abstract class ParentRunner<T> extends Runner implements Filterable, /** * Returns a {@link Statement}: run all non-overridden {@code @AfterClass} methods on this class - * and superclasses after executing {@code statement}; all AfterClass methods are + * 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 org.junit.runners.model.MultipleFailureException}. @@ -275,10 +251,9 @@ public abstract class ParentRunner<T> extends Runner implements Filterable, * each method in the tested class. */ protected List<TestRule> classRules() { - ClassRuleCollector collector = new ClassRuleCollector(); - testClass.collectAnnotatedMethodValues(null, ClassRule.class, TestRule.class, collector); - testClass.collectAnnotatedFieldValues(null, ClassRule.class, TestRule.class, collector); - return collector.getOrderedRules(); + List<TestRule> result = testClass.getAnnotatedMethodValues(null, ClassRule.class, TestRule.class); + result.addAll(testClass.getAnnotatedFieldValues(null, ClassRule.class, TestRule.class)); + return result; } /** @@ -296,22 +271,6 @@ public abstract class ParentRunner<T> extends Runner implements Filterable, } /** - * @return a {@link Statement}: clears interrupt status of current thread after execution of statement - */ - protected final Statement withInterruptIsolation(final Statement statement) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - try { - statement.evaluate(); - } finally { - Thread.interrupted(); // clearing thread interrupted status for isolation - } - } - }; - } - - /** * Evaluates whether a child is ignored. The default implementation always * returns <code>false</code>. * @@ -387,16 +346,8 @@ public abstract class ParentRunner<T> extends Runner implements Filterable, @Override public Description getDescription() { - Class<?> clazz = getTestClass().getJavaClass(); - Description description; - // if subclass overrides `getName()` then we should use it - // to maintain backwards compatibility with JUnit 4.12 - if (clazz == null || !clazz.getName().equals(getName())) { - description = Description.createSuiteDescription(getName(), getRunnerAnnotations()); - } else { - description = Description.createSuiteDescription(clazz, getRunnerAnnotations()); - } - + Description description = Description.createSuiteDescription(getName(), + getRunnerAnnotations()); for (T child : getFilteredChildren()) { description.addChild(describeChild(child)); } @@ -407,7 +358,6 @@ public abstract class ParentRunner<T> extends Runner implements Filterable, public void run(final RunNotifier notifier) { EachTestNotifier testNotifier = new EachTestNotifier(notifier, getDescription()); - testNotifier.fireTestSuiteStarted(); try { Statement statement = classBlock(notifier); statement.evaluate(); @@ -417,8 +367,6 @@ public abstract class ParentRunner<T> extends Runner implements Filterable, throw e; } catch (Throwable e) { testNotifier.addFailure(e); - } finally { - testNotifier.fireTestSuiteFinished(); } } @@ -427,8 +375,7 @@ public abstract class ParentRunner<T> extends Runner implements Filterable, // public void filter(Filter filter) throws NoTestsRemainException { - childrenLock.lock(); - try { + synchronized (childrenLock) { List<T> children = new ArrayList<T>(getFilteredChildren()); for (Iterator<T> iter = children.iterator(); iter.hasNext(); ) { T each = iter.next(); @@ -442,70 +389,21 @@ public abstract class ParentRunner<T> extends Runner implements Filterable, iter.remove(); } } - filteredChildren = Collections.unmodifiableList(children); + filteredChildren = Collections.unmodifiableCollection(children); if (filteredChildren.isEmpty()) { throw new NoTestsRemainException(); } - } finally { - childrenLock.unlock(); } } public void sort(Sorter sorter) { - if (shouldNotReorder()) { - return; - } - - childrenLock.lock(); - try { + synchronized (childrenLock) { for (T each : getFilteredChildren()) { sorter.apply(each); } List<T> sortedChildren = new ArrayList<T>(getFilteredChildren()); Collections.sort(sortedChildren, comparator(sorter)); - filteredChildren = Collections.unmodifiableList(sortedChildren); - } finally { - childrenLock.unlock(); - } - } - - /** - * Implementation of {@link Orderable#order(Orderer)}. - * - * @since 4.13 - */ - public void order(Orderer orderer) throws InvalidOrderingException { - if (shouldNotReorder()) { - return; - } - - childrenLock.lock(); - try { - List<T> children = getFilteredChildren(); - // In theory, we could have duplicate Descriptions. De-dup them before ordering, - // and add them back at the end. - Map<Description, List<T>> childMap = new LinkedHashMap<Description, List<T>>( - children.size()); - for (T child : children) { - Description description = describeChild(child); - List<T> childrenWithDescription = childMap.get(description); - if (childrenWithDescription == null) { - childrenWithDescription = new ArrayList<T>(1); - childMap.put(description, childrenWithDescription); - } - childrenWithDescription.add(child); - orderer.apply(child); - } - - List<Description> inOrder = orderer.order(childMap.keySet()); - - children = new ArrayList<T>(children.size()); - for (Description description : inOrder) { - children.addAll(childMap.get(description)); - } - filteredChildren = Collections.unmodifiableList(children); - } finally { - childrenLock.unlock(); + filteredChildren = Collections.unmodifiableCollection(sortedChildren); } } @@ -513,29 +411,20 @@ public abstract class ParentRunner<T> extends Runner implements Filterable, // Private implementation // - private boolean shouldNotReorder() { - // If the test specifies a specific order, do not reorder. - return getDescription().getAnnotation(FixMethodOrder.class) != null; - } - private void validate() throws InitializationError { List<Throwable> errors = new ArrayList<Throwable>(); collectInitializationErrors(errors); if (!errors.isEmpty()) { - throw new InvalidTestClassError(testClass.getJavaClass(), errors); + throw new InitializationError(errors); } } - private List<T> getFilteredChildren() { + private Collection<T> getFilteredChildren() { if (filteredChildren == null) { - childrenLock.lock(); - try { + synchronized (childrenLock) { if (filteredChildren == null) { - filteredChildren = Collections.unmodifiableList( - new ArrayList<T>(getChildren())); + filteredChildren = Collections.unmodifiableCollection(getChildren()); } - } finally { - childrenLock.unlock(); } } return filteredChildren; @@ -560,23 +449,4 @@ public abstract class ParentRunner<T> extends Runner implements Filterable, public void setScheduler(RunnerScheduler scheduler) { this.scheduler = scheduler; } - - private static class ClassRuleCollector implements MemberValueConsumer<TestRule> { - final List<RuleContainer.RuleEntry> entries = new ArrayList<RuleContainer.RuleEntry>(); - - public void accept(FrameworkMember<?> member, TestRule value) { - ClassRule rule = member.getAnnotation(ClassRule.class); - entries.add(new RuleContainer.RuleEntry(value, RuleContainer.RuleEntry.TYPE_TEST_RULE, - rule != null ? rule.order() : null)); - } - - public List<TestRule> getOrderedRules() { - Collections.sort(entries, RuleContainer.ENTRY_COMPARATOR); - List<TestRule> result = new ArrayList<TestRule>(entries.size()); - for (RuleContainer.RuleEntry entry : entries) { - result.add((TestRule) entry.rule); - } - return result; - } - } } diff --git a/src/main/java/org/junit/runners/RuleContainer.java b/src/main/java/org/junit/runners/RuleContainer.java deleted file mode 100644 index 30ddd8d..0000000 --- a/src/main/java/org/junit/runners/RuleContainer.java +++ /dev/null @@ -1,113 +0,0 @@ -package org.junit.runners; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.IdentityHashMap; -import java.util.List; - -import org.junit.Rule; -import org.junit.rules.MethodRule; -import org.junit.rules.TestRule; -import org.junit.runner.Description; -import org.junit.runners.model.FrameworkMethod; -import org.junit.runners.model.Statement; - -/** - * Data structure for ordering of {@link TestRule}/{@link MethodRule} instances. - * - * @since 4.13 - */ -class RuleContainer { - private final IdentityHashMap<Object, Integer> orderValues = new IdentityHashMap<Object, Integer>(); - private final List<TestRule> testRules = new ArrayList<TestRule>(); - private final List<MethodRule> methodRules = new ArrayList<MethodRule>(); - - /** - * Sets order value for the specified rule. - */ - public void setOrder(Object rule, int order) { - orderValues.put(rule, order); - } - - public void add(MethodRule methodRule) { - methodRules.add(methodRule); - } - - public void add(TestRule testRule) { - testRules.add(testRule); - } - - static final Comparator<RuleEntry> ENTRY_COMPARATOR = new Comparator<RuleEntry>() { - public int compare(RuleEntry o1, RuleEntry o2) { - int result = compareInt(o1.order, o2.order); - return result != 0 ? result : o1.type - o2.type; - } - - private int compareInt(int a, int b) { - return (a < b) ? 1 : (a == b ? 0 : -1); - } - }; - - /** - * Returns entries in the order how they should be applied, i.e. inner-to-outer. - */ - private List<RuleEntry> getSortedEntries() { - List<RuleEntry> ruleEntries = new ArrayList<RuleEntry>( - methodRules.size() + testRules.size()); - for (MethodRule rule : methodRules) { - ruleEntries.add(new RuleEntry(rule, RuleEntry.TYPE_METHOD_RULE, orderValues.get(rule))); - } - for (TestRule rule : testRules) { - ruleEntries.add(new RuleEntry(rule, RuleEntry.TYPE_TEST_RULE, orderValues.get(rule))); - } - Collections.sort(ruleEntries, ENTRY_COMPARATOR); - return ruleEntries; - } - - /** - * Applies all the rules ordered accordingly to the specified {@code statement}. - */ - public Statement apply(FrameworkMethod method, Description description, Object target, - Statement statement) { - if (methodRules.isEmpty() && testRules.isEmpty()) { - return statement; - } - Statement result = statement; - for (RuleEntry ruleEntry : getSortedEntries()) { - if (ruleEntry.type == RuleEntry.TYPE_TEST_RULE) { - result = ((TestRule) ruleEntry.rule).apply(result, description); - } else { - result = ((MethodRule) ruleEntry.rule).apply(result, method, target); - } - } - return result; - } - - /** - * Returns rule instances in the order how they should be applied, i.e. inner-to-outer. - * VisibleForTesting - */ - List<Object> getSortedRules() { - List<Object> result = new ArrayList<Object>(); - for (RuleEntry entry : getSortedEntries()) { - result.add(entry.rule); - } - return result; - } - - static class RuleEntry { - static final int TYPE_TEST_RULE = 1; - static final int TYPE_METHOD_RULE = 0; - - final Object rule; - final int type; - final int order; - - RuleEntry(Object rule, int type, Integer order) { - this.rule = rule; - this.type = type; - this.order = order != null ? order.intValue() : Rule.DEFAULT_ORDER; - } - } -} diff --git a/src/main/java/org/junit/runners/Suite.java b/src/main/java/org/junit/runners/Suite.java index c2c8e58..b37179f 100644 --- a/src/main/java/org/junit/runners/Suite.java +++ b/src/main/java/org/junit/runners/Suite.java @@ -47,7 +47,7 @@ public class Suite extends ParentRunner<Runner> { /** * @return the classes to be run */ - Class<?>[] value(); + public Class<?>[] value(); } private static Class<?>[] getAnnotatedClasses(Class<?> klass) throws InitializationError { @@ -88,7 +88,7 @@ public class Suite extends ParentRunner<Runner> { * @param suiteClasses the classes in the suite */ protected Suite(Class<?> klass, Class<?>[] suiteClasses) throws InitializationError { - this(new AllDefaultPossibilitiesBuilder(), klass, suiteClasses); + this(new AllDefaultPossibilitiesBuilder(true), klass, suiteClasses); } /** diff --git a/src/main/java/org/junit/runners/model/FrameworkField.java b/src/main/java/org/junit/runners/model/FrameworkField.java index ea2b16f..945e389 100644 --- a/src/main/java/org/junit/runners/model/FrameworkField.java +++ b/src/main/java/org/junit/runners/model/FrameworkField.java @@ -14,26 +14,12 @@ import org.junit.runners.BlockJUnit4ClassRunner; public class FrameworkField extends FrameworkMember<FrameworkField> { private final Field field; - /** - * Returns a new {@code FrameworkField} for {@code field}. - * - * <p>Access relaxed to {@code public} since version 4.13.1. - */ - public FrameworkField(Field field) { + FrameworkField(Field field) { if (field == null) { throw new NullPointerException( "FrameworkField cannot be created without an underlying field."); } this.field = field; - - if (isPublic()) { - // This field could be a public field in a package-scope base class - try { - field.setAccessible(true); - } catch (SecurityException e) { - // We may get an IllegalAccessException when we try to access the field - } - } } @Override @@ -55,11 +41,6 @@ public class FrameworkField extends FrameworkMember<FrameworkField> { } @Override - boolean isBridgeMethod() { - return false; - } - - @Override protected int getModifiers() { return field.getModifiers(); } diff --git a/src/main/java/org/junit/runners/model/FrameworkMember.java b/src/main/java/org/junit/runners/model/FrameworkMember.java index 5634b3f..724f096 100644 --- a/src/main/java/org/junit/runners/model/FrameworkMember.java +++ b/src/main/java/org/junit/runners/model/FrameworkMember.java @@ -12,29 +12,15 @@ public abstract class FrameworkMember<T extends FrameworkMember<T>> implements Annotatable { abstract boolean isShadowedBy(T otherMember); - T handlePossibleBridgeMethod(List<T> members) { - for (int i = members.size() - 1; i >=0; i--) { - T otherMember = members.get(i); - if (isShadowedBy(otherMember)) { - if (otherMember.isBridgeMethod()) { - /* - * We need to return the previously-encountered bridge method - * because JUnit won't be able to call the parent method, - * because the parent class isn't public. - */ - members.remove(i); - return otherMember; - } - // We found a shadowed member that isn't a bridge method. Ignore it. - return null; + boolean isShadowedBy(List<T> members) { + for (T each : members) { + if (isShadowedBy(each)) { + return true; } } - // No shadow or bridge method found. The caller should add *this* member. - return (T) this; + return false; } - abstract boolean isBridgeMethod(); - protected abstract int getModifiers(); /** diff --git a/src/main/java/org/junit/runners/model/FrameworkMethod.java b/src/main/java/org/junit/runners/model/FrameworkMethod.java index 4471407..3580052 100644 --- a/src/main/java/org/junit/runners/model/FrameworkMethod.java +++ b/src/main/java/org/junit/runners/model/FrameworkMethod.java @@ -28,15 +28,6 @@ public class FrameworkMethod extends FrameworkMember<FrameworkMethod> { "FrameworkMethod cannot be created without an underlying method."); } this.method = method; - - if (isPublic()) { - // This method could be a public method in a package-scope base class - try { - method.setAccessible(true); - } catch (SecurityException e) { - // We may get an IllegalAccessException when we try to call the method - } - } } /** @@ -158,11 +149,6 @@ public class FrameworkMethod extends FrameworkMember<FrameworkMethod> { } @Override - boolean isBridgeMethod() { - return method.isBridge(); - } - - @Override public boolean equals(Object obj) { if (!FrameworkMethod.class.isInstance(obj)) { return false; diff --git a/src/main/java/org/junit/runners/model/InitializationError.java b/src/main/java/org/junit/runners/model/InitializationError.java index dd9c8b3..841b565 100644 --- a/src/main/java/org/junit/runners/model/InitializationError.java +++ b/src/main/java/org/junit/runners/model/InitializationError.java @@ -14,7 +14,7 @@ public class InitializationError extends Exception { /* * We have to use the f prefix until the next major release to ensure * serialization compatibility. - * See https://github.com/junit-team/junit4/issues/976 + * See https://github.com/junit-team/junit/issues/976 */ private final List<Throwable> fErrors; diff --git a/src/main/java/org/junit/runners/model/InvalidTestClassError.java b/src/main/java/org/junit/runners/model/InvalidTestClassError.java deleted file mode 100644 index 57be610..0000000 --- a/src/main/java/org/junit/runners/model/InvalidTestClassError.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.junit.runners.model; - -import java.util.List; - -/** - * Thrown by {@link org.junit.runner.Runner}s in case the class under test is not valid. - * <p> - * Its message conveniently lists all of the validation errors. - * - * @since 4.13 - */ -public class InvalidTestClassError extends InitializationError { - private static final long serialVersionUID = 1L; - - private final String message; - - public InvalidTestClassError(Class<?> offendingTestClass, List<Throwable> validationErrors) { - super(validationErrors); - this.message = createMessage(offendingTestClass, validationErrors); - } - - private static String createMessage(Class<?> testClass, List<Throwable> validationErrors) { - StringBuilder sb = new StringBuilder(); - sb.append(String.format("Invalid test class '%s':", testClass.getName())); - int i = 1; - for (Throwable error : validationErrors) { - sb.append("\n " + (i++) + ". " + error.getMessage()); - } - return sb.toString(); - } - - /** - * @return a message with a list of all of the validation errors - */ - @Override - public String getMessage() { - return message; - } -} diff --git a/src/main/java/org/junit/runners/model/MemberValueConsumer.java b/src/main/java/org/junit/runners/model/MemberValueConsumer.java deleted file mode 100644 index a6157bf..0000000 --- a/src/main/java/org/junit/runners/model/MemberValueConsumer.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.junit.runners.model; - -/** - * Represents a receiver for values of annotated fields/methods together with the declaring member. - * - * @see TestClass#collectAnnotatedFieldValues(Object, Class, Class, MemberValueConsumer) - * @see TestClass#collectAnnotatedMethodValues(Object, Class, Class, MemberValueConsumer) - * @since 4.13 - */ -public interface MemberValueConsumer<T> { - /** - * Receives the next value and its declaring member. - * - * @param member declaring member ({@link FrameworkMethod} or {@link FrameworkField}) - * @param value the value of the next member - */ - void accept(FrameworkMember<?> member, T value); -} diff --git a/src/main/java/org/junit/runners/model/MultipleFailureException.java b/src/main/java/org/junit/runners/model/MultipleFailureException.java index 8e355a7..325c645 100644 --- a/src/main/java/org/junit/runners/model/MultipleFailureException.java +++ b/src/main/java/org/junit/runners/model/MultipleFailureException.java @@ -1,13 +1,9 @@ package org.junit.runners.model; -import java.io.PrintStream; -import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.junit.TestCouldNotBeSkippedException; -import org.junit.internal.AssumptionViolatedException; import org.junit.internal.Throwables; /** @@ -21,22 +17,12 @@ public class MultipleFailureException extends Exception { /* * We have to use the f prefix until the next major release to ensure * serialization compatibility. - * See https://github.com/junit-team/junit4/issues/976 + * See https://github.com/junit-team/junit/issues/976 */ private final List<Throwable> fErrors; public MultipleFailureException(List<Throwable> errors) { - if (errors.isEmpty()) { - throw new IllegalArgumentException( - "List of Throwables must not be empty"); - } - this.fErrors = new ArrayList<Throwable>(errors.size()); - for (Throwable error : errors) { - if (error instanceof AssumptionViolatedException) { - error = new TestCouldNotBeSkippedException((AssumptionViolatedException) error); - } - fErrors.add(error); - } + this.fErrors = new ArrayList<Throwable>(errors); } public List<Throwable> getFailures() { @@ -48,32 +34,11 @@ public class MultipleFailureException extends Exception { 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())); + sb.append(String.format("\n %s(%s)", e.getClass().getName(), e.getMessage())); } return sb.toString(); } - @Override - public void printStackTrace() { - for (Throwable e: fErrors) { - e.printStackTrace(); - } - } - - @Override - public void printStackTrace(PrintStream s) { - for (Throwable e: fErrors) { - e.printStackTrace(s); - } - } - - @Override - public void printStackTrace(PrintWriter s) { - for (Throwable e: fErrors) { - e.printStackTrace(s); - } - } - /** * Asserts that a list of throwables is empty. If it isn't empty, * will throw {@link MultipleFailureException} (if there are diff --git a/src/main/java/org/junit/runners/model/RunnerBuilder.java b/src/main/java/org/junit/runners/model/RunnerBuilder.java index ba7c9e2..7d3eee3 100644 --- a/src/main/java/org/junit/runners/model/RunnerBuilder.java +++ b/src/main/java/org/junit/runners/model/RunnerBuilder.java @@ -6,11 +6,7 @@ import java.util.List; import java.util.Set; import org.junit.internal.runners.ErrorReportingRunner; -import org.junit.runner.Description; -import org.junit.runner.OrderWith; import org.junit.runner.Runner; -import org.junit.runner.manipulation.InvalidOrderingException; -import org.junit.runner.manipulation.Ordering; /** * A RunnerBuilder is a strategy for constructing runners for classes. @@ -53,39 +49,19 @@ public abstract class RunnerBuilder { public abstract Runner runnerForClass(Class<?> testClass) throws Throwable; /** - * Always returns a runner for the given test class. - * - * <p>In case of an exception a runner will be returned that prints an error instead of running - * tests. - * - * <p>Note that some of the internal JUnit implementations of RunnerBuilder will return - * {@code null} from this method, but no RunnerBuilder passed to a Runner constructor will - * return {@code null} from this method. + * 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 { - Runner runner = runnerForClass(testClass); - if (runner != null) { - configureRunner(runner); - } - return runner; + return runnerForClass(testClass); } catch (Throwable e) { return new ErrorReportingRunner(testClass, e); } } - private void configureRunner(Runner runner) throws InvalidOrderingException { - Description description = runner.getDescription(); - OrderWith orderWith = description.getAnnotation(OrderWith.class); - if (orderWith != null) { - Ordering ordering = Ordering.definedBy(orderWith.value(), description); - ordering.apply(runner); - } - } - 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())); @@ -120,7 +96,7 @@ public abstract class RunnerBuilder { } private List<Runner> runners(Class<?>[] children) { - List<Runner> runners = new ArrayList<Runner>(); + ArrayList<Runner> runners = new ArrayList<Runner>(); for (Class<?> each : children) { Runner childRunner = safeRunnerForClass(each); if (childRunner != null) { diff --git a/src/main/java/org/junit/runners/model/TestClass.java b/src/main/java/org/junit/runners/model/TestClass.java index 5962c2b..c8a544d 100644..100755 --- a/src/main/java/org/junit/runners/model/TestClass.java +++ b/src/main/java/org/junit/runners/model/TestClass.java @@ -84,21 +84,20 @@ public class TestClass implements Annotatable { for (Annotation each : member.getAnnotations()) { Class<? extends Annotation> type = each.annotationType(); List<T> members = getAnnotatedMembers(map, type, true); - T memberToAdd = member.handlePossibleBridgeMethod(members); - if (memberToAdd == null) { + if (member.isShadowedBy(members)) { return; } if (runsTopToBottom(type)) { - members.add(0, memberToAdd); + members.add(0, member); } else { - members.add(memberToAdd); + members.add(member); } } } private static <T extends FrameworkMember<T>> Map<Class<? extends Annotation>, List<T>> makeDeeplyUnmodifiable(Map<Class<? extends Annotation>, List<T>> source) { - Map<Class<? extends Annotation>, List<T>> copy = + LinkedHashMap<Class<? extends Annotation>, List<T>> copy = new LinkedHashMap<Class<? extends Annotation>, List<T>>(); for (Map.Entry<Class<? extends Annotation>, List<T>> entry : source.entrySet()) { copy.put(entry.getKey(), Collections.unmodifiableList(entry.getValue())); @@ -169,7 +168,7 @@ public class TestClass implements Annotatable { } private static List<Class<?>> getSuperClasses(Class<?> testClass) { - List<Class<?>> results = new ArrayList<Class<?>>(); + ArrayList<Class<?>> results = new ArrayList<Class<?>>(); Class<?> current = testClass; while (current != null) { results.add(current); @@ -225,59 +224,24 @@ public class TestClass implements Annotatable { public <T> List<T> getAnnotatedFieldValues(Object test, Class<? extends Annotation> annotationClass, Class<T> valueClass) { - final List<T> results = new ArrayList<T>(); - collectAnnotatedFieldValues(test, annotationClass, valueClass, - new MemberValueConsumer<T>() { - public void accept(FrameworkMember<?> member, T value) { - results.add(value); - } - }); - return results; - } - - /** - * Finds the fields annotated with the specified annotation and having the specified type, - * retrieves the values and passes those to the specified consumer. - * - * @since 4.13 - */ - public <T> void collectAnnotatedFieldValues(Object test, - Class<? extends Annotation> annotationClass, Class<T> valueClass, - MemberValueConsumer<T> consumer) { + List<T> results = new ArrayList<T>(); for (FrameworkField each : getAnnotatedFields(annotationClass)) { try { Object fieldValue = each.get(test); if (valueClass.isInstance(fieldValue)) { - consumer.accept(each, valueClass.cast(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 <T> List<T> getAnnotatedMethodValues(Object test, Class<? extends Annotation> annotationClass, Class<T> valueClass) { - final List<T> results = new ArrayList<T>(); - collectAnnotatedMethodValues(test, annotationClass, valueClass, - new MemberValueConsumer<T>() { - public void accept(FrameworkMember<?> member, T value) { - results.add(value); - } - }); - return results; - } - - /** - * Finds the methods annotated with the specified annotation and returning the specified type, - * invokes it and pass the return value to the specified consumer. - * - * @since 4.13 - */ - public <T> void collectAnnotatedMethodValues(Object test, - Class<? extends Annotation> annotationClass, Class<T> valueClass, - MemberValueConsumer<T> consumer) { + List<T> results = new ArrayList<T>(); for (FrameworkMethod each : getAnnotatedMethods(annotationClass)) { try { /* @@ -290,13 +254,14 @@ public class TestClass implements Annotatable { */ if (valueClass.isAssignableFrom(each.getReturnType())) { Object fieldValue = each.invokeExplosively(test); - consumer.accept(each, valueClass.cast(fieldValue)); + results.add(valueClass.cast(fieldValue)); } } catch (Throwable e) { throw new RuntimeException( "Exception in " + each.getName(), e); } } + return results; } public boolean isPublic() { diff --git a/src/main/java/org/junit/runners/parameterized/BlockJUnit4ClassRunnerWithParameters.java b/src/main/java/org/junit/runners/parameterized/BlockJUnit4ClassRunnerWithParameters.java index 5c70a75..1c49f84 100644 --- a/src/main/java/org/junit/runners/parameterized/BlockJUnit4ClassRunnerWithParameters.java +++ b/src/main/java/org/junit/runners/parameterized/BlockJUnit4ClassRunnerWithParameters.java @@ -4,12 +4,8 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.List; -import org.junit.internal.runners.statements.RunAfters; -import org.junit.internal.runners.statements.RunBefores; -import org.junit.runner.RunWith; import org.junit.runner.notification.RunNotifier; import org.junit.runners.BlockJUnit4ClassRunner; -import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import org.junit.runners.model.FrameworkField; import org.junit.runners.model.FrameworkMethod; @@ -22,17 +18,13 @@ import org.junit.runners.model.Statement; */ public class BlockJUnit4ClassRunnerWithParameters extends BlockJUnit4ClassRunner { - private enum InjectionType { - CONSTRUCTOR, FIELD - } - private final Object[] parameters; private final String name; public BlockJUnit4ClassRunnerWithParameters(TestWithParameters test) throws InitializationError { - super(test.getTestClass()); + super(test.getTestClass().getJavaClass()); parameters = test.getParameters().toArray( new Object[test.getParameters().size()]); name = test.getName(); @@ -40,15 +32,10 @@ public class BlockJUnit4ClassRunnerWithParameters extends @Override public Object createTest() throws Exception { - InjectionType injectionType = getInjectionType(); - switch (injectionType) { - case CONSTRUCTOR: - return createTestUsingConstructorInjection(); - case FIELD: - return createTestUsingFieldInjection(); - default: - throw new IllegalStateException("The injection type " - + injectionType + " is not supported."); + if (fieldsAreAnnotated()) { + return createTestUsingFieldInjection(); + } else { + return createTestUsingConstructorInjection(); } } @@ -73,13 +60,6 @@ public class BlockJUnit4ClassRunnerWithParameters extends int index = annotation.value(); try { field.set(testClassInstance, parameters[index]); - } catch (IllegalAccessException e) { - IllegalAccessException wrappedException = new IllegalAccessException( - "Cannot set parameter '" + field.getName() - + "'. Ensure that the field '" + field.getName() - + "' is public."); - wrappedException.initCause(e); - throw wrappedException; } catch (IllegalArgumentException iare) { throw new Exception(getTestClass().getName() + ": Trying to set " + field.getName() @@ -106,7 +86,7 @@ public class BlockJUnit4ClassRunnerWithParameters extends @Override protected void validateConstructor(List<Throwable> errors) { validateOnlyOneConstructor(errors); - if (getInjectionType() != InjectionType.CONSTRUCTOR) { + if (fieldsAreAnnotated()) { validateZeroArgConstructor(errors); } } @@ -114,7 +94,7 @@ public class BlockJUnit4ClassRunnerWithParameters extends @Override protected void validateFields(List<Throwable> errors) { super.validateFields(errors); - if (getInjectionType() == InjectionType.FIELD) { + if (fieldsAreAnnotated()) { List<FrameworkField> annotatedFieldsByParameter = getAnnotatedFieldsByParameter(); int[] usedIndices = new int[annotatedFieldsByParameter.size()]; for (FrameworkField each : annotatedFieldsByParameter) { @@ -145,74 +125,18 @@ public class BlockJUnit4ClassRunnerWithParameters extends @Override protected Statement classBlock(RunNotifier notifier) { - Statement statement = childrenInvoker(notifier); - statement = withBeforeParams(statement); - statement = withAfterParams(statement); - return statement; - } - - private Statement withBeforeParams(Statement statement) { - List<FrameworkMethod> befores = getTestClass() - .getAnnotatedMethods(Parameterized.BeforeParam.class); - return befores.isEmpty() ? statement : new RunBeforeParams(statement, befores); - } - - private class RunBeforeParams extends RunBefores { - RunBeforeParams(Statement next, List<FrameworkMethod> befores) { - super(next, befores, null); - } - - @Override - protected void invokeMethod(FrameworkMethod method) throws Throwable { - int paramCount = method.getMethod().getParameterTypes().length; - method.invokeExplosively(null, paramCount == 0 ? (Object[]) null : parameters); - } - } - - private Statement withAfterParams(Statement statement) { - List<FrameworkMethod> afters = getTestClass() - .getAnnotatedMethods(Parameterized.AfterParam.class); - return afters.isEmpty() ? statement : new RunAfterParams(statement, afters); - } - - private class RunAfterParams extends RunAfters { - RunAfterParams(Statement next, List<FrameworkMethod> afters) { - super(next, afters, null); - } - - @Override - protected void invokeMethod(FrameworkMethod method) throws Throwable { - int paramCount = method.getMethod().getParameterTypes().length; - method.invokeExplosively(null, paramCount == 0 ? (Object[]) null : parameters); - } + return childrenInvoker(notifier); } @Override protected Annotation[] getRunnerAnnotations() { - Annotation[] allAnnotations = super.getRunnerAnnotations(); - Annotation[] annotationsWithoutRunWith = new Annotation[allAnnotations.length - 1]; - int i = 0; - for (Annotation annotation: allAnnotations) { - if (!annotation.annotationType().equals(RunWith.class)) { - annotationsWithoutRunWith[i] = annotation; - ++i; - } - } - return annotationsWithoutRunWith; + return new Annotation[0]; } private List<FrameworkField> getAnnotatedFieldsByParameter() { return getTestClass().getAnnotatedFields(Parameter.class); } - private InjectionType getInjectionType() { - if (fieldsAreAnnotated()) { - return InjectionType.FIELD; - } else { - return InjectionType.CONSTRUCTOR; - } - } - private boolean fieldsAreAnnotated() { return !getAnnotatedFieldsByParameter().isEmpty(); } diff --git a/src/main/java/org/junit/runners/parameterized/ParametersRunnerFactory.java b/src/main/java/org/junit/runners/parameterized/ParametersRunnerFactory.java index 8123e83..16ea1f3 100644 --- a/src/main/java/org/junit/runners/parameterized/ParametersRunnerFactory.java +++ b/src/main/java/org/junit/runners/parameterized/ParametersRunnerFactory.java @@ -4,7 +4,7 @@ import org.junit.runner.Runner; import org.junit.runners.model.InitializationError; /** - * A {@code ParametersRunnerFactory} creates a runner for a single + * A {@code ParameterizedRunnerFactory} creates a runner for a single * {@link TestWithParameters}. * * @since 4.12 diff --git a/src/main/java/org/junit/runners/parameterized/TestWithParameters.java b/src/main/java/org/junit/runners/parameterized/TestWithParameters.java index 1c5abd9..1b86644 100644 --- a/src/main/java/org/junit/runners/parameterized/TestWithParameters.java +++ b/src/main/java/org/junit/runners/parameterized/TestWithParameters.java @@ -1,7 +1,6 @@ package org.junit.runners.parameterized; import static java.util.Collections.unmodifiableList; -import static org.junit.internal.Checks.notNull; import java.util.ArrayList; import java.util.List; @@ -74,4 +73,10 @@ public class TestWithParameters { return testClass.getName() + " '" + name + "' with parameters " + parameters; } + + private static void notNull(Object value, String message) { + if (value == null) { + throw new NullPointerException(message); + } + } } |