View Javadoc
1   package org.apache.maven.surefire.common.junit48;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.surefire.group.match.AndGroupMatcher;
23  import org.apache.maven.surefire.group.match.GroupMatcher;
24  import org.apache.maven.surefire.group.match.InverseGroupMatcher;
25  import org.junit.experimental.categories.Category;
26  import org.junit.runner.Description;
27  import org.junit.runner.manipulation.Filter;
28  
29  import java.lang.annotation.Inherited;
30  import java.util.ArrayList;
31  import java.util.HashSet;
32  import java.util.Set;
33  
34  import static java.util.Collections.addAll;
35  import static org.junit.runner.Description.createSuiteDescription;
36  
37  final class GroupMatcherCategoryFilter extends Filter
38  {
39      /**
40       * Only traverse the tree if <code>@Category</code> annotation is inherited (since <code>junit 4.12</code>).
41       */
42      private static final boolean IS_CATEGORY_INHERITED = Category.class.isAnnotationPresent( Inherited.class );
43  
44      private final AndGroupMatcher matcher;
45  
46      GroupMatcherCategoryFilter( GroupMatcher included, GroupMatcher excluded )
47      {
48          GroupMatcher invertedExclude = excluded == null ? null : new InverseGroupMatcher( excluded );
49          if ( included != null || invertedExclude != null )
50          {
51              matcher = new AndGroupMatcher();
52              if ( included != null )
53              {
54                  matcher.addMatcher( included );
55              }
56  
57              if ( invertedExclude != null )
58              {
59                  matcher.addMatcher( invertedExclude );
60              }
61          }
62          else
63          {
64              matcher = null;
65          }
66      }
67  
68      @Override
69      public boolean shouldRun( Description description )
70      {
71          if ( invalidTestClass( description ) )
72          {
73              return shouldRun( description, null, null );
74          }
75  
76          if ( describesTestClass( description ) ) // is a test class
77          {
78              Class<?> testClass = description.getTestClass();
79              return shouldRun( description, null, testClass );
80          }
81          else
82          // is a test method
83          {
84              Class<?> testClass = description.getTestClass();
85              return shouldRun( description, createSuiteDescription( testClass ), testClass );
86          }
87      }
88  
89      private boolean describesTestClass( Description description )
90      {
91          String methodName = description.getMethodName();
92          // Description parser in Junit 4.8 can return "null" String.
93          return methodName == null || methodName.equals( "null" );
94      }
95  
96      private boolean invalidTestClass( Description description )
97      {
98          return description.getTestClass() == null;
99      }
100 
101     private static void findSuperclassCategories( Set<Class<?>> cats, Class<?> clazz )
102     {
103         if ( IS_CATEGORY_INHERITED && hasSuperclass( clazz ) )
104         {
105             Category cat = clazz.getSuperclass().getAnnotation( Category.class );
106             if ( cat != null )
107             {
108                 // Found categories in current superclass
109                 addAll( cats, cat.value() );
110             }
111             // Search the hierarchy
112             findSuperclassCategories( cats, clazz.getSuperclass() );
113         }
114     }
115 
116     private static boolean hasSuperclass( Class<?> clazz )
117     {
118         return clazz != null && clazz.getSuperclass() != null;
119     }
120 
121     private boolean shouldRun( Description description, Description parent, Class<?> parentClass )
122     {
123         if ( matcher == null )
124         {
125             return true;
126         }
127         else
128         {
129             Set<Class<?>> cats = new HashSet<>();
130             Category cat = description.getAnnotation( Category.class );
131             if ( cat != null )
132             {
133                 // Found categories in current description
134                 addAll( cats, cat.value() );
135             }
136 
137             if ( parent != null )
138             {
139                 cat = parent.getAnnotation( Category.class );
140                 if ( cat != null )
141                 {
142                     // Found categories in current parent
143                     addAll( cats, cat.value() );
144                 }
145             }
146             if ( parentClass != null )
147             {
148                 findSuperclassCategories( cats, parentClass );
149             }
150 
151             Class<?> testClass = description.getTestClass();
152             if ( testClass != null )
153             {
154                 cat = testClass.getAnnotation( Category.class );
155                 if ( cat != null )
156                 {
157                     // Found categories in current testClass
158                     addAll( cats, cat.value() );
159                 }
160             }
161 
162             cats.remove( null );
163             boolean result = matcher.enabled( cats.toArray( new Class<?>[cats.size()] ) );
164 
165             if ( !result )
166             {
167                 ArrayList<Description> children = description.getChildren();
168                 if ( children != null )
169                 {
170                     for ( Description child : children )
171                     {
172                         if ( shouldRun( child, description, null ) )
173                         {
174                             result = true;
175                             break;
176                         }
177                     }
178                 }
179             }
180 
181             return result;
182         }
183     }
184 
185     @Override
186     public String describe()
187     {
188         return matcher == null ? "ANY" : matcher.toString();
189     }
190 }