Trac #120: New attribute 'line' for methods in XML report.
diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html
index eeb3d01..05dd9cb 100644
--- a/org.jacoco.doc/docroot/doc/changes.html
+++ b/org.jacoco.doc/docroot/doc/changes.html
@@ -22,7 +22,12 @@
<h3>New Features</h3>
<ul>
- <li>Optional locale attribute for HTML reports (Track #122).</li>
+ <li>New attribute <code>line</code> for <code>method</code> elements in the
+ XML report containing the first source line number of the method.
+ (Track #120).</li>
+ <li>Optional <code>locale</code> attribute for number rendering HTML reports,
+ also available as an attribute of the <code>html</code> tag of the
+ <code>report</code> Ant task (Track #122).</li>
<li>Coverage tables in HTML report are now sortable (Track #98).</li>
<li>The <code>report</code> Ant task issues a warning if source files are
provided but class files do not contain debug information to collect line
diff --git a/org.jacoco.report.test/src/org/jacoco/report/xml/XMLReportNodeHandlerTest.java b/org.jacoco.report.test/src/org/jacoco/report/xml/XMLReportNodeHandlerTest.java
new file mode 100644
index 0000000..02d4b55
--- /dev/null
+++ b/org.jacoco.report.test/src/org/jacoco/report/xml/XMLReportNodeHandlerTest.java
@@ -0,0 +1,190 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Marc R. Hoffmann - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.report.xml;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.jacoco.core.analysis.CounterImpl;
+import org.jacoco.core.analysis.CoverageNodeImpl;
+import org.jacoco.core.analysis.ICoverageNode.ElementType;
+import org.jacoco.core.analysis.MethodCoverage;
+import org.jacoco.report.IReportVisitor;
+import org.junit.Before;
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+/**
+ * Unit tests for {@link XMLReportNodeHandler}.
+ *
+ * @author Marc R. Hoffmann
+ * @version $qualified.bundle.version$
+ */
+public class XMLReportNodeHandlerTest {
+
+ private XMLElement root;
+
+ private StringWriter buffer;
+
+ private XMLSupport support;
+
+ private XMLReportNodeHandler handler;
+
+ @Before
+ public void setup() throws Exception {
+ buffer = new StringWriter();
+ support = new XMLSupport(XMLReportNodeHandler.class);
+ root = new XMLDocument("report", "-//JACOCO//DTD Report 1.0//EN",
+ "report.dtd", "UTF-8", true, buffer);
+ handler = new XMLReportNodeHandler(root, new CoverageNodeImpl(
+ ElementType.GROUP, "Sample", false));
+ }
+
+ @Test
+ public void testRoot() throws Exception {
+ final Document doc = getDocument();
+ assertEquals("Sample", support.findStr(doc, "//report/@name"));
+ }
+
+ @Test
+ public void testGroup() throws Exception {
+ handler.visitChild(
+ new CoverageNodeImpl(ElementType.GROUP, "Group1", false))
+ .visitEnd(null);
+ final Document doc = getDocument();
+ assertEquals("Group1", support.findStr(doc, "//report/group/@name"));
+ }
+
+ @Test
+ public void testCounters() throws Exception {
+ final CoverageNodeImpl node = new CoverageNodeImpl(ElementType.GROUP,
+ "Group1", false) {
+ {
+ classCounter = CounterImpl.getInstance(10, 1);
+ methodCounter = CounterImpl.getInstance(20, 2);
+ blockCounter = CounterImpl.getInstance(30, 3);
+ instructionCounter = CounterImpl.getInstance(40, 4);
+ lineCounter = CounterImpl.getInstance(50, 5);
+ }
+ };
+ handler.visitChild(node).visitEnd(null);
+ final Document doc = getDocument();
+ assertEquals("1", support.findStr(doc,
+ "//report/group/counter[@type='CLASS']/@covered"));
+ assertEquals("9", support.findStr(doc,
+ "//report/group/counter[@type='CLASS']/@missed"));
+ assertEquals("2", support.findStr(doc,
+ "//report/group/counter[@type='METHOD']/@covered"));
+ assertEquals("18", support.findStr(doc,
+ "//report/group/counter[@type='METHOD']/@missed"));
+ assertEquals("3", support.findStr(doc,
+ "//report/group/counter[@type='BLOCK']/@covered"));
+ assertEquals("27", support.findStr(doc,
+ "//report/group/counter[@type='BLOCK']/@missed"));
+ assertEquals("4", support.findStr(doc,
+ "//report/group/counter[@type='INSTRUCTION']/@covered"));
+ assertEquals("36", support.findStr(doc,
+ "//report/group/counter[@type='INSTRUCTION']/@missed"));
+ assertEquals("5", support.findStr(doc,
+ "//report/group/counter[@type='LINE']/@covered"));
+ assertEquals("45", support.findStr(doc,
+ "//report/group/counter[@type='LINE']/@missed"));
+ }
+
+ @Test
+ public void testPackage() throws Exception {
+ handler.visitChild(
+ new CoverageNodeImpl(ElementType.PACKAGE, "org.jacoco.example",
+ false)).visitEnd(null);
+ final Document doc = getDocument();
+ assertEquals("org.jacoco.example",
+ support.findStr(doc, "//report/package/@name"));
+ }
+
+ @Test
+ public void testClass() throws Exception {
+ final IReportVisitor packageHandler = handler
+ .visitChild(new CoverageNodeImpl(ElementType.PACKAGE,
+ "org.jacoco.example", false));
+ packageHandler.visitChild(
+ new CoverageNodeImpl(ElementType.CLASS, "Foo", true)).visitEnd(
+ null);
+ packageHandler.visitEnd(null);
+ final Document doc = getDocument();
+ assertEquals("Foo",
+ support.findStr(doc, "//report/package/class/@name"));
+ }
+
+ @Test
+ public void testMethod() throws Exception {
+ final IReportVisitor packageHandler = handler
+ .visitChild(new CoverageNodeImpl(ElementType.PACKAGE,
+ "org.jacoco.example", false));
+ final IReportVisitor classHandler = packageHandler
+ .visitChild(new CoverageNodeImpl(ElementType.CLASS, "Foo", true));
+ MethodCoverage node = new MethodCoverage("doit", "()V", null);
+ node.addBlock(5, new int[] { 15, 16, 17 }, false);
+ classHandler.visitChild(node).visitEnd(null);
+ classHandler.visitEnd(null);
+ packageHandler.visitEnd(null);
+ final Document doc = getDocument();
+ assertEquals("doit",
+ support.findStr(doc, "//report/package/class/method/@name"));
+ assertEquals("()V",
+ support.findStr(doc, "//report/package/class/method/@desc"));
+ assertEquals("15",
+ support.findStr(doc, "//report/package/class/method/@line"));
+ }
+
+ @Test
+ public void testSourcefile() throws Exception {
+ final IReportVisitor packageHandler = handler
+ .visitChild(new CoverageNodeImpl(ElementType.PACKAGE,
+ "org.jacoco.example", false));
+ final CoverageNodeImpl node = new CoverageNodeImpl(
+ ElementType.SOURCEFILE, "Foo.java", true) {
+ {
+ lines.increment(new int[] { 11, 13 }, false);
+ lines.increment(new int[] { 13, 14 }, true);
+ }
+ };
+ packageHandler.visitChild(node).visitEnd(null);
+ packageHandler.visitEnd(null);
+ final Document doc = getDocument();
+ assertEquals("Foo.java",
+ support.findStr(doc, "//report/package/sourcefile/@name"));
+ assertEquals("11",
+ support.findStr(doc, "//report/package/sourcefile/line[1]/@nr"));
+ assertEquals("N", support.findStr(doc,
+ "//report/package/sourcefile/line[1]/@status"));
+ assertEquals("13",
+ support.findStr(doc, "//report/package/sourcefile/line[2]/@nr"));
+ assertEquals("P", support.findStr(doc,
+ "//report/package/sourcefile/line[2]/@status"));
+ assertEquals("14",
+ support.findStr(doc, "//report/package/sourcefile/line[3]/@nr"));
+ assertEquals("F", support.findStr(doc,
+ "//report/package/sourcefile/line[3]/@status"));
+ }
+
+ private Document getDocument() throws SAXException, IOException,
+ ParserConfigurationException {
+ handler.visitEnd(null);
+ return support.parse(buffer.toString());
+ }
+
+}
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 0fedb88..cab19e6 100644
--- a/org.jacoco.report/src/org/jacoco/report/xml/XMLReportNodeHandler.java
+++ b/org.jacoco.report/src/org/jacoco/report/xml/XMLReportNodeHandler.java
@@ -16,10 +16,10 @@
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;
+import org.jacoco.core.analysis.ILines;
+import org.jacoco.core.analysis.MethodCoverage;
import org.jacoco.report.IReportVisitor;
import org.jacoco.report.ISourceFileLocator;
@@ -61,8 +61,7 @@
* this element
* @throws IOException
*/
- protected void insertElementsBefore(final XMLElement element)
- throws IOException {
+ void insertElementsBefore(final XMLElement element) throws IOException {
}
/**
@@ -72,8 +71,7 @@
* this element
* @throws IOException
*/
- protected void insertElementsAfter(final XMLElement element)
- throws IOException {
+ void insertElementsAfter(final XMLElement element) throws IOException {
}
public IReportVisitor visitChild(final ICoverageNode node)
@@ -89,7 +87,12 @@
return new XMLReportNodeHandler(element.element("class"), node);
case METHOD:
final XMLElement methodChild = element.element("method");
- methodChild.attr("desc", ((MethodCoverage) node).getDesc());
+ final MethodCoverage methodNode = (MethodCoverage) node;
+ methodChild.attr("desc", methodNode.getDesc());
+ final int line = methodNode.getLines().getFirstLine();
+ if (line != -1) {
+ methodChild.attr("line", line);
+ }
return new XMLReportNodeHandler(methodChild, node);
case SOURCEFILE:
return new XMLReportNodeHandler(element.element("sourcefile"), node) {
@@ -99,16 +102,17 @@
writeLines(node.getLines(), element);
}
};
+ default:
+ throw new AssertionError(type);
}
- return IReportVisitor.NOP;
}
public final void visitEnd(final ISourceFileLocator sourceFileLocator)
throws IOException {
+ insertElementsAfter(element);
for (final CounterEntity counterEntity : CounterEntity.values()) {
createCounterElement(counterEntity);
}
- insertElementsAfter(element);
element.close();
}
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 0196301..cb72c70 100644
--- a/org.jacoco.report/src/org/jacoco/report/xml/report.dtd
+++ b/org.jacoco.report/src/org/jacoco/report/xml/report.dtd
@@ -44,9 +44,10 @@
<!ELEMENT method (counter*)>
<!ATTLIST method
name CDATA #REQUIRED
- desc CDATA #REQUIRED>
+ desc CDATA #REQUIRED
+ line CDATA #IMPLIED>
-<!ELEMENT sourcefile (line*)>
+<!ELEMENT sourcefile (line*, counter*)>
<!ATTLIST sourcefile
name CDATA #REQUIRED>
@@ -57,6 +58,6 @@
<!ELEMENT counter EMPTY>
<!ATTLIST counter
- type CDATA #REQUIRED
+ type (INSTRUCTION|BLOCK|LINE|METHOD|CLASS) #REQUIRED
covered CDATA #REQUIRED
missed CDATA #REQUIRED>
\ No newline at end of file