1 package org.junit.runners;
2
3 import static org.junit.internal.runners.rules.RuleMemberValidator.RULE_METHOD_VALIDATOR;
4 import static org.junit.internal.runners.rules.RuleMemberValidator.RULE_VALIDATOR;
5
6 import java.util.List;
7 import java.util.concurrent.ConcurrentHashMap;
8 import java.util.concurrent.TimeUnit;
9
10 import org.junit.After;
11 import org.junit.Before;
12 import org.junit.Ignore;
13 import org.junit.Rule;
14 import org.junit.Test;
15 import org.junit.Test.None;
16 import org.junit.internal.runners.model.ReflectiveCallable;
17 import org.junit.internal.runners.statements.ExpectException;
18 import org.junit.internal.runners.statements.Fail;
19 import org.junit.internal.runners.statements.FailOnTimeout;
20 import org.junit.internal.runners.statements.InvokeMethod;
21 import org.junit.internal.runners.statements.RunAfters;
22 import org.junit.internal.runners.statements.RunBefores;
23 import org.junit.rules.RunRules;
24 import org.junit.rules.TestRule;
25 import org.junit.runner.Description;
26 import org.junit.runner.notification.RunNotifier;
27 import org.junit.runners.model.FrameworkMethod;
28 import org.junit.runners.model.InitializationError;
29 import org.junit.runners.model.MultipleFailureException;
30 import org.junit.runners.model.Statement;
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 public class BlockJUnit4ClassRunner extends ParentRunner<FrameworkMethod> {
57 private final ConcurrentHashMap<FrameworkMethod, Description> methodDescriptions = new ConcurrentHashMap<FrameworkMethod, Description>();
58
59
60
61
62
63 public BlockJUnit4ClassRunner(Class<?> klass) throws InitializationError {
64 super(klass);
65 }
66
67
68
69
70
71 @Override
72 protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
73 Description description = describeChild(method);
74 if (isIgnored(method)) {
75 notifier.fireTestIgnored(description);
76 } else {
77 runLeaf(methodBlock(method), description, notifier);
78 }
79 }
80
81
82
83
84
85 @Override
86 protected boolean isIgnored(FrameworkMethod child) {
87 return child.getAnnotation(Ignore.class) != null;
88 }
89
90 @Override
91 protected Description describeChild(FrameworkMethod method) {
92 Description description = methodDescriptions.get(method);
93
94 if (description == null) {
95 description = Description.createTestDescription(getTestClass().getJavaClass(),
96 testName(method), method.getAnnotations());
97 methodDescriptions.putIfAbsent(method, description);
98 }
99
100 return description;
101 }
102
103 @Override
104 protected List<FrameworkMethod> getChildren() {
105 return computeTestMethods();
106 }
107
108
109
110
111
112
113
114
115
116
117 protected List<FrameworkMethod> computeTestMethods() {
118 return getTestClass().getAnnotatedMethods(Test.class);
119 }
120
121 @Override
122 protected void collectInitializationErrors(List<Throwable> errors) {
123 super.collectInitializationErrors(errors);
124
125 validateNoNonStaticInnerClass(errors);
126 validateConstructor(errors);
127 validateInstanceMethods(errors);
128 validateFields(errors);
129 validateMethods(errors);
130 }
131
132 protected void validateNoNonStaticInnerClass(List<Throwable> errors) {
133 if (getTestClass().isANonStaticInnerClass()) {
134 String gripe = "The inner class " + getTestClass().getName()
135 + " is not static.";
136 errors.add(new Exception(gripe));
137 }
138 }
139
140
141
142
143
144
145 protected void validateConstructor(List<Throwable> errors) {
146 validateOnlyOneConstructor(errors);
147 validateZeroArgConstructor(errors);
148 }
149
150
151
152
153
154 protected void validateOnlyOneConstructor(List<Throwable> errors) {
155 if (!hasOneConstructor()) {
156 String gripe = "Test class should have exactly one public constructor";
157 errors.add(new Exception(gripe));
158 }
159 }
160
161
162
163
164
165 protected void validateZeroArgConstructor(List<Throwable> errors) {
166 if (!getTestClass().isANonStaticInnerClass()
167 && hasOneConstructor()
168 && (getTestClass().getOnlyConstructor().getParameterTypes().length != 0)) {
169 String gripe = "Test class should have exactly one public zero-argument constructor";
170 errors.add(new Exception(gripe));
171 }
172 }
173
174 private boolean hasOneConstructor() {
175 return getTestClass().getJavaClass().getConstructors().length == 1;
176 }
177
178
179
180
181
182
183 @Deprecated
184 protected void validateInstanceMethods(List<Throwable> errors) {
185 validatePublicVoidNoArgMethods(After.class, false, errors);
186 validatePublicVoidNoArgMethods(Before.class, false, errors);
187 validateTestMethods(errors);
188
189 if (computeTestMethods().size() == 0) {
190 errors.add(new Exception("No runnable methods"));
191 }
192 }
193
194 protected void validateFields(List<Throwable> errors) {
195 RULE_VALIDATOR.validate(getTestClass(), errors);
196 }
197
198 private void validateMethods(List<Throwable> errors) {
199 RULE_METHOD_VALIDATOR.validate(getTestClass(), errors);
200 }
201
202
203
204
205
206 protected void validateTestMethods(List<Throwable> errors) {
207 validatePublicVoidNoArgMethods(Test.class, false, errors);
208 }
209
210
211
212
213
214
215 protected Object createTest() throws Exception {
216 return getTestClass().getOnlyConstructor().newInstance();
217 }
218
219
220
221
222
223 protected String testName(FrameworkMethod method) {
224 return method.getName();
225 }
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259 protected Statement methodBlock(FrameworkMethod method) {
260 Object test;
261 try {
262 test = new ReflectiveCallable() {
263 @Override
264 protected Object runReflectiveCall() throws Throwable {
265 return createTest();
266 }
267 }.run();
268 } catch (Throwable e) {
269 return new Fail(e);
270 }
271
272 Statement statement = methodInvoker(method, test);
273 statement = possiblyExpectingExceptions(method, test, statement);
274 statement = withPotentialTimeout(method, test, statement);
275 statement = withBefores(method, test, statement);
276 statement = withAfters(method, test, statement);
277 statement = withRules(method, test, statement);
278 return statement;
279 }
280
281
282
283
284
285
286
287
288 protected Statement methodInvoker(FrameworkMethod method, Object test) {
289 return new InvokeMethod(method, test);
290 }
291
292
293
294
295
296
297
298 protected Statement possiblyExpectingExceptions(FrameworkMethod method,
299 Object test, Statement next) {
300 Test annotation = method.getAnnotation(Test.class);
301 return expectsException(annotation) ? new ExpectException(next,
302 getExpectedException(annotation)) : next;
303 }
304
305
306
307
308
309
310 @Deprecated
311 protected Statement withPotentialTimeout(FrameworkMethod method,
312 Object test, Statement next) {
313 long timeout = getTimeout(method.getAnnotation(Test.class));
314 if (timeout <= 0) {
315 return next;
316 }
317 return FailOnTimeout.builder()
318 .withTimeout(timeout, TimeUnit.MILLISECONDS)
319 .build(next);
320 }
321
322
323
324
325
326
327 protected Statement withBefores(FrameworkMethod method, Object target,
328 Statement statement) {
329 List<FrameworkMethod> befores = getTestClass().getAnnotatedMethods(
330 Before.class);
331 return befores.isEmpty() ? statement : new RunBefores(statement,
332 befores, target);
333 }
334
335
336
337
338
339
340
341
342 protected Statement withAfters(FrameworkMethod method, Object target,
343 Statement statement) {
344 List<FrameworkMethod> afters = getTestClass().getAnnotatedMethods(
345 After.class);
346 return afters.isEmpty() ? statement : new RunAfters(statement, afters,
347 target);
348 }
349
350 private Statement withRules(FrameworkMethod method, Object target,
351 Statement statement) {
352 List<TestRule> testRules = getTestRules(target);
353 Statement result = statement;
354 result = withMethodRules(method, testRules, target, result);
355 result = withTestRules(method, testRules, result);
356
357 return result;
358 }
359
360 private Statement withMethodRules(FrameworkMethod method, List<TestRule> testRules,
361 Object target, Statement result) {
362 for (org.junit.rules.MethodRule each : getMethodRules(target)) {
363 if (!testRules.contains(each)) {
364 result = each.apply(result, method, target);
365 }
366 }
367 return result;
368 }
369
370 private List<org.junit.rules.MethodRule> getMethodRules(Object target) {
371 return rules(target);
372 }
373
374
375
376
377
378
379 protected List<org.junit.rules.MethodRule> rules(Object target) {
380 return getTestClass().getAnnotatedFieldValues(target, Rule.class,
381 org.junit.rules.MethodRule.class);
382 }
383
384
385
386
387
388
389
390
391
392 private Statement withTestRules(FrameworkMethod method, List<TestRule> testRules,
393 Statement statement) {
394 return testRules.isEmpty() ? statement :
395 new RunRules(statement, testRules, describeChild(method));
396 }
397
398
399
400
401
402
403 protected List<TestRule> getTestRules(Object target) {
404 List<TestRule> result = getTestClass().getAnnotatedMethodValues(target,
405 Rule.class, TestRule.class);
406
407 result.addAll(getTestClass().getAnnotatedFieldValues(target,
408 Rule.class, TestRule.class));
409
410 return result;
411 }
412
413 private Class<? extends Throwable> getExpectedException(Test annotation) {
414 if (annotation == null || annotation.expected() == None.class) {
415 return null;
416 } else {
417 return annotation.expected();
418 }
419 }
420
421 private boolean expectsException(Test annotation) {
422 return getExpectedException(annotation) != null;
423 }
424
425 private long getTimeout(Test annotation) {
426 if (annotation == null) {
427 return 0;
428 }
429 return annotation.timeout();
430 }
431 }