XMLCoverageWriter.java revision 57f7cf06888f1e34f9ab2e3129c3d433826ecbe1
1/*******************************************************************************
2 * Copyright (c) 2009, 2013 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	 *             if XML can't be written to the underlying output
44	 *
45	 */
46	public static XMLElement createChild(final XMLElement parent,
47			final String tagname, final String name) throws IOException {
48		final XMLElement child = parent.element(tagname);
49		child.attr("name", name);
50		return child;
51	}
52
53	/**
54	 * Writes the structure of a given bundle.
55	 *
56	 * @param bundle
57	 *            bundle coverage data
58	 * @param element
59	 *            container element for the bundle data
60	 * @throws IOException
61	 *             if XML can't be written to the underlying output
62	 */
63	public static void writeBundle(final IBundleCoverage bundle,
64			final XMLElement element) throws IOException {
65		for (final IPackageCoverage p : bundle.getPackages()) {
66			writePackage(p, element);
67		}
68		writeCounters(bundle, element);
69	}
70
71	private static void writePackage(final IPackageCoverage p,
72			final XMLElement parent) throws IOException {
73		final XMLElement element = createChild(parent, "package", p.getName());
74		for (final IClassCoverage c : p.getClasses()) {
75			writeClass(c, element);
76		}
77		for (final ISourceFileCoverage s : p.getSourceFiles()) {
78			writeSourceFile(s, element);
79		}
80		writeCounters(p, element);
81	}
82
83	private static void writeClass(final IClassCoverage c,
84			final XMLElement parent) throws IOException {
85		final XMLElement element = createChild(parent, "class", c.getName());
86		for (final IMethodCoverage m : c.getMethods()) {
87			writeMethod(m, element);
88		}
89		writeCounters(c, element);
90	}
91
92	private static void writeMethod(final IMethodCoverage m,
93			final XMLElement parent) throws IOException {
94		final XMLElement element = createChild(parent, "method", m.getName());
95		element.attr("desc", m.getDesc());
96		final int line = m.getFirstLine();
97		if (line != -1) {
98			element.attr("line", line);
99		}
100		writeCounters(m, element);
101	}
102
103	private static void writeSourceFile(final ISourceFileCoverage s,
104			final XMLElement parent) throws IOException {
105		final XMLElement element = createChild(parent, "sourcefile",
106				s.getName());
107		writeLines(s, element);
108		writeCounters(s, element);
109	}
110
111	/**
112	 * Writes all non-zero counters of the given node.
113	 *
114	 * @param node
115	 *            node to retrieve counters from
116	 * @param parent
117	 *            container for the counter elements
118	 * @throws IOException
119	 *             if XML can't be written to the underlying output
120	 */
121	public static void writeCounters(final ICoverageNode node,
122			final XMLElement parent) throws IOException {
123		for (final CounterEntity counterEntity : CounterEntity.values()) {
124			final ICounter counter = node.getCounter(counterEntity);
125			if (counter.getTotalCount() > 0) {
126				final XMLElement counterNode = parent.element("counter");
127				counterNode.attr("type", counterEntity.name());
128				writeCounter(counterNode, "missed", "covered", counter);
129				counterNode.close();
130			}
131		}
132	}
133
134	private static void writeLines(final ISourceNode source,
135			final XMLElement parent) throws IOException {
136		final int last = source.getLastLine();
137		for (int nr = source.getFirstLine(); nr <= last; nr++) {
138			final ILine line = source.getLine(nr);
139			if (line.getStatus() != ICounter.EMPTY) {
140				final XMLElement element = parent.element("line");
141				element.attr("nr", nr);
142				writeCounter(element, "mi", "ci", line.getInstructionCounter());
143				writeCounter(element, "mb", "cb", line.getBranchCounter());
144			}
145		}
146	}
147
148	private static void writeCounter(final XMLElement element,
149			final String missedattr, final String coveredattr,
150			final ICounter counter) throws IOException {
151		element.attr(missedattr, counter.getMissedCount());
152		element.attr(coveredattr, counter.getCoveredCount());
153	}
154
155	private XMLCoverageWriter() {
156	}
157
158}
159