/*
* This program is copyright (c) 2007 Hortis-GRC SA.
*
* This file is part of Sonar.
* Sonar is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Sonar is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Sonar; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package ch.hortis.sonar.mvn.mc;
import ch.hortis.sonar.model.Collectable;
import ch.hortis.sonar.model.FileMeasure;
import ch.hortis.sonar.model.Metrics;
import ch.hortis.sonar.model.ProjectMeasure;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.File;
import java.io.FilenameFilter;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
public class SurefireCollector extends BaseMeasuresCollector {
private File[] reports;
private List<UnitTestReport> unitTestReports;
private List<FileMeasure> fileMeasures;
public boolean initialize( MavenProject project ) {
String baseDir = project.getBuild().getDirectory() + "/surefire-reports";
reports = findSureFireReportFiles( baseDir );
unitTestReports = new ArrayList<UnitTestReport>();
return ( reports != null && reports.length > 0 );
}
public List<Collectable> collect() throws MojoExecutionException {
List<Collectable> result = new ArrayList<Collectable>();
result.addAll( collectProjectMeasures() );
result.addAll( fileMeasures );
return result;
}
public List<ProjectMeasure> collectProjectMeasures() throws MojoExecutionException {
fileMeasures = collectFileMeasures();
ReportDataContainer dataContainer = new ReportDataContainer();
for ( UnitTestReport fileReport : unitTestReports) {
dataContainer.cumulate( fileReport );
}
return dataContainer.asProjectMeasures();
}
public List<FileMeasure> collectFileMeasures() throws MojoExecutionException {
List<FileMeasure> measures = new ArrayList<FileMeasure>();
try {
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
for (File report : reports) {
Document document = builder.parse( report );
XPath xpath = XPathFactory.newInstance().newXPath();
UnitTestReport fileReport = parseReport( xpath, document );
unitTestReports.add(fileReport);
measures.addAll( fileReport.asFileMeasures() );
}
} catch (Exception ex) {
throw new MojoExecutionException( "Error during surefire reports parsing", ex );
}
return measures;
}
private UnitTestReport parseReport( XPath xpath, Node root ) throws XPathExpressionException, ParseException {
Node testSuite = (Node) xpath.evaluate( "//testsuite", root, XPathConstants.NODE );
UnitTestReport test = new UnitTestReport();
test.file = getFileFromClassName( xpath.evaluate( "@name", testSuite ) );
test.errors = ((Number)xpath.evaluate( "@errors", testSuite, XPathConstants.NUMBER )).doubleValue();
test.skipped = ((Number) xpath.evaluate( "@skipped", testSuite, XPathConstants.NUMBER )).doubleValue();
test.tests = ((Number) xpath.evaluate( "@tests", testSuite, XPathConstants.NUMBER )).doubleValue();
test.time = parseNumber( xpath.evaluate( "@time", testSuite ) );
test.failures = ((Number) xpath.evaluate( "@failures", testSuite, XPathConstants.NUMBER )).doubleValue();
return test;
}
private File[] findSureFireReportFiles( String sureFireOutputDirectory ) {
File reportsDir = new File( sureFireOutputDirectory );
if ( !reportsDir.exists() ) {
return null;
}
return reportsDir.listFiles( new FilenameFilter() {
public boolean accept( File dir, String name ) {
return name.startsWith( "TEST-" ) && name.endsWith( ".xml" );
}
} );
}
private class ReportDataContainer {
private UnitTestReport sum = new UnitTestReport();
private void cumulate( UnitTestReport toSum ) {
sum.errors += toSum.errors;
sum.skipped += toSum.skipped;
sum.failures += toSum.failures;
sum.tests += toSum.tests;
sum.time += toSum.time;
}
private List<ProjectMeasure> asProjectMeasures() {
List<ProjectMeasure> measures = new ArrayList<ProjectMeasure>();
List<FileMeasure> sumAsFileMeasures = sum.asFileMeasures();
for (FileMeasure fileMeasure : sumAsFileMeasures) {
ProjectMeasure measure = new ProjectMeasure();
measure.setMetric( fileMeasure.getMetric() );
measure.setValue( fileMeasure.getValue() );
measures.add( measure );
}
return measures;
}
}
private class UnitTestReport {
private ch.hortis.sonar.model.File file;
private double errors;
private double skipped;
private double tests;
private double time;
private double failures;
private List<FileMeasure> asFileMeasures() {
List<FileMeasure> measures = new ArrayList<FileMeasure>();
FileMeasure measure = new FileMeasure();
measure.setFile(file);
measure.setMetric( loadMetric( Metrics.SUREFIRE_ERRORS ) );
measure.setValue( errors );
measures.add( measure );
measure = new FileMeasure();
measure.setFile(file);
measure.setMetric( loadMetric( Metrics.SUREFIRE_SKIPPED ) );
measure.setValue( skipped );
measures.add( measure );
measure = new FileMeasure();
measure.setFile(file);
measure.setMetric( loadMetric( Metrics.SUREFIRE_FAILURES ) );
measure.setValue( failures );
measures.add( measure );
measure = new FileMeasure();
measure.setFile(file);
measure.setMetric( loadMetric( Metrics.SUREFIRE_TESTS ) );
measure.setValue( tests );
measures.add( measure );
measure = new FileMeasure();
measure.setFile(file);
measure.setMetric( loadMetric( Metrics.SUREFIRE_TIME ) );
measure.setValue( scaleValue( time * 1000, 3 ) );
measures.add( measure );
if ( tests > 0 ) {
measure = new FileMeasure();
measure.setFile(file);
measure.setMetric( loadMetric( Metrics.SUREFIRE_SUCCESS_PERCENTAGE ) );
measure.setValue( scaleValue( 100d - ( ( errors + failures ) * 100d / tests ) ) );
measures.add( measure );
measure = new FileMeasure();
measure.setFile(file);
measure.setMetric( loadMetric( Metrics.SUREFIRE_ERRORS_PERCENTAGE ) );
measure.setValue( scaleValue( errors * 100d / tests ) );
measures.add( measure );
measure = new FileMeasure();
measure.setFile(file);
measure.setMetric( loadMetric( Metrics.SUREFIRE_FAILURE_PERCENTAGE ) );
measure.setValue( scaleValue( failures * 100d / tests ) );
measures.add( measure );
}
return measures;
}
}
}