Merge lp:~yshavit/namedparameterizedrunner/init_dump into lp:namedparameterizedrunner
- init_dump
- Merge into trunk
Proposed by
Yuval Shavit
Status: | Merged |
---|---|
Merged at revision: | 2 |
Proposed branch: | lp:~yshavit/namedparameterizedrunner/init_dump |
Merge into: | lp:namedparameterizedrunner |
Diff against target: |
1616 lines (+1551/-0) 11 files modified
.bzrignore (+4/-0) pom.xml (+67/-0) src/main/java/com/motpot/npr/Failing.java (+22/-0) src/main/java/com/motpot/npr/NamedParameterizedRunner.java (+570/-0) src/main/java/com/motpot/npr/OnlyIf.java (+20/-0) src/main/java/com/motpot/npr/OnlyIfNot.java (+20/-0) src/main/java/com/motpot/npr/Parameterization.java (+152/-0) src/main/java/com/motpot/npr/ParameterizationBuilder.java (+159/-0) src/test/java/com/motpot/npr/NamedParameterizedRunnerTest.java (+316/-0) src/test/java/com/motpot/npr/OnlyIfUsageTest.java (+68/-0) src/test/java/com/motpot/npr/ParameterizationBuilderTest.java (+153/-0) |
To merge this branch: | bzr merge lp:~yshavit/namedparameterizedrunner/init_dump |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Yuval Shavit | Pending | ||
Review via email: mp+74631@code.launchpad.net |
Commit message
Description of the change
Initial commit, copied from lp:akiban-server/trunk
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file '.bzrignore' | |||
2 | --- .bzrignore 1970-01-01 00:00:00 +0000 | |||
3 | +++ .bzrignore 2011-09-08 16:01:22 +0000 | |||
4 | @@ -0,0 +1,4 @@ | |||
5 | 1 | named-parameterized-runner.iml | ||
6 | 2 | named-parameterized-runner.ipr | ||
7 | 3 | named-parameterized-runner.iws | ||
8 | 4 | ./target | ||
9 | 0 | 5 | ||
10 | === added file 'pom.xml' | |||
11 | --- pom.xml 1970-01-01 00:00:00 +0000 | |||
12 | +++ pom.xml 2011-09-08 16:01:22 +0000 | |||
13 | @@ -0,0 +1,67 @@ | |||
14 | 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
15 | 2 | <project> | ||
16 | 3 | <modelVersion>4.0.0</modelVersion> | ||
17 | 4 | <groupId>com.motpot</groupId> | ||
18 | 5 | <artifactId>named-parameterized-runner</artifactId> | ||
19 | 6 | <packaging>jar</packaging> | ||
20 | 7 | <version>0.8.0</version> | ||
21 | 8 | <name>named-parameterized-runner</name> | ||
22 | 9 | <dependencies> | ||
23 | 10 | <dependency> | ||
24 | 11 | <groupId>junit</groupId> | ||
25 | 12 | <artifactId>junit</artifactId> | ||
26 | 13 | <version>4.8.1</version> | ||
27 | 14 | </dependency> | ||
28 | 15 | <dependency> | ||
29 | 16 | <groupId>org.slf4j</groupId> | ||
30 | 17 | <artifactId>slf4j-api</artifactId> | ||
31 | 18 | <version>1.6.1</version> | ||
32 | 19 | </dependency> | ||
33 | 20 | </dependencies> | ||
34 | 21 | <build> | ||
35 | 22 | <plugins> | ||
36 | 23 | <plugin> | ||
37 | 24 | <groupId>org.apache.maven.plugins</groupId> | ||
38 | 25 | <artifactId>maven-jar-plugin</artifactId> | ||
39 | 26 | <version>2.2</version> | ||
40 | 27 | <executions> | ||
41 | 28 | <execution> | ||
42 | 29 | <goals> | ||
43 | 30 | <goal>test-jar</goal> | ||
44 | 31 | </goals> | ||
45 | 32 | </execution> | ||
46 | 33 | </executions> | ||
47 | 34 | </plugin> | ||
48 | 35 | <plugin> | ||
49 | 36 | <groupId>org.apache.maven.plugins</groupId> | ||
50 | 37 | <artifactId>maven-compiler-plugin</artifactId> | ||
51 | 38 | <version>2.3.2</version> | ||
52 | 39 | <configuration> | ||
53 | 40 | <source>1.6</source> | ||
54 | 41 | <target>1.6</target> | ||
55 | 42 | </configuration> | ||
56 | 43 | </plugin> | ||
57 | 44 | <plugin> | ||
58 | 45 | <groupId>org.apache.maven.plugins</groupId> | ||
59 | 46 | <artifactId>maven-source-plugin</artifactId> | ||
60 | 47 | <version>2.1.2</version> | ||
61 | 48 | <executions> | ||
62 | 49 | <execution> | ||
63 | 50 | <id>attach-sources</id> | ||
64 | 51 | <phase>package</phase> | ||
65 | 52 | <goals> | ||
66 | 53 | <goal>jar</goal> | ||
67 | 54 | </goals> | ||
68 | 55 | </execution> | ||
69 | 56 | </executions> | ||
70 | 57 | </plugin> | ||
71 | 58 | <plugin> | ||
72 | 59 | <groupId>org.apache.maven.plugins</groupId> | ||
73 | 60 | <artifactId>maven-surefire-plugin</artifactId> | ||
74 | 61 | <version>2.6</version> | ||
75 | 62 | </plugin> | ||
76 | 63 | </plugins> | ||
77 | 64 | </build> | ||
78 | 65 | |||
79 | 66 | </project> | ||
80 | 67 | |||
81 | 0 | 68 | ||
82 | === added directory 'src' | |||
83 | === added directory 'src/main' | |||
84 | === added directory 'src/main/java' | |||
85 | === added directory 'src/main/java/com' | |||
86 | === added directory 'src/main/java/com/motpot' | |||
87 | === added directory 'src/main/java/com/motpot/npr' | |||
88 | === added file 'src/main/java/com/motpot/npr/Failing.java' | |||
89 | --- src/main/java/com/motpot/npr/Failing.java 1970-01-01 00:00:00 +0000 | |||
90 | +++ src/main/java/com/motpot/npr/Failing.java 2011-09-08 16:01:22 +0000 | |||
91 | @@ -0,0 +1,22 @@ | |||
92 | 1 | package com.motpot.npr; | ||
93 | 2 | |||
94 | 3 | import java.lang.annotation.ElementType; | ||
95 | 4 | import java.lang.annotation.Retention; | ||
96 | 5 | import java.lang.annotation.RetentionPolicy; | ||
97 | 6 | import java.lang.annotation.Target; | ||
98 | 7 | |||
99 | 8 | /** | ||
100 | 9 | * Represents a failing test. | ||
101 | 10 | */ | ||
102 | 11 | @Retention(RetentionPolicy.RUNTIME) | ||
103 | 12 | @Target(ElementType.METHOD) | ||
104 | 13 | public @interface Failing | ||
105 | 14 | { | ||
106 | 15 | /** | ||
107 | 16 | * For parameterized tests, the optional list of parameterizations that are failing. | ||
108 | 17 | * | ||
109 | 18 | * This is ignored by non-parameterized class runners. For parameterized runners, | ||
110 | 19 | * not specifying this value means that all parameterizations are failing. | ||
111 | 20 | */ | ||
112 | 21 | String[] value() default {}; | ||
113 | 22 | } | ||
114 | 0 | 23 | ||
115 | === added file 'src/main/java/com/motpot/npr/NamedParameterizedRunner.java' | |||
116 | --- src/main/java/com/motpot/npr/NamedParameterizedRunner.java 1970-01-01 00:00:00 +0000 | |||
117 | +++ src/main/java/com/motpot/npr/NamedParameterizedRunner.java 2011-09-08 16:01:22 +0000 | |||
118 | @@ -0,0 +1,570 @@ | |||
119 | 1 | package com.motpot.npr; | ||
120 | 2 | |||
121 | 3 | import org.slf4j.Logger; | ||
122 | 4 | import org.slf4j.LoggerFactory; | ||
123 | 5 | import org.junit.Ignore; | ||
124 | 6 | import org.junit.internal.builders.IgnoredClassRunner; | ||
125 | 7 | import org.junit.runner.Runner; | ||
126 | 8 | import org.junit.runner.notification.RunNotifier; | ||
127 | 9 | import org.junit.runners.BlockJUnit4ClassRunner; | ||
128 | 10 | import org.junit.runners.Suite; | ||
129 | 11 | import org.junit.runners.model.FrameworkMethod; | ||
130 | 12 | import org.junit.runners.model.InitializationError; | ||
131 | 13 | import org.junit.runners.model.Statement; | ||
132 | 14 | import org.junit.runners.model.TestClass; | ||
133 | 15 | |||
134 | 16 | import java.lang.annotation.ElementType; | ||
135 | 17 | import java.lang.annotation.Retention; | ||
136 | 18 | import java.lang.annotation.RetentionPolicy; | ||
137 | 19 | import java.lang.annotation.Target; | ||
138 | 20 | import java.lang.reflect.Field; | ||
139 | 21 | import java.lang.reflect.Method; | ||
140 | 22 | import java.lang.reflect.Modifier; | ||
141 | 23 | import java.lang.reflect.ParameterizedType; | ||
142 | 24 | import java.lang.reflect.Type; | ||
143 | 25 | import java.util.*; | ||
144 | 26 | import java.util.regex.Pattern; | ||
145 | 27 | |||
146 | 28 | public final class NamedParameterizedRunner extends Suite | ||
147 | 29 | { | ||
148 | 30 | /** | ||
149 | 31 | * <p>Parameterization override filter (works by name).</p> | ||
150 | 32 | * | ||
151 | 33 | * <p>If this property is set, then only parameterization names that match its value will be processed. These | ||
152 | 34 | * names behave like @Failing names (in terms of regexes, etc). If this property is set and a test that matches | ||
153 | 35 | * it is marked as @Failing, that test will still get run. For instance, if a parameterization named | ||
154 | 36 | * <tt>myFooTest</tt> is marked as failing for a given test (either because the entire parameterization is marked | ||
155 | 37 | * as failing, or because of a <tt>@Failing</tt> annotation on the method), and if you have a system property | ||
156 | 38 | * <tt>{@value} == "/myFoo/"</tt>, then the test <em>will</em> be run. | ||
157 | 39 | */ | ||
158 | 40 | public final static String PARAMETERIZATION_OVERRIDE = "test.params"; | ||
159 | 41 | /** | ||
160 | 42 | * <p>Annotation for a method which provides parameters for an | ||
161 | 43 | * {@link NamedParameterizedRunner} suite.</p> | ||
162 | 44 | * | ||
163 | 45 | * <p>A class that is run with {@linkplain NamedParameterizedRunner} <em>must</em> have exactly one method | ||
164 | 46 | * marked with this annotation, and that method must:</p> | ||
165 | 47 | * <ul> | ||
166 | 48 | * <li>be public</li> | ||
167 | 49 | * <li>be static</li> | ||
168 | 50 | * <li>take no arguments</li> | ||
169 | 51 | * <li>return Collection of {@link Parameterization} objects.</li> | ||
170 | 52 | * </ul> | ||
171 | 53 | */ | ||
172 | 54 | @Retention(RetentionPolicy.RUNTIME) | ||
173 | 55 | @Target(ElementType.METHOD) | ||
174 | 56 | public static @interface TestParameters { | ||
175 | 57 | } | ||
176 | 58 | |||
177 | 59 | private final static Logger logger = LoggerFactory.getLogger(NamedParameterizedRunner.class); | ||
178 | 60 | private final List<Runner> runners; | ||
179 | 61 | |||
180 | 62 | /** | ||
181 | 63 | * Adapted from {@link org.junit.runners.Parameterized}'s nested class | ||
182 | 64 | * @see | ||
183 | 65 | */ | ||
184 | 66 | static class ReifiedParamRunner extends BlockJUnit4ClassRunner | ||
185 | 67 | { | ||
186 | 68 | private final Parameterization parameterization; | ||
187 | 69 | private final boolean overrideOn; | ||
188 | 70 | private Object testObject = null; | ||
189 | 71 | |||
190 | 72 | private static class OnlyIfErrorFrameworkMethod extends FrameworkMethod { | ||
191 | 73 | private final OnlyIfException exception; | ||
192 | 74 | |||
193 | 75 | private OnlyIfErrorFrameworkMethod(Method method, OnlyIfException exception) { | ||
194 | 76 | super(method); | ||
195 | 77 | this.exception = exception; | ||
196 | 78 | } | ||
197 | 79 | |||
198 | 80 | @Override | ||
199 | 81 | public Object invokeExplosively(Object target, Object... params) throws Throwable { | ||
200 | 82 | throw exception; | ||
201 | 83 | } | ||
202 | 84 | } | ||
203 | 85 | |||
204 | 86 | public ReifiedParamRunner(Class<?> klass, Parameterization parameterization, boolean overrideOn) | ||
205 | 87 | throws InitializationError | ||
206 | 88 | { | ||
207 | 89 | super(klass); | ||
208 | 90 | this.parameterization = parameterization; | ||
209 | 91 | this.overrideOn = overrideOn; | ||
210 | 92 | } | ||
211 | 93 | |||
212 | 94 | /** | ||
213 | 95 | * For debugging. | ||
214 | 96 | * @return parameterization.toString() | ||
215 | 97 | * @throws NullPointerException if parameterization is null | ||
216 | 98 | */ | ||
217 | 99 | String paramToString() | ||
218 | 100 | { | ||
219 | 101 | return parameterization.toString(); | ||
220 | 102 | } | ||
221 | 103 | |||
222 | 104 | /** | ||
223 | 105 | * For debugging | ||
224 | 106 | * @return the override value | ||
225 | 107 | */ | ||
226 | 108 | boolean overrideOn() | ||
227 | 109 | { | ||
228 | 110 | return overrideOn; | ||
229 | 111 | } | ||
230 | 112 | |||
231 | 113 | /** | ||
232 | 114 | * For debugging. | ||
233 | 115 | * @param name the name of the child FrameworkMethod to get | ||
234 | 116 | * @return the child, or null if it doesn't exist | ||
235 | 117 | */ | ||
236 | 118 | FrameworkMethod getChild(String name) | ||
237 | 119 | { | ||
238 | 120 | for (FrameworkMethod method : getChildren()) | ||
239 | 121 | { | ||
240 | 122 | if (method.getMethod().toString().equals(name)) | ||
241 | 123 | { | ||
242 | 124 | return method; | ||
243 | 125 | } | ||
244 | 126 | } | ||
245 | 127 | return null; | ||
246 | 128 | } | ||
247 | 129 | |||
248 | 130 | /** | ||
249 | 131 | * For debugging | ||
250 | 132 | * @return the number of children in this runner | ||
251 | 133 | */ | ||
252 | 134 | int getChildrenCount() { | ||
253 | 135 | return getChildren().size(); | ||
254 | 136 | } | ||
255 | 137 | |||
256 | 138 | /** | ||
257 | 139 | * For debugging (and only for assertion messages) | ||
258 | 140 | * @return shows human-readable info about the children | ||
259 | 141 | */ | ||
260 | 142 | String describeChildren() { | ||
261 | 143 | List<FrameworkMethod> children = getChildren(); | ||
262 | 144 | if (children == null) { | ||
263 | 145 | return "null"; | ||
264 | 146 | } | ||
265 | 147 | List<String> descriptions = new ArrayList<String>(children.size()); | ||
266 | 148 | for (FrameworkMethod method : children) { | ||
267 | 149 | descriptions.add( method.getName() ); | ||
268 | 150 | } | ||
269 | 151 | return descriptions.toString(); | ||
270 | 152 | } | ||
271 | 153 | |||
272 | 154 | @Override | ||
273 | 155 | public Object createTest() throws Exception | ||
274 | 156 | { | ||
275 | 157 | if (testObject != null) { | ||
276 | 158 | return testObject; | ||
277 | 159 | } | ||
278 | 160 | try | ||
279 | 161 | { | ||
280 | 162 | testObject = getTestClass().getOnlyConstructor().newInstance(parameterization.getArguments()); | ||
281 | 163 | return testObject; | ||
282 | 164 | } | ||
283 | 165 | catch(IllegalArgumentException e) | ||
284 | 166 | { | ||
285 | 167 | throw new IllegalArgumentException("parameters: " + Arrays.toString(parameterization.getArguments()), e); | ||
286 | 168 | } | ||
287 | 169 | } | ||
288 | 170 | |||
289 | 171 | @Override | ||
290 | 172 | protected List<FrameworkMethod> getChildren() { | ||
291 | 173 | List<FrameworkMethod> ret = super.getChildren(); | ||
292 | 174 | for(ListIterator<FrameworkMethod> iter = ret.listIterator(); iter.hasNext(); ) { | ||
293 | 175 | FrameworkMethod frameworkMethod = iter.next(); | ||
294 | 176 | try { | ||
295 | 177 | if (!onlyIfFilter(frameworkMethod)) { | ||
296 | 178 | iter.remove(); | ||
297 | 179 | } | ||
298 | 180 | } catch (OnlyIfException e) { | ||
299 | 181 | iter.set(new OnlyIfErrorFrameworkMethod(frameworkMethod.getMethod(), e)); | ||
300 | 182 | } | ||
301 | 183 | } | ||
302 | 184 | return ret; | ||
303 | 185 | } | ||
304 | 186 | |||
305 | 187 | @Override | ||
306 | 188 | public String getName() | ||
307 | 189 | { | ||
308 | 190 | return parameterization.getName(); | ||
309 | 191 | } | ||
310 | 192 | |||
311 | 193 | @Override | ||
312 | 194 | public String testName(FrameworkMethod method) | ||
313 | 195 | { | ||
314 | 196 | return String.format("%s [%s]", method.getName(), parameterization.getName()); | ||
315 | 197 | } | ||
316 | 198 | |||
317 | 199 | @Override | ||
318 | 200 | protected void validateConstructor(List<Throwable> errors) | ||
319 | 201 | { | ||
320 | 202 | validateOnlyOneConstructor(errors); | ||
321 | 203 | } | ||
322 | 204 | |||
323 | 205 | @Override | ||
324 | 206 | protected Statement classBlock(RunNotifier notifier) | ||
325 | 207 | { | ||
326 | 208 | return childrenInvoker(notifier); | ||
327 | 209 | } | ||
328 | 210 | |||
329 | 211 | @Override | ||
330 | 212 | protected void runChild(FrameworkMethod method, RunNotifier notifier) | ||
331 | 213 | { | ||
332 | 214 | if (expectedToPass(method)) | ||
333 | 215 | { | ||
334 | 216 | super.runChild(method, notifier); | ||
335 | 217 | } | ||
336 | 218 | else | ||
337 | 219 | { | ||
338 | 220 | notifier.fireTestIgnored( describeChild(method)); | ||
339 | 221 | } | ||
340 | 222 | } | ||
341 | 223 | |||
342 | 224 | private static class OnlyIfException extends Exception { | ||
343 | 225 | private OnlyIfException(String message, Throwable cause) { | ||
344 | 226 | super(message, cause); | ||
345 | 227 | } | ||
346 | 228 | |||
347 | 229 | private OnlyIfException(String message) { | ||
348 | 230 | super(message); | ||
349 | 231 | } | ||
350 | 232 | } | ||
351 | 233 | |||
352 | 234 | boolean onlyIfFilter(FrameworkMethod method) throws OnlyIfException { | ||
353 | 235 | OnlyIf onlyIf = method.getAnnotation(OnlyIf.class); | ||
354 | 236 | if (onlyIf != null) { | ||
355 | 237 | if (!runOnlyIf(onlyIf.value(), true)) { | ||
356 | 238 | return false; | ||
357 | 239 | } | ||
358 | 240 | } | ||
359 | 241 | OnlyIfNot onlyIfNot = method.getAnnotation(OnlyIfNot.class); | ||
360 | 242 | return onlyIfNot == null || runOnlyIf(onlyIfNot.value(), false); | ||
361 | 243 | } | ||
362 | 244 | |||
363 | 245 | private boolean runOnlyIf(String methodName, boolean mustEqual) throws OnlyIfException { | ||
364 | 246 | boolean result; | ||
365 | 247 | if (methodName.endsWith("()")) { | ||
366 | 248 | methodName = methodName.substring(0, methodName.length() - 2); // snip off the "()" | ||
367 | 249 | result = execOnlyIfMethod(methodName); | ||
368 | 250 | } | ||
369 | 251 | else { | ||
370 | 252 | result = getOnlyIfField(methodName); | ||
371 | 253 | } | ||
372 | 254 | return result == mustEqual; | ||
373 | 255 | } | ||
374 | 256 | |||
375 | 257 | |||
376 | 258 | private boolean execOnlyIfMethod(String methodName) throws OnlyIfException { | ||
377 | 259 | final Object result; | ||
378 | 260 | final Method onlyIfMethod; | ||
379 | 261 | final Class<?> testClass = getTestClass().getJavaClass(); | ||
380 | 262 | try { | ||
381 | 263 | onlyIfMethod = testClass.getMethod(methodName); | ||
382 | 264 | } catch (NoSuchMethodException e) { | ||
383 | 265 | throw new OnlyIfException("no such method: public boolean " + methodName + "()", e); | ||
384 | 266 | } | ||
385 | 267 | if (!onlyIfMethod.getReturnType().equals(boolean.class)) { | ||
386 | 268 | throw new OnlyIfException("no such method: public boolean " + methodName + "()"); | ||
387 | 269 | } | ||
388 | 270 | try { | ||
389 | 271 | Object test = createTest(); | ||
390 | 272 | result = onlyIfMethod.invoke(test); | ||
391 | 273 | } catch (Exception e) { | ||
392 | 274 | throw new OnlyIfException("couldn't invoke " + methodName + "()", e); | ||
393 | 275 | } | ||
394 | 276 | try { | ||
395 | 277 | return (Boolean) result; | ||
396 | 278 | } catch (ClassCastException e) { | ||
397 | 279 | throw new OnlyIfException("method " + methodName + "() didn't return boolean", e); | ||
398 | 280 | } | ||
399 | 281 | } | ||
400 | 282 | |||
401 | 283 | private boolean getOnlyIfField(String fieldName) throws OnlyIfException { | ||
402 | 284 | final Class<?> testClass = getTestClass().getJavaClass(); | ||
403 | 285 | final Field field; | ||
404 | 286 | try { | ||
405 | 287 | field = testClass.getField(fieldName); | ||
406 | 288 | } catch (Exception e) { | ||
407 | 289 | throw new OnlyIfException("Can't get field: " + fieldName, e); | ||
408 | 290 | } | ||
409 | 291 | try { | ||
410 | 292 | Object test = createTest(); | ||
411 | 293 | return field.getBoolean(test); | ||
412 | 294 | } catch (Exception e) { | ||
413 | 295 | throw new OnlyIfException("couldn't get boolean field " + fieldName + "()", e); | ||
414 | 296 | } | ||
415 | 297 | } | ||
416 | 298 | |||
417 | 299 | boolean expectedToPass(FrameworkMethod method) | ||
418 | 300 | { | ||
419 | 301 | if (overrideOn) | ||
420 | 302 | { | ||
421 | 303 | return true; | ||
422 | 304 | } | ||
423 | 305 | if (! parameterization.expectedToPass()) | ||
424 | 306 | { | ||
425 | 307 | return false; | ||
426 | 308 | } | ||
427 | 309 | Failing failing = method.getAnnotation(Failing.class); | ||
428 | 310 | if (failing == null) | ||
429 | 311 | { | ||
430 | 312 | return true; | ||
431 | 313 | } | ||
432 | 314 | if (failing.value().length == 0) | ||
433 | 315 | { | ||
434 | 316 | return false; | ||
435 | 317 | } | ||
436 | 318 | |||
437 | 319 | for (final String paramName : failing.value()) | ||
438 | 320 | { | ||
439 | 321 | if (paramNameUsesRegex(paramName)) | ||
440 | 322 | { | ||
441 | 323 | if (paramNameMatchesRegex(parameterization.getName(), paramName)) | ||
442 | 324 | { | ||
443 | 325 | return false; | ||
444 | 326 | } | ||
445 | 327 | } | ||
446 | 328 | else if (parameterization.getName().equals(paramName)) | ||
447 | 329 | { | ||
448 | 330 | return false; | ||
449 | 331 | } | ||
450 | 332 | } | ||
451 | 333 | return true; | ||
452 | 334 | } | ||
453 | 335 | } | ||
454 | 336 | |||
455 | 337 | static boolean paramNameUsesRegex(String paramName) | ||
456 | 338 | { | ||
457 | 339 | return paramName.length() > 2 | ||
458 | 340 | && (paramName.charAt(0)=='/') | ||
459 | 341 | && (paramName.charAt(paramName.length()-1)=='/'); | ||
460 | 342 | } | ||
461 | 343 | |||
462 | 344 | /** | ||
463 | 345 | * Returns whether a given parameterization matches a given regex. The regex should be in "/regex/" format. | ||
464 | 346 | * @param paramName the haystack, as it were | ||
465 | 347 | * @param paramRegex a string that starts and ends with '/', and between them has a needle. | ||
466 | 348 | * @return whether the paramRegex is found in paramName | ||
467 | 349 | */ | ||
468 | 350 | static boolean paramNameMatchesRegex(String paramName, String paramRegex) | ||
469 | 351 | { | ||
470 | 352 | assert paramRegex.charAt(0)=='/'; | ||
471 | 353 | assert paramRegex.charAt(paramRegex.length()-1)=='/'; | ||
472 | 354 | assert paramRegex.length() > 2; | ||
473 | 355 | String regex = paramRegex.substring(1, paramRegex.length()-1); | ||
474 | 356 | return Pattern.compile(regex).matcher(paramName).find(); | ||
475 | 357 | } | ||
476 | 358 | |||
477 | 359 | @SuppressWarnings("unused") // Invoked by reflection | ||
478 | 360 | public NamedParameterizedRunner(Class<?> klass) throws Throwable | ||
479 | 361 | { | ||
480 | 362 | super(klass, Collections.<Runner>emptyList()); | ||
481 | 363 | |||
482 | 364 | if (getTestClass().getJavaClass().getAnnotation(Ignore.class) != null) | ||
483 | 365 | { | ||
484 | 366 | runners = Collections.unmodifiableList(Arrays.asList((Runner)new IgnoredClassRunner(klass))); | ||
485 | 367 | return; | ||
486 | 368 | } | ||
487 | 369 | |||
488 | 370 | List<Runner> localRunners = new LinkedList<Runner>(); | ||
489 | 371 | |||
490 | 372 | Collection<Parameterization> parameterizations = getParameterizations(); | ||
491 | 373 | checkFailingParameterizations(parameterizations); | ||
492 | 374 | |||
493 | 375 | final String override = System.getProperty(PARAMETERIZATION_OVERRIDE); | ||
494 | 376 | final boolean overrideIsRegex = (override != null) && paramNameUsesRegex(override); | ||
495 | 377 | if (override != null) | ||
496 | 378 | { | ||
497 | 379 | String msg = "Override is set to"; | ||
498 | 380 | if (overrideIsRegex) | ||
499 | 381 | { | ||
500 | 382 | msg += " regex"; | ||
501 | 383 | } | ||
502 | 384 | msg += ":" + override; | ||
503 | 385 | logger.info(msg); | ||
504 | 386 | } | ||
505 | 387 | for (Parameterization param : parameterizations) | ||
506 | 388 | { | ||
507 | 389 | final boolean useThisParam; | ||
508 | 390 | if (override == null) | ||
509 | 391 | { | ||
510 | 392 | useThisParam = true; | ||
511 | 393 | } | ||
512 | 394 | else if (overrideIsRegex) | ||
513 | 395 | { | ||
514 | 396 | useThisParam = paramNameMatchesRegex(param.getName(), override); | ||
515 | 397 | } | ||
516 | 398 | else | ||
517 | 399 | { | ||
518 | 400 | useThisParam = param.getName().equals(override); | ||
519 | 401 | } | ||
520 | 402 | if (useThisParam) | ||
521 | 403 | { | ||
522 | 404 | if (override != null) | ||
523 | 405 | { | ||
524 | 406 | logger.info("Adding parameterization: " + param.getName()); | ||
525 | 407 | } | ||
526 | 408 | localRunners.add(new ReifiedParamRunner(getTestClass().getJavaClass(), param, override != null)); | ||
527 | 409 | } | ||
528 | 410 | } | ||
529 | 411 | runners = Collections.unmodifiableList(localRunners); | ||
530 | 412 | } | ||
531 | 413 | |||
532 | 414 | @Override | ||
533 | 415 | protected List<Runner> getChildren() | ||
534 | 416 | { | ||
535 | 417 | return runners; | ||
536 | 418 | } | ||
537 | 419 | |||
538 | 420 | /** | ||
539 | 421 | * Gets the parameterization | ||
540 | 422 | * @return the parameterization collection | ||
541 | 423 | * @throws Throwable if the annotation requirements are not met, or if there's an error in invoking | ||
542 | 424 | * the class's "get parameterizations" method. | ||
543 | 425 | */ | ||
544 | 426 | private Collection<Parameterization> getParameterizations() throws Throwable | ||
545 | 427 | { | ||
546 | 428 | TestClass cls = getTestClass(); | ||
547 | 429 | List<FrameworkMethod> methods = cls.getAnnotatedMethods(TestParameters.class); | ||
548 | 430 | |||
549 | 431 | if (methods.size() != 1) | ||
550 | 432 | { | ||
551 | 433 | throw new Exception("class " + cls.getName() + " must have exactly 1 method annotated with " | ||
552 | 434 | + TestParameters.class.getSimpleName() +"; found " + methods.size()); | ||
553 | 435 | } | ||
554 | 436 | |||
555 | 437 | FrameworkMethod method = methods.get(0); | ||
556 | 438 | checkParameterizationMethod(method); | ||
557 | 439 | |||
558 | 440 | @SuppressWarnings("unchecked") | ||
559 | 441 | Collection<Parameterization> ret = (Collection<Parameterization>) method.invokeExplosively(null); | ||
560 | 442 | checkParameterizations(ret); | ||
561 | 443 | return ret; | ||
562 | 444 | } | ||
563 | 445 | |||
564 | 446 | /** | ||
565 | 447 | * Checks the parameterizations collection for correctness | ||
566 | 448 | * @param collection the collection | ||
567 | 449 | * @throws Exception if the collection was null or contained duplicates | ||
568 | 450 | */ | ||
569 | 451 | private void checkParameterizations(Collection<Parameterization> collection) throws Exception | ||
570 | 452 | { | ||
571 | 453 | if (collection == null) | ||
572 | 454 | { | ||
573 | 455 | throw new Exception("parameterizations collection may not return null"); | ||
574 | 456 | } | ||
575 | 457 | Set<String> duplicates = new HashSet<String>(); | ||
576 | 458 | Set<Parameterization> checkSet = new HashSet<Parameterization>(); | ||
577 | 459 | for (Parameterization param : collection) | ||
578 | 460 | { | ||
579 | 461 | if (param == null) | ||
580 | 462 | { | ||
581 | 463 | throw new Exception("parameterization collection may not contain null values"); | ||
582 | 464 | } | ||
583 | 465 | if (!checkSet.add(param)) | ||
584 | 466 | { | ||
585 | 467 | duplicates.add(param.getName()); | ||
586 | 468 | } | ||
587 | 469 | } | ||
588 | 470 | if (duplicates.size() != 0) | ||
589 | 471 | { | ||
590 | 472 | throw new Exception("duplicated parameterization names: " + duplicates); | ||
591 | 473 | } | ||
592 | 474 | } | ||
593 | 475 | |||
594 | 476 | /** | ||
595 | 477 | * Checks the @Failing annotations on @Test methods. | ||
596 | 478 | * | ||
597 | 479 | * Specifically, this checks that no item in the @Failing list is repeated, and that each item in that list | ||
598 | 480 | * corresponds to an actual parameterization. | ||
599 | 481 | * @param parameterizations the known parameterizations; will not be modified. | ||
600 | 482 | * @throws org.junit.runners.model.InitializationError if a check fails | ||
601 | 483 | */ | ||
602 | 484 | private void checkFailingParameterizations(Collection<Parameterization> parameterizations) throws InitializationError | ||
603 | 485 | { | ||
604 | 486 | Collection<String> paramNames = new HashSet<String>(); | ||
605 | 487 | for (Parameterization param : parameterizations) | ||
606 | 488 | { | ||
607 | 489 | boolean added = paramNames.add(param.getName()); | ||
608 | 490 | assert added : "uncaught duplicate: " + param; | ||
609 | 491 | } | ||
610 | 492 | |||
611 | 493 | Set<String> duplicatesChecker = new HashSet<String>(); | ||
612 | 494 | for(FrameworkMethod method : super.getTestClass().getAnnotatedMethods(Failing.class)) | ||
613 | 495 | { | ||
614 | 496 | String[] failing = method.getAnnotation(Failing.class).value(); | ||
615 | 497 | if (failing != null) | ||
616 | 498 | { | ||
617 | 499 | for(int i=0; i < failing.length; ++i) | ||
618 | 500 | { | ||
619 | 501 | if (!duplicatesChecker.add(failing[i])) | ||
620 | 502 | { | ||
621 | 503 | throw new InitializationError("duplicate parameterization name in @Failing list: " | ||
622 | 504 | + method.getName() + "[" + i + "]<" + failing[i] + ">"); | ||
623 | 505 | } | ||
624 | 506 | if ( !(paramNameUsesRegex(failing[i]) || paramNames.contains(failing[i])) ) | ||
625 | 507 | { | ||
626 | 508 | throw new InitializationError("parameterization is marked as failing, " | ||
627 | 509 | + "but isn't in list of parameterizations: " | ||
628 | 510 | + method.getName() + "[" + i + "]<" + failing[i] +"> not in " + paramNames); | ||
629 | 511 | } | ||
630 | 512 | } | ||
631 | 513 | duplicatesChecker.clear(); | ||
632 | 514 | } | ||
633 | 515 | } | ||
634 | 516 | } | ||
635 | 517 | |||
636 | 518 | |||
637 | 519 | /** | ||
638 | 520 | * Checks the parameterization method for correctness. | ||
639 | 521 | * @param frameworkMethod the method | ||
640 | 522 | * @throws Exception if the annotation requirements are not met | ||
641 | 523 | */ | ||
642 | 524 | private static void checkParameterizationMethod(FrameworkMethod frameworkMethod) throws Exception | ||
643 | 525 | { | ||
644 | 526 | final Method method = frameworkMethod.getMethod(); | ||
645 | 527 | |||
646 | 528 | if (method.getParameterTypes().length != 0) | ||
647 | 529 | { | ||
648 | 530 | throw new Exception(complainingThat(method, "must take no arguments")); | ||
649 | 531 | } | ||
650 | 532 | |||
651 | 533 | final int modifiers = frameworkMethod.getMethod().getModifiers(); | ||
652 | 534 | if (! Modifier.isPublic(modifiers)) | ||
653 | 535 | { | ||
654 | 536 | throw new Exception(complainingThat(method, "must be public")); | ||
655 | 537 | } | ||
656 | 538 | if (! Modifier.isStatic(modifiers)) | ||
657 | 539 | { | ||
658 | 540 | throw new Exception(complainingThat(method, "must be static")); | ||
659 | 541 | } | ||
660 | 542 | |||
661 | 543 | final Type genericRet = method.getGenericReturnType(); | ||
662 | 544 | final String mustReturnCorrectly = "must return Collection of " + Parameterization.class; | ||
663 | 545 | if (! (genericRet instanceof ParameterizedType)) | ||
664 | 546 | { | ||
665 | 547 | throw new Exception(complainingThat(method, mustReturnCorrectly)); | ||
666 | 548 | } | ||
667 | 549 | final ParameterizedType ret = (ParameterizedType) genericRet; | ||
668 | 550 | if (!(ret.getRawType() instanceof Class) && Collection.class.isAssignableFrom((Class)ret.getRawType())) | ||
669 | 551 | { | ||
670 | 552 | throw new Exception(complainingThat(method, mustReturnCorrectly)); | ||
671 | 553 | } | ||
672 | 554 | if (ret.getActualTypeArguments().length != 1) | ||
673 | 555 | { | ||
674 | 556 | throw new Exception(complainingThat(method, mustReturnCorrectly + "; raw Collection is not allowed")); | ||
675 | 557 | } | ||
676 | 558 | if (!ret.getActualTypeArguments()[0].equals(Parameterization.class)) | ||
677 | 559 | { | ||
678 | 560 | throw new Exception(complainingThat(method, mustReturnCorrectly)); | ||
679 | 561 | } | ||
680 | 562 | } | ||
681 | 563 | |||
682 | 564 | private static String complainingThat(Method method, String mustBe) | ||
683 | 565 | { | ||
684 | 566 | assert method != null; | ||
685 | 567 | assert mustBe != null; | ||
686 | 568 | return String.format("%s.%s() %s", method.getDeclaringClass().getName(), method.getName(), mustBe); | ||
687 | 569 | } | ||
688 | 570 | } | ||
689 | 0 | 571 | ||
690 | === added file 'src/main/java/com/motpot/npr/OnlyIf.java' | |||
691 | --- src/main/java/com/motpot/npr/OnlyIf.java 1970-01-01 00:00:00 +0000 | |||
692 | +++ src/main/java/com/motpot/npr/OnlyIf.java 2011-09-08 16:01:22 +0000 | |||
693 | @@ -0,0 +1,20 @@ | |||
694 | 1 | package com.motpot.npr; | ||
695 | 2 | |||
696 | 3 | import java.lang.annotation.ElementType; | ||
697 | 4 | import java.lang.annotation.Retention; | ||
698 | 5 | import java.lang.annotation.RetentionPolicy; | ||
699 | 6 | import java.lang.annotation.Target; | ||
700 | 7 | |||
701 | 8 | /** | ||
702 | 9 | * Represents a condition for running a test. | ||
703 | 10 | */ | ||
704 | 11 | @Retention(RetentionPolicy.RUNTIME) | ||
705 | 12 | @Target(ElementType.METHOD) | ||
706 | 13 | public @interface OnlyIf | ||
707 | 14 | { | ||
708 | 15 | /** | ||
709 | 16 | * The method that should be invoked to see if this annotated method should be run | ||
710 | 17 | * @return | ||
711 | 18 | */ | ||
712 | 19 | String value(); | ||
713 | 20 | } | ||
714 | 0 | 21 | ||
715 | === added file 'src/main/java/com/motpot/npr/OnlyIfNot.java' | |||
716 | --- src/main/java/com/motpot/npr/OnlyIfNot.java 1970-01-01 00:00:00 +0000 | |||
717 | +++ src/main/java/com/motpot/npr/OnlyIfNot.java 2011-09-08 16:01:22 +0000 | |||
718 | @@ -0,0 +1,20 @@ | |||
719 | 1 | package com.motpot.npr; | ||
720 | 2 | |||
721 | 3 | import java.lang.annotation.ElementType; | ||
722 | 4 | import java.lang.annotation.Retention; | ||
723 | 5 | import java.lang.annotation.RetentionPolicy; | ||
724 | 6 | import java.lang.annotation.Target; | ||
725 | 7 | |||
726 | 8 | /** | ||
727 | 9 | * Represents a condition for running a test. | ||
728 | 10 | */ | ||
729 | 11 | @Retention(RetentionPolicy.RUNTIME) | ||
730 | 12 | @Target(ElementType.METHOD) | ||
731 | 13 | public @interface OnlyIfNot | ||
732 | 14 | { | ||
733 | 15 | /** | ||
734 | 16 | * The method that should be invoked to see if this annotated method should be run | ||
735 | 17 | * @return | ||
736 | 18 | */ | ||
737 | 19 | String value(); | ||
738 | 20 | } | ||
739 | 0 | 21 | ||
740 | === added file 'src/main/java/com/motpot/npr/Parameterization.java' | |||
741 | --- src/main/java/com/motpot/npr/Parameterization.java 1970-01-01 00:00:00 +0000 | |||
742 | +++ src/main/java/com/motpot/npr/Parameterization.java 2011-09-08 16:01:22 +0000 | |||
743 | @@ -0,0 +1,152 @@ | |||
744 | 1 | package com.motpot.npr; | ||
745 | 2 | |||
746 | 3 | import java.util.Arrays; | ||
747 | 4 | import java.util.Iterator; | ||
748 | 5 | import java.util.LinkedList; | ||
749 | 6 | import java.util.List; | ||
750 | 7 | |||
751 | 8 | public final class Parameterization | ||
752 | 9 | { | ||
753 | 10 | private String name; | ||
754 | 11 | private final List<Object> args; | ||
755 | 12 | private boolean expectedToPass; | ||
756 | 13 | |||
757 | 14 | public static Parameterization create(String name, Object... args) | ||
758 | 15 | { | ||
759 | 16 | return new Parameterization(name, true, args); | ||
760 | 17 | } | ||
761 | 18 | |||
762 | 19 | public static Parameterization failing(String name, Object... args) | ||
763 | 20 | { | ||
764 | 21 | return new Parameterization(name, false, args); | ||
765 | 22 | } | ||
766 | 23 | |||
767 | 24 | public Parameterization(String name, boolean isPassing, Object... args) | ||
768 | 25 | { | ||
769 | 26 | if (name == null) { | ||
770 | 27 | throw new IllegalArgumentException("name can't be null"); | ||
771 | 28 | } | ||
772 | 29 | if (args == null) { | ||
773 | 30 | throw new IllegalArgumentException("args can't be null"); | ||
774 | 31 | } | ||
775 | 32 | this.name = name; | ||
776 | 33 | this.args = new LinkedList<Object>(Arrays.asList(args)); | ||
777 | 34 | this.expectedToPass = isPassing; | ||
778 | 35 | } | ||
779 | 36 | |||
780 | 37 | /** | ||
781 | 38 | * <p>Creates a copy of this parameterization.</p> | ||
782 | 39 | * | ||
783 | 40 | * <p>The original parameterization's arguments list is copied shallowly.</p> | ||
784 | 41 | * @param copyFrom the original parameterization | ||
785 | 42 | */ | ||
786 | 43 | public Parameterization(Parameterization copyFrom) | ||
787 | 44 | { | ||
788 | 45 | this.name = copyFrom.name; | ||
789 | 46 | this.args = new LinkedList<Object>(copyFrom.args); | ||
790 | 47 | this.expectedToPass = copyFrom.expectedToPass; | ||
791 | 48 | } | ||
792 | 49 | |||
793 | 50 | public String getName() | ||
794 | 51 | { | ||
795 | 52 | return name; | ||
796 | 53 | } | ||
797 | 54 | |||
798 | 55 | public void setName(String name) | ||
799 | 56 | { | ||
800 | 57 | this.name = name; | ||
801 | 58 | } | ||
802 | 59 | |||
803 | 60 | /** | ||
804 | 61 | * Returns this parameterization's arguments as an Object array. | ||
805 | 62 | * | ||
806 | 63 | * This array is <em>not</em> backed by the parameterization, so changes in one are not reflected in the other. | ||
807 | 64 | * However, the array is a shallow copy, so modifying an element of the parameterization in the list will be | ||
808 | 65 | * reflected in the array, and the vice versa. | ||
809 | 66 | * @return the arguments | ||
810 | 67 | */ | ||
811 | 68 | public Object[] getArguments() | ||
812 | 69 | { | ||
813 | 70 | return args.toArray(); | ||
814 | 71 | } | ||
815 | 72 | |||
816 | 73 | /** | ||
817 | 74 | * Returns this parameterization's arguments as a list. | ||
818 | 75 | * | ||
819 | 76 | * This list is backed by the parameterization, so changes to one are reflected in the other. | ||
820 | 77 | * @return a list of arguments, backed by the parameterization | ||
821 | 78 | */ | ||
822 | 79 | public List<Object> getArgsAsList() | ||
823 | 80 | { | ||
824 | 81 | return args; | ||
825 | 82 | } | ||
826 | 83 | |||
827 | 84 | public boolean expectedToPass() | ||
828 | 85 | { | ||
829 | 86 | return expectedToPass; | ||
830 | 87 | } | ||
831 | 88 | |||
832 | 89 | public void setExpectedToPass(boolean expectedToPass) | ||
833 | 90 | { | ||
834 | 91 | this.expectedToPass = expectedToPass; | ||
835 | 92 | } | ||
836 | 93 | |||
837 | 94 | @Override | ||
838 | 95 | public boolean equals(Object o) | ||
839 | 96 | { | ||
840 | 97 | if (this == o) | ||
841 | 98 | { | ||
842 | 99 | return true; | ||
843 | 100 | } | ||
844 | 101 | if (o == null || getClass() != o.getClass()) | ||
845 | 102 | { | ||
846 | 103 | return false; | ||
847 | 104 | } | ||
848 | 105 | Parameterization that = (Parameterization) o; | ||
849 | 106 | return name.equals(that.name); | ||
850 | 107 | } | ||
851 | 108 | |||
852 | 109 | @Override | ||
853 | 110 | public int hashCode() | ||
854 | 111 | { | ||
855 | 112 | return name.hashCode(); | ||
856 | 113 | } | ||
857 | 114 | |||
858 | 115 | public boolean equivalent(Parameterization other) | ||
859 | 116 | { | ||
860 | 117 | if (!this.name.equals(other.name)) | ||
861 | 118 | return false; | ||
862 | 119 | if (this.expectedToPass != other.expectedToPass) | ||
863 | 120 | return false; | ||
864 | 121 | if (this.args.size() != other.args.size()) | ||
865 | 122 | return false; | ||
866 | 123 | |||
867 | 124 | Iterator<Object> myIter = this.args.iterator(); | ||
868 | 125 | Iterator<Object> otherIter = other.args.iterator(); | ||
869 | 126 | |||
870 | 127 | while (myIter.hasNext()) | ||
871 | 128 | { | ||
872 | 129 | Object mine = myIter.next(); | ||
873 | 130 | Object his = otherIter.next(); | ||
874 | 131 | |||
875 | 132 | if (mine == null) | ||
876 | 133 | { | ||
877 | 134 | if (his != null) | ||
878 | 135 | { | ||
879 | 136 | return false; | ||
880 | 137 | } | ||
881 | 138 | } | ||
882 | 139 | else if (!mine.equals(his)) | ||
883 | 140 | { | ||
884 | 141 | return false; | ||
885 | 142 | } | ||
886 | 143 | } | ||
887 | 144 | return true; | ||
888 | 145 | } | ||
889 | 146 | |||
890 | 147 | @Override | ||
891 | 148 | public String toString() | ||
892 | 149 | { | ||
893 | 150 | return "Parameterization[" + (expectedToPass? "PASSING " : "FAILING ") + name + ": " + args + " ]"; | ||
894 | 151 | } | ||
895 | 152 | } | ||
896 | 0 | 153 | ||
897 | === added file 'src/main/java/com/motpot/npr/ParameterizationBuilder.java' | |||
898 | --- src/main/java/com/motpot/npr/ParameterizationBuilder.java 1970-01-01 00:00:00 +0000 | |||
899 | +++ src/main/java/com/motpot/npr/ParameterizationBuilder.java 2011-09-08 16:01:22 +0000 | |||
900 | @@ -0,0 +1,159 @@ | |||
901 | 1 | package com.motpot.npr; | ||
902 | 2 | |||
903 | 3 | import java.util.LinkedList; | ||
904 | 4 | import java.util.List; | ||
905 | 5 | |||
906 | 6 | public final class ParameterizationBuilder | ||
907 | 7 | { | ||
908 | 8 | private final List<Parameterization> list; | ||
909 | 9 | |||
910 | 10 | /** | ||
911 | 11 | * Creates a builder with no starting parameterizations. | ||
912 | 12 | */ | ||
913 | 13 | public ParameterizationBuilder() | ||
914 | 14 | { | ||
915 | 15 | this(new LinkedList<Parameterization>()); | ||
916 | 16 | } | ||
917 | 17 | |||
918 | 18 | /** | ||
919 | 19 | * Creates a builder backed by a list. Changes to the one will be reflected in the other, and {@linkplain #asList()} | ||
920 | 20 | * will return the same instance as is passed to this method. | ||
921 | 21 | * @param backingList The list that backs this builder. | ||
922 | 22 | */ | ||
923 | 23 | public ParameterizationBuilder(List<Parameterization> backingList) | ||
924 | 24 | { | ||
925 | 25 | list = backingList; | ||
926 | 26 | } | ||
927 | 27 | |||
928 | 28 | /** | ||
929 | 29 | * Adds a parameterization to the end of the list. | ||
930 | 30 | * @param name the parameterization's name | ||
931 | 31 | * @param args the parameterization's arguments | ||
932 | 32 | */ | ||
933 | 33 | public void add(String name, Object... args) | ||
934 | 34 | { | ||
935 | 35 | list.add(Parameterization.create(name, args)); | ||
936 | 36 | } | ||
937 | 37 | |||
938 | 38 | /** | ||
939 | 39 | * Adds a parameterization that's expected to fail to the end of the list | ||
940 | 40 | * @param name the parameterization's name | ||
941 | 41 | * @param args the parameterization's arguments | ||
942 | 42 | */ | ||
943 | 43 | public void addFailing(String name, Object... args) | ||
944 | 44 | { | ||
945 | 45 | list.add(Parameterization.failing(name, args)); | ||
946 | 46 | } | ||
947 | 47 | |||
948 | 48 | /** | ||
949 | 49 | * Adds a parameterization to the end of the list. | ||
950 | 50 | * @param name the parameterization's name | ||
951 | 51 | * @param expectedToPass whether the parameterization is expected to pass any tests | ||
952 | 52 | * @param args the parameterization's arguments | ||
953 | 53 | */ | ||
954 | 54 | public void create(String name, boolean expectedToPass, Object... args) | ||
955 | 55 | { | ||
956 | 56 | list.add(new Parameterization(name, expectedToPass, args)); | ||
957 | 57 | } | ||
958 | 58 | |||
959 | 59 | /** | ||
960 | 60 | * <p>Performs a cartesian product of parameterizations by prepending each of the incoming args to each | ||
961 | 61 | * existing parameter's arg list.</p> | ||
962 | 62 | * | ||
963 | 63 | * For instance, if you have parameters <tt>[ ("A", 1, 2, 3) and ("B", 4, 5, 6) ]</tt>, and you called | ||
964 | 64 | * <tt>multiplyParametersByPrepending("foo-", 'c', "bar", 'd')</tt>, you would get the following | ||
965 | 65 | * parameterizations, in this order: | ||
966 | 66 | * <ol> | ||
967 | 67 | * <li>"foo-A", 'c', 1, 2, 3</li> | ||
968 | 68 | * <li>"bar-A", 'd', 1, 2, 3</li> | ||
969 | 69 | * <li>"foo-B", 'c', 4, 5, 6</li> | ||
970 | 70 | * <li>"bar-B", 'd', 1, 2, 3</li> | ||
971 | 71 | * </ol> | ||
972 | 72 | * @param args the list of named args to multiply by. Every other element (starting with the first) in the list must | ||
973 | 73 | * be a String that represents the name prefix; the element following each prefix is the argument to append to | ||
974 | 74 | * the args list. | ||
975 | 75 | * @throws IllegalArgumentException if the args aren't given as String-Object pairings. | ||
976 | 76 | * @throws IllegalStateException if there are no existing parameterizations to multiply by | ||
977 | 77 | */ | ||
978 | 78 | public void multiplyParametersByPrepending(Object... args) | ||
979 | 79 | { | ||
980 | 80 | cartesianProduct(false, args); | ||
981 | 81 | } | ||
982 | 82 | |||
983 | 83 | /** | ||
984 | 84 | * <p>Performs a cartesian product of parameterizations by appending each of the incoming args to each | ||
985 | 85 | * existing parameter's arg list. If you supply a prefix, it will also be appended to each parameter's name.</p> | ||
986 | 86 | * | ||
987 | 87 | * <p>This works just like {@link #multiplyParametersByPrepending(Object...)}, only each parameter label and | ||
988 | 88 | * value is appended instead of prepended.</p> | ||
989 | 89 | * @param args the list of named args to multiply by. Every other element (starting with the first) in the list must | ||
990 | 90 | * be a String that represents the name suffix; the element following each suffix is the argument to append to | ||
991 | 91 | * the args list. | ||
992 | 92 | * @throws IllegalArgumentException if the args aren't given as String-Object pairings. | ||
993 | 93 | * @throws IllegalStateException if there are no existing parameterizations to multiply by | ||
994 | 94 | * @see #multiplyParametersByPrepending(Object...) | ||
995 | 95 | */ | ||
996 | 96 | public void multiplyParametersByAppending(Object... args) | ||
997 | 97 | { | ||
998 | 98 | cartesianProduct(true, args); | ||
999 | 99 | } | ||
1000 | 100 | |||
1001 | 101 | private void cartesianProduct(boolean append, Object[] args) | ||
1002 | 102 | { | ||
1003 | 103 | if (list.size() == 0) | ||
1004 | 104 | { | ||
1005 | 105 | throw new IllegalStateException("can't multiply yet -- no args defined"); | ||
1006 | 106 | } | ||
1007 | 107 | if ( (args.length % 2) != 0) | ||
1008 | 108 | { | ||
1009 | 109 | throw new IllegalArgumentException("odd number of arguments"); | ||
1010 | 110 | } | ||
1011 | 111 | |||
1012 | 112 | List<Parameterization> product = new LinkedList<Parameterization>(); | ||
1013 | 113 | for (Parameterization param : list) | ||
1014 | 114 | { | ||
1015 | 115 | Object[] origArgs = param.getArguments(); | ||
1016 | 116 | Object[] newArgs = new Object[origArgs.length + 1]; | ||
1017 | 117 | System.arraycopy(origArgs, 0, newArgs, append ? 0 : 1, origArgs.length); | ||
1018 | 118 | |||
1019 | 119 | for(int i=0; i < args.length; i+= 2) | ||
1020 | 120 | { | ||
1021 | 121 | String label; | ||
1022 | 122 | try | ||
1023 | 123 | { | ||
1024 | 124 | label = (String)args[i]; | ||
1025 | 125 | } | ||
1026 | 126 | catch (ClassCastException e) | ||
1027 | 127 | { | ||
1028 | 128 | throw new IllegalArgumentException("argument at index " + i + " is not a String"); | ||
1029 | 129 | } | ||
1030 | 130 | |||
1031 | 131 | if (label == null) | ||
1032 | 132 | { | ||
1033 | 133 | label = param.getName(); | ||
1034 | 134 | } | ||
1035 | 135 | else | ||
1036 | 136 | { | ||
1037 | 137 | label = append ? | ||
1038 | 138 | param.getName() + label | ||
1039 | 139 | : label + param.getName(); | ||
1040 | 140 | } | ||
1041 | 141 | newArgs[append ? origArgs.length : 0] = args[i+1]; | ||
1042 | 142 | product.add(new Parameterization(label, param.expectedToPass(), newArgs)); | ||
1043 | 143 | } | ||
1044 | 144 | } | ||
1045 | 145 | |||
1046 | 146 | list.clear(); | ||
1047 | 147 | list.addAll(product); | ||
1048 | 148 | } | ||
1049 | 149 | |||
1050 | 150 | /** | ||
1051 | 151 | * Represents this builder's parameterizations. The returning list is backed by this builder, so changes | ||
1052 | 152 | * to either are seen in both. | ||
1053 | 153 | * @return the list that backs this builder | ||
1054 | 154 | */ | ||
1055 | 155 | public List<Parameterization> asList() | ||
1056 | 156 | { | ||
1057 | 157 | return list; | ||
1058 | 158 | } | ||
1059 | 159 | } | ||
1060 | 0 | 160 | ||
1061 | === added directory 'src/test' | |||
1062 | === added directory 'src/test/java' | |||
1063 | === added directory 'src/test/java/com' | |||
1064 | === added directory 'src/test/java/com/motpot' | |||
1065 | === added directory 'src/test/java/com/motpot/npr' | |||
1066 | === added file 'src/test/java/com/motpot/npr/NamedParameterizedRunnerTest.java' | |||
1067 | --- src/test/java/com/motpot/npr/NamedParameterizedRunnerTest.java 1970-01-01 00:00:00 +0000 | |||
1068 | +++ src/test/java/com/motpot/npr/NamedParameterizedRunnerTest.java 2011-09-08 16:01:22 +0000 | |||
1069 | @@ -0,0 +1,316 @@ | |||
1070 | 1 | package com.motpot.npr; | ||
1071 | 2 | |||
1072 | 3 | import com.motpot.npr.NamedParameterizedRunner.ReifiedParamRunner; | ||
1073 | 4 | import org.junit.After; | ||
1074 | 5 | import org.junit.Before; | ||
1075 | 6 | import org.junit.Test; | ||
1076 | 7 | import org.junit.runner.Runner; | ||
1077 | 8 | import org.junit.runners.model.FrameworkMethod; | ||
1078 | 9 | |||
1079 | 10 | import java.util.*; | ||
1080 | 11 | |||
1081 | 12 | import static junit.framework.Assert.*; | ||
1082 | 13 | |||
1083 | 14 | public final class NamedParameterizedRunnerTest | ||
1084 | 15 | { | ||
1085 | 16 | private final static List<Parameterization> builderList = new LinkedList<Parameterization>(); | ||
1086 | 17 | private Properties oldProperties; | ||
1087 | 18 | private Properties workingProperties; | ||
1088 | 19 | |||
1089 | 20 | @Before | ||
1090 | 21 | public void setUp() | ||
1091 | 22 | { | ||
1092 | 23 | builderList.clear(); | ||
1093 | 24 | oldProperties = System.getProperties(); | ||
1094 | 25 | workingProperties = new Properties(oldProperties); | ||
1095 | 26 | System.setProperties(workingProperties); | ||
1096 | 27 | } | ||
1097 | 28 | |||
1098 | 29 | @After | ||
1099 | 30 | public void tearDown() | ||
1100 | 31 | { | ||
1101 | 32 | System.setProperties(oldProperties); | ||
1102 | 33 | } | ||
1103 | 34 | |||
1104 | 35 | public final static class RunEverythingTest | ||
1105 | 36 | { | ||
1106 | 37 | @NamedParameterizedRunner.TestParameters | ||
1107 | 38 | @SuppressWarnings("unused") | ||
1108 | 39 | public static List<Parameterization> params() { return builderList; } | ||
1109 | 40 | |||
1110 | 41 | public RunEverythingTest(char unused) | ||
1111 | 42 | { | ||
1112 | 43 | assert unused != 'a'; // just to shut it up about it not being used | ||
1113 | 44 | } | ||
1114 | 45 | |||
1115 | 46 | @Test | ||
1116 | 47 | public void one() {} | ||
1117 | 48 | |||
1118 | 49 | @Test | ||
1119 | 50 | public void two() {} | ||
1120 | 51 | } | ||
1121 | 52 | |||
1122 | 53 | public final static class OneFailingTest | ||
1123 | 54 | { | ||
1124 | 55 | @NamedParameterizedRunner.TestParameters | ||
1125 | 56 | @SuppressWarnings("unused") | ||
1126 | 57 | public static List<Parameterization> params() { return builderList; } | ||
1127 | 58 | |||
1128 | 59 | public OneFailingTest(char unused) | ||
1129 | 60 | { | ||
1130 | 61 | assert unused != 'a'; // just to shut it up about it not being used | ||
1131 | 62 | } | ||
1132 | 63 | |||
1133 | 64 | @Test | ||
1134 | 65 | public void passing() {} | ||
1135 | 66 | |||
1136 | 67 | @Failing @Test | ||
1137 | 68 | public void failing() {} | ||
1138 | 69 | } | ||
1139 | 70 | |||
1140 | 71 | public final static class OnlyIfTest | ||
1141 | 72 | { | ||
1142 | 73 | @NamedParameterizedRunner.TestParameters | ||
1143 | 74 | @SuppressWarnings("unused") | ||
1144 | 75 | public static List<Parameterization> params() { return builderList; } | ||
1145 | 76 | |||
1146 | 77 | private final int number; | ||
1147 | 78 | @SuppressWarnings("unused") public final boolean numberIs1; // used by @OnlyIf | ||
1148 | 79 | |||
1149 | 80 | public OnlyIfTest(int number) { | ||
1150 | 81 | this.number = number; | ||
1151 | 82 | this.numberIs1 = is1(); | ||
1152 | 83 | } | ||
1153 | 84 | |||
1154 | 85 | @Test | ||
1155 | 86 | public void alwaysRun() {} | ||
1156 | 87 | |||
1157 | 88 | @Test @OnlyIf("is1()") | ||
1158 | 89 | public void testIs1Method() { | ||
1159 | 90 | assertEquals("number", 1, number); | ||
1160 | 91 | } | ||
1161 | 92 | |||
1162 | 93 | @Test @OnlyIf("numberIs1") | ||
1163 | 94 | public void testIs1Field() { | ||
1164 | 95 | assertEquals("number", 1, number); | ||
1165 | 96 | } | ||
1166 | 97 | |||
1167 | 98 | public boolean is1() { | ||
1168 | 99 | return number == 1; | ||
1169 | 100 | } | ||
1170 | 101 | } | ||
1171 | 102 | |||
1172 | 103 | @Test | ||
1173 | 104 | public void testRegexUsed() | ||
1174 | 105 | { | ||
1175 | 106 | assertFalse("//", NamedParameterizedRunner.paramNameUsesRegex("//")); | ||
1176 | 107 | assertTrue("/a/", NamedParameterizedRunner.paramNameUsesRegex("/a/")); | ||
1177 | 108 | } | ||
1178 | 109 | |||
1179 | 110 | @Test | ||
1180 | 111 | public void testRegexMatches() | ||
1181 | 112 | { | ||
1182 | 113 | assertFalse("/a/ against 'foo'", NamedParameterizedRunner.paramNameMatchesRegex("foo", "/a/")); | ||
1183 | 114 | assertTrue("/a/ against 'foo bar'", NamedParameterizedRunner.paramNameMatchesRegex("foo bar", "/a/")); | ||
1184 | 115 | assertFalse("/foo/ against 'o'", NamedParameterizedRunner.paramNameMatchesRegex("o", "/foo/")); | ||
1185 | 116 | } | ||
1186 | 117 | |||
1187 | 118 | @Test | ||
1188 | 119 | public void testRunEverythingPasses() throws Throwable | ||
1189 | 120 | { | ||
1190 | 121 | ParameterizationBuilder builder = new ParameterizationBuilder(builderList); | ||
1191 | 122 | builder.add("alpha", 'a'); | ||
1192 | 123 | builder.add("beta", 'b'); | ||
1193 | 124 | |||
1194 | 125 | NamedParameterizedRunner runner = new NamedParameterizedRunner(RunEverythingTest.class); | ||
1195 | 126 | |||
1196 | 127 | Map<String,ReifiedParamRunner> map = testParameterizations(runner, | ||
1197 | 128 | "Parameterization[PASSING alpha: [a] ]", | ||
1198 | 129 | "Parameterization[PASSING beta: [b] ]"); | ||
1199 | 130 | |||
1200 | 131 | testOverrides(map.values(), false); | ||
1201 | 132 | |||
1202 | 133 | testFrameworkMethod(map.get("Parameterization[PASSING alpha: [a] ]"), RunEverythingTest.class, "one", true); | ||
1203 | 134 | testFrameworkMethod(map.get("Parameterization[PASSING alpha: [a] ]"), RunEverythingTest.class, "two", true); | ||
1204 | 135 | testFrameworkMethod(map.get("Parameterization[PASSING beta: [b] ]"), RunEverythingTest.class, "one", true); | ||
1205 | 136 | testFrameworkMethod(map.get("Parameterization[PASSING beta: [b] ]"), RunEverythingTest.class, "two", true); | ||
1206 | 137 | } | ||
1207 | 138 | |||
1208 | 139 | @Test | ||
1209 | 140 | public void testRunEverythingAlphaPasses() throws Throwable | ||
1210 | 141 | { | ||
1211 | 142 | ParameterizationBuilder builder = new ParameterizationBuilder(builderList); | ||
1212 | 143 | builder.add("alpha", 'a'); | ||
1213 | 144 | builder.addFailing("beta", 'b'); | ||
1214 | 145 | |||
1215 | 146 | NamedParameterizedRunner runner = new NamedParameterizedRunner(RunEverythingTest.class); | ||
1216 | 147 | |||
1217 | 148 | Map<String,ReifiedParamRunner> map = testParameterizations(runner, | ||
1218 | 149 | "Parameterization[PASSING alpha: [a] ]", | ||
1219 | 150 | "Parameterization[FAILING beta: [b] ]"); | ||
1220 | 151 | |||
1221 | 152 | testOverrides(map.values(), false); | ||
1222 | 153 | |||
1223 | 154 | testFrameworkMethod(map.get("Parameterization[PASSING alpha: [a] ]"), RunEverythingTest.class, "one", true); | ||
1224 | 155 | testFrameworkMethod(map.get("Parameterization[PASSING alpha: [a] ]"), RunEverythingTest.class, "two", true); | ||
1225 | 156 | testFrameworkMethod(map.get("Parameterization[FAILING beta: [b] ]"), RunEverythingTest.class, "one", false); | ||
1226 | 157 | testFrameworkMethod(map.get("Parameterization[FAILING beta: [b] ]"), RunEverythingTest.class, "two", false); | ||
1227 | 158 | } | ||
1228 | 159 | |||
1229 | 160 | @Test | ||
1230 | 161 | public void testOneMethodFailing() throws Throwable | ||
1231 | 162 | { | ||
1232 | 163 | ParameterizationBuilder builder = new ParameterizationBuilder(builderList); | ||
1233 | 164 | builder.add("alpha", 'a'); | ||
1234 | 165 | builder.add("beta", 'b'); | ||
1235 | 166 | |||
1236 | 167 | NamedParameterizedRunner runner = new NamedParameterizedRunner(OneFailingTest.class); | ||
1237 | 168 | |||
1238 | 169 | Map<String,ReifiedParamRunner> map = testParameterizations(runner, | ||
1239 | 170 | "Parameterization[PASSING alpha: [a] ]", | ||
1240 | 171 | "Parameterization[PASSING beta: [b] ]"); | ||
1241 | 172 | |||
1242 | 173 | testOverrides(map.values(), false); | ||
1243 | 174 | |||
1244 | 175 | testFrameworkMethod(map.get("Parameterization[PASSING alpha: [a] ]"), OneFailingTest.class, "passing", true); | ||
1245 | 176 | testFrameworkMethod(map.get("Parameterization[PASSING alpha: [a] ]"), OneFailingTest.class, "failing", false); | ||
1246 | 177 | testFrameworkMethod(map.get("Parameterization[PASSING beta: [b] ]"), OneFailingTest.class, "passing", true); | ||
1247 | 178 | testFrameworkMethod(map.get("Parameterization[PASSING beta: [b] ]"), OneFailingTest.class, "failing", false); | ||
1248 | 179 | } | ||
1249 | 180 | |||
1250 | 181 | @Test | ||
1251 | 182 | public void testOverrideOfFailingMethod() throws Throwable | ||
1252 | 183 | { | ||
1253 | 184 | workingProperties.put(NamedParameterizedRunner.PARAMETERIZATION_OVERRIDE, "beta"); | ||
1254 | 185 | ParameterizationBuilder builder = new ParameterizationBuilder(builderList); | ||
1255 | 186 | builder.add("alpha", 'a'); | ||
1256 | 187 | builder.add("beta", 'b'); | ||
1257 | 188 | |||
1258 | 189 | NamedParameterizedRunner runner = new NamedParameterizedRunner(OneFailingTest.class); | ||
1259 | 190 | |||
1260 | 191 | Map<String,ReifiedParamRunner> map = testParameterizations(runner, | ||
1261 | 192 | "Parameterization[PASSING beta: [b] ]"); | ||
1262 | 193 | |||
1263 | 194 | testOverrides(map.values(), true); | ||
1264 | 195 | |||
1265 | 196 | testFrameworkMethod(map.get("Parameterization[PASSING beta: [b] ]"), OneFailingTest.class, "passing", true); | ||
1266 | 197 | testFrameworkMethod(map.get("Parameterization[PASSING beta: [b] ]"), OneFailingTest.class, "failing", true); | ||
1267 | 198 | } | ||
1268 | 199 | |||
1269 | 200 | @Test | ||
1270 | 201 | public void testOverrideOfFailingParam() throws Throwable | ||
1271 | 202 | { | ||
1272 | 203 | workingProperties.put(NamedParameterizedRunner.PARAMETERIZATION_OVERRIDE, "beta"); | ||
1273 | 204 | ParameterizationBuilder builder = new ParameterizationBuilder(builderList); | ||
1274 | 205 | builder.add("alpha", 'a'); | ||
1275 | 206 | builder.addFailing("beta", 'b'); | ||
1276 | 207 | |||
1277 | 208 | NamedParameterizedRunner runner = new NamedParameterizedRunner(OneFailingTest.class); | ||
1278 | 209 | |||
1279 | 210 | Map<String,ReifiedParamRunner> map = testParameterizations(runner, | ||
1280 | 211 | "Parameterization[FAILING beta: [b] ]"); | ||
1281 | 212 | |||
1282 | 213 | testOverrides(map.values(), true); | ||
1283 | 214 | |||
1284 | 215 | testFrameworkMethod(map.get("Parameterization[FAILING beta: [b] ]"), OneFailingTest.class, "passing", true); | ||
1285 | 216 | testFrameworkMethod(map.get("Parameterization[FAILING beta: [b] ]"), OneFailingTest.class, "failing", true); | ||
1286 | 217 | } | ||
1287 | 218 | |||
1288 | 219 | @Test | ||
1289 | 220 | public void testOverrideUsingRegex() throws Throwable | ||
1290 | 221 | { | ||
1291 | 222 | workingProperties.put(NamedParameterizedRunner.PARAMETERIZATION_OVERRIDE, "/a/"); | ||
1292 | 223 | ParameterizationBuilder builder = new ParameterizationBuilder(builderList); | ||
1293 | 224 | builder.add("alpha", 'a'); | ||
1294 | 225 | builder.addFailing("beta", 'b'); | ||
1295 | 226 | |||
1296 | 227 | NamedParameterizedRunner runner = new NamedParameterizedRunner(OneFailingTest.class); | ||
1297 | 228 | |||
1298 | 229 | Map<String,ReifiedParamRunner> map = testParameterizations(runner, | ||
1299 | 230 | "Parameterization[PASSING alpha: [a] ]", | ||
1300 | 231 | "Parameterization[FAILING beta: [b] ]"); | ||
1301 | 232 | |||
1302 | 233 | testOverrides(map.values(), true); | ||
1303 | 234 | |||
1304 | 235 | testFrameworkMethod(map.get("Parameterization[PASSING alpha: [a] ]"), OneFailingTest.class, "passing", true); | ||
1305 | 236 | testFrameworkMethod(map.get("Parameterization[PASSING alpha: [a] ]"), OneFailingTest.class, "failing", true); | ||
1306 | 237 | testFrameworkMethod(map.get("Parameterization[FAILING beta: [b] ]"), OneFailingTest.class, "passing", true); | ||
1307 | 238 | testFrameworkMethod(map.get("Parameterization[FAILING beta: [b] ]"), OneFailingTest.class, "failing", true); | ||
1308 | 239 | } | ||
1309 | 240 | |||
1310 | 241 | @Test | ||
1311 | 242 | public void testOnlyIf() throws Throwable { | ||
1312 | 243 | ParameterizationBuilder builder = new ParameterizationBuilder(builderList); | ||
1313 | 244 | builder.add("one", 1); | ||
1314 | 245 | builder.add("two", 2); | ||
1315 | 246 | |||
1316 | 247 | NamedParameterizedRunner runner = new NamedParameterizedRunner(OnlyIfTest.class); | ||
1317 | 248 | |||
1318 | 249 | Map<String,ReifiedParamRunner> map = testParameterizations(runner, | ||
1319 | 250 | "Parameterization[PASSING one: [1] ]", | ||
1320 | 251 | "Parameterization[PASSING two: [2] ]"); | ||
1321 | 252 | |||
1322 | 253 | { | ||
1323 | 254 | ReifiedParamRunner forOne = map.get("Parameterization[PASSING one: [1] ]"); | ||
1324 | 255 | assertEquals("param one: " + forOne.describeChildren(), 3, forOne.getChildrenCount()); | ||
1325 | 256 | testFrameworkMethod(forOne, OnlyIfTest.class, "testIs1Method", true); | ||
1326 | 257 | testFrameworkMethod(forOne, OnlyIfTest.class, "testIs1Field", true); | ||
1327 | 258 | testFrameworkMethod(forOne, OnlyIfTest.class, "alwaysRun", true); | ||
1328 | 259 | } | ||
1329 | 260 | { | ||
1330 | 261 | ReifiedParamRunner forTwo = map.get("Parameterization[PASSING two: [2] ]"); | ||
1331 | 262 | assertEquals("param two: " + forTwo.describeChildren(), 1, forTwo.getChildrenCount()); | ||
1332 | 263 | testFrameworkMethod(forTwo, OnlyIfTest.class, "alwaysRun", true); | ||
1333 | 264 | } | ||
1334 | 265 | } | ||
1335 | 266 | |||
1336 | 267 | private static void testOverrides(Collection<ReifiedParamRunner> runners, boolean expectedOverride) | ||
1337 | 268 | { | ||
1338 | 269 | for (ReifiedParamRunner runner : runners) | ||
1339 | 270 | { | ||
1340 | 271 | assertEquals(runner.toString(), expectedOverride, runner.overrideOn()); | ||
1341 | 272 | } | ||
1342 | 273 | } | ||
1343 | 274 | |||
1344 | 275 | private static void testFrameworkMethod(ReifiedParamRunner runner, Class<?> testClass, String testMethod, | ||
1345 | 276 | boolean expectedToPass) | ||
1346 | 277 | { | ||
1347 | 278 | String frameworkMethodString = "public void " + testClass.getName() + "." + testMethod + "()"; | ||
1348 | 279 | FrameworkMethod method = runner.getChild(frameworkMethodString); | ||
1349 | 280 | assertNotNull(frameworkMethodString, method); | ||
1350 | 281 | assertEquals(frameworkMethodString, expectedToPass, runner.expectedToPass(method)); | ||
1351 | 282 | } | ||
1352 | 283 | |||
1353 | 284 | /** | ||
1354 | 285 | * Confirms that each given name has a {@linkplain ReifiedParamRunner} associated with it, and returns the | ||
1355 | 286 | * name -> runner map | ||
1356 | 287 | * @param runner the parameterized runner | ||
1357 | 288 | * @param names the expected names | ||
1358 | 289 | * @return a map of names to reified runners | ||
1359 | 290 | */ | ||
1360 | 291 | private static Map<String,ReifiedParamRunner> testParameterizations(NamedParameterizedRunner runner, String... names) | ||
1361 | 292 | { | ||
1362 | 293 | List<Runner> children = runner.getChildren(); | ||
1363 | 294 | assertEquals("children.size()", names.length, children.size()); | ||
1364 | 295 | |||
1365 | 296 | Set<String> expectedNames = new HashSet<String>(names.length, 1.0f); | ||
1366 | 297 | for (String name : names) { | ||
1367 | 298 | assertTrue("unexpected error, duplicate name: " + name, expectedNames.add(name)); | ||
1368 | 299 | } | ||
1369 | 300 | |||
1370 | 301 | Map<String,ReifiedParamRunner> foundRunners = new HashMap<String, ReifiedParamRunner>(); | ||
1371 | 302 | for (Runner child : children) | ||
1372 | 303 | { | ||
1373 | 304 | ReifiedParamRunner reified = (ReifiedParamRunner)child; | ||
1374 | 305 | String paramToString = reified.paramToString(); | ||
1375 | 306 | assertNull("duplicate name: " + paramToString, foundRunners.put(paramToString, reified)); | ||
1376 | 307 | } | ||
1377 | 308 | |||
1378 | 309 | for (String expected : expectedNames) | ||
1379 | 310 | { | ||
1380 | 311 | assertTrue("didn't find expected param: " + expected, foundRunners.containsKey(expected)); | ||
1381 | 312 | } | ||
1382 | 313 | |||
1383 | 314 | return foundRunners; | ||
1384 | 315 | } | ||
1385 | 316 | } | ||
1386 | 0 | 317 | ||
1387 | === added file 'src/test/java/com/motpot/npr/OnlyIfUsageTest.java' | |||
1388 | --- src/test/java/com/motpot/npr/OnlyIfUsageTest.java 1970-01-01 00:00:00 +0000 | |||
1389 | +++ src/test/java/com/motpot/npr/OnlyIfUsageTest.java 2011-09-08 16:01:22 +0000 | |||
1390 | @@ -0,0 +1,68 @@ | |||
1391 | 1 | package com.motpot.npr; | ||
1392 | 2 | |||
1393 | 3 | import org.junit.Test; | ||
1394 | 4 | import org.junit.runner.RunWith; | ||
1395 | 5 | |||
1396 | 6 | import java.util.List; | ||
1397 | 7 | |||
1398 | 8 | import static org.junit.Assert.*; | ||
1399 | 9 | |||
1400 | 10 | @RunWith(NamedParameterizedRunner.class) | ||
1401 | 11 | public final class OnlyIfUsageTest { | ||
1402 | 12 | @NamedParameterizedRunner.TestParameters | ||
1403 | 13 | public static List<Parameterization> params() { | ||
1404 | 14 | ParameterizationBuilder builder = new ParameterizationBuilder(); | ||
1405 | 15 | builder.add("foo", "foo"); | ||
1406 | 16 | builder.add("bar", "bar"); | ||
1407 | 17 | return builder.asList(); | ||
1408 | 18 | } | ||
1409 | 19 | |||
1410 | 20 | private final String string; | ||
1411 | 21 | public final boolean stringIsFoo; | ||
1412 | 22 | |||
1413 | 23 | public OnlyIfUsageTest(String string) { | ||
1414 | 24 | this.string = string; | ||
1415 | 25 | stringIsFoo = "foo".equals(string); | ||
1416 | 26 | } | ||
1417 | 27 | |||
1418 | 28 | @Test @OnlyIf("isFoo()") | ||
1419 | 29 | public void equalsFoo() { | ||
1420 | 30 | assertEquals("string", "foo", string); | ||
1421 | 31 | } | ||
1422 | 32 | |||
1423 | 33 | @Test @OnlyIf("stringIsFoo") | ||
1424 | 34 | public void equalsFooByField() { | ||
1425 | 35 | assertEquals("string", "foo", string); | ||
1426 | 36 | } | ||
1427 | 37 | |||
1428 | 38 | @Test @OnlyIfNot("isFoo()") | ||
1429 | 39 | public void notEqualsFoo() { | ||
1430 | 40 | if ("foo".equals(string)) { | ||
1431 | 41 | fail("found a foo!"); | ||
1432 | 42 | } | ||
1433 | 43 | } | ||
1434 | 44 | |||
1435 | 45 | @Test @OnlyIf("hasThreeChars()") @OnlyIfNot("lastCharR()") | ||
1436 | 46 | public void threeCharNoTrailingR() { | ||
1437 | 47 | assertEquals("string length", 3, string.length()); | ||
1438 | 48 | assertFalse("last char was r! <" + string + '>', string.charAt(2) == 'r'); | ||
1439 | 49 | } | ||
1440 | 50 | |||
1441 | 51 | @Test | ||
1442 | 52 | public void stringNotNull() { | ||
1443 | 53 | assertNotNull("string", string); | ||
1444 | 54 | } | ||
1445 | 55 | |||
1446 | 56 | public boolean isFoo() { | ||
1447 | 57 | return "foo".equals(string); | ||
1448 | 58 | } | ||
1449 | 59 | |||
1450 | 60 | public boolean hasThreeChars() { | ||
1451 | 61 | return string.length() == 3; | ||
1452 | 62 | } | ||
1453 | 63 | |||
1454 | 64 | public boolean lastCharR() { | ||
1455 | 65 | // for simplicity, we'll assume string not null, string.length > 0 | ||
1456 | 66 | return string.charAt( string.length() - 1) == 'r'; | ||
1457 | 67 | } | ||
1458 | 68 | } | ||
1459 | 0 | 69 | ||
1460 | === added file 'src/test/java/com/motpot/npr/ParameterizationBuilderTest.java' | |||
1461 | --- src/test/java/com/motpot/npr/ParameterizationBuilderTest.java 1970-01-01 00:00:00 +0000 | |||
1462 | +++ src/test/java/com/motpot/npr/ParameterizationBuilderTest.java 2011-09-08 16:01:22 +0000 | |||
1463 | @@ -0,0 +1,153 @@ | |||
1464 | 1 | package com.motpot.npr; | ||
1465 | 2 | |||
1466 | 3 | import org.junit.Test; | ||
1467 | 4 | |||
1468 | 5 | import java.util.Arrays; | ||
1469 | 6 | import java.util.List; | ||
1470 | 7 | |||
1471 | 8 | import static junit.framework.Assert.*; | ||
1472 | 9 | |||
1473 | 10 | |||
1474 | 11 | public final class ParameterizationBuilderTest | ||
1475 | 12 | { | ||
1476 | 13 | @Test | ||
1477 | 14 | public void testAdd() | ||
1478 | 15 | { | ||
1479 | 16 | ParameterizationBuilder builder = new ParameterizationBuilder(); | ||
1480 | 17 | builder.add("hello", 1, "someString", 50L); | ||
1481 | 18 | |||
1482 | 19 | List<Parameterization> params = builder.asList(); | ||
1483 | 20 | assertEquals("params size", 1, params.size()); | ||
1484 | 21 | assertEquivalent("only one", | ||
1485 | 22 | Parameterization.create("hello", 1, "someString", 50L), | ||
1486 | 23 | params.get(0)); | ||
1487 | 24 | } | ||
1488 | 25 | |||
1489 | 26 | @Test | ||
1490 | 27 | public void testAddFailing() | ||
1491 | 28 | { | ||
1492 | 29 | ParameterizationBuilder builder = new ParameterizationBuilder(); | ||
1493 | 30 | builder.addFailing("hello", 1, "someString", 50L); | ||
1494 | 31 | |||
1495 | 32 | List<Parameterization> params = builder.asList(); | ||
1496 | 33 | assertEquals("params size", 1, params.size()); | ||
1497 | 34 | assertEquivalent("only one", | ||
1498 | 35 | Parameterization.failing("hello", 1, "someString", 50L), | ||
1499 | 36 | params.get(0)); | ||
1500 | 37 | } | ||
1501 | 38 | |||
1502 | 39 | @Test | ||
1503 | 40 | public void testCreate() | ||
1504 | 41 | { | ||
1505 | 42 | ParameterizationBuilder builder = new ParameterizationBuilder(); | ||
1506 | 43 | builder.create("hello", true, 1, "someString", 50L); | ||
1507 | 44 | builder.create("hi", false, -1, "anotherString", -50L); | ||
1508 | 45 | |||
1509 | 46 | List<Parameterization> params = builder.asList(); | ||
1510 | 47 | assertEquals("params size", 2, params.size()); | ||
1511 | 48 | assertEquivalent("passing", | ||
1512 | 49 | new Parameterization("hello", true, 1, "someString", 50L), | ||
1513 | 50 | params.get(0)); | ||
1514 | 51 | assertEquivalent("failing", | ||
1515 | 52 | new Parameterization("hi", false, -1, "anotherString", -50L), | ||
1516 | 53 | params.get(1)); | ||
1517 | 54 | } | ||
1518 | 55 | |||
1519 | 56 | @Test | ||
1520 | 57 | public void testAppend() | ||
1521 | 58 | { | ||
1522 | 59 | ParameterizationBuilder builder = new ParameterizationBuilder(); | ||
1523 | 60 | builder.add("ONE", 1, 2, 3); | ||
1524 | 61 | builder.addFailing("TWO", 4, 5, 6); | ||
1525 | 62 | builder.multiplyParametersByAppending("-a", 'a', "-b", 'b', "-c", 'c'); | ||
1526 | 63 | |||
1527 | 64 | List<Parameterization> expected = Arrays.asList( | ||
1528 | 65 | Parameterization.create("ONE-a", 1, 2, 3, 'a'), | ||
1529 | 66 | Parameterization.create("ONE-b", 1, 2, 3, 'b'), | ||
1530 | 67 | Parameterization.create("ONE-c", 1, 2, 3, 'c'), | ||
1531 | 68 | Parameterization.failing("TWO-a", 4, 5, 6, 'a'), | ||
1532 | 69 | Parameterization.failing("TWO-b", 4, 5, 6, 'b'), | ||
1533 | 70 | Parameterization.failing("TWO-c", 4, 5, 6, 'c') | ||
1534 | 71 | ); | ||
1535 | 72 | List<Parameterization> actual = builder.asList(); | ||
1536 | 73 | |||
1537 | 74 | assertEquals("params size", expected.size(), actual.size()); | ||
1538 | 75 | |||
1539 | 76 | for(int i=0, len=expected.size(); i<len; ++i) | ||
1540 | 77 | { | ||
1541 | 78 | assertEquivalent("param " + i, expected.get(i), actual.get(i)); | ||
1542 | 79 | } | ||
1543 | 80 | } | ||
1544 | 81 | |||
1545 | 82 | @Test | ||
1546 | 83 | public void testPrepend() | ||
1547 | 84 | { | ||
1548 | 85 | ParameterizationBuilder builder = new ParameterizationBuilder(); | ||
1549 | 86 | builder.add("ONE", 1, 2, 3); | ||
1550 | 87 | builder.addFailing("TWO", 4, 5, 6); | ||
1551 | 88 | builder.multiplyParametersByPrepending("a:", 'a', "b:", 'b', "c:", 'c'); | ||
1552 | 89 | |||
1553 | 90 | List<Parameterization> expected = Arrays.asList( | ||
1554 | 91 | Parameterization.create("a:ONE", 'a', 1, 2, 3), | ||
1555 | 92 | Parameterization.create("b:ONE", 'b', 1, 2, 3), | ||
1556 | 93 | Parameterization.create("c:ONE", 'c', 1, 2, 3), | ||
1557 | 94 | Parameterization.failing("a:TWO", 'a', 4, 5, 6), | ||
1558 | 95 | Parameterization.failing("b:TWO", 'b', 4, 5, 6), | ||
1559 | 96 | Parameterization.failing("c:TWO", 'c', 4, 5, 6) | ||
1560 | 97 | ); | ||
1561 | 98 | List<Parameterization> actual = builder.asList(); | ||
1562 | 99 | |||
1563 | 100 | assertEquals("params size", expected.size(), actual.size()); | ||
1564 | 101 | |||
1565 | 102 | for(int i=0, len=expected.size(); i<len; ++i) | ||
1566 | 103 | { | ||
1567 | 104 | assertEquivalent("param " + i, expected.get(i), actual.get(i)); | ||
1568 | 105 | } | ||
1569 | 106 | } | ||
1570 | 107 | |||
1571 | 108 | @Test | ||
1572 | 109 | public void testListBackedByBuilder() | ||
1573 | 110 | { | ||
1574 | 111 | ParameterizationBuilder builder = new ParameterizationBuilder(); | ||
1575 | 112 | List<Parameterization> list = builder.asList(); | ||
1576 | 113 | |||
1577 | 114 | assertEquals("list size before building", 0, list.size()); | ||
1578 | 115 | |||
1579 | 116 | builder.add("whatever", 'a'); | ||
1580 | 117 | assertEquals("list size after building", 1, list.size()); | ||
1581 | 118 | |||
1582 | 119 | assertSame("new list", builder.asList(), list); | ||
1583 | 120 | } | ||
1584 | 121 | |||
1585 | 122 | @Test(expected=IllegalArgumentException.class) | ||
1586 | 123 | public void builderMultiplierArgsNotPaired() | ||
1587 | 124 | { | ||
1588 | 125 | ParameterizationBuilder builder = new ParameterizationBuilder(); | ||
1589 | 126 | builder.add("whatever", 1); | ||
1590 | 127 | |||
1591 | 128 | builder.multiplyParametersByAppending("label", 2, 3); | ||
1592 | 129 | } | ||
1593 | 130 | |||
1594 | 131 | @Test(expected=IllegalArgumentException.class) | ||
1595 | 132 | public void builderMultiplierArgsLabelNotString() | ||
1596 | 133 | { | ||
1597 | 134 | ParameterizationBuilder builder = new ParameterizationBuilder(); | ||
1598 | 135 | builder.add("whatever", 1); | ||
1599 | 136 | |||
1600 | 137 | builder.multiplyParametersByAppending("label", 2, 3, "this label is in the wrong place"); | ||
1601 | 138 | } | ||
1602 | 139 | |||
1603 | 140 | @Test(expected=IllegalStateException.class) | ||
1604 | 141 | public void builderMultipliesByZero() | ||
1605 | 142 | { | ||
1606 | 143 | new ParameterizationBuilder().multiplyParametersByAppending(); | ||
1607 | 144 | } | ||
1608 | 145 | |||
1609 | 146 | private static void assertEquivalent(String message, Parameterization expected, Parameterization actual) | ||
1610 | 147 | { | ||
1611 | 148 | if (!expected.equivalent(actual)) | ||
1612 | 149 | { | ||
1613 | 150 | fail(message + " expected<" + expected + "> but was <" + actual + ">"); | ||
1614 | 151 | } | ||
1615 | 152 | } | ||
1616 | 153 | } |