blob: be326eca5e0099bc2daa53bd03e0c825f4dd76b3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2018 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.internal.xml;
import java.io.IOException;
import org.jacoco.core.analysis.IBundleCoverage;
import org.jacoco.core.analysis.IClassCoverage;
import org.jacoco.core.analysis.ICounter;
import org.jacoco.core.analysis.ICoverageNode;
import org.jacoco.core.analysis.ICoverageNode.CounterEntity;
import org.jacoco.core.analysis.ILine;
import org.jacoco.core.analysis.IMethodCoverage;
import org.jacoco.core.analysis.IPackageCoverage;
import org.jacoco.core.analysis.ISourceFileCoverage;
import org.jacoco.core.analysis.ISourceNode;
/**
* Serializes coverage data as XML fragments.
*/
public final class XMLCoverageWriter {
/**
* Creates a child element with a name attribute.
*
* @param parent
* parent element
* @param tagname
* name of the child tag
* @param name
* value of the name attribute
* @return child element
* @throws IOException
* if XML can't be written to the underlying output
*
*/
public static XMLElement createChild(final XMLElement parent,
final String tagname, final String name) throws IOException {
final XMLElement child = parent.element(tagname);
child.attr("name", name);
return child;
}
/**
* Writes the structure of a given bundle.
*
* @param bundle
* bundle coverage data
* @param element
* container element for the bundle data
* @throws IOException
* if XML can't be written to the underlying output
*/
public static void writeBundle(final IBundleCoverage bundle,
final XMLElement element) throws IOException {
for (final IPackageCoverage p : bundle.getPackages()) {
writePackage(p, element);
}
writeCounters(bundle, element);
}
private static void writePackage(final IPackageCoverage p,
final XMLElement parent) throws IOException {
final XMLElement element = createChild(parent, "package", p.getName());
for (final IClassCoverage c : p.getClasses()) {
writeClass(c, element);
}
for (final ISourceFileCoverage s : p.getSourceFiles()) {
writeSourceFile(s, element);
}
writeCounters(p, element);
}
private static void writeClass(final IClassCoverage c,
final XMLElement parent) throws IOException {
final XMLElement element = createChild(parent, "class", c.getName());
for (final IMethodCoverage m : c.getMethods()) {
writeMethod(m, element);
}
writeCounters(c, element);
}
private static void writeMethod(final IMethodCoverage m,
final XMLElement parent) throws IOException {
final XMLElement element = createChild(parent, "method", m.getName());
element.attr("desc", m.getDesc());
final int line = m.getFirstLine();
if (line != -1) {
element.attr("line", line);
}
writeCounters(m, element);
}
private static void writeSourceFile(final ISourceFileCoverage s,
final XMLElement parent) throws IOException {
final XMLElement element = createChild(parent, "sourcefile",
s.getName());
writeLines(s, element);
writeCounters(s, element);
}
/**
* Writes all non-zero counters of the given node.
*
* @param node
* node to retrieve counters from
* @param parent
* container for the counter elements
* @throws IOException
* if XML can't be written to the underlying output
*/
public static void writeCounters(final ICoverageNode node,
final XMLElement parent) throws IOException {
for (final CounterEntity counterEntity : CounterEntity.values()) {
final ICounter counter = node.getCounter(counterEntity);
if (counter.getTotalCount() > 0) {
final XMLElement counterNode = parent.element("counter");
counterNode.attr("type", counterEntity.name());
writeCounter(counterNode, "missed", "covered", counter);
counterNode.close();
}
}
}
private static void writeLines(final ISourceNode source,
final XMLElement parent) throws IOException {
final int last = source.getLastLine();
for (int nr = source.getFirstLine(); nr <= last; nr++) {
final ILine line = source.getLine(nr);
if (line.getStatus() != ICounter.EMPTY) {
final XMLElement element = parent.element("line");
element.attr("nr", nr);
writeCounter(element, "mi", "ci", line.getInstructionCounter());
writeCounter(element, "mb", "cb", line.getBranchCounter());
}
}
}
private static void writeCounter(final XMLElement element,
final String missedattr, final String coveredattr,
final ICounter counter) throws IOException {
element.attr(missedattr, counter.getMissedCount());
element.attr(coveredattr, counter.getCoveredCount());
}
private XMLCoverageWriter() {
}
}