1package org.junit.runners;
2
3import static org.junit.internal.runners.rules.RuleFieldValidator.RULE_VALIDATOR;
4
5import java.util.List;
6
7import org.junit.After;
8import org.junit.Before;
9import org.junit.Ignore;
10import org.junit.Rule;
11import org.junit.Test;
12import org.junit.Test.None;
13import org.junit.internal.runners.model.ReflectiveCallable;
14import org.junit.internal.runners.statements.ExpectException;
15import org.junit.internal.runners.statements.Fail;
16import org.junit.internal.runners.statements.FailOnTimeout;
17import org.junit.internal.runners.statements.InvokeMethod;
18import org.junit.internal.runners.statements.RunAfters;
19import org.junit.internal.runners.statements.RunBefores;
20import org.junit.rules.RunRules;
21import org.junit.rules.TestRule;
22import org.junit.runner.Description;
23import org.junit.runner.notification.RunNotifier;
24import org.junit.runners.model.FrameworkMethod;
25import org.junit.runners.model.InitializationError;
26import org.junit.runners.model.MultipleFailureException;
27import org.junit.runners.model.Statement;
28
29/**
30 * Implements the JUnit 4 standard test case class model, as defined by the
31 * annotations in the org.junit package. Many users will never notice this
32 * class: it is now the default test class runner, but it should have exactly
33 * the same behavior as the old test class runner ({@code JUnit4ClassRunner}).
34 *
35 * BlockJUnit4ClassRunner has advantages for writers of custom JUnit runners
36 * that are slight changes to the default behavior, however:
37 *
38 * <ul>
39 * <li>It has a much simpler implementation based on {@link Statement}s,
40 * allowing new operations to be inserted into the appropriate point in the
41 * execution flow.
42 *
43 * <li>It is published, and extension and reuse are encouraged, whereas {@code
44 * JUnit4ClassRunner} was in an internal package, and is now deprecated.
45 * </ul>
46 */
47public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> {
48	/**
49	 * Creates a BlockJUnit4ClassRunner to run {@code klass}
50	 *
51	 * @throws InitializationError
52	 *             if the test class is malformed.
53	 */
54	public BlockJUnit4ClassRunner(Class<?> klass) throws InitializationError {
55		super(klass);
56	}
57
58	//
59	// Implementation of ParentRunner
60	//
61
62	@Override
63	protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
64		Description description= describeChild(method);
65		if (method.getAnnotation(Ignore.class) != null) {
66			notifier.fireTestIgnored(description);
67		} else {
68			runLeaf(methodBlock(method), description, notifier);
69		}
70	}
71
72	@Override
73	protected Description describeChild(FrameworkMethod method) {
74		return Description.createTestDescription(getTestClass().getJavaClass(),
75				testName(method), method.getAnnotations());
76	}
77
78	@Override
79	protected List<FrameworkMethod> getChildren() {
80		return computeTestMethods();
81	}
82
83	//
84	// Override in subclasses
85	//
86
87	/**
88	 * Returns the methods that run tests. Default implementation returns all
89	 * methods annotated with {@code @Test} on this class and superclasses that
90	 * are not overridden.
91	 */
92	protected List<FrameworkMethod> computeTestMethods() {
93		return getTestClass().getAnnotatedMethods(Test.class);
94	}
95
96	@Override
97	protected void collectInitializationErrors(List<Throwable> errors) {
98		super.collectInitializationErrors(errors);
99
100		validateNoNonStaticInnerClass(errors);
101		validateConstructor(errors);
102		validateInstanceMethods(errors);
103		validateFields(errors);
104	}
105
106	protected void validateNoNonStaticInnerClass(List<Throwable> errors) {
107		if (getTestClass().isANonStaticInnerClass()) {
108			String gripe= "The inner class " + getTestClass().getName()
109					+ " is not static.";
110			errors.add(new Exception(gripe));
111		}
112	}
113
114	/**
115	 * Adds to {@code errors} if the test class has more than one constructor,
116	 * or if the constructor takes parameters. Override if a subclass requires
117	 * different validation rules.
118	 */
119	protected void validateConstructor(List<Throwable> errors) {
120		validateOnlyOneConstructor(errors);
121		validateZeroArgConstructor(errors);
122	}
123
124	/**
125	 * Adds to {@code errors} if the test class has more than one constructor
126	 * (do not override)
127	 */
128	protected void validateOnlyOneConstructor(List<Throwable> errors) {
129		if (!hasOneConstructor()) {
130			String gripe= "Test class should have exactly one public constructor";
131			errors.add(new Exception(gripe));
132		}
133	}
134
135	/**
136	 * Adds to {@code errors} if the test class's single constructor takes
137	 * parameters (do not override)
138	 */
139	protected void validateZeroArgConstructor(List<Throwable> errors) {
140		if (!getTestClass().isANonStaticInnerClass()
141				&& hasOneConstructor()
142				&& (getTestClass().getOnlyConstructor().getParameterTypes().length != 0)) {
143			String gripe= "Test class should have exactly one public zero-argument constructor";
144			errors.add(new Exception(gripe));
145		}
146	}
147
148	private boolean hasOneConstructor() {
149		return getTestClass().getJavaClass().getConstructors().length == 1;
150	}
151
152	/**
153	 * Adds to {@code errors} for each method annotated with {@code @Test},
154	 * {@code @Before}, or {@code @After} that is not a public, void instance
155	 * method with no arguments.
156	 *
157	 * @deprecated unused API, will go away in future version
158	 */
159	@Deprecated
160	protected void validateInstanceMethods(List<Throwable> errors) {
161		validatePublicVoidNoArgMethods(After.class, false, errors);
162		validatePublicVoidNoArgMethods(Before.class, false, errors);
163		validateTestMethods(errors);
164
165		if (computeTestMethods().size() == 0)
166			errors.add(new Exception("No runnable methods"));
167	}
168
169	private void validateFields(List<Throwable> errors) {
170		RULE_VALIDATOR.validate(getTestClass(), errors);
171	}
172
173	/**
174	 * Adds to {@code errors} for each method annotated with {@code @Test}that
175	 * is not a public, void instance method with no arguments.
176	 */
177	protected void validateTestMethods(List<Throwable> errors) {
178		validatePublicVoidNoArgMethods(Test.class, false, errors);
179	}
180
181	/**
182	 * Returns a new fixture for running a test. Default implementation executes
183	 * the test class's no-argument constructor (validation should have ensured
184	 * one exists).
185	 */
186	protected Object createTest() throws Exception {
187		return getTestClass().getOnlyConstructor().newInstance();
188	}
189
190	/**
191	 * Returns the name that describes {@code method} for {@link Description}s.
192	 * Default implementation is the method's name
193	 */
194	protected String testName(FrameworkMethod method) {
195		return method.getName();
196	}
197
198	/**
199	 * Returns a Statement that, when executed, either returns normally if
200	 * {@code method} passes, or throws an exception if {@code method} fails.
201	 *
202	 * Here is an outline of the default implementation:
203	 *
204	 * <ul>
205	 * <li>Invoke {@code method} on the result of {@code createTest()}, and
206	 * throw any exceptions thrown by either operation.
207	 * <li>HOWEVER, if {@code method}'s {@code @Test} annotation has the {@code
208	 * expecting} attribute, return normally only if the previous step threw an
209	 * exception of the correct type, and throw an exception otherwise.
210	 * <li>HOWEVER, if {@code method}'s {@code @Test} annotation has the {@code
211	 * timeout} attribute, throw an exception if the previous step takes more
212	 * than the specified number of milliseconds.
213	 * <li>ALWAYS run all non-overridden {@code @Before} methods on this class
214	 * and superclasses before any of the previous steps; if any throws an
215	 * Exception, stop execution and pass the exception on.
216	 * <li>ALWAYS run all non-overridden {@code @After} methods on this class
217	 * and superclasses after any of the previous steps; all After methods are
218	 * always executed: exceptions thrown by previous steps are combined, if
219	 * necessary, with exceptions from After methods into a
220	 * {@link MultipleFailureException}.
221	 * <li>ALWAYS allow {@code @Rule} fields to modify the execution of the
222	 * above steps. A {@code Rule} may prevent all execution of the above steps,
223	 * or add additional behavior before and after, or modify thrown exceptions.
224	 * For more information, see {@link TestRule}
225	 * </ul>
226	 *
227	 * This can be overridden in subclasses, either by overriding this method,
228	 * or the implementations creating each sub-statement.
229	 */
230	protected Statement methodBlock(FrameworkMethod method) {
231		Object test;
232		try {
233			test= new ReflectiveCallable() {
234				@Override
235				protected Object runReflectiveCall() throws Throwable {
236					return createTest();
237				}
238			}.run();
239		} catch (Throwable e) {
240			return new Fail(e);
241		}
242
243		Statement statement= methodInvoker(method, test);
244		statement= possiblyExpectingExceptions(method, test, statement);
245		statement= withPotentialTimeout(method, test, statement);
246		statement= withBefores(method, test, statement);
247		statement= withAfters(method, test, statement);
248		statement= withRules(method, test, statement);
249		return statement;
250	}
251
252	//
253	// Statement builders
254	//
255
256	/**
257	 * Returns a {@link Statement} that invokes {@code method} on {@code test}
258	 */
259	protected Statement methodInvoker(FrameworkMethod method, Object test) {
260		return new InvokeMethod(method, test);
261	}
262
263	/**
264	 * Returns a {@link Statement}: if {@code method}'s {@code @Test} annotation
265	 * has the {@code expecting} attribute, return normally only if {@code next}
266	 * throws an exception of the correct type, and throw an exception
267	 * otherwise.
268	 *
269	 * @deprecated Will be private soon: use Rules instead
270	 */
271	@Deprecated
272	protected Statement possiblyExpectingExceptions(FrameworkMethod method,
273			Object test, Statement next) {
274		Test annotation= method.getAnnotation(Test.class);
275		return expectsException(annotation) ? new ExpectException(next,
276				getExpectedException(annotation)) : next;
277	}
278
279	/**
280	 * Returns a {@link Statement}: if {@code method}'s {@code @Test} annotation
281	 * has the {@code timeout} attribute, throw an exception if {@code next}
282	 * takes more than the specified number of milliseconds.
283	 *
284	 * @deprecated Will be private soon: use Rules instead
285	 */
286	@Deprecated
287	protected Statement withPotentialTimeout(FrameworkMethod method,
288			Object test, Statement next) {
289		long timeout= getTimeout(method.getAnnotation(Test.class));
290		return timeout > 0 ? new FailOnTimeout(next, timeout) : next;
291	}
292
293	/**
294	 * Returns a {@link Statement}: run all non-overridden {@code @Before}
295	 * methods on this class and superclasses before running {@code next}; if
296	 * any throws an Exception, stop execution and pass the exception on.
297	 *
298	 * @deprecated Will be private soon: use Rules instead
299	 */
300	@Deprecated
301	protected Statement withBefores(FrameworkMethod method, Object target,
302			Statement statement) {
303		List<FrameworkMethod> befores= getTestClass().getAnnotatedMethods(
304				Before.class);
305		return befores.isEmpty() ? statement : new RunBefores(statement,
306				befores, target);
307	}
308
309	/**
310	 * Returns a {@link Statement}: run all non-overridden {@code @After}
311	 * methods on this class and superclasses before running {@code next}; all
312	 * After methods are always executed: exceptions thrown by previous steps
313	 * are combined, if necessary, with exceptions from After methods into a
314	 * {@link MultipleFailureException}.
315	 *
316	 * @deprecated Will be private soon: use Rules instead
317	 */
318	@Deprecated
319	protected Statement withAfters(FrameworkMethod method, Object target,
320			Statement statement) {
321		List<FrameworkMethod> afters= getTestClass().getAnnotatedMethods(
322				After.class);
323		return afters.isEmpty() ? statement : new RunAfters(statement, afters,
324				target);
325	}
326
327	private Statement withRules(FrameworkMethod method, Object target,
328			Statement statement) {
329		Statement result= statement;
330		result= withMethodRules(method, target, result);
331		result= withTestRules(method, target, result);
332		return result;
333	}
334
335	@SuppressWarnings("deprecation")
336	private Statement withMethodRules(FrameworkMethod method, Object target,
337			Statement result) {
338		List<TestRule> testRules= getTestRules(target);
339		for (org.junit.rules.MethodRule each : getMethodRules(target))
340			if (! testRules.contains(each))
341				result= each.apply(result, method, target);
342		return result;
343	}
344
345	@SuppressWarnings("deprecation")
346	private List<org.junit.rules.MethodRule> getMethodRules(Object target) {
347		return rules(target);
348	}
349
350	/**
351	 * @param target
352	 *            the test case instance
353	 * @return a list of MethodRules that should be applied when executing this
354	 *         test
355	 * @deprecated {@link org.junit.rules.MethodRule} is a deprecated interface. Port to
356	 *             {@link TestRule} and
357	 *             {@link BlockJUnit4ClassRunner#getTestRules(Object)}
358	 */
359	@Deprecated
360	protected List<org.junit.rules.MethodRule> rules(Object target) {
361		return getTestClass().getAnnotatedFieldValues(target, Rule.class,
362				org.junit.rules.MethodRule.class);
363	}
364
365	/**
366	 * Returns a {@link Statement}: apply all non-static {@link Value} fields
367	 * annotated with {@link Rule}.
368	 *
369	 * @param statement The base statement
370	 * @return a RunRules statement if any class-level {@link Rule}s are
371	 *         found, or the base statement
372	 */
373	private Statement withTestRules(FrameworkMethod method, Object target,
374			Statement statement) {
375		List<TestRule> testRules= getTestRules(target);
376		return testRules.isEmpty() ? statement :
377			new RunRules(statement, testRules, describeChild(method));
378	}
379
380	/**
381	 * @param target
382	 *            the test case instance
383	 * @return a list of TestRules that should be applied when executing this
384	 *         test
385	 */
386	protected List<TestRule> getTestRules(Object target) {
387		return getTestClass().getAnnotatedFieldValues(target,
388				Rule.class, TestRule.class);
389	}
390
391	private Class<? extends Throwable> getExpectedException(Test annotation) {
392		if (annotation == null || annotation.expected() == None.class)
393			return null;
394		else
395			return annotation.expected();
396	}
397
398	private boolean expectsException(Test annotation) {
399		return getExpectedException(annotation) != null;
400	}
401
402	private long getTimeout(Test annotation) {
403		if (annotation == null)
404			return 0;
405		return annotation.timeout();
406	}
407}
408