2 * Sonar, open source software quality management tool.
3 * Copyright (C) 2008-2011 SonarSource
4 * mailto:contact AT sonarsource DOT com
6 * Sonar is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * Sonar is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with Sonar; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
20 package org.sonar.plugins.surefire.api;
22 import org.apache.commons.lang.StringUtils;
23 import org.sonar.api.batch.SensorContext;
24 import org.sonar.api.measures.CoreMetrics;
25 import org.sonar.api.measures.Measure;
26 import org.sonar.api.measures.Metric;
27 import org.sonar.api.resources.Project;
28 import org.sonar.api.resources.Resource;
29 import org.sonar.api.utils.ParsingUtils;
30 import org.sonar.api.utils.SonarException;
31 import org.sonar.api.utils.StaxParser;
32 import org.sonar.plugins.surefire.data.SurefireStaxHandler;
33 import org.sonar.plugins.surefire.data.UnitTestClassReport;
34 import org.sonar.plugins.surefire.data.UnitTestIndex;
37 import java.io.FilenameFilter;
40 import javax.xml.stream.XMLStreamException;
45 public abstract class AbstractSurefireParser {
47 public void collect(Project project, SensorContext context, File reportsDir) {
48 File[] xmlFiles = getReports(reportsDir);
50 if (xmlFiles.length == 0) {
51 // See http://jira.codehaus.org/browse/SONAR-2371
52 if (project.getModules().isEmpty()) {
53 context.saveMeasure(CoreMetrics.TESTS, 0.0);
56 parseFiles(context, xmlFiles);
60 private File[] getReports(File dir) {
61 if (dir == null || !dir.isDirectory() || !dir.exists()) {
64 return dir.listFiles(new FilenameFilter() {
65 public boolean accept(File dir, String name) {
66 return name.startsWith("TEST") && name.endsWith(".xml");
71 private void parseFiles(SensorContext context, File[] reports) {
72 UnitTestIndex index = new UnitTestIndex();
73 parseFiles(reports, index);
78 private void parseFiles(File[] reports, UnitTestIndex index) {
79 SurefireStaxHandler staxParser = new SurefireStaxHandler(index);
80 StaxParser parser = new StaxParser(staxParser, false);
81 for (File report : reports) {
84 } catch (XMLStreamException e) {
85 throw new SonarException("Fail to parse the Surefire report: " + report, e);
90 private void sanitize(UnitTestIndex index) {
91 for (String classname : index.getClassnames()) {
92 if (StringUtils.contains(classname, "$")) {
93 // Surefire reports classes whereas sonar supports files
94 String parentClassName = StringUtils.substringBeforeLast(classname, "$");
95 index.merge(classname, parentClassName);
100 private void save(UnitTestIndex index, SensorContext context) {
101 for (Map.Entry<String, UnitTestClassReport> entry : index.getIndexByClassname().entrySet()) {
102 UnitTestClassReport report = entry.getValue();
103 if (report.getTests() > 0) {
104 Resource resource = getUnitTestResource(entry.getKey());
105 double testsCount = report.getTests() - report.getSkipped();
106 saveMeasure(context, resource, CoreMetrics.SKIPPED_TESTS, report.getSkipped());
107 saveMeasure(context, resource, CoreMetrics.TESTS, testsCount);
108 saveMeasure(context, resource, CoreMetrics.TEST_ERRORS, report.getErrors());
109 saveMeasure(context, resource, CoreMetrics.TEST_FAILURES, report.getFailures());
110 saveMeasure(context, resource, CoreMetrics.TEST_EXECUTION_TIME, report.getDurationMilliseconds());
111 double passedTests = testsCount - report.getErrors() - report.getFailures();
112 if (testsCount > 0) {
113 double percentage = passedTests * 100d / testsCount;
114 saveMeasure(context, resource, CoreMetrics.TEST_SUCCESS_DENSITY, ParsingUtils.scaleValue(percentage));
116 saveResults(context, resource, report);
121 private void saveMeasure(SensorContext context, Resource resource, Metric metric, double value) {
122 if (!Double.isNaN(value)) {
123 context.saveMeasure(resource, metric, value);
127 private void saveResults(SensorContext context, Resource resource, UnitTestClassReport report) {
128 context.saveMeasure(resource, new Measure(CoreMetrics.TEST_DATA, report.toXml()));
131 protected abstract Resource<?> getUnitTestResource(String classKey);