1 /*******************************************************************************
2  * Copyright (c) 2009, 2019 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  *******************************************************************************/
12 package org.jacoco.report.internal.xml;
13 
14 import java.io.IOException;
15 import java.io.OutputStream;
16 
17 import org.jacoco.core.analysis.IClassCoverage;
18 import org.jacoco.core.analysis.ICounter;
19 import org.jacoco.core.analysis.ICoverageNode.CounterEntity;
20 import org.jacoco.core.analysis.ILine;
21 import org.jacoco.core.analysis.IMethodCoverage;
22 import org.jacoco.core.data.SessionInfo;
23 
24 /**
25  * A {@link XMLElement} with utility methods to create JaCoCo XML reports.
26  */
27 public class ReportElement extends XMLElement {
28 
29 	private static final String PUBID = "-//JACOCO//DTD Report 1.1//EN";
30 
31 	private static final String SYSTEM = "report.dtd";
32 
33 	/**
34 	 * Creates a <code>report</code> root element for a XML report.
35 	 *
36 	 * @param name
37 	 *            value for the name attribute
38 	 * @param encoding
39 	 *            character encoding used for output
40 	 * @param output
41 	 *            output stream will be closed if the root element is closed
42 	 * @throws IOException
43 	 *             in case of problems with the underlying output
44 	 */
ReportElement(final String name, final OutputStream output, final String encoding)45 	public ReportElement(final String name, final OutputStream output,
46 			final String encoding) throws IOException {
47 		super("report", PUBID, SYSTEM, true, encoding, output);
48 		attr("name", name);
49 	}
50 
ReportElement(final String name, final ReportElement parent)51 	private ReportElement(final String name, final ReportElement parent)
52 			throws IOException {
53 		super(name, parent);
54 	}
55 
56 	@Override
element(final String name)57 	public ReportElement element(final String name) throws IOException {
58 		return new ReportElement(name, this);
59 	}
60 
namedElement(final String elementName, final String name)61 	private ReportElement namedElement(final String elementName,
62 			final String name) throws IOException {
63 		final ReportElement element = element(elementName);
64 		element.attr("name", name);
65 		return element;
66 	}
67 
68 	/**
69 	 * Creates a 'sessioninfo' element.
70 	 *
71 	 * @param info
72 	 *            info object to write out
73 	 * @throws IOException
74 	 *             in case of problems with the underlying output
75 	 */
sessioninfo(final SessionInfo info)76 	public void sessioninfo(final SessionInfo info) throws IOException {
77 		final ReportElement sessioninfo = element("sessioninfo");
78 		sessioninfo.attr("id", info.getId());
79 		sessioninfo.attr("start", info.getStartTimeStamp());
80 		sessioninfo.attr("dump", info.getDumpTimeStamp());
81 	}
82 
83 	/**
84 	 * Creates a 'group' element.
85 	 *
86 	 * @param name
87 	 *            value for the name attribute
88 	 * @return 'group' element
89 	 * @throws IOException
90 	 *             in case of problems with the underlying output
91 	 */
group(final String name)92 	public ReportElement group(final String name) throws IOException {
93 		return namedElement("group", name);
94 	}
95 
96 	/**
97 	 * Creates a 'package' element.
98 	 *
99 	 * @param name
100 	 *            value for the name attribute
101 	 * @return 'package' element
102 	 * @throws IOException
103 	 *             in case of problems with the underlying output
104 	 */
packageElement(final String name)105 	public ReportElement packageElement(final String name) throws IOException {
106 		return namedElement("package", name);
107 	}
108 
109 	/**
110 	 * Creates a 'class' element.
111 	 *
112 	 * @param coverage
113 	 *            class coverage node to write out
114 	 * @return 'class' element
115 	 * @throws IOException
116 	 *             in case of problems with the underlying output
117 	 */
classElement(final IClassCoverage coverage)118 	public ReportElement classElement(final IClassCoverage coverage)
119 			throws IOException {
120 		final ReportElement element = namedElement("class", coverage.getName());
121 		element.attr("sourcefilename", coverage.getSourceFileName());
122 		return element;
123 	}
124 
125 	/**
126 	 * Creates a 'method' element.
127 	 *
128 	 * @param coverage
129 	 *            method coverage node to write out
130 	 * @return 'method' element
131 	 * @throws IOException
132 	 *             in case of problems with the underlying output
133 	 */
method(final IMethodCoverage coverage)134 	public ReportElement method(final IMethodCoverage coverage)
135 			throws IOException {
136 		final ReportElement element = namedElement("method",
137 				coverage.getName());
138 		element.attr("desc", coverage.getDesc());
139 		final int line = coverage.getFirstLine();
140 		if (line != -1) {
141 			element.attr("line", line);
142 		}
143 		return element;
144 	}
145 
146 	/**
147 	 * Creates a 'sourcefile' element.
148 	 *
149 	 * @param name
150 	 *            value for the name attribute
151 	 * @return 'sourcefile' element
152 	 * @throws IOException
153 	 *             in case of problems with the underlying output
154 	 */
sourcefile(final String name)155 	public ReportElement sourcefile(final String name) throws IOException {
156 		return namedElement("sourcefile", name);
157 	}
158 
159 	/**
160 	 * Creates a 'line' element.
161 	 *
162 	 * @param nr
163 	 *            line number
164 	 * @param line
165 	 *            line object to write out
166 	 *
167 	 * @throws IOException
168 	 *             in case of problems with the underlying output
169 	 */
line(final int nr, final ILine line)170 	public void line(final int nr, final ILine line) throws IOException {
171 		final ReportElement element = element("line");
172 		element.attr("nr", nr);
173 		counterAttributes(element, "mi", "ci", line.getInstructionCounter());
174 		counterAttributes(element, "mb", "cb", line.getBranchCounter());
175 	}
176 
177 	/**
178 	 * Creates a 'counter' element.
179 	 *
180 	 * @param counterEntity
181 	 *            entity of this counter
182 	 *
183 	 * @param counter
184 	 *            counter object to write out
185 	 *
186 	 * @throws IOException
187 	 *             in case of problems with the underlying output
188 	 */
counter(final CounterEntity counterEntity, final ICounter counter)189 	public void counter(final CounterEntity counterEntity,
190 			final ICounter counter) throws IOException {
191 		final ReportElement counterNode = element("counter");
192 		counterNode.attr("type", counterEntity.name());
193 		counterAttributes(counterNode, "missed", "covered", counter);
194 	}
195 
counterAttributes(final XMLElement element, final String missedattr, final String coveredattr, final ICounter counter)196 	private static void counterAttributes(final XMLElement element,
197 			final String missedattr, final String coveredattr,
198 			final ICounter counter) throws IOException {
199 		element.attr(missedattr, counter.getMissedCount());
200 		element.attr(coveredattr, counter.getCoveredCount());
201 	}
202 
203 }
204