View Javadoc
1   package org.apache.maven.surefire.common.junit4;
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 java.util.Collection;
23  import java.util.HashMap;
24  import java.util.HashSet;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Set;
28  
29  import org.apache.maven.surefire.testset.TestSetFailedException;
30  import org.apache.maven.surefire.util.internal.StringUtils;
31  
32  import org.junit.runner.Description;
33  import org.junit.runner.notification.Failure;
34  
35  /**
36   *
37   * Utility method used among all JUnit4 providers
38   *
39   * @author Qingzhou Luo
40   *
41   */
42  public final class JUnit4ProviderUtil
43  {
44  
45      private JUnit4ProviderUtil()
46      {
47          throw new IllegalStateException( "Cannot instantiate." );
48      }
49  
50      /**
51       * Organize all the failures in previous run into a map between test classes and corresponding failing test methods
52       *
53       * @param allFailures all the failures in previous run
54       * @param testClassLoader ClassLoader used for test classes
55       * @return a map between failing test classes and their corresponding failing test methods
56       */
57      public static Map<Class<?>, Set<String>> generateFailingTests( List<Failure> allFailures,
58                                                                     ClassLoader testClassLoader )
59          throws TestSetFailedException
60      {
61          Map<Class<?>, Set<String>> testClassMethods = new HashMap<Class<?>, Set<String>>();
62          Set<ClassMethod> failingTests = generateFailingTests( allFailures );
63          for ( ClassMethod classMethod: failingTests )
64          {
65              try
66              {
67                  Class testClassObj = Class.forName( classMethod.getClazz(), false, testClassLoader );
68                  Set<String> failingMethods = testClassMethods.get( testClassObj );
69                  if ( failingMethods == null )
70                  {
71                      failingMethods = new HashSet<String>();
72                      testClassMethods.put( testClassObj, failingMethods );
73                  }
74                  failingMethods.add( classMethod.getMethod() );
75              }
76              catch ( ClassNotFoundException e )
77              {
78                  throw new TestSetFailedException( "Unable to create test class '" + classMethod.getClazz() + "'", e );
79              }
80          }
81          return testClassMethods;
82      }
83  
84      /**
85       * Get all test methods from a list of Failures
86       *
87       * @param allFailures the list of failures for a given test class
88       * @return the list of test methods
89       */
90      public static Set<ClassMethod> generateFailingTests( List<Failure> allFailures )
91      {
92          Set<ClassMethod> failingMethods = new HashSet<ClassMethod>();
93  
94          for ( Failure failure : allFailures )
95          {
96              Description description = failure.getDescription();
97              if ( description.isTest() && !isFailureInsideJUnitItself( description ) )
98              {
99                  ClassMethod classMethod = cutTestClassAndMethod( description );
100                 if ( classMethod.isValid() )
101                 {
102                     failingMethods.add( classMethod );
103                 }
104             }
105         }
106         return failingMethods;
107     }
108 
109     public static Description createSuiteDescription( Collection<Class<?>> classes )
110     {
111         return JUnit4Reflector.createRequest( classes.toArray( new Class[classes.size()] ) )
112                 .getRunner()
113                 .getDescription();
114     }
115 
116     public static boolean isFailureInsideJUnitItself( Description failure )
117     {
118         return Description.TEST_MECHANISM.equals( failure );
119     }
120 
121     /**
122      * Java Patterns of regex is slower than cutting a substring.
123      * @param description method(class) or method[#](class) or method[#whatever-literals](class)
124      * @return method JUnit test method
125      */
126     public static ClassMethod cutTestClassAndMethod( Description description )
127     {
128         String name = description.getDisplayName();
129         String clazz = null;
130         String method = null;
131         if ( name != null )
132         {
133             // The order is : 1.method and then 2.class
134             // method(class)
135             name = name.trim();
136             if ( name.endsWith( ")" ) )
137             {
138                 int classBracket = name.lastIndexOf( '(' );
139                 if ( classBracket != -1 )
140                 {
141                     clazz = tryBlank( name.substring( classBracket + 1, name.length() - 1 ) );
142                     method = tryBlank( name.substring( 0, classBracket ) );
143                 }
144             }
145         }
146         return new ClassMethod( clazz, method );
147     }
148 
149     private static String tryBlank( String s )
150     {
151         s = s.trim();
152         return StringUtils.isBlank( s ) ? null : s;
153     }
154 
155 }