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
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 }