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 parseFiles(context, xmlFiles);
55 private File[] getReports(File dir) {
56 if (dir == null || !dir.isDirectory() || !dir.exists()) {
59 return dir.listFiles(new FilenameFilter() {
60 public boolean accept(File dir, String name) {
61 return name.startsWith("TEST") && name.endsWith(".xml");
66 private void parseFiles(SensorContext context, File[] reports) {
67 UnitTestIndex index = new UnitTestIndex();
68 parseFiles(reports, index);
73 private void parseFiles(File[] reports, UnitTestIndex index) {
74 SurefireStaxHandler staxParser = new SurefireStaxHandler(index);
75 StaxParser parser = new StaxParser(staxParser, false);
76 for (File report : reports) {
79 } catch (XMLStreamException e) {
80 throw new SonarException("Fail to parse the Surefire report: " + report, e);
85 private void sanitize(UnitTestIndex index) {
86 for (String classname : index.getClassnames()) {
87 if (StringUtils.contains(classname, "$")) {
88 // Surefire reports classes whereas sonar supports files
89 String parentClassName = StringUtils.substringBeforeLast(classname, "$");
90 index.merge(classname, parentClassName);
95 private void save(UnitTestIndex index, SensorContext context) {
96 for (Map.Entry<String, UnitTestClassReport> entry : index.getIndexByClassname().entrySet()) {
97 UnitTestClassReport report = entry.getValue();
98 if (report.getTests() > 0) {
99 Resource resource = getUnitTestResource(entry.getKey());
100 double testsCount = report.getTests() - report.getSkipped();
101 saveMeasure(context, resource, CoreMetrics.SKIPPED_TESTS, report.getSkipped());
102 saveMeasure(context, resource, CoreMetrics.TESTS, testsCount);
103 saveMeasure(context, resource, CoreMetrics.TEST_ERRORS, report.getErrors());
104 saveMeasure(context, resource, CoreMetrics.TEST_FAILURES, report.getFailures());
105 saveMeasure(context, resource, CoreMetrics.TEST_EXECUTION_TIME, report.getDurationMilliseconds());
106 double passedTests = testsCount - report.getErrors() - report.getFailures();
107 if (testsCount > 0) {
108 double percentage = passedTests * 100d / testsCount;
109 saveMeasure(context, resource, CoreMetrics.TEST_SUCCESS_DENSITY, ParsingUtils.scaleValue(percentage));
111 saveResults(context, resource, report);
116 private void saveMeasure(SensorContext context, Resource resource, Metric metric, double value) {
117 if (!Double.isNaN(value)) {
118 context.saveMeasure(resource, metric, value);
122 private void saveResults(SensorContext context, Resource resource, UnitTestClassReport report) {
123 context.saveMeasure(resource, new Measure(CoreMetrics.TEST_DATA, report.toXml()));
126 protected abstract Resource<?> getUnitTestResource(String classKey);