XML report with line level info for Sonar integration.
diff --git a/org.jacoco.doc/buildhook.xml b/org.jacoco.doc/buildhook.xml
index 27ba72f..50aebbf 100644
--- a/org.jacoco.doc/buildhook.xml
+++ b/org.jacoco.doc/buildhook.xml
@@ -91,6 +91,10 @@
<csv destfile="${result.dist.coverage.dir}/coverage.csv"/>
<xml destfile="${result.dist.coverage.dir}/coverage.xml"/>
</jacoco:report>
+
+ <copy todir="${result.dist.coverage.dir}">
+ <fileset dir="${source.org.jacoco.report.dir}/src/org/jacoco/report/xml" includes="report.dtd"/>
+ </copy>
</target>
diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html
index 0531576..0584d9d 100644
--- a/org.jacoco.doc/docroot/doc/changes.html
+++ b/org.jacoco.doc/docroot/doc/changes.html
@@ -23,6 +23,7 @@
<ul>
<li>Support for different archives (jar, war, ear etc.) and nested archives
(Trac #78).</li>
+ <li>XML report with line level coverage information (requested for Sonar).</li>
</ul>
<h2>Release 0.3.2 (2010/04/01)</h2>
diff --git a/org.jacoco.report/src/org/jacoco/report/xml/XMLReportNodeHandler.java b/org.jacoco.report/src/org/jacoco/report/xml/XMLReportNodeHandler.java
index 5dc7cd8..7c42131 100644
--- a/org.jacoco.report/src/org/jacoco/report/xml/XMLReportNodeHandler.java
+++ b/org.jacoco.report/src/org/jacoco/report/xml/XMLReportNodeHandler.java
@@ -7,7 +7,7 @@
*
* Contributors:
* Brock Janiczak - initial API and implementation
- * Marc R. Hoffmann - generalized structure
+ * Marc R. Hoffmann - generalized structure, line info
*
* $Id: $
*******************************************************************************/
@@ -15,9 +15,9 @@
import java.io.IOException;
-import org.jacoco.core.analysis.ClassCoverage;
import org.jacoco.core.analysis.ICounter;
import org.jacoco.core.analysis.ICoverageNode;
+import org.jacoco.core.analysis.ILines;
import org.jacoco.core.analysis.MethodCoverage;
import org.jacoco.core.analysis.ICoverageNode.CounterEntity;
import org.jacoco.core.analysis.ICoverageNode.ElementType;
@@ -64,13 +64,21 @@
case PACKAGE:
return new XMLReportNodeHandler(element.element("package"), node);
case CLASS:
- final XMLElement classChild = element.element("class");
- addClassAttributes(classChild, (ClassCoverage) node);
- return new XMLReportNodeHandler(classChild, node);
+ return new XMLReportNodeHandler(element.element("class"), node);
case METHOD:
final XMLElement methodChild = element.element("method");
- addMethodAttributes(methodChild, (MethodCoverage) node);
+ methodChild.attr("desc", ((MethodCoverage) node).getDesc());
return new XMLReportNodeHandler(methodChild, node);
+ case SOURCEFILE:
+ return new XMLReportNodeHandler(element.element("sourcefile"), node) {
+ @Override
+ public void visitEnd(final ISourceFileLocator sourceFileLocator)
+ throws IOException {
+ writeLines(node.getLines(), element);
+ super.visitEnd(sourceFileLocator);
+ }
+
+ };
}
return IReportVisitor.NOP;
}
@@ -95,35 +103,26 @@
}
}
- private static void addClassAttributes(final XMLElement element,
- final ClassCoverage node) throws IOException {
- if (node.getSignature() != null) {
- element.attr("signature", node.getSignature());
- }
- if (node.getSuperName() != null) {
- element.attr("superclass", node.getSuperName());
- }
- if (node.getInterfaceNames() != null) {
- boolean first = true;
- final StringBuilder builder = new StringBuilder();
- for (final String iface : node.getInterfaceNames()) {
- if (first) {
- first = false;
- } else {
- builder.append(' ');
+ private void writeLines(final ILines lines, final XMLElement parent)
+ throws IOException {
+ final int last = lines.getLastLine();
+ for (int nr = lines.getFirstLine(); nr <= last; nr++) {
+ final byte status = lines.getStatus(nr);
+ if (status != ILines.NO_CODE) {
+ final XMLElement line = parent.element("line");
+ line.attr("nr", nr);
+ switch (status) {
+ case ILines.NOT_COVERED:
+ line.attr("status", "N");
+ break;
+ case ILines.PARTLY_COVERED:
+ line.attr("status", "P");
+ break;
+ case ILines.FULLY_COVERED:
+ line.attr("status", "F");
+ break;
}
- builder.append(iface);
}
- element.attr("interfaces", builder.toString());
- }
- }
-
- private static void addMethodAttributes(final XMLElement element,
- final MethodCoverage node) throws IOException {
- element.attr("desc", node.getDesc());
- final String signature = node.getSignature();
- if (signature != null) {
- element.attr("signature", signature);
}
}
diff --git a/org.jacoco.report/src/org/jacoco/report/xml/report.dtd b/org.jacoco.report/src/org/jacoco/report/xml/report.dtd
index 11164d9..2264242 100644
--- a/org.jacoco.report/src/org/jacoco/report/xml/report.dtd
+++ b/org.jacoco.report/src/org/jacoco/report/xml/report.dtd
@@ -7,35 +7,40 @@
Contributors:
Brock Janiczak - initial API and implementation
- Marc R. Hoffmann - generalized report structure
+ Marc R. Hoffmann - generalized report structure, line info
$Id: $
-->
-<!ELEMENT report ((group* , package*) , counter*)>
+<!ELEMENT report (group* , package* , counter*)>
<!ATTLIST report
name CDATA #REQUIRED>
-<!ELEMENT group ((group* , package*) , counter*)>
+<!ELEMENT group (group* , package* , counter*)>
<!ATTLIST group
name CDATA #REQUIRED>
-<!ELEMENT package ((class*) , counter*)>
+<!ELEMENT package ((class | sourcefile)* , counter*)>
<!ATTLIST package
name CDATA #REQUIRED>
-<!ELEMENT class ((method*), counter*)>
+<!ELEMENT class (method*, counter*)>
<!ATTLIST class
- name CDATA #REQUIRED
- signature CDATA #IMPLIED
- superclass CDATA #IMPLIED
- interfaces CDATA #IMPLIED>
+ name CDATA #REQUIRED>
<!ELEMENT method (counter*)>
<!ATTLIST method
name CDATA #REQUIRED
- desc CDATA #REQUIRED
- signature CDATA #IMPLIED>
+ desc CDATA #REQUIRED>
+
+<!ELEMENT sourcefile (line*)>
+<!ATTLIST sourcefile
+ name CDATA #REQUIRED>
+
+<!ELEMENT line EMPTY>
+<!ATTLIST line
+ nr CDATA #REQUIRED
+ status (N|P|F) #REQUIRED>
<!ELEMENT counter EMPTY>
<!ATTLIST counter