Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

XmlReportParser.java 8.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. * Sonar, open source software quality management tool.
  3. * Copyright (C) 2009 SonarSource SA
  4. * mailto:contact AT sonarsource DOT com
  5. *
  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.
  10. *
  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.
  15. *
  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
  19. */
  20. package org.sonar.plugins.clover;
  21. import org.apache.commons.lang.StringUtils;
  22. import org.codehaus.staxmate.in.*;
  23. import org.slf4j.Logger;
  24. import org.slf4j.LoggerFactory;
  25. import org.sonar.api.batch.SensorContext;
  26. import org.sonar.api.measures.CoreMetrics;
  27. import org.sonar.api.measures.PropertiesBuilder;
  28. import org.sonar.api.resources.JavaFile;
  29. import org.sonar.api.resources.JavaPackage;
  30. import org.sonar.api.resources.Resource;
  31. import org.sonar.api.utils.ParsingUtils;
  32. import static org.sonar.api.utils.ParsingUtils.scaleValue;
  33. import org.sonar.api.utils.StaxParser;
  34. import org.sonar.api.utils.XmlParserException;
  35. import java.io.File;
  36. import java.text.ParseException;
  37. import javax.xml.stream.XMLStreamException;
  38. public class XmlReportParser {
  39. private static final Logger LOG = LoggerFactory.getLogger(XmlReportParser.class);
  40. private SensorContext context;
  41. final PropertiesBuilder<String, Integer> lineHitsBuilder = new PropertiesBuilder<String, Integer>(CoreMetrics.COVERAGE_LINE_HITS_DATA);
  42. final PropertiesBuilder<String, String> branchHitsBuilder = new PropertiesBuilder<String, String>(CoreMetrics.BRANCH_COVERAGE_HITS_DATA);
  43. public XmlReportParser(SensorContext context) {
  44. this.context = context;
  45. }
  46. private boolean reportExists(File report) {
  47. return report != null && report.exists() && report.isFile();
  48. }
  49. protected void collect(File xmlFile) {
  50. try {
  51. if (reportExists(xmlFile)) {
  52. LOG.info("Parsing " + xmlFile.getCanonicalPath());
  53. StaxParser parser = new StaxParser(new StaxParser.XmlStreamHandler() {
  54. public void stream(SMHierarchicCursor rootCursor) throws XMLStreamException {
  55. try {
  56. collectProjectMeasures(rootCursor.advance());
  57. } catch (ParseException e) {
  58. throw new XMLStreamException(e);
  59. }
  60. }
  61. });
  62. parser.parse(xmlFile);
  63. }
  64. } catch (Exception e) {
  65. throw new XmlParserException(e);
  66. }
  67. }
  68. private void collectProjectMeasures(SMInputCursor rootCursor) throws ParseException, XMLStreamException {
  69. SMInputCursor projectCursor = rootCursor.descendantElementCursor("project");
  70. SMInputCursor projectChildrenCursor = projectCursor.advance().childElementCursor();
  71. projectChildrenCursor.setFilter(new SimpleFilter(SMEvent.START_ELEMENT));
  72. SMInputCursor metricsCursor = projectChildrenCursor.advance();
  73. analyseMetricsNode(null, metricsCursor);
  74. collectPackageMeasures(projectChildrenCursor);
  75. }
  76. private void analyseMetricsNode(Resource resource, SMInputCursor metricsCursor) throws ParseException, XMLStreamException {
  77. int elements = (int) ParsingUtils.parseNumber(metricsCursor.getAttrValue("elements"));
  78. if (elements == 0) {
  79. return;
  80. }
  81. int statements = (int) ParsingUtils.parseNumber(metricsCursor.getAttrValue("statements"));
  82. int methods = (int) ParsingUtils.parseNumber(metricsCursor.getAttrValue("methods"));
  83. int conditionals = (int) ParsingUtils.parseNumber(metricsCursor.getAttrValue("conditionals"));
  84. int coveredElements = (int) ParsingUtils.parseNumber(metricsCursor.getAttrValue("coveredelements"));
  85. int coveredStatements = (int) ParsingUtils.parseNumber(metricsCursor.getAttrValue("coveredstatements"));
  86. int coveredMethods = (int) ParsingUtils.parseNumber(metricsCursor.getAttrValue("coveredmethods"));
  87. int coveredConditionals = (int) ParsingUtils.parseNumber(metricsCursor.getAttrValue("coveredconditionals"));
  88. context.saveMeasure(resource, CoreMetrics.COVERAGE, calculateCoverage(coveredElements, elements));
  89. context.saveMeasure(resource, CoreMetrics.LINE_COVERAGE, calculateCoverage(coveredMethods + coveredStatements, methods + statements));
  90. context.saveMeasure(resource, CoreMetrics.LINES_TO_COVER, (double) (statements + methods));
  91. context.saveMeasure(resource, CoreMetrics.UNCOVERED_LINES, (double) (statements + methods - coveredStatements - coveredMethods));
  92. if (conditionals > 0) {
  93. context.saveMeasure(resource, CoreMetrics.BRANCH_COVERAGE, calculateCoverage(coveredConditionals, conditionals));
  94. context.saveMeasure(resource, CoreMetrics.CONDITIONS_TO_COVER, (double) (conditionals));
  95. context.saveMeasure(resource, CoreMetrics.UNCOVERED_CONDITIONS, (double) (conditionals - coveredConditionals));
  96. }
  97. }
  98. private double calculateCoverage(int coveredElements, int elements) {
  99. if (elements > 0) {
  100. return scaleValue(100.0 * ((double) coveredElements / (double) elements));
  101. }
  102. return 0.0;
  103. }
  104. private void collectPackageMeasures(SMInputCursor packCursor) throws ParseException, XMLStreamException {
  105. while (packCursor.getNext() != null) {
  106. JavaPackage pack = new JavaPackage(packCursor.getAttrValue("name"));
  107. SMInputCursor packChildrenCursor = packCursor.descendantElementCursor();
  108. packChildrenCursor.setFilter(new SimpleFilter(SMEvent.START_ELEMENT));
  109. SMInputCursor metricsCursor = packChildrenCursor.advance();
  110. analyseMetricsNode(pack, metricsCursor);
  111. collectFileMeasures(packChildrenCursor, pack);
  112. }
  113. }
  114. private void collectFileMeasures(SMInputCursor fileCursor, JavaPackage pack) throws ParseException, XMLStreamException {
  115. fileCursor.setFilter(SMFilterFactory.getElementOnlyFilter("file"));
  116. while (fileCursor.getNext() != null) {
  117. if (fileCursor.asEvent().isStartElement()) {
  118. String classKey = extractClassName(fileCursor.getAttrValue("name"));
  119. if (classKey != null) {
  120. SMInputCursor fileChildrenCursor = fileCursor.childCursor(new SimpleFilter(SMEvent.START_ELEMENT));
  121. // cursor should be on the metrics element
  122. if (canBeIncludedInFileMetrics(fileChildrenCursor)) {
  123. JavaFile resource = new JavaFile(pack.getKey(), classKey, false);
  124. analyseMetricsNode(resource, fileChildrenCursor);
  125. // cursor should be now on the line cursor
  126. saveHitsData(resource, fileChildrenCursor);
  127. }
  128. }
  129. }
  130. }
  131. }
  132. private void saveHitsData(Resource resource, SMInputCursor lineCursor) throws ParseException, XMLStreamException {
  133. lineHitsBuilder.clear();
  134. branchHitsBuilder.clear();
  135. boolean hasBranches = false;
  136. while (lineCursor.getNext() != null) {
  137. // skip class elements on format 2_3_2
  138. if (lineCursor.getLocalName().equals("class")) {
  139. continue;
  140. }
  141. final String lineId = lineCursor.getAttrValue("num");
  142. int hits;
  143. String count = lineCursor.getAttrValue("count");
  144. if (StringUtils.isBlank(count)) {
  145. int trueCount = (int) ParsingUtils.parseNumber(lineCursor.getAttrValue("truecount"));
  146. int falseCount = (int) ParsingUtils.parseNumber(lineCursor.getAttrValue("falsecount"));
  147. hits = trueCount + falseCount;
  148. String branchHits;
  149. if (trueCount > 0 && falseCount > 0) {
  150. branchHits = "100%";
  151. } else if (trueCount == 0 && falseCount == 0) {
  152. branchHits = "0%";
  153. } else {
  154. branchHits = "50%";
  155. }
  156. branchHitsBuilder.add(lineId, branchHits);
  157. hasBranches = true;
  158. } else {
  159. hits = (int) ParsingUtils.parseNumber(count);
  160. }
  161. lineHitsBuilder.add(lineId, hits);
  162. }
  163. context.saveMeasure(resource, lineHitsBuilder.build());
  164. if (hasBranches) {
  165. context.saveMeasure(resource, branchHitsBuilder.build());
  166. }
  167. }
  168. private boolean canBeIncludedInFileMetrics(SMInputCursor metricsCursor) throws ParseException, XMLStreamException {
  169. // skip class elements on 1.x xml format
  170. while (metricsCursor.getNext() != null && metricsCursor.getLocalName().equals("class")) {
  171. }
  172. return ParsingUtils.parseNumber(metricsCursor.getAttrValue("elements")) > 0;
  173. }
  174. protected String extractClassName(String filename) {
  175. if (filename != null) {
  176. filename = StringUtils.replaceChars(filename, '\\', '/');
  177. filename = StringUtils.substringBeforeLast(filename, ".java");
  178. if (filename.indexOf('/') >= 0) {
  179. filename = StringUtils.substringAfterLast(filename, "/");
  180. }
  181. }
  182. return filename;
  183. }
  184. }