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.Collection;
25 import java.util.Collections;
26 import java.util.HashSet;
27 import java.util.List;
28 import java.util.Properties;
29 import java.util.Set;
30
31 import org.apache.maven.shared.utils.io.SelectorUtils;
32 import org.apache.maven.surefire.booter.ProviderParameterNames;
33 import org.apache.maven.surefire.group.match.AndGroupMatcher;
34 import org.apache.maven.surefire.group.match.GroupMatcher;
35 import org.apache.maven.surefire.group.match.InverseGroupMatcher;
36 import org.apache.maven.surefire.group.parse.GroupMatcherParser;
37 import org.apache.maven.surefire.group.parse.ParseException;
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 if ( included != null && testClassLoader != null )
88 {
89 included.loadGroupClasses( testClassLoader );
90 }
91
92 if ( excluded != null && testClassLoader != null )
93 {
94 excluded.loadGroupClasses( testClassLoader );
95 }
96
97 return new GroupMatcherCategoryFilter( included, excluded );
98 }
99
100 public Filter createMethodFilter( String requestedTestMethod )
101 {
102 return new MethodFilter( requestedTestMethod );
103 }
104
105 public Filter and( Filter filter1, Filter filter2 )
106 {
107 return new AndFilter( filter1, filter2 );
108 }
109
110 private static class MethodFilter
111 extends Filter
112 {
113 private final String requestedTestMethod;
114
115 public MethodFilter( String requestedTestMethod )
116 {
117 this.requestedTestMethod = requestedTestMethod;
118 }
119
120 @Override
121 public boolean shouldRun( Description description )
122 {
123 for ( Description o : description.getChildren() )
124 {
125 if ( isDescriptionMatch( o ) )
126 {
127 return true;
128 }
129
130 }
131 return isDescriptionMatch( description );
132 }
133
134 private boolean isDescriptionMatch( Description description )
135 {
136 return description.getMethodName() != null
137 && SelectorUtils.match( requestedTestMethod, description.getMethodName() );
138 }
139
140 @Override
141 public String describe()
142 {
143 return "By method" + requestedTestMethod;
144 }
145 }
146
147 private static class GroupMatcherCategoryFilter
148 extends Filter
149 {
150
151 private AndGroupMatcher matcher;
152
153 public GroupMatcherCategoryFilter( GroupMatcher included, GroupMatcher excluded )
154 {
155 GroupMatcher invertedExclude = excluded == null ? null : new InverseGroupMatcher( excluded );
156 if ( included != null || invertedExclude != null )
157 {
158 matcher = new AndGroupMatcher();
159 if ( included != null )
160 {
161 matcher.addMatcher( included );
162 }
163
164 if ( invertedExclude != null )
165 {
166 matcher.addMatcher( invertedExclude );
167 }
168 }
169 }
170
171 @Override
172 public boolean shouldRun( Description description )
173 {
174 if ( description.getMethodName() == null || description.getTestClass() == null )
175 {
176 return shouldRun( description, null, null );
177 }
178 else
179 {
180 return shouldRun( description, Description.createSuiteDescription( description.getTestClass() ),
181 description.getTestClass() );
182 }
183 }
184
185 private Collection<Class<?>> findSuperclassCategories( Class<?> clazz )
186 {
187 if ( clazz != null && clazz.getSuperclass() != null )
188 {
189 Category cat = clazz.getSuperclass().getAnnotation( Category.class );
190 if ( cat != null )
191 {
192 return new HashSet<Class<?>>( Arrays.asList( cat.value() ) );
193 }
194 else
195 {
196 return findSuperclassCategories( clazz.getSuperclass() );
197 }
198 }
199
200 return Collections.emptySet();
201 }
202
203 private boolean shouldRun( Description description, Description parent, Class<?> parentClass )
204 {
205 if ( matcher == null )
206 {
207 return true;
208 }
209
210 Set<Class<?>> cats = new HashSet<Class<?>>();
211 Category cat = description.getAnnotation( Category.class );
212 if ( cat != null )
213 {
214 cats.addAll( Arrays.asList( cat.value() ) );
215 }
216
217 if ( parent != null )
218 {
219 cat = parent.getAnnotation( Category.class );
220 if ( cat != null )
221 {
222 cats.addAll( Arrays.asList( cat.value() ) );
223 }
224 }
225
226 if ( parentClass != null )
227 {
228 cats.addAll( findSuperclassCategories( parentClass ) );
229 }
230
231 boolean result = matcher.enabled( cats.toArray( new Class<?>[] {} ) );
232
233 if ( parent == null )
234 {
235 if ( cats.size() == 0 )
236 {
237 result = true;
238 }
239 else if ( !result )
240 {
241 ArrayList<Description> children = description.getChildren();
242 if ( children != null )
243 {
244 for ( Description child : children )
245 {
246 if ( shouldRun( child, description, null ) )
247 {
248 result = true;
249 break;
250 }
251 }
252 }
253 }
254 }
255
256 return result;
257 }
258
259 @Override
260 public String describe()
261 {
262 return matcher == null ? "ANY" : matcher.toString();
263 }
264
265 }
266
267 private static class AndFilter
268 extends Filter
269 {
270 private final Filter filter1;
271
272 private final Filter filter2;
273
274 public AndFilter( Filter filter1, Filter filter2 )
275 {
276 this.filter1 = filter1;
277 this.filter2 = filter2;
278 }
279
280 @Override
281 public boolean shouldRun( Description description )
282 {
283 return filter1.shouldRun( description ) && filter2.shouldRun( description );
284 }
285
286 @Override
287 public String describe()
288 {
289 return filter1.describe() + " AND " + filter2.describe();
290 }
291 }
292
293 @SuppressWarnings( "unused" )
294 private static class CombinedCategoryFilter
295 extends Filter
296 {
297 private final List<Filter> includedFilters;
298
299 private final List<Filter> excludedFilters;
300
301 public CombinedCategoryFilter( List<Filter> includedFilters, List<Filter> excludedFilters )
302 {
303 this.includedFilters = includedFilters;
304 this.excludedFilters = excludedFilters;
305 }
306
307 @Override
308 public boolean shouldRun( Description description )
309 {
310 return ( includedFilters.isEmpty() || inOneOfFilters( includedFilters, description ) )
311 && ( excludedFilters.isEmpty() || !inOneOfFilters( excludedFilters, description ) );
312 }
313
314 private boolean inOneOfFilters( List<Filter> filters, Description description )
315 {
316 for ( Filter f : filters )
317 {
318 if ( f.shouldRun( description ) )
319 {
320 return true;
321 }
322 }
323 return false;
324 }
325
326 @Override
327 public String describe()
328 {
329 StringBuilder sb = new StringBuilder();
330 if ( !includedFilters.isEmpty() )
331 {
332 sb.append( "(" );
333 sb.append( joinFilters( includedFilters, " OR " ) );
334 sb.append( ")" );
335 if ( !excludedFilters.isEmpty() )
336 {
337 sb.append( " AND " );
338 }
339 }
340 if ( !excludedFilters.isEmpty() )
341 {
342 sb.append( "NOT (" );
343 sb.append( joinFilters( includedFilters, " OR " ) );
344 sb.append( ")" );
345 }
346
347 return sb.toString();
348 }
349
350 private String joinFilters( List<Filter> filters, String sep )
351 {
352 int i = 0;
353 StringBuilder sb = new StringBuilder();
354 for ( Filter f : filters )
355 {
356 if ( i++ > 0 )
357 {
358 sb.append( sep );
359 }
360 sb.append( f.describe() );
361 }
362 return sb.toString();
363 }
364 }
365
366 }