• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.junit.runners;
2 
3 import static org.junit.internal.runners.rules.RuleFieldValidator.CLASS_RULE_VALIDATOR;
4 
5 import java.lang.annotation.Annotation;
6 import java.lang.reflect.Method;
7 import java.util.ArrayList;
8 import java.util.Collections;
9 import java.util.Comparator;
10 import java.util.Iterator;
11 import java.util.List;
12 
13 import org.junit.AfterClass;
14 import org.junit.BeforeClass;
15 import org.junit.ClassRule;
16 import org.junit.Rule;
17 import org.junit.internal.AssumptionViolatedException;
18 import org.junit.internal.runners.model.EachTestNotifier;
19 import org.junit.internal.runners.statements.RunAfters;
20 import org.junit.internal.runners.statements.RunBefores;
21 import org.junit.rules.RunRules;
22 import org.junit.rules.TestRule;
23 import org.junit.runner.Description;
24 import org.junit.runner.Runner;
25 import org.junit.runner.manipulation.Filter;
26 import org.junit.runner.manipulation.Filterable;
27 import org.junit.runner.manipulation.NoTestsRemainException;
28 import org.junit.runner.manipulation.Sortable;
29 import org.junit.runner.manipulation.Sorter;
30 import org.junit.runner.notification.RunNotifier;
31 import org.junit.runner.notification.StoppedByUserException;
32 import org.junit.runners.model.FrameworkMethod;
33 import org.junit.runners.model.InitializationError;
34 import org.junit.runners.model.MultipleFailureException;
35 import org.junit.runners.model.RunnerScheduler;
36 import org.junit.runners.model.Statement;
37 import org.junit.runners.model.TestClass;
38 
39 /**
40  * Provides most of the functionality specific to a Runner that implements a
41  * "parent node" in the test tree, with children defined by objects of some data
42  * type {@code T}. (For {@link BlockJUnit4ClassRunner}, {@code T} is
43  * {@link Method} . For {@link Suite}, {@code T} is {@link Class}.) Subclasses
44  * must implement finding the children of the node, describing each child, and
45  * running each child. ParentRunner will filter and sort children, handle
46  * {@code @BeforeClass} and {@code @AfterClass} methods,
47  * handle annotated {@link ClassRule}s, create a composite
48  * {@link Description}, and run children sequentially.
49  */
50 public abstract class ParentRunner<T> extends Runner implements Filterable,
51 		Sortable {
52 	private final TestClass fTestClass;
53 
54 	private Sorter fSorter= Sorter.NULL;
55 
56 	private List<T> fFilteredChildren= null;
57 
58 	private RunnerScheduler fScheduler= new RunnerScheduler() {
59 		public void schedule(Runnable childStatement) {
60 			childStatement.run();
61 		}
62 
63 		public void finished() {
64 			// do nothing
65 		}
66 	};
67 
68 	/**
69 	 * Constructs a new {@code ParentRunner} that will run {@code @TestClass}
70 	 * @throws InitializationError
71 	 */
ParentRunner(Class<?> testClass)72 	protected ParentRunner(Class<?> testClass) throws InitializationError {
73 		fTestClass= new TestClass(testClass);
74 		validate();
75 	}
76 
77 	//
78 	// Must be overridden
79 	//
80 
81 	/**
82 	 * Returns a list of objects that define the children of this Runner.
83 	 */
getChildren()84 	protected abstract List<T> getChildren();
85 
86 	/**
87 	 * Returns a {@link Description} for {@code child}, which can be assumed to
88 	 * be an element of the list returned by {@link ParentRunner#getChildren()}
89 	 */
describeChild(T child)90 	protected abstract Description describeChild(T child);
91 
92 	/**
93 	 * Runs the test corresponding to {@code child}, which can be assumed to be
94 	 * an element of the list returned by {@link ParentRunner#getChildren()}.
95 	 * Subclasses are responsible for making sure that relevant test events are
96 	 * reported through {@code notifier}
97 	 */
runChild(T child, RunNotifier notifier)98 	protected abstract void runChild(T child, RunNotifier notifier);
99 
100 	//
101 	// May be overridden
102 	//
103 
104 	/**
105 	 * Adds to {@code errors} a throwable for each problem noted with the test class (available from {@link #getTestClass()}).
106 	 * Default implementation adds an error for each method annotated with
107 	 * {@code @BeforeClass} or {@code @AfterClass} that is not
108 	 * {@code public static void} with no arguments.
109 	 */
collectInitializationErrors(List<Throwable> errors)110 	protected void collectInitializationErrors(List<Throwable> errors) {
111 		validatePublicVoidNoArgMethods(BeforeClass.class, true, errors);
112 		validatePublicVoidNoArgMethods(AfterClass.class, true, errors);
113 		validateClassRules(errors);
114 	}
115 
116 	/**
117 	 * Adds to {@code errors} if any method in this class is annotated with
118 	 * {@code annotation}, but:
119 	 * <ul>
120 	 * <li>is not public, or
121 	 * <li>takes parameters, or
122 	 * <li>returns something other than void, or
123 	 * <li>is static (given {@code isStatic is false}), or
124 	 * <li>is not static (given {@code isStatic is true}).
125 	 */
validatePublicVoidNoArgMethods(Class<? extends Annotation> annotation, boolean isStatic, List<Throwable> errors)126 	protected void validatePublicVoidNoArgMethods(Class<? extends Annotation> annotation,
127 			boolean isStatic, List<Throwable> errors) {
128 		List<FrameworkMethod> methods= getTestClass().getAnnotatedMethods(annotation);
129 
130 		for (FrameworkMethod eachTestMethod : methods)
131 			eachTestMethod.validatePublicVoidNoArg(isStatic, errors);
132 	}
133 
validateClassRules(List<Throwable> errors)134 	private void validateClassRules(List<Throwable> errors) {
135 		CLASS_RULE_VALIDATOR.validate(getTestClass(), errors);
136 	}
137 
138 	/**
139 	 * Constructs a {@code Statement} to run all of the tests in the test class. Override to add pre-/post-processing.
140 	 * Here is an outline of the implementation:
141 	 * <ul>
142 	 * <li>Call {@link #runChild(Object, RunNotifier)} on each object returned by {@link #getChildren()} (subject to any imposed filter and sort).</li>
143 	 * <li>ALWAYS run all non-overridden {@code @BeforeClass} methods on this class
144 	 * and superclasses before the previous step; if any throws an
145 	 * Exception, stop execution and pass the exception on.
146 	 * <li>ALWAYS run all non-overridden {@code @AfterClass} methods on this class
147 	 * and superclasses before any of the previous steps; all AfterClass methods are
148 	 * always executed: exceptions thrown by previous steps are combined, if
149 	 * necessary, with exceptions from AfterClass methods into a
150 	 * {@link MultipleFailureException}.
151 	 * </ul>
152 	 * @param notifier
153 	 * @return {@code Statement}
154 	 */
classBlock(final RunNotifier notifier)155 	protected Statement classBlock(final RunNotifier notifier) {
156 		Statement statement= childrenInvoker(notifier);
157 		statement= withBeforeClasses(statement);
158 		statement= withAfterClasses(statement);
159 		statement= withClassRules(statement);
160 		return statement;
161 	}
162 
163 	/**
164 	 * Returns a {@link Statement}: run all non-overridden {@code @BeforeClass} methods on this class
165 	 * and superclasses before executing {@code statement}; if any throws an
166 	 * Exception, stop execution and pass the exception on.
167 	 */
withBeforeClasses(Statement statement)168 	protected Statement withBeforeClasses(Statement statement) {
169 		List<FrameworkMethod> befores= fTestClass
170 				.getAnnotatedMethods(BeforeClass.class);
171 		return befores.isEmpty() ? statement :
172 			new RunBefores(statement, befores, null);
173 	}
174 
175 	/**
176 	 * Returns a {@link Statement}: run all non-overridden {@code @AfterClass} methods on this class
177 	 * and superclasses before executing {@code statement}; all AfterClass methods are
178 	 * always executed: exceptions thrown by previous steps are combined, if
179 	 * necessary, with exceptions from AfterClass methods into a
180 	 * {@link MultipleFailureException}.
181 	 */
withAfterClasses(Statement statement)182 	protected Statement withAfterClasses(Statement statement) {
183 		List<FrameworkMethod> afters= fTestClass
184 				.getAnnotatedMethods(AfterClass.class);
185 		return afters.isEmpty() ? statement :
186 			new RunAfters(statement, afters, null);
187 	}
188 
189 	/**
190 	 * Returns a {@link Statement}: apply all
191 	 * static fields assignable to {@link TestRule}
192 	 * annotated with {@link ClassRule}.
193 	 *
194 	 * @param statement
195 	 *            the base statement
196 	 * @return a RunRules statement if any class-level {@link Rule}s are
197 	 *         found, or the base statement
198 	 */
withClassRules(Statement statement)199 	private Statement withClassRules(Statement statement) {
200 		List<TestRule> classRules= classRules();
201 		return classRules.isEmpty() ? statement :
202 		    new RunRules(statement, classRules, getDescription());
203 	}
204 
205 	/**
206 	 * @return the {@code ClassRule}s that can transform the block that runs
207 	 *         each method in the tested class.
208 	 */
classRules()209 	protected List<TestRule> classRules() {
210 		return fTestClass.getAnnotatedFieldValues(null, ClassRule.class, TestRule.class);
211 	}
212 
213 	/**
214 	 * Returns a {@link Statement}: Call {@link #runChild(Object, RunNotifier)}
215 	 * on each object returned by {@link #getChildren()} (subject to any imposed
216 	 * filter and sort)
217 	 */
childrenInvoker(final RunNotifier notifier)218 	protected Statement childrenInvoker(final RunNotifier notifier) {
219 		return new Statement() {
220 			@Override
221 			public void evaluate() {
222 				runChildren(notifier);
223 			}
224 		};
225 	}
226 
227 	private void runChildren(final RunNotifier notifier) {
228 		for (final T each : getFilteredChildren())
229  			fScheduler.schedule(new Runnable() {
230 				public void run() {
231 					ParentRunner.this.runChild(each, notifier);
232 				}
233 			});
234 		fScheduler.finished();
235 	}
236 
237 	/**
238 	 * Returns a name used to describe this Runner
239 	 */
240 	protected String getName() {
241 		return fTestClass.getName();
242 	}
243 
244 	//
245 	// Available for subclasses
246 	//
247 
248 	/**
249 	 * Returns a {@link TestClass} object wrapping the class to be executed.
250 	 */
251 	public final TestClass getTestClass() {
252 		return fTestClass;
253 	}
254 
255 	/**
256 	 * Runs a {@link Statement} that represents a leaf (aka atomic) test.
257 	 */
258 	protected final void runLeaf(Statement statement, Description description,
259 			RunNotifier notifier) {
260 		EachTestNotifier eachNotifier= new EachTestNotifier(notifier, description);
261 		eachNotifier.fireTestStarted();
262 		try {
263 		    statement.evaluate();
264 		} catch (AssumptionViolatedException e) {
265 			eachNotifier.addFailedAssumption(e);
266 		} catch (Throwable e) {
267 			eachNotifier.addFailure(e);
268 		} finally {
269 			eachNotifier.fireTestFinished();
270 		}
271 	}
272 
273 	/**
274 	 * @return the annotations that should be attached to this runner's
275 	 * description.
276 	 */
277 	protected Annotation[] getRunnerAnnotations() {
278 		return fTestClass.getAnnotations();
279 	}
280 
281 	//
282 	// Implementation of Runner
283 	//
284 
285 	@Override
286 	public Description getDescription() {
287 		Description description= Description.createSuiteDescription(getName(),
288 				getRunnerAnnotations());
289 		for (T child : getFilteredChildren())
290 			description.addChild(describeChild(child));
291 		return description;
292 	}
293 
294 	@Override
295 	public void run(final RunNotifier notifier) {
296 		EachTestNotifier testNotifier= new EachTestNotifier(notifier,
297 				getDescription());
298 		try {
299 			Statement statement= classBlock(notifier);
300 			statement.evaluate();
301 		} catch (AssumptionViolatedException e) {
302 			testNotifier.fireTestIgnored();
303 		} catch (StoppedByUserException e) {
304 			throw e;
305 		} catch (Throwable e) {
306 			testNotifier.addFailure(e);
307 		}
308 	}
309 
310 	//
311 	// Implementation of Filterable and Sortable
312 	//
313 
314 	public void filter(Filter filter) throws NoTestsRemainException {
315 		for (Iterator<T> iter = getFilteredChildren().iterator(); iter.hasNext(); ) {
316 			T each = iter.next();
317 			if (shouldRun(filter, each))
318 				try {
319 					filter.apply(each);
320 				} catch (NoTestsRemainException e) {
321 					iter.remove();
322 				}
323 			else
324 				iter.remove();
325 		}
326 	    if (getFilteredChildren().isEmpty()) {
327 	        throw new NoTestsRemainException();
328 	    }
329 	}
330 
331 	public void sort(Sorter sorter) {
332 		fSorter= sorter;
333 		for (T each : getFilteredChildren())
334 			sortChild(each);
335 		Collections.sort(getFilteredChildren(), comparator());
336 	}
337 
338 	//
339 	// Private implementation
340 	//
341 
342 	private void validate() throws InitializationError {
343 		List<Throwable> errors= new ArrayList<Throwable>();
344 		collectInitializationErrors(errors);
345 		if (!errors.isEmpty())
346 			throw new InitializationError(errors);
347 	}
348 
349 	private List<T> getFilteredChildren() {
350 		if (fFilteredChildren == null)
351 			fFilteredChildren = new ArrayList<T>(getChildren());
352 		return fFilteredChildren;
353 	}
354 
355 	private void sortChild(T child) {
356 		fSorter.apply(child);
357 	}
358 
359 	private boolean shouldRun(Filter filter, T each) {
360 		return filter.shouldRun(describeChild(each));
361 	}
362 
363 	private Comparator<? super T> comparator() {
364 		return new Comparator<T>() {
365 			public int compare(T o1, T o2) {
366 				return fSorter.compare(describeChild(o1), describeChild(o2));
367 			}
368 		};
369 	}
370 
371 	/**
372 	 * Sets a scheduler that determines the order and parallelization
373 	 * of children.  Highly experimental feature that may change.
374 	 */
375 	public void setScheduler(RunnerScheduler scheduler) {
376 		this.fScheduler = scheduler;
377 	}
378 }
379