XMLCoverageWriter.java revision 61e905db9ae03f604fbc38890dce997c05559d0a
1/*******************************************************************************
2 * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 *    Marc R. Hoffmann - initial API and implementation
10 *
11 *******************************************************************************/
12package org.jacoco.report.internal.xml;
13
14import java.io.IOException;
15
16import org.jacoco.core.analysis.IBundleCoverage;
17import org.jacoco.core.analysis.IClassCoverage;
18import org.jacoco.core.analysis.ICounter;
19import org.jacoco.core.analysis.ICoverageNode;
20import org.jacoco.core.analysis.ICoverageNode.CounterEntity;
21import org.jacoco.core.analysis.ILine;
22import org.jacoco.core.analysis.IMethodCoverage;
23import org.jacoco.core.analysis.IPackageCoverage;
24import org.jacoco.core.analysis.ISourceFileCoverage;
25import org.jacoco.core.analysis.ISourceNode;
26
27/**
28 * Serializes coverage data as XML fragments.
29 */
30public final class XMLCoverageWriter {
31
32	/**
33	 * Creates a child element with a name attribute.
34	 *
35	 * @param parent
36	 *            parent element
37	 * @param tagname
38	 *            name of the child tag
39	 * @param name
40	 *            value of the name attribute
41	 * @return child element
42	 * @throws IOException
43	 */
44	public static XMLElement createChild(final XMLElement parent,
45			final String tagname, final String name) throws IOException {
46		final XMLElement child = parent.element(tagname);
47		child.attr("name", name);
48		return child;
49	}
50
51	/**
52	 * Writes the structure of a given bundle.
53	 *
54	 * @param bundle
55	 *            bundle coverage data
56	 * @param element
57	 *            container element for the bundle data
58	 * @throws IOException
59	 */
60	public static void writeBundle(final IBundleCoverage bundle,
61			final XMLElement element) throws IOException {
62		for (final IPackageCoverage p : bundle.getPackages()) {
63			writePackage(p, element);
64		}
65		writeCounters(bundle, element);
66	}
67
68	private static void writePackage(final IPackageCoverage p,
69			final XMLElement parent) throws IOException {
70		final XMLElement element = createChild(parent, "package", p.getName());
71		for (final IClassCoverage c : p.getClasses()) {
72			writeClass(c, element);
73		}
74		for (final ISourceFileCoverage s : p.getSourceFiles()) {
75			writeSourceFile(s, element);
76		}
77		writeCounters(p, element);
78	}
79
80	private static void writeClass(final IClassCoverage c,
81			final XMLElement parent) throws IOException {
82		final XMLElement element = createChild(parent, "class", c.getName());
83		for (final IMethodCoverage m : c.getMethods()) {
84			writeMethod(m, element);
85		}
86		writeCounters(c, element);
87	}
88
89	private static void writeMethod(final IMethodCoverage m,
90			final XMLElement parent) throws IOException {
91		final XMLElement element = createChild(parent, "method", m.getName());
92		element.attr("desc", m.getDesc());
93		final int line = m.getFirstLine();
94		if (line != -1) {
95			element.attr("line", line);
96		}
97		writeCounters(m, element);
98	}
99
100	private static void writeSourceFile(final ISourceFileCoverage s,
101			final XMLElement parent) throws IOException {
102		final XMLElement element = createChild(parent, "sourcefile",
103				s.getName());
104		writeLines(s, element);
105		writeCounters(s, element);
106	}
107
108	/**
109	 * Writes all non-zero counters of the given node.
110	 *
111	 * @param node
112	 *            node to retrieve counters from
113	 * @param parent
114	 *            container for the counter elements
115	 * @throws IOException
116	 */
117	public static void writeCounters(final ICoverageNode node,
118			final XMLElement parent) throws IOException {
119		for (final CounterEntity counterEntity : CounterEntity.values()) {
120			final ICounter counter = node.getCounter(counterEntity);
121			if (counter.getTotalCount() > 0) {
122				final XMLElement counterNode = parent.element("counter");
123				counterNode.attr("type", counterEntity.name());
124				writeCounter(counterNode, "missed", "covered", counter);
125				counterNode.close();
126			}
127		}
128	}
129
130	private static void writeLines(final ISourceNode source,
131			final XMLElement parent) throws IOException {
132		final int last = source.getLastLine();
133		for (int nr = source.getFirstLine(); nr <= last; nr++) {
134			final ILine line = source.getLine(nr);
135			if (line.getStatus() != ICounter.EMPTY) {
136				final XMLElement element = parent.element("line");
137				element.attr("nr", nr);
138				writeCounter(element, "mi", "ci", line.getInstructionCounter());
139				writeCounter(element, "mb", "cb", line.getBranchCounter());
140			}
141		}
142	}
143
144	private static void writeCounter(final XMLElement element,
145			final String missedattr, final String coveredattr,
146			final ICounter counter) throws IOException {
147		element.attr(missedattr, counter.getMissedCount());
148		element.attr(coveredattr, counter.getCoveredCount());
149	}
150
151	private XMLCoverageWriter() {
152	}
153
154}
155