View Javadoc
1   package org.apache.maven.plugins.surefire.report;
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.io.File;
23  import java.io.IOException;
24  import java.text.NumberFormat;
25  import java.util.ArrayList;
26  import java.util.Collection;
27  import java.util.Collections;
28  import java.util.HashMap;
29  import java.util.List;
30  import java.util.Locale;
31  import java.util.Map;
32  
33  import javax.xml.parsers.ParserConfigurationException;
34  
35  import org.apache.maven.reporting.MavenReportException;
36  import org.apache.maven.shared.utils.StringUtils;
37  import org.apache.maven.shared.utils.io.DirectoryScanner;
38  import org.xml.sax.SAXException;
39  
40  /**
41   *
42   */
43  public final class SurefireReportParser
44  {
45      private static final String INCLUDES = "*.xml";
46  
47      private static final String EXCLUDES =
48                      "*.txt, testng-failed.xml, testng-failures.xml, testng-results.xml, failsafe-summary*.xml";
49  
50      private static final int PCENT = 100;
51  
52      private final List<ReportTestSuite> testSuites = new ArrayList<ReportTestSuite>();
53  
54      private final NumberFormat numberFormat;
55  
56      private List<File> reportsDirectories;
57  
58      public SurefireReportParser( List<File> reportsDirectoriesFiles, Locale locale )
59      {
60          reportsDirectories = reportsDirectoriesFiles;
61          numberFormat = NumberFormat.getInstance( locale );
62      }
63  
64      public List<ReportTestSuite> parseXMLReportFiles()
65          throws MavenReportException
66      {
67          final Collection<File> xmlReportFiles = new ArrayList<File>();
68          for ( File reportsDirectory : reportsDirectories )
69          {
70              if ( reportsDirectory.exists() )
71              {
72                  for ( String xmlReportFile : getIncludedFiles( reportsDirectory, INCLUDES, EXCLUDES ) )
73                  {
74                      xmlReportFiles.add( new File( reportsDirectory, xmlReportFile ) );
75                  }
76              }
77          }
78          final TestSuiteXmlParser parser = new TestSuiteXmlParser();
79          for ( File aXmlReportFileList : xmlReportFiles )
80          {
81              try
82              {
83                  testSuites.addAll( parser.parse( aXmlReportFileList.getAbsolutePath() ) );
84              }
85              catch ( ParserConfigurationException e )
86              {
87                  throw new MavenReportException( "Error setting up parser for JUnit XML report", e );
88              }
89              catch ( SAXException e )
90              {
91                  throw new MavenReportException( "Error parsing JUnit XML report " + aXmlReportFileList, e );
92              }
93              catch ( IOException e )
94              {
95                  throw new MavenReportException( "Error reading JUnit XML report " + aXmlReportFileList, e );
96              }
97          }
98  
99          return testSuites;
100     }
101 
102     protected String parseTestSuiteName( String lineString )
103     {
104         return lineString.substring( lineString.lastIndexOf( "." ) + 1, lineString.length() );
105     }
106 
107     protected String parseTestSuitePackageName( String lineString )
108     {
109         return lineString.substring( lineString.indexOf( ":" ) + 2, lineString.lastIndexOf( "." ) );
110     }
111 
112     protected String parseTestCaseName( String lineString )
113     {
114         return lineString.substring( 0, lineString.indexOf( "(" ) );
115     }
116 
117     public Map<String, String> getSummary( List<ReportTestSuite> suites )
118     {
119         Map<String, String> totalSummary = new HashMap<String, String>();
120 
121         int totalNumberOfTests = 0;
122 
123         int totalNumberOfErrors = 0;
124 
125         int totalNumberOfFailures = 0;
126 
127         int totalNumberOfSkipped = 0;
128 
129         float totalElapsedTime = 0.0f;
130 
131         for ( ReportTestSuite suite : suites )
132         {
133             totalNumberOfTests += suite.getNumberOfTests();
134 
135             totalNumberOfErrors += suite.getNumberOfErrors();
136 
137             totalNumberOfFailures += suite.getNumberOfFailures();
138 
139             totalNumberOfSkipped += suite.getNumberOfSkipped();
140 
141             totalElapsedTime += suite.getTimeElapsed();
142         }
143 
144         String totalPercentage =
145             computePercentage( totalNumberOfTests, totalNumberOfErrors, totalNumberOfFailures, totalNumberOfSkipped );
146 
147         totalSummary.put( "totalTests", Integer.toString( totalNumberOfTests ) );
148 
149         totalSummary.put( "totalErrors", Integer.toString( totalNumberOfErrors ) );
150 
151         totalSummary.put( "totalFailures", Integer.toString( totalNumberOfFailures ) );
152 
153         totalSummary.put( "totalSkipped", Integer.toString( totalNumberOfSkipped ) );
154 
155         totalSummary.put( "totalElapsedTime", numberFormat.format( totalElapsedTime ) );
156 
157         totalSummary.put( "totalPercentage", totalPercentage );
158 
159         return totalSummary;
160     }
161 
162     public void setReportsDirectory( File reportsDirectory )
163     {
164         reportsDirectories = Collections.singletonList( reportsDirectory );
165     }
166 
167     public NumberFormat getNumberFormat()
168     {
169         return numberFormat;
170     }
171 
172     public Map<String, List<ReportTestSuite>> getSuitesGroupByPackage( List<ReportTestSuite> testSuitesList )
173     {
174         Map<String, List<ReportTestSuite>> suitePackage = new HashMap<String, List<ReportTestSuite>>();
175 
176         for ( ReportTestSuite suite : testSuitesList )
177         {
178             List<ReportTestSuite> suiteList = new ArrayList<ReportTestSuite>();
179 
180             if ( suitePackage.get( suite.getPackageName() ) != null )
181             {
182                 suiteList = suitePackage.get( suite.getPackageName() );
183             }
184 
185             suiteList.add( suite );
186 
187             suitePackage.put( suite.getPackageName(), suiteList );
188         }
189 
190         return suitePackage;
191     }
192 
193     public String computePercentage( int tests, int errors, int failures, int skipped )
194     {
195         float percentage =
196             tests == 0 ? 0 : ( (float) ( tests - errors - failures - skipped ) / (float) tests ) * PCENT;
197         return numberFormat.format( percentage );
198     }
199 
200     public List<ReportTestCase> getFailureDetails( List<ReportTestSuite> testSuites )
201     {
202         List<ReportTestCase> failureDetailList = new ArrayList<ReportTestCase>();
203 
204         for ( ReportTestSuite suite : testSuites )
205         {
206             List<ReportTestCase> testCases = suite.getTestCases();
207             if ( testCases != null )
208             {
209                 for ( ReportTestCase tCase : testCases )
210                 {
211                     if ( tCase.hasFailure() )
212                     {
213                         failureDetailList.add( tCase );
214                     }
215                 }
216             }
217         }
218 
219         return failureDetailList;
220     }
221 
222     /**
223      * Returns {@code true} if the specified directory contains at least one report file.
224      *
225      * @param directory the directory
226      * @return {@code true} if the specified directory contains at least one report file.
227      */
228     public static boolean hasReportFiles( File directory )
229     {
230         return directory != null && directory.isDirectory()
231             && getIncludedFiles( directory, INCLUDES, EXCLUDES ).length != 0;
232     }
233 
234     private static String[] getIncludedFiles( File directory, String includes, String excludes )
235     {
236         DirectoryScanner scanner = new DirectoryScanner();
237 
238         scanner.setBasedir( directory );
239 
240         scanner.setIncludes( StringUtils.split( includes, "," ) );
241 
242         scanner.setExcludes( StringUtils.split( excludes, "," ) );
243 
244         scanner.scan();
245 
246         return scanner.getIncludedFiles();
247     }
248 }