1 package org.apache.maven.surefire.common.junit48;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Properties;
29 import java.util.Set;
30 import org.apache.maven.shared.utils.io.SelectorUtils;
31 import org.apache.maven.surefire.booter.ProviderParameterNames;
32 import org.apache.maven.surefire.group.match.AndGroupMatcher;
33 import org.apache.maven.surefire.group.match.GroupMatcher;
34 import org.apache.maven.surefire.group.match.InverseGroupMatcher;
35 import org.apache.maven.surefire.group.parse.GroupMatcherParser;
36 import org.apache.maven.surefire.group.parse.ParseException;
37
38 import org.junit.experimental.categories.Category;
39 import org.junit.runner.Description;
40 import org.junit.runner.manipulation.Filter;
41
42
43
44
45 public class FilterFactory
46 {
47 private final ClassLoader testClassLoader;
48
49 public FilterFactory( ClassLoader testClassLoader )
50 {
51 this.testClassLoader = testClassLoader;
52 }
53
54 public Filter createGroupFilter( Properties providerProperties )
55 {
56 String groups = providerProperties.getProperty( ProviderParameterNames.TESTNG_GROUPS_PROP );
57 String excludedGroups = providerProperties.getProperty( ProviderParameterNames.TESTNG_EXCLUDEDGROUPS_PROP );
58
59 GroupMatcher included = null;
60 if ( groups != null && groups.trim().length() > 0 )
61 {
62 try
63 {
64 included = new GroupMatcherParser( groups ).parse();
65 }
66 catch ( ParseException e )
67 {
68 throw new IllegalArgumentException( "Invalid group expression: '" + groups + "'. Reason: "
69 + e.getMessage(), e );
70 }
71 }
72
73 GroupMatcher excluded = null;
74 if ( excludedGroups != null && excludedGroups.trim().length() > 0 )
75 {
76 try
77 {
78 excluded = new GroupMatcherParser( excludedGroups ).parse();
79 }
80 catch ( ParseException e )
81 {
82 throw new IllegalArgumentException( "Invalid group expression: '" + excludedGroups + "'. Reason: "
83 + e.getMessage(), e );
84 }
85 }
86
87
88
89
90
91 if ( included != null && testClassLoader != null )
92 {
93 included.loadGroupClasses( testClassLoader );
94 }
95
96 if ( excluded != null && testClassLoader != null )
97 {
98 excluded.loadGroupClasses( testClassLoader );
99 }
100
101 return new GroupMatcherCategoryFilter( included, excluded );
102 }
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137 public Filter createMethodFilter( String requestedTestMethod )
138 {
139 return new MethodFilter( requestedTestMethod );
140 }
141
142 public Filter and( Filter filter1, Filter filter2 )
143 {
144 return new AndFilter( filter1, filter2 );
145 }
146
147 private static class MethodFilter
148 extends Filter
149 {
150 private final String requestedTestMethod;
151
152 public MethodFilter( String requestedTestMethod )
153 {
154 this.requestedTestMethod = requestedTestMethod;
155 }
156
157 @Override
158 public boolean shouldRun( Description description )
159 {
160 for ( Description o : description.getChildren() )
161 {
162 if ( isDescriptionMatch( o ) )
163 {
164 return true;
165 }
166
167 }
168 return isDescriptionMatch( description );
169 }
170
171 private boolean isDescriptionMatch( Description description )
172 {
173 return description.getMethodName() != null
174 && SelectorUtils.match( requestedTestMethod, description.getMethodName() );
175 }
176
177 @Override
178 public String describe()
179 {
180 return "By method" + requestedTestMethod;
181 }
182 }
183
184 private static class GroupMatcherCategoryFilter
185 extends Filter
186 {
187
188 private AndGroupMatcher matcher;
189
190 private Map<Description, Boolean> shouldRunAnswers = new HashMap<Description, Boolean>();
191
192 public GroupMatcherCategoryFilter( GroupMatcher included, GroupMatcher excluded )
193 {
194 GroupMatcher invertedExclude = excluded == null ? null : new InverseGroupMatcher( excluded );
195 if ( included != null || invertedExclude != null )
196 {
197 matcher = new AndGroupMatcher();
198 if ( included != null )
199 {
200 matcher.addMatcher( included );
201 }
202
203 if ( invertedExclude != null )
204 {
205 matcher.addMatcher( invertedExclude );
206 }
207 }
208 }
209
210 @Override
211 public boolean shouldRun( Description description )
212 {
213 return shouldRun( description,
214 ( description.getMethodName() == null ? null
215 : Description.createSuiteDescription( description.getTestClass() ) ) );
216 }
217
218 private boolean shouldRun( Description description, Description parent )
219 {
220 Boolean result = shouldRunAnswers.get( description );
221 if ( result != null )
222 {
223 return result;
224 }
225
226 if ( matcher == null )
227 {
228 return true;
229 }
230
231
232
233
234
235 Set<Class<?>> cats = new HashSet<Class<?>>();
236 Category cat = description.getAnnotation( Category.class );
237 if ( cat != null )
238 {
239
240
241 cats.addAll( Arrays.asList( cat.value() ) );
242 }
243
244 if ( parent != null )
245 {
246 cat = parent.getAnnotation( Category.class );
247 if ( cat != null )
248 {
249
250
251 cats.addAll( Arrays.asList( cat.value() ) );
252 }
253 }
254
255
256
257
258
259
260 result = matcher.enabled( cats.toArray( new Class<?>[] {} ) );
261
262 if ( parent == null )
263 {
264 if ( cats.size() == 0 )
265 {
266
267
268
269 result = true;
270 }
271 else if ( !result )
272 {
273 ArrayList<Description> children = description.getChildren();
274 if ( children != null )
275 {
276 for ( Description child : children )
277 {
278 if ( shouldRun( child, description ) )
279 {
280 result = true;
281 break;
282 }
283 }
284 }
285 }
286 }
287
288 shouldRunAnswers.put( description, result );
289 return result == null ? false : result;
290 }
291
292 @Override
293 public String describe()
294 {
295 return matcher == null ? "ANY" : matcher.toString();
296 }
297
298 }
299
300 private static class AndFilter
301 extends Filter
302 {
303 private final Filter filter1;
304
305 private final Filter filter2;
306
307 public AndFilter( Filter filter1, Filter filter2 )
308 {
309 this.filter1 = filter1;
310 this.filter2 = filter2;
311 }
312
313 @Override
314 public boolean shouldRun( Description description )
315 {
316 return filter1.shouldRun( description ) && filter2.shouldRun( description );
317 }
318
319 @Override
320 public String describe()
321 {
322 return filter1.describe() + " AND " + filter2.describe();
323 }
324 }
325
326 @SuppressWarnings( "unused" )
327 private static class CombinedCategoryFilter
328 extends Filter
329 {
330 private final List<Filter> includedFilters;
331
332 private final List<Filter> excludedFilters;
333
334 public CombinedCategoryFilter( List<Filter> includedFilters, List<Filter> excludedFilters )
335 {
336 this.includedFilters = includedFilters;
337 this.excludedFilters = excludedFilters;
338 }
339
340 @Override
341 public boolean shouldRun( Description description )
342 {
343 return ( includedFilters.isEmpty() || inOneOfFilters( includedFilters, description ) )
344 && ( excludedFilters.isEmpty() || !inOneOfFilters( excludedFilters, description ) );
345 }
346
347 private boolean inOneOfFilters( List<Filter> filters, Description description )
348 {
349 for ( Filter f : filters )
350 {
351 if ( f.shouldRun( description ) )
352 {
353 return true;
354 }
355 }
356 return false;
357 }
358
359 @Override
360 public String describe()
361 {
362 StringBuilder sb = new StringBuilder();
363 if ( !includedFilters.isEmpty() )
364 {
365 sb.append( "(" );
366 sb.append( joinFilters( includedFilters, " OR " ) );
367 sb.append( ")" );
368 if ( !excludedFilters.isEmpty() )
369 {
370 sb.append( " AND " );
371 }
372 }
373 if ( !excludedFilters.isEmpty() )
374 {
375 sb.append( "NOT (" );
376 sb.append( joinFilters( includedFilters, " OR " ) );
377 sb.append( ")" );
378 }
379
380 return sb.toString();
381 }
382
383 private String joinFilters( List<Filter> filters, String sep )
384 {
385 int i = 0;
386 StringBuilder sb = new StringBuilder();
387 for ( Filter f : filters )
388 {
389 if ( i++ > 0 )
390 {
391 sb.append( sep );
392 }
393 sb.append( f.describe() );
394 }
395 return sb.toString();
396 }
397 }
398
399 }