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 }