    001    package org.junit.runners;
    002
    003    import static org.junit.internal.Checks.notNull;
    004    import static org.junit.internal.runners.rules.RuleMemberValidator.CLASS_RULE_METHOD_VALIDATOR;
    005    import static org.junit.internal.runners.rules.RuleMemberValidator.CLASS_RULE_VALIDATOR;
    006
    007    import java.lang.annotation.Annotation;
    008    import java.lang.reflect.Method;
    009    import java.util.ArrayList;
    010    import java.util.Collections;
    011    import java.util.Comparator;
    012    import java.util.Iterator;
    013    import java.util.LinkedHashMap;
    014    import java.util.List;
    015    import java.util.Map;
    016    import java.util.concurrent.locks.Lock;
    017    import java.util.concurrent.locks.ReentrantLock;
    018
    019    import org.junit.AfterClass;
    020    import org.junit.BeforeClass;
    021    import org.junit.ClassRule;
    022    import org.junit.FixMethodOrder;
    023    import org.junit.Ignore;
    024    import org.junit.Rule;
    025    import org.junit.internal.AssumptionViolatedException;
    026    import org.junit.internal.runners.model.EachTestNotifier;
    027    import org.junit.internal.runners.statements.RunAfters;
    028    import org.junit.internal.runners.statements.RunBefores;
    029    import org.junit.rules.RunRules;
    030    import org.junit.rules.TestRule;
    031    import org.junit.runner.Description;
    032    import org.junit.runner.Runner;
    033    import org.junit.runner.manipulation.Filter;
    034    import org.junit.runner.manipulation.Filterable;
    035    import org.junit.runner.manipulation.Orderer;
    036    import org.junit.runner.manipulation.InvalidOrderingException;
    037    import org.junit.runner.manipulation.NoTestsRemainException;
    038    import org.junit.runner.manipulation.Orderable;
    039    import org.junit.runner.manipulation.Sorter;
    040    import org.junit.runner.notification.RunNotifier;
    041    import org.junit.runner.notification.StoppedByUserException;
    042    import org.junit.runners.model.FrameworkMember;
    043    import org.junit.runners.model.FrameworkMethod;
    044    import org.junit.runners.model.InitializationError;
    045    import org.junit.runners.model.InvalidTestClassError;
    046    import org.junit.runners.model.MemberValueConsumer;
    047    import org.junit.runners.model.RunnerScheduler;
    048    import org.junit.runners.model.Statement;
    049    import org.junit.runners.model.TestClass;
    050    import org.junit.validator.AnnotationsValidator;
    051    import org.junit.validator.TestClassValidator;
    052
    053    /**
    054     * Provides most of the functionality specific to a Runner that implements a
    055     * "parent node" in the test tree, with children defined by objects of some data
    056     * type {@code T}. (For {@link BlockJUnit4ClassRunner}, {@code T} is
    057     * {@link Method} . For {@link Suite}, {@code T} is {@link Class}.) Subclasses
    058     * must implement finding the children of the node, describing each child, and
    059     * running each child. ParentRunner will filter and sort children, handle
    060     * {@code @BeforeClass} and {@code @AfterClass} methods,
    061     * handle annotated {@link ClassRule}s, create a composite
    062     * {@link Description}, and run children sequentially.
    063     *
    064     * @since 4.5
    065     */
    066    public abstract class ParentRunner<T> extends Runner implements Filterable,
    067            Orderable {
    068        private static final List<TestClassValidator> VALIDATORS = Collections.<TestClassValidator>singletonList(
    069                new AnnotationsValidator());
    070
    071        private final Lock childrenLock = new ReentrantLock();
    072        private final TestClass testClass;
    073
    074        // Guarded by childrenLock
    075        private volatile List<T> filteredChildren = null;
    076
    077        private volatile RunnerScheduler scheduler = new RunnerScheduler() {
    078            public void schedule(Runnable childStatement) {
    079                childStatement.run();
    080            }
    081
    082            public void finished() {
    083                // do nothing
    084            }
    085        };
    086
    087        /**
    088         * Constructs a new {@code ParentRunner} that will run {@code @TestClass}
    089         */
    090        protected ParentRunner(Class<?> testClass) throws InitializationError {
    091            this.testClass = createTestClass(testClass);
    092            validate();
    093        }
    094
    095       /**
    096        * Constructs a new {@code ParentRunner} that will run the {@code TestClass}.
    097        *
    098        * @since 4.13
    099        */
    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
    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         */
    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         */
    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         */
    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         */
    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
    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         */
    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
    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         */
    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
    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         */
    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         */
    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         */
    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         */
    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         */
    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    }