View Javadoc

1   package net.sf.twip;
2   
3   import java.lang.annotation.Annotation;
4   import java.util.*;
5   import java.util.concurrent.Callable;
6   
7   import net.sf.twip.internal.*;
8   import net.sf.twip.util.ServiceLoadingException;
9   
10  import org.junit.*;
11  import org.junit.runner.Description;
12  import org.junit.runners.BlockJUnit4ClassRunner;
13  import org.junit.runners.model.*;
14  
15  public class ClassTwip extends BlockJUnit4ClassRunner {
16  
17  	private List<FrameworkMethod> testMethods;
18  
19  	private final List<TwipExtension> extensions = new ArrayList<TwipExtension>();
20  
21  	private final Callable<?> testConstructor;
22  
23  	private final Object[] parameterValues;
24  
25  	public ClassTwip(Class<?> testClass, Callable<?> testConstructor, Object[] parameterValues)
26  			throws InitializationError {
27  		super(testClass);
28  		this.testConstructor = testConstructor;
29  		this.parameterValues = parameterValues;
30  		initExtensions(testClass);
31  	}
32  
33  	@Override
34  	protected void collectInitializationErrors(List<Throwable> errors) {
35  		validatePublicVoidNoArgMethods(BeforeClass.class, true, errors);
36  		validatePublicVoidNoArgMethods(AfterClass.class, true, errors);
37  		// don't validate constructor!
38  		validateInstanceMethods(errors);
39  	}
40  
41  	@Override
42  	protected Object createTest() throws Exception {
43  		return testConstructor.call();
44  	}
45  
46  	@Override
47  	protected List<FrameworkMethod> computeTestMethods() {
48  		if (testMethods == null) {
49  			testMethods = new ArrayList<FrameworkMethod>();
50  			for (final FrameworkMethod method : getTestClass().getAnnotatedMethods(Test.class)) {
51  				if (method.getMethod().getParameterTypes().length == 0) {
52  					testMethods.add(method);
53  					continue;
54  				}
55  				List<? extends FrameworkMethod> parameterizedTestMethods;
56  				try {
57  					parameterizedTestMethods = FrameworkMethodWithArgs.of(method.getMethod());
58  				} catch (final TwipConfigurationError e) {
59  					parameterizedTestMethods = createFailedMethod(method, e);
60  				}
61  				testMethods.addAll(parameterizedTestMethods);
62  			}
63  		}
64  		return testMethods;
65  	}
66  
67  	private List<FailedFrameworkMethod> createFailedMethod(final FrameworkMethod method,
68  			final Throwable e) {
69  		return Collections.singletonList(new FailedFrameworkMethod(method.getMethod(), e));
70  	}
71  
72  	private void initExtensions(Class<?> testClass) throws InitializationError {
73  		final List<Throwable> errors = new ArrayList<Throwable>();
74  
75  		final Set<Class<? extends TwipExtension>> loaded = instantiateServiceLoaderExtensions(errors);
76  
77  		instantiateAnnotatedExtensions(testClass, loaded, errors);
78  
79  		if (!errors.isEmpty()) {
80  			throw new InitializationError(errors);
81  		}
82  	}
83  
84  	private Set<Class<? extends TwipExtension>> instantiateServiceLoaderExtensions(
85  			List<Throwable> errors) {
86  		final Set<Class<? extends TwipExtension>> serviceLoadedTypes = new HashSet<Class<? extends TwipExtension>>();
87  		final Iterator<TwipExtension> loaders = ServiceLoader.load(TwipExtension.class).iterator();
88  		while (loaders.hasNext()) {
89  			try {
90  				final TwipExtension extension = loaders.next();
91  				extensions.add(extension);
92  				serviceLoadedTypes.add(extension.getClass());
93  			} catch (final ServiceLoadingException e) {
94  				errors.add(e);
95  			}
96  		}
97  		return serviceLoadedTypes;
98  	}
99  
100 	private void instantiateAnnotatedExtensions(Class<?> testClass,
101 			Set<Class<? extends TwipExtension>> loaded, final List<Throwable> errors) {
102 		final TwipExtensions annotation = testClass.getAnnotation(TwipExtensions.class);
103 		if (annotation != null) {
104 			for (final Class<? extends TwipExtension> type : annotation.value()) {
105 				if (loaded.contains(type))
106 					continue;
107 				try {
108 					extensions.add(type.newInstance());
109 				} catch (final InstantiationException e) {
110 					final String message = "can't instantiate " + type;
111 					errors.add(new TwipConfigurationErrorCantInstantiateExtension(message, e));
112 				} catch (final IllegalAccessException e) {
113 					errors.add(new TwipConfigurationErrorCantAccessExtension(
114 							"can't access " + type, e));
115 				}
116 			}
117 		}
118 	}
119 
120 	@Override
121 	protected Statement methodInvoker(FrameworkMethod method, final Object testInstance) {
122 		Statement statement = super.methodInvoker(method, testInstance);
123 		for (final TwipExtension extension : extensions) {
124 			statement = extension.wrapInner(method, testInstance, statement);
125 		}
126 		return statement;
127 	}
128 
129 	@Override
130 	protected Description describeChild(FrameworkMethod method) {
131 		String text = testName(method) + "(" + Arrays.toString(parameterValues) + ")";
132 		return Description.createSuiteDescription(text, method.getAnnotations());
133 	}
134 
135 	@Override
136 	protected String testName(FrameworkMethod method) {
137 		return (method instanceof FrameworkMethodWithArgs) ? method.toString() : super
138 				.testName(method);
139 	}
140 
141 	@Override
142 	protected String getName() {
143 		return (parameterValues == null) ? super.getName() : Arrays.toString(parameterValues);
144 	}
145 
146 	@Override
147 	protected void validatePublicVoidNoArgMethods(Class<? extends Annotation> annotation,
148 			boolean isStatic, List<Throwable> errors) {
149 		final List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(annotation);
150 		for (final FrameworkMethod eachTestMethod : methods) {
151 			eachTestMethod.validatePublicVoid(isStatic, errors);
152 		}
153 	}
154 
155 	@Override
156 	protected Statement withAfters(FrameworkMethod method, final Object testInstance,
157 			Statement statement) {
158 		Statement result = super.withAfters(method, testInstance, statement);
159 		for (final TwipExtension extension : extensions) {
160 			result = extension.wrapOuter(method, testInstance, result);
161 		}
162 		return result;
163 	}
164 
165 	public Object[] getParameterValues() {
166 		return parameterValues;
167 	}
168 }