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