• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.junit.runners;
2 
3 import static org.junit.internal.Checks.notNull;
4 import static org.junit.internal.runners.rules.RuleMemberValidator.CLASS_RULE_METHOD_VALIDATOR;
5 import static org.junit.internal.runners.rules.RuleMemberValidator.CLASS_RULE_VALIDATOR;
6 
7 import java.lang.annotation.Annotation;
8 import java.lang.reflect.Method;
9 import java.util.ArrayList;
10 import java.util.Collections;
11 import java.util.Comparator;
12 import java.util.Iterator;
13 import java.util.LinkedHashMap;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.concurrent.locks.Lock;
17 import java.util.concurrent.locks.ReentrantLock;
18 
19 import org.junit.AfterClass;
20 import org.junit.BeforeClass;
21 import org.junit.ClassRule;
22 import org.junit.FixMethodOrder;
23 import org.junit.Ignore;
24 import org.junit.Rule;
25 import org.junit.internal.AssumptionViolatedException;
26 import org.junit.internal.runners.model.EachTestNotifier;
27 import org.junit.internal.runners.statements.RunAfters;
28 import org.junit.internal.runners.statements.RunBefores;
29 import org.junit.rules.RunRules;
30 import org.junit.rules.TestRule;
31 import org.junit.runner.Description;
32 import org.junit.runner.Runner;
33 import org.junit.runner.manipulation.Filter;
34 import org.junit.runner.manipulation.Filterable;
35 import org.junit.runner.manipulation.Orderer;
36 import org.junit.runner.manipulation.InvalidOrderingException;
37 import org.junit.runner.manipulation.NoTestsRemainException;
38 import org.junit.runner.manipulation.Orderable;
39 import org.junit.runner.manipulation.Sorter;
40 import org.junit.runner.notification.RunNotifier;
41 import org.junit.runner.notification.StoppedByUserException;
42 import org.junit.runners.model.FrameworkMember;
43 import org.junit.runners.model.FrameworkMethod;
44 import org.junit.runners.model.InitializationError;
45 import org.junit.runners.model.InvalidTestClassError;
46 import org.junit.runners.model.MemberValueConsumer;
47 import org.junit.runners.model.RunnerScheduler;
48 import org.junit.runners.model.Statement;
49 import org.junit.runners.model.TestClass;
50 import org.junit.validator.AnnotationsValidator;
51 import org.junit.validator.TestClassValidator;
52 
53 /**
54  * Provides most of the functionality specific to a Runner that implements a
55  * "parent node" in the test tree, with children defined by objects of some data
56  * type {@code T}. (For {@link BlockJUnit4ClassRunner}, {@code T} is
57  * {@link Method} . For {@link Suite}, {@code T} is {@link Class}.) Subclasses
58  * must implement finding the children of the node, describing each child, and
59  * running each child. ParentRunner will filter and sort children, handle
60  * {@code @BeforeClass} and {@code @AfterClass} methods,
61  * handle annotated {@link ClassRule}s, create a composite
62  * {@link Description}, and run children sequentially.
63  *
64  * @since 4.5
65  */
66 public abstract class ParentRunner<T> extends Runner implements Filterable,
67         Orderable {
68     private static final List<TestClassValidator> VALIDATORS = Collections.<TestClassValidator>singletonList(
69             new AnnotationsValidator());
70 
71     private final Lock childrenLock = new ReentrantLock();
72     private final TestClass testClass;
73 
74     // Guarded by childrenLock
75     private volatile List<T> filteredChildren = null;
76 
77     private volatile RunnerScheduler scheduler = new RunnerScheduler() {
78         public void schedule(Runnable childStatement) {
79             childStatement.run();
80         }
81 
82         public void finished() {
83             // do nothing
84         }
85     };
86 
87     /**
88      * Constructs a new {@code ParentRunner} that will run {@code @TestClass}
89      */
ParentRunner(Class<?> testClass)90     protected ParentRunner(Class<?> testClass) throws InitializationError {
91         this.testClass = createTestClass(testClass);
92         validate();
93     }
94 
95    /**
96     * Constructs a new {@code ParentRunner} that will run the {@code TestClass}.
97     *
98     * @since 4.13
99     */
ParentRunner(TestClass testClass)100     protected ParentRunner(TestClass testClass) throws InitializationError {
101        this.testClass = notNull(testClass);
102        validate();
103     }
104 
105     /**
106      * @deprecated Please use {@link #ParentRunner(org.junit.runners.model.TestClass)}.
107      * @since 4.12
108      */
109     @Deprecated
createTestClass(Class<?> testClass)110     protected TestClass createTestClass(Class<?> testClass) {
111         return new TestClass(testClass);
112     }
113 
114     //
115     // Must be overridden
116     //
117 
118     /**
119      * Returns a list of objects that define the children of this Runner.
120      */
getChildren()121     protected abstract List<T> getChildren();
122 
123     /**
124      * Returns a {@link Description} for {@code child}, which can be assumed to
125      * be an element of the list returned by {@link ParentRunner#getChildren()}
126      */
describeChild(T child)127     protected abstract Description describeChild(T child);
128 
129     /**
130      * Runs the test corresponding to {@code child}, which can be assumed to be
131      * an element of the list returned by {@link ParentRunner#getChildren()}.
132      * Subclasses are responsible for making sure that relevant test events are
133      * reported through {@code notifier}
134      */
runChild(T child, RunNotifier notifier)135     protected abstract void runChild(T child, RunNotifier notifier);
136 
137     //
138     // May be overridden
139     //
140 
141     /**
142      * Adds to {@code errors} a throwable for each problem noted with the test class (available from {@link #getTestClass()}).
143      * Default implementation adds an error for each method annotated with
144      * {@code @BeforeClass} or {@code @AfterClass} that is not
145      * {@code public static void} with no arguments.
146      */
collectInitializationErrors(List<Throwable> errors)147     protected void collectInitializationErrors(List<Throwable> errors) {
148         validatePublicVoidNoArgMethods(BeforeClass.class, true, errors);
149         validatePublicVoidNoArgMethods(AfterClass.class, true, errors);
150         validateClassRules(errors);
151         applyValidators(errors);
152     }
153 
applyValidators(List<Throwable> errors)154     private void applyValidators(List<Throwable> errors) {
155         if (getTestClass().getJavaClass() != null) {
156             for (TestClassValidator each : VALIDATORS) {
157                 errors.addAll(each.validateTestClass(getTestClass()));
158             }
159         }
160     }
161 
162     /**
163      * Adds to {@code errors} if any method in this class is annotated with
164      * {@code annotation}, but:
165      * <ul>
166      * <li>is not public, or
167      * <li>takes parameters, or
168      * <li>returns something other than void, or
169      * <li>is static (given {@code isStatic is false}), or
170      * <li>is not static (given {@code isStatic is true}).
171      * </ul>
172      */
validatePublicVoidNoArgMethods(Class<? extends Annotation> annotation, boolean isStatic, List<Throwable> errors)173     protected void validatePublicVoidNoArgMethods(Class<? extends Annotation> annotation,
174             boolean isStatic, List<Throwable> errors) {
175         List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(annotation);
176 
177         for (FrameworkMethod eachTestMethod : methods) {
178             eachTestMethod.validatePublicVoidNoArg(isStatic, errors);
179         }
180     }
181 
validateClassRules(List<Throwable> errors)182     private void validateClassRules(List<Throwable> errors) {
183         CLASS_RULE_VALIDATOR.validate(getTestClass(), errors);
184         CLASS_RULE_METHOD_VALIDATOR.validate(getTestClass(), errors);
185     }
186 
187     /**
188      * Constructs a {@code Statement} to run all of the tests in the test class.
189      * Override to add pre-/post-processing. Here is an outline of the
190      * implementation:
191      * <ol>
192      * <li>Determine the children to be run using {@link #getChildren()}
193      * (subject to any imposed filter and sort).</li>
194      * <li>If there are any children remaining after filtering and ignoring,
195      * construct a statement that will:
196      * <ol>
197      * <li>Apply all {@code ClassRule}s on the test-class and superclasses.</li>
198      * <li>Run all non-overridden {@code @BeforeClass} methods on the test-class
199      * and superclasses; if any throws an Exception, stop execution and pass the
200      * exception on.</li>
201      * <li>Run all remaining tests on the test-class.</li>
202      * <li>Run all non-overridden {@code @AfterClass} methods on the test-class
203      * and superclasses: exceptions thrown by previous steps are combined, if
204      * necessary, with exceptions from AfterClass methods into a
205      * {@link org.junit.runners.model.MultipleFailureException}.</li>
206      * </ol>
207      * </li>
208      * </ol>
209      *
210      * @return {@code Statement}
211      */
classBlock(final RunNotifier notifier)212     protected Statement classBlock(final RunNotifier notifier) {
213         Statement statement = childrenInvoker(notifier);
214         if (!areAllChildrenIgnored()) {
215             statement = withBeforeClasses(statement);
216             statement = withAfterClasses(statement);
217             statement = withClassRules(statement);
218             statement = withInterruptIsolation(statement);
219         }
220         return statement;
221     }
222 
areAllChildrenIgnored()223     private boolean areAllChildrenIgnored() {
224         for (T child : getFilteredChildren()) {
225             if (!isIgnored(child)) {
226                 return false;
227             }
228         }
229         return true;
230     }
231 
232     /**
233      * Returns a {@link Statement}: run all non-overridden {@code @BeforeClass} methods on this class
234      * and superclasses before executing {@code statement}; if any throws an
235      * Exception, stop execution and pass the exception on.
236      */
withBeforeClasses(Statement statement)237     protected Statement withBeforeClasses(Statement statement) {
238         List<FrameworkMethod> befores = testClass
239                 .getAnnotatedMethods(BeforeClass.class);
240         return befores.isEmpty() ? statement :
241                 new RunBefores(statement, befores, null);
242     }
243 
244     /**
245      * Returns a {@link Statement}: run all non-overridden {@code @AfterClass} methods on this class
246      * and superclasses after executing {@code statement}; all AfterClass methods are
247      * always executed: exceptions thrown by previous steps are combined, if
248      * necessary, with exceptions from AfterClass methods into a
249      * {@link org.junit.runners.model.MultipleFailureException}.
250      */
withAfterClasses(Statement statement)251     protected Statement withAfterClasses(Statement statement) {
252         List<FrameworkMethod> afters = testClass
253                 .getAnnotatedMethods(AfterClass.class);
254         return afters.isEmpty() ? statement :
255                 new RunAfters(statement, afters, null);
256     }
257 
258     /**
259      * Returns a {@link Statement}: apply all
260      * static fields assignable to {@link TestRule}
261      * annotated with {@link ClassRule}.
262      *
263      * @param statement the base statement
264      * @return a RunRules statement if any class-level {@link Rule}s are
265      *         found, or the base statement
266      */
withClassRules(Statement statement)267     private Statement withClassRules(Statement statement) {
268         List<TestRule> classRules = classRules();
269         return classRules.isEmpty() ? statement :
270                 new RunRules(statement, classRules, getDescription());
271     }
272 
273     /**
274      * @return the {@code ClassRule}s that can transform the block that runs
275      *         each method in the tested class.
276      */
classRules()277     protected List<TestRule> classRules() {
278         ClassRuleCollector collector = new ClassRuleCollector();
279         testClass.collectAnnotatedMethodValues(null, ClassRule.class, TestRule.class, collector);
280         testClass.collectAnnotatedFieldValues(null, ClassRule.class, TestRule.class, collector);
281         return collector.getOrderedRules();
282     }
283 
284     /**
285      * Returns a {@link Statement}: Call {@link #runChild(Object, RunNotifier)}
286      * on each object returned by {@link #getChildren()} (subject to any imposed
287      * filter and sort)
288      */
childrenInvoker(final RunNotifier notifier)289     protected Statement childrenInvoker(final RunNotifier notifier) {
290         return new Statement() {
291             @Override
292             public void evaluate() {
293                 runChildren(notifier);
294             }
295         };
296     }
297 
298     /**
299      * @return a {@link Statement}: clears interrupt status of current thread after execution of statement
300      */
301     protected final Statement withInterruptIsolation(final Statement statement) {
302         return new Statement() {
303             @Override
304             public void evaluate() throws Throwable {
305                 try {
306                     statement.evaluate();
307                 } finally {
308                     Thread.interrupted(); // clearing thread interrupted status for isolation
309                 }
310             }
311         };
312     }
313 
314     /**
315      * Evaluates whether a child is ignored. The default implementation always
316      * returns <code>false</code>.
317      *
318      * <p>{@link BlockJUnit4ClassRunner}, for example, overrides this method to
319      * filter tests based on the {@link Ignore} annotation.
320      */
321     protected boolean isIgnored(T child) {
322         return false;
323     }
324 
325     private void runChildren(final RunNotifier notifier) {
326         final RunnerScheduler currentScheduler = scheduler;
327         try {
328             for (final T each : getFilteredChildren()) {
329                 currentScheduler.schedule(new Runnable() {
330                     public void run() {
331                         ParentRunner.this.runChild(each, notifier);
332                     }
333                 });
334             }
335         } finally {
336             currentScheduler.finished();
337         }
338     }
339 
340     /**
341      * Returns a name used to describe this Runner
342      */
343     protected String getName() {
344         return testClass.getName();
345     }
346 
347     //
348     // Available for subclasses
349     //
350 
351     /**
352      * Returns a {@link TestClass} object wrapping the class to be executed.
353      */
354     public final TestClass getTestClass() {
355         return testClass;
356     }
357 
358     /**
359      * Runs a {@link Statement} that represents a leaf (aka atomic) test.
360      */
361     protected final void runLeaf(Statement statement, Description description,
362             RunNotifier notifier) {
363         EachTestNotifier eachNotifier = new EachTestNotifier(notifier, description);
364         eachNotifier.fireTestStarted();
365         try {
366             statement.evaluate();
367         } catch (AssumptionViolatedException e) {
368             eachNotifier.addFailedAssumption(e);
369         } catch (Throwable e) {
370             eachNotifier.addFailure(e);
371         } finally {
372             eachNotifier.fireTestFinished();
373         }
374     }
375 
376     /**
377      * @return the annotations that should be attached to this runner's
378      *         description.
379      */
380     protected Annotation[] getRunnerAnnotations() {
381         return testClass.getAnnotations();
382     }
383 
384     //
385     // Implementation of Runner
386     //
387 
388     @Override
389     public Description getDescription() {
390         Class<?> clazz = getTestClass().getJavaClass();
391         Description description;
392         // if subclass overrides `getName()` then we should use it
393         // to maintain backwards compatibility with JUnit 4.12
394         if (clazz == null || !clazz.getName().equals(getName())) {
395             description = Description.createSuiteDescription(getName(), getRunnerAnnotations());
396         } else {
397             description = Description.createSuiteDescription(clazz, getRunnerAnnotations());
398         }
399 
400         for (T child : getFilteredChildren()) {
401             description.addChild(describeChild(child));
402         }
403         return description;
404     }
405 
406     @Override
407     public void run(final RunNotifier notifier) {
408         EachTestNotifier testNotifier = new EachTestNotifier(notifier,
409                 getDescription());
410         testNotifier.fireTestSuiteStarted();
411         try {
412             Statement statement = classBlock(notifier);
413             statement.evaluate();
414         } catch (AssumptionViolatedException e) {
415             testNotifier.addFailedAssumption(e);
416         } catch (StoppedByUserException e) {
417             throw e;
418         } catch (Throwable e) {
419             testNotifier.addFailure(e);
420         } finally {
421             testNotifier.fireTestSuiteFinished();
422         }
423     }
424 
425     //
426     // Implementation of Filterable and Sortable
427     //
428 
429     public void filter(Filter filter) throws NoTestsRemainException {
430         childrenLock.lock();
431         try {
432             List<T> children = new ArrayList<T>(getFilteredChildren());
433             for (Iterator<T> iter = children.iterator(); iter.hasNext(); ) {
434                 T each = iter.next();
435                 if (shouldRun(filter, each)) {
436                     try {
437                         filter.apply(each);
438                     } catch (NoTestsRemainException e) {
439                         iter.remove();
440                     }
441                 } else {
442                     iter.remove();
443                 }
444             }
445             filteredChildren = Collections.unmodifiableList(children);
446             if (filteredChildren.isEmpty()) {
447                 throw new NoTestsRemainException();
448             }
449         } finally {
450             childrenLock.unlock();
451         }
452     }
453 
454     public void sort(Sorter sorter) {
455         if (shouldNotReorder()) {
456             return;
457         }
458 
459         childrenLock.lock();
460         try {
461             for (T each : getFilteredChildren()) {
462                 sorter.apply(each);
463             }
464             List<T> sortedChildren = new ArrayList<T>(getFilteredChildren());
465             Collections.sort(sortedChildren, comparator(sorter));
466             filteredChildren = Collections.unmodifiableList(sortedChildren);
467         } finally {
468             childrenLock.unlock();
469         }
470     }
471 
472     /**
473      * Implementation of {@link Orderable#order(Orderer)}.
474      *
475      * @since 4.13
476      */
477     public void order(Orderer orderer) throws InvalidOrderingException {
478         if (shouldNotReorder()) {
479             return;
480         }
481 
482         childrenLock.lock();
483         try {
484             List<T> children = getFilteredChildren();
485             // In theory, we could have duplicate Descriptions. De-dup them before ordering,
486             // and add them back at the end.
487             Map<Description, List<T>> childMap = new LinkedHashMap<Description, List<T>>(
488                     children.size());
489             for (T child : children) {
490                 Description description = describeChild(child);
491                 List<T> childrenWithDescription = childMap.get(description);
492                 if (childrenWithDescription == null) {
493                     childrenWithDescription = new ArrayList<T>(1);
494                     childMap.put(description, childrenWithDescription);
495                 }
496                 childrenWithDescription.add(child);
497                 orderer.apply(child);
498             }
499 
500             List<Description> inOrder = orderer.order(childMap.keySet());
501 
502             children = new ArrayList<T>(children.size());
503             for (Description description : inOrder) {
504                 children.addAll(childMap.get(description));
505             }
506             filteredChildren = Collections.unmodifiableList(children);
507         } finally {
508             childrenLock.unlock();
509         }
510     }
511 
512     //
513     // Private implementation
514     //
515 
516     private boolean shouldNotReorder() {
517         // If the test specifies a specific order, do not reorder.
518         return getDescription().getAnnotation(FixMethodOrder.class) != null;
519     }
520 
521     private void validate() throws InitializationError {
522         List<Throwable> errors = new ArrayList<Throwable>();
523         collectInitializationErrors(errors);
524         if (!errors.isEmpty()) {
525             throw new InvalidTestClassError(testClass.getJavaClass(), errors);
526         }
527     }
528 
529     private List<T> getFilteredChildren() {
530         if (filteredChildren == null) {
531             childrenLock.lock();
532             try {
533                 if (filteredChildren == null) {
534                     filteredChildren = Collections.unmodifiableList(
535                             new ArrayList<T>(getChildren()));
536                 }
537             } finally {
538                 childrenLock.unlock();
539             }
540         }
541         return filteredChildren;
542     }
543 
544     private boolean shouldRun(Filter filter, T each) {
545         return filter.shouldRun(describeChild(each));
546     }
547 
548     private Comparator<? super T> comparator(final Sorter sorter) {
549         return new Comparator<T>() {
550             public int compare(T o1, T o2) {
551                 return sorter.compare(describeChild(o1), describeChild(o2));
552             }
553         };
554     }
555 
556     /**
557      * Sets a scheduler that determines the order and parallelization
558      * of children.  Highly experimental feature that may change.
559      */
560     public void setScheduler(RunnerScheduler scheduler) {
561         this.scheduler = scheduler;
562     }
563 
564     private static class ClassRuleCollector implements MemberValueConsumer<TestRule> {
565         final List<RuleContainer.RuleEntry> entries = new ArrayList<RuleContainer.RuleEntry>();
566 
567         public void accept(FrameworkMember<?> member, TestRule value) {
568             ClassRule rule = member.getAnnotation(ClassRule.class);
569             entries.add(new RuleContainer.RuleEntry(value, RuleContainer.RuleEntry.TYPE_TEST_RULE,
570                     rule != null ? rule.order() : null));
571         }
572 
573         public List<TestRule> getOrderedRules() {
574             Collections.sort(entries, RuleContainer.ENTRY_COMPARATOR);
575             List<TestRule> result = new ArrayList<TestRule>(entries.size());
576             for (RuleContainer.RuleEntry entry : entries) {
577                 result.add((TestRule) entry.rule);
578             }
579             return result;
580         }
581     }
582 }
583