001    package org.junit.runners;
002    
003    import static org.junit.internal.runners.rules.RuleMemberValidator.CLASS_RULE_METHOD_VALIDATOR;
004    import static org.junit.internal.runners.rules.RuleMemberValidator.CLASS_RULE_VALIDATOR;
005    
006    import java.lang.annotation.Annotation;
007    import java.lang.reflect.Method;
008    import java.util.ArrayList;
009    import java.util.Arrays;
010    import java.util.Collection;
011    import java.util.Collections;
012    import java.util.Comparator;
013    import java.util.Iterator;
014    import java.util.List;
015    
016    import org.junit.AfterClass;
017    import org.junit.BeforeClass;
018    import org.junit.ClassRule;
019    import org.junit.Ignore;
020    import org.junit.Rule;
021    import org.junit.internal.AssumptionViolatedException;
022    import org.junit.internal.runners.model.EachTestNotifier;
023    import org.junit.internal.runners.statements.RunAfters;
024    import org.junit.internal.runners.statements.RunBefores;
025    import org.junit.rules.RunRules;
026    import org.junit.rules.TestRule;
027    import org.junit.runner.Description;
028    import org.junit.runner.Runner;
029    import org.junit.runner.manipulation.Filter;
030    import org.junit.runner.manipulation.Filterable;
031    import org.junit.runner.manipulation.NoTestsRemainException;
032    import org.junit.runner.manipulation.Sortable;
033    import org.junit.runner.manipulation.Sorter;
034    import org.junit.runner.notification.RunNotifier;
035    import org.junit.runner.notification.StoppedByUserException;
036    import org.junit.runners.model.FrameworkMethod;
037    import org.junit.runners.model.InitializationError;
038    import org.junit.runners.model.RunnerScheduler;
039    import org.junit.runners.model.Statement;
040    import org.junit.runners.model.TestClass;
041    import org.junit.validator.AnnotationsValidator;
042    import org.junit.validator.PublicClassValidator;
043    import 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     */
058    public 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    }