001package org.junit.runners;
002
003import static org.junit.internal.runners.rules.RuleMemberValidator.CLASS_RULE_METHOD_VALIDATOR;
004import static org.junit.internal.runners.rules.RuleMemberValidator.CLASS_RULE_VALIDATOR;
005
006import java.lang.annotation.Annotation;
007import java.lang.reflect.Method;
008import java.util.ArrayList;
009import java.util.Arrays;
010import java.util.Collection;
011import java.util.Collections;
012import java.util.Comparator;
013import java.util.Iterator;
014import java.util.List;
015
016import org.junit.AfterClass;
017import org.junit.BeforeClass;
018import org.junit.ClassRule;
019import org.junit.Ignore;
020import org.junit.Rule;
021import org.junit.internal.AssumptionViolatedException;
022import org.junit.internal.runners.model.EachTestNotifier;
023import org.junit.internal.runners.statements.RunAfters;
024import org.junit.internal.runners.statements.RunBefores;
025import org.junit.rules.RunRules;
026import org.junit.rules.TestRule;
027import org.junit.runner.Description;
028import org.junit.runner.Runner;
029import org.junit.runner.manipulation.Filter;
030import org.junit.runner.manipulation.Filterable;
031import org.junit.runner.manipulation.NoTestsRemainException;
032import org.junit.runner.manipulation.Sortable;
033import org.junit.runner.manipulation.Sorter;
034import org.junit.runner.notification.RunNotifier;
035import org.junit.runner.notification.StoppedByUserException;
036import org.junit.runners.model.FrameworkMethod;
037import org.junit.runners.model.InitializationError;
038import org.junit.runners.model.RunnerScheduler;
039import org.junit.runners.model.Statement;
040import org.junit.runners.model.TestClass;
041import org.junit.validator.AnnotationsValidator;
042import org.junit.validator.PublicClassValidator;
043import org.junit.validator.TestClassValidator;
044
045/**
046 * Provides most of the functionality specific to a Runner that implements a
047 * "parent node" in the test tree, with children defined by objects of some data
048 * type {@code T}. (For {@link BlockJUnit4ClassRunner}, {@code T} is
049 * {@link Method} . For {@link Suite}, {@code T} is {@link Class}.) Subclasses
050 * must implement finding the children of the node, describing each child, and
051 * running each child. ParentRunner will filter and sort children, handle
052 * {@code @BeforeClass} and {@code @AfterClass} methods,
053 * handle annotated {@link ClassRule}s, create a composite
054 * {@link Description}, and run children sequentially.
055 *
056 * @since 4.5
057 */
058public abstract class ParentRunner<T> extends Runner implements Filterable,
059        Sortable {
060    private static final List<TestClassValidator> VALIDATORS = Arrays.asList(
061            new AnnotationsValidator(), new PublicClassValidator());
062
063    private final Object childrenLock = new Object();
064    private final TestClass testClass;
065
066    // Guarded by childrenLock
067    private volatile Collection<T> filteredChildren = null;
068
069    private volatile RunnerScheduler scheduler = new RunnerScheduler() {
070        public void schedule(Runnable childStatement) {
071            childStatement.run();
072        }
073
074        public void finished() {
075            // do nothing
076        }
077    };
078
079    /**
080     * Constructs a new {@code ParentRunner} that will run {@code @TestClass}
081     */
082    protected ParentRunner(Class<?> testClass) throws InitializationError {
083        this.testClass = createTestClass(testClass);
084        validate();
085    }
086
087    protected TestClass createTestClass(Class<?> testClass) {
088        return new TestClass(testClass);
089    }
090
091    //
092    // Must be overridden
093    //
094
095    /**
096     * Returns a list of objects that define the children of this Runner.
097     */
098    protected abstract List<T> getChildren();
099
100    /**
101     * Returns a {@link Description} for {@code child}, which can be assumed to
102     * be an element of the list returned by {@link ParentRunner#getChildren()}
103     */
104    protected abstract Description describeChild(T child);
105
106    /**
107     * Runs the test corresponding to {@code child}, which can be assumed to be
108     * an element of the list returned by {@link ParentRunner#getChildren()}.
109     * Subclasses are responsible for making sure that relevant test events are
110     * reported through {@code notifier}
111     */
112    protected abstract void runChild(T child, RunNotifier notifier);
113
114    //
115    // May be overridden
116    //
117
118    /**
119     * Adds to {@code errors} a throwable for each problem noted with the test class (available from {@link #getTestClass()}).
120     * Default implementation adds an error for each method annotated with
121     * {@code @BeforeClass} or {@code @AfterClass} that is not
122     * {@code public static void} with no arguments.
123     */
124    protected void collectInitializationErrors(List<Throwable> errors) {
125        validatePublicVoidNoArgMethods(BeforeClass.class, true, errors);
126        validatePublicVoidNoArgMethods(AfterClass.class, true, errors);
127        validateClassRules(errors);
128        applyValidators(errors);
129    }
130
131    private void applyValidators(List<Throwable> errors) {
132        if (getTestClass().getJavaClass() != null) {
133            for (TestClassValidator each : VALIDATORS) {
134                errors.addAll(each.validateTestClass(getTestClass()));
135            }
136        }
137    }
138
139    /**
140     * Adds to {@code errors} if any method in this class is annotated with
141     * {@code annotation}, but:
142     * <ul>
143     * <li>is not public, or
144     * <li>takes parameters, or
145     * <li>returns something other than void, or
146     * <li>is static (given {@code isStatic is false}), or
147     * <li>is not static (given {@code isStatic is true}).
148     * </ul>
149     */
150    protected void validatePublicVoidNoArgMethods(Class<? extends Annotation> annotation,
151            boolean isStatic, List<Throwable> errors) {
152        List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(annotation);
153
154        for (FrameworkMethod eachTestMethod : methods) {
155            eachTestMethod.validatePublicVoidNoArg(isStatic, errors);
156        }
157    }
158
159    private void validateClassRules(List<Throwable> errors) {
160        CLASS_RULE_VALIDATOR.validate(getTestClass(), errors);
161        CLASS_RULE_METHOD_VALIDATOR.validate(getTestClass(), errors);
162    }
163
164    /**
165     * Constructs a {@code Statement} to run all of the tests in the test class.
166     * Override to add pre-/post-processing. Here is an outline of the
167     * implementation:
168     * <ol>
169     * <li>Determine the children to be run using {@link #getChildren()}
170     * (subject to any imposed filter and sort).</li>
171     * <li>If there are any children remaining after filtering and ignoring,
172     * construct a statement that will:
173     * <ol>
174     * <li>Apply all {@code ClassRule}s on the test-class and superclasses.</li>
175     * <li>Run all non-overridden {@code @BeforeClass} methods on the test-class
176     * and superclasses; if any throws an Exception, stop execution and pass the
177     * exception on.</li>
178     * <li>Run all remaining tests on the test-class.</li>
179     * <li>Run all non-overridden {@code @AfterClass} methods on the test-class
180     * and superclasses: exceptions thrown by previous steps are combined, if
181     * necessary, with exceptions from AfterClass methods into a
182     * {@link org.junit.runners.model.MultipleFailureException}.</li>
183     * </ol>
184     * </li>
185     * </ol>
186     *
187     * @return {@code Statement}
188     */
189    protected Statement classBlock(final RunNotifier notifier) {
190        Statement statement = childrenInvoker(notifier);
191        if (!areAllChildrenIgnored()) {
192            statement = withBeforeClasses(statement);
193            statement = withAfterClasses(statement);
194            statement = withClassRules(statement);
195        }
196        return statement;
197    }
198
199    private boolean areAllChildrenIgnored() {
200        for (T child : getFilteredChildren()) {
201            if (!isIgnored(child)) {
202                return false;
203            }
204        }
205        return true;
206    }
207
208    /**
209     * Returns a {@link Statement}: run all non-overridden {@code @BeforeClass} methods on this class
210     * and superclasses before executing {@code statement}; if any throws an
211     * Exception, stop execution and pass the exception on.
212     */
213    protected Statement withBeforeClasses(Statement statement) {
214        List<FrameworkMethod> befores = testClass
215                .getAnnotatedMethods(BeforeClass.class);
216        return befores.isEmpty() ? statement :
217                new RunBefores(statement, befores, null);
218    }
219
220    /**
221     * Returns a {@link Statement}: run all non-overridden {@code @AfterClass} methods on this class
222     * and superclasses before executing {@code statement}; all AfterClass methods are
223     * always executed: exceptions thrown by previous steps are combined, if
224     * necessary, with exceptions from AfterClass methods into a
225     * {@link org.junit.runners.model.MultipleFailureException}.
226     */
227    protected Statement withAfterClasses(Statement statement) {
228        List<FrameworkMethod> afters = testClass
229                .getAnnotatedMethods(AfterClass.class);
230        return afters.isEmpty() ? statement :
231                new RunAfters(statement, afters, null);
232    }
233
234    /**
235     * Returns a {@link Statement}: apply all
236     * static fields assignable to {@link TestRule}
237     * annotated with {@link ClassRule}.
238     *
239     * @param statement the base statement
240     * @return a RunRules statement if any class-level {@link Rule}s are
241     *         found, or the base statement
242     */
243    private Statement withClassRules(Statement statement) {
244        List<TestRule> classRules = classRules();
245        return classRules.isEmpty() ? statement :
246                new RunRules(statement, classRules, getDescription());
247    }
248
249    /**
250     * @return the {@code ClassRule}s that can transform the block that runs
251     *         each method in the tested class.
252     */
253    protected List<TestRule> classRules() {
254        List<TestRule> result = testClass.getAnnotatedMethodValues(null, ClassRule.class, TestRule.class);
255        result.addAll(testClass.getAnnotatedFieldValues(null, ClassRule.class, TestRule.class));
256        return result;
257    }
258
259    /**
260     * Returns a {@link Statement}: Call {@link #runChild(Object, RunNotifier)}
261     * on each object returned by {@link #getChildren()} (subject to any imposed
262     * filter and sort)
263     */
264    protected Statement childrenInvoker(final RunNotifier notifier) {
265        return new Statement() {
266            @Override
267            public void evaluate() {
268                runChildren(notifier);
269            }
270        };
271    }
272
273    /**
274     * Evaluates whether a child is ignored. The default implementation always
275     * returns <code>false</code>.
276     * 
277     * <p>{@link BlockJUnit4ClassRunner}, for example, overrides this method to
278     * filter tests based on the {@link Ignore} annotation.
279     */
280    protected boolean isIgnored(T child) {
281        return false;
282    }
283
284    private void runChildren(final RunNotifier notifier) {
285        final RunnerScheduler currentScheduler = scheduler;
286        try {
287            for (final T each : getFilteredChildren()) {
288                currentScheduler.schedule(new Runnable() {
289                    public void run() {
290                        ParentRunner.this.runChild(each, notifier);
291                    }
292                });
293            }
294        } finally {
295            currentScheduler.finished();
296        }
297    }
298
299    /**
300     * Returns a name used to describe this Runner
301     */
302    protected String getName() {
303        return testClass.getName();
304    }
305
306    //
307    // Available for subclasses
308    //
309
310    /**
311     * Returns a {@link TestClass} object wrapping the class to be executed.
312     */
313    public final TestClass getTestClass() {
314        return testClass;
315    }
316
317    /**
318     * Runs a {@link Statement} that represents a leaf (aka atomic) test.
319     */
320    protected final void runLeaf(Statement statement, Description description,
321            RunNotifier notifier) {
322        EachTestNotifier eachNotifier = new EachTestNotifier(notifier, description);
323        eachNotifier.fireTestStarted();
324        try {
325            statement.evaluate();
326        } catch (AssumptionViolatedException e) {
327            eachNotifier.addFailedAssumption(e);
328        } catch (Throwable e) {
329            eachNotifier.addFailure(e);
330        } finally {
331            eachNotifier.fireTestFinished();
332        }
333    }
334
335    /**
336     * @return the annotations that should be attached to this runner's
337     *         description.
338     */
339    protected Annotation[] getRunnerAnnotations() {
340        return testClass.getAnnotations();
341    }
342
343    //
344    // Implementation of Runner
345    //
346
347    @Override
348    public Description getDescription() {
349        Description description = Description.createSuiteDescription(getName(),
350                getRunnerAnnotations());
351        for (T child : getFilteredChildren()) {
352            description.addChild(describeChild(child));
353        }
354        return description;
355    }
356
357    @Override
358    public void run(final RunNotifier notifier) {
359        EachTestNotifier testNotifier = new EachTestNotifier(notifier,
360                getDescription());
361        try {
362            Statement statement = classBlock(notifier);
363            statement.evaluate();
364        } catch (AssumptionViolatedException e) {
365            testNotifier.addFailedAssumption(e);
366        } catch (StoppedByUserException e) {
367            throw e;
368        } catch (Throwable e) {
369            testNotifier.addFailure(e);
370        }
371    }
372
373    //
374    // Implementation of Filterable and Sortable
375    //
376
377    public void filter(Filter filter) throws NoTestsRemainException {
378        synchronized (childrenLock) {
379            List<T> children = new ArrayList<T>(getFilteredChildren());
380            for (Iterator<T> iter = children.iterator(); iter.hasNext(); ) {
381                T each = iter.next();
382                if (shouldRun(filter, each)) {
383                    try {
384                        filter.apply(each);
385                    } catch (NoTestsRemainException e) {
386                        iter.remove();
387                    }
388                } else {
389                    iter.remove();
390                }
391            }
392            filteredChildren = Collections.unmodifiableCollection(children);
393            if (filteredChildren.isEmpty()) {
394                throw new NoTestsRemainException();
395            }
396        }
397    }
398
399    public void sort(Sorter sorter) {
400        synchronized (childrenLock) {
401            for (T each : getFilteredChildren()) {
402                sorter.apply(each);
403            }
404            List<T> sortedChildren = new ArrayList<T>(getFilteredChildren());
405            Collections.sort(sortedChildren, comparator(sorter));
406            filteredChildren = Collections.unmodifiableCollection(sortedChildren);
407        }
408    }
409
410    //
411    // Private implementation
412    //
413
414    private void validate() throws InitializationError {
415        List<Throwable> errors = new ArrayList<Throwable>();
416        collectInitializationErrors(errors);
417        if (!errors.isEmpty()) {
418            throw new InitializationError(errors);
419        }
420    }
421
422    private Collection<T> getFilteredChildren() {
423        if (filteredChildren == null) {
424            synchronized (childrenLock) {
425                if (filteredChildren == null) {
426                    filteredChildren = Collections.unmodifiableCollection(getChildren());
427                }
428            }
429        }
430        return filteredChildren;
431    }
432
433    private boolean shouldRun(Filter filter, T each) {
434        return filter.shouldRun(describeChild(each));
435    }
436
437    private Comparator<? super T> comparator(final Sorter sorter) {
438        return new Comparator<T>() {
439            public int compare(T o1, T o2) {
440                return sorter.compare(describeChild(o1), describeChild(o2));
441            }
442        };
443    }
444
445    /**
446     * Sets a scheduler that determines the order and parallelization
447     * of children.  Highly experimental feature that may change.
448     */
449    public void setScheduler(RunnerScheduler scheduler) {
450        this.scheduler = scheduler;
451    }
452}