1 /******************************************************************************* 2 * Copyright (c) 2009, 2018 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 16 import org.jacoco.core.analysis.IBundleCoverage; 17 import org.jacoco.core.analysis.IClassCoverage; 18 import org.jacoco.core.analysis.ICounter; 19 import org.jacoco.core.analysis.ICoverageNode; 20 import org.jacoco.core.analysis.ICoverageNode.CounterEntity; 21 import org.jacoco.core.analysis.ILine; 22 import org.jacoco.core.analysis.IMethodCoverage; 23 import org.jacoco.core.analysis.IPackageCoverage; 24 import org.jacoco.core.analysis.ISourceFileCoverage; 25 import org.jacoco.core.analysis.ISourceNode; 26 27 /** 28 * Serializes coverage data as XML fragments. 29 */ 30 public 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 */ createChild(final XMLElement parent, final String tagname, final String name)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 */ writeBundle(final IBundleCoverage bundle, final XMLElement element)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 writePackage(final IPackageCoverage p, final XMLElement parent)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 writeClass(final IClassCoverage c, final XMLElement parent)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 writeMethod(final IMethodCoverage m, final XMLElement parent)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 writeSourceFile(final ISourceFileCoverage s, final XMLElement parent)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 */ writeCounters(final ICoverageNode node, final XMLElement parent)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 writeLines(final ISourceNode source, final XMLElement parent)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 writeCounter(final XMLElement element, final String missedattr, final String coveredattr, final ICounter counter)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 XMLCoverageWriter()155 private XMLCoverageWriter() { 156 } 157 158 } 159