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