2121import java .io .IOException ;
2222import java .io .StringReader ;
2323import java .io .UncheckedIOException ;
24+ import java .lang .annotation .Annotation ;
25+ import java .lang .reflect .Method ;
2426import java .util .ArrayList ;
27+ import java .util .Collections ;
2528import java .util .HashMap ;
2629import java .util .LinkedHashSet ;
2730import java .util .List ;
3134import java .util .concurrent .atomic .AtomicBoolean ;
3235import java .util .concurrent .atomic .AtomicInteger ;
3336import java .util .logging .Logger ;
37+ import java .util .stream .Collectors ;
3438
3539import org .apache .maven .plugin .surefire .log .api .ConsoleLogger ;
3640import org .apache .maven .surefire .api .provider .AbstractProvider ;
4852import org .apache .maven .surefire .shared .utils .StringUtils ;
4953import org .junit .platform .engine .DiscoverySelector ;
5054import org .junit .platform .engine .Filter ;
55+ import org .junit .platform .engine .FilterResult ;
56+ import org .junit .platform .engine .support .descriptor .ClassSource ;
57+ import org .junit .platform .engine .support .descriptor .MethodSource ;
5158import org .junit .platform .launcher .EngineFilter ;
5259import org .junit .platform .launcher .LauncherDiscoveryRequest ;
60+ import org .junit .platform .launcher .PostDiscoveryFilter ;
5361import org .junit .platform .launcher .TagFilter ;
5462import org .junit .platform .launcher .TestExecutionListener ;
5563import org .junit .platform .launcher .TestIdentifier ;
6270import static java .util .stream .Collectors .toList ;
6371import static org .apache .maven .surefire .api .booter .ProviderParameterNames .EXCLUDE_JUNIT5_ENGINES_PROP ;
6472import static org .apache .maven .surefire .api .booter .ProviderParameterNames .INCLUDE_JUNIT5_ENGINES_PROP ;
73+ import static org .apache .maven .surefire .api .booter .ProviderParameterNames .JUNIT_VINTAGE_DETECTED ;
6574import static org .apache .maven .surefire .api .booter .ProviderParameterNames .TESTNG_EXCLUDEDGROUPS_PROP ;
6675import static org .apache .maven .surefire .api .booter .ProviderParameterNames .TESTNG_GROUPS_PROP ;
6776import static org .apache .maven .surefire .api .report .ConsoleOutputCapture .startCapture ;
@@ -228,11 +237,20 @@ private LauncherDiscoveryRequestBuilder newRequest() {
228237 private Filter <?>[] newFilters () {
229238 List <Filter <?>> filters = new ArrayList <>();
230239
231- getPropertiesList (TESTNG_GROUPS_PROP ).map (TagFilter ::includeTags ).ifPresent (filters ::add );
240+ if (!Boolean .parseBoolean (parameters .getProviderProperties ().get (JUNIT_VINTAGE_DETECTED ))) {
241+ getPropertiesList (TESTNG_GROUPS_PROP ).map (TagFilter ::includeTags ).ifPresent (filters ::add );
232242
233- getPropertiesList (TESTNG_EXCLUDEDGROUPS_PROP )
234- .map (TagFilter ::excludeTags )
235- .ifPresent (filters ::add );
243+ getPropertiesList (TESTNG_EXCLUDEDGROUPS_PROP )
244+ .map (TagFilter ::excludeTags )
245+ .ifPresent (filters ::add );
246+ } else {
247+ Optional <Class <?>> categoryClass = getCategoryClass ();
248+ if (categoryClass .isPresent ()) {
249+ getPropertiesList (TESTNG_GROUPS_PROP )
250+ .map (strings -> getIncludeCategoryFilter (strings , categoryClass ))
251+ .ifPresent (filters ::add );
252+ }
253+ }
236254
237255 of (optionallyWildcardFilter (parameters .getTestRequest ().getTestListResolver ()))
238256 .filter (f -> !f .isEmpty ())
@@ -255,6 +273,87 @@ Filter<?>[] getFilters() {
255273 return filters ;
256274 }
257275
276+ PostDiscoveryFilter getIncludeCategoryFilter (List <String > categories , Optional <Class <?>> categoryClass ) {
277+
278+ return testDescriptor -> {
279+ Optional <MethodSource > methodSource = testDescriptor
280+ .getSource ()
281+ .filter (testSource -> testSource instanceof MethodSource )
282+ .map (testSource -> (MethodSource ) testSource );
283+ boolean hasCategoryClass = false , hasCategoryMethod = false ;
284+ if (methodSource .isPresent ()) {
285+ if (categoryClass .isPresent ()) {
286+ hasCategoryClass = hasCategoryAnnotation (
287+ methodSource .get ().getJavaMethod (), categoryClass .orElse (null ), categories );
288+ }
289+ }
290+
291+ Optional <ClassSource > classSource = testDescriptor
292+ .getSource ()
293+ .filter (testSource -> testSource instanceof ClassSource )
294+ .map (testSource -> (ClassSource ) testSource );
295+ if (classSource .isPresent ()) {
296+ if (categoryClass .isPresent ()) {
297+ hasCategoryMethod = hasCategoryAnnotation (
298+ getClass (classSource .get ().getClassName ()).get (), categoryClass .orElse (null ), categories );
299+ }
300+ }
301+
302+ return hasCategoryClass || hasCategoryMethod
303+ ? FilterResult .included ("Category found" )
304+ : FilterResult .excluded ("Does not have category annotation" );
305+ };
306+ }
307+
308+ private boolean hasCategoryAnnotation (Class <?> clazz , Class <?> categoryClass , List <String > categories ) {
309+ Optional <Annotation > anno = stream (clazz .getAnnotations ())
310+ .filter (annotation -> annotation .annotationType ().equals (categoryClass ))
311+ .findFirst ();
312+ if (anno .isPresent ()) {
313+ List <String > catValue = getCategoryValue (of (anno .get ()));
314+ return catValue .stream ().anyMatch (categories ::contains );
315+ }
316+ return false ;
317+ }
318+
319+ private boolean hasCategoryAnnotation (Method method , Class <?> categoryClass , List <String > categories ) {
320+ Optional <Annotation > anno = stream (method .getAnnotations ())
321+ .filter (annotation -> annotation .annotationType ().equals (categoryClass ))
322+ .findFirst ();
323+ if (anno .isPresent ()) {
324+ List <String > catValue = getCategoryValue (of (anno .get ()));
325+ return catValue .stream ().anyMatch (categories ::contains );
326+ }
327+ return false ;
328+ }
329+
330+ private Optional <Class <?>> getCategoryClass () {
331+ return getClass ("org.junit.experimental.categories.Category" );
332+ }
333+
334+ private Optional <Class <?>> getClass (String className ) {
335+ Thread currentThread = Thread .currentThread ();
336+ try {
337+ return Optional .of (currentThread .getContextClassLoader ().loadClass (className ));
338+ } catch (Exception e ) {
339+ return Optional .empty ();
340+ }
341+ }
342+
343+ private List <String > getCategoryValue (Optional <Object > instance ) {
344+ Optional <Class <?>> optionalClass = getCategoryClass ();
345+ if (optionalClass .isPresent ()) {
346+ try {
347+ Class <?>[] classes =
348+ (Class <?>[]) optionalClass .get ().getMethod ("value" ).invoke (instance .get ());
349+ return stream (classes ).map (Class ::getName ).collect (Collectors .toList ());
350+ } catch (Exception e ) {
351+ // ignore
352+ }
353+ }
354+ return Collections .emptyList ();
355+ }
356+
258357 private Map <String , String > newConfigurationParameters () {
259358 String content = parameters .getProviderProperties ().get (CONFIGURATION_PARAMETERS );
260359 if (content == null ) {
0 commit comments