1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package vogar.target.junit;
18 
19 import java.util.ArrayList;
20 import java.util.List;
21 import org.junit.rules.TestRule;
22 import org.junit.runners.model.FrameworkMethod;
23 import org.junit.runners.model.InitializationError;
24 import org.junit.runners.model.Statement;
25 
26 /**
27  * Defers the validation of test methods until just before they are run.
28  *
29  * <p>This does not throw an {@link InitializationError} during construction if a test method, i.e.
30  * one marked with {@link org.junit.Test @Test} annotation, is not valid. Instead it waits until the
31  * test is actually run until it does that. This is better than the standard JUnit behavior, where
32  * a single invalid test method would prevent all methods in the class from being run.
33  */
34 public class ValidateTestMethodWhenRunBlockJUnit4ClassRunner
35         extends ApplyGlobalRulesBlockJUnit4ClassRunner {
36 
ValidateTestMethodWhenRunBlockJUnit4ClassRunner(Class<?> klass, TestRule testRule)37     protected ValidateTestMethodWhenRunBlockJUnit4ClassRunner(Class<?> klass, TestRule testRule)
38             throws InitializationError {
39         super(klass, testRule);
40     }
41 
42     @Override
validateTestMethods(List<Throwable> errors)43     protected void validateTestMethods(List<Throwable> errors) {
44         // Overridden to avoid validation during initialization.
45     }
46 
47     @Override
methodInvoker(final FrameworkMethod frameworkMethod, Object test)48     protected Statement methodInvoker(final FrameworkMethod frameworkMethod, Object test) {
49         // Overridden to perform validation of the method.
50         Statement statement = super.methodInvoker(frameworkMethod, test);
51 
52         // Wrap the Statement that will invoke the method with one that will validate that the
53         // method is of the correct form.
54         return new ValidateMethodStatement(frameworkMethod, statement);
55     }
56 
57     /**
58      * A {@link Statement} that validates the underlying {@link FrameworkMethod}
59      */
60     protected static class ValidateMethodStatement extends Statement {
61         private final FrameworkMethod frameworkMethod;
62         private final Statement methodInvoker;
63 
ValidateMethodStatement(FrameworkMethod frameworkMethod, Statement methodInvoker)64         public ValidateMethodStatement(FrameworkMethod frameworkMethod, Statement methodInvoker) {
65             this.frameworkMethod = frameworkMethod;
66             this.methodInvoker = methodInvoker;
67         }
68 
69         @Override
evaluate()70         public void evaluate() throws Throwable {
71             validateFrameworkMethod();
72             methodInvoker.evaluate();
73         }
74 
validateFrameworkMethod()75         private void validateFrameworkMethod() throws Throwable {
76             ArrayList<Throwable> errors = new ArrayList<>();
77             frameworkMethod.validatePublicVoidNoArg(false, errors);
78             if (!errors.isEmpty()) {
79                 throw errors.get(0);
80             }
81         }
82     }
83 }
84