XMLReportNodeHandler.java
1/*******************************************************************************
2 * Copyright (c) 2009, 2010 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 * Brock Janiczak - initial API and implementation
10 * Marc R. Hoffmann - generalized structure, line info
11 *
12 * $Id: $
13 *******************************************************************************/
14package org.jacoco.report.xml;
15
16import java.io.IOException;
17
18import org.jacoco.core.analysis.ICounter;
19import org.jacoco.core.analysis.ICoverageNode;
20import org.jacoco.core.analysis.ILines;
21import org.jacoco.core.analysis.MethodCoverage;
22import org.jacoco.core.analysis.ICoverageNode.CounterEntity;
23import org.jacoco.core.analysis.ICoverageNode.ElementType;
24import org.jacoco.report.IReportVisitor;
25import org.jacoco.report.ISourceFileLocator;
26
27/**
28 * Report visitor that transforms the report structure into XML elements.
29 *
30 * @author Brock Janiczak
31 * @version $Revision: $
32 */
33class XMLReportNodeHandler implements IReportVisitor {
34
35 protected final XMLElement element;
36
37 protected final ICoverageNode node;
38
39 /**
40 * New handler for the given coverage node.
41 *
42 * @param element
43 * XML-Element representing this coverage node. The start tag
44 * must not be closed yet to allow adding additional attributes.
45 * @param node
46 * corresponding coverage node
47 * @throws IOException
48 * in case of problems with the underlying writer
49 */
50 public XMLReportNodeHandler(final XMLElement element,
51 final ICoverageNode node) throws IOException {
52 this.element = element;
53 this.node = node;
54 element.attr("name", node.getName());
55 }
56
57 public IReportVisitor visitChild(final ICoverageNode node)
58 throws IOException {
59 final ElementType type = node.getElementType();
60 switch (type) {
61 case GROUP:
62 case BUNDLE:
63 return new XMLReportNodeHandler(element.element("group"), node);
64 case PACKAGE:
65 return new XMLReportNodeHandler(element.element("package"), node);
66 case CLASS:
67 return new XMLReportNodeHandler(element.element("class"), node);
68 case METHOD:
69 final XMLElement methodChild = element.element("method");
70 methodChild.attr("desc", ((MethodCoverage) node).getDesc());
71 return new XMLReportNodeHandler(methodChild, node);
72 case SOURCEFILE:
73 return new XMLReportNodeHandler(element.element("sourcefile"), node) {
74 @Override
75 public void visitEnd(final ISourceFileLocator sourceFileLocator)
76 throws IOException {
77 writeLines(node.getLines(), element);
78 super.visitEnd(sourceFileLocator);
79 }
80
81 };
82 }
83 return IReportVisitor.NOP;
84 }
85
86 public void visitEnd(final ISourceFileLocator sourceFileLocator)
87 throws IOException {
88 for (final CounterEntity counterEntity : CounterEntity.values()) {
89 createCounterElement(counterEntity);
90 }
91 this.element.close();
92 }
93
94 private void createCounterElement(final CounterEntity counterEntity)
95 throws IOException {
96 final ICounter counter = node.getCounter(counterEntity);
97 if (counter.getTotalCount() > 0) {
98 final XMLElement counterNode = this.element.element("counter");
99 counterNode.attr("type", counterEntity.name());
100 counterNode.attr("covered", counter.getCoveredCount());
101 counterNode.attr("missed", counter.getMissedCount());
102 counterNode.close();
103 }
104 }
105
106 private void writeLines(final ILines lines, final XMLElement parent)
107 throws IOException {
108 final int last = lines.getLastLine();
109 for (int nr = lines.getFirstLine(); nr <= last; nr++) {
110 final byte status = lines.getStatus(nr);
111 if (status != ILines.NO_CODE) {
112 final XMLElement line = parent.element("line");
113 line.attr("nr", nr);
114 switch (status) {
115 case ILines.NOT_COVERED:
116 line.attr("status", "N");
117 break;
118 case ILines.PARTLY_COVERED:
119 line.attr("status", "P");
120 break;
121 case ILines.FULLY_COVERED:
122 line.attr("status", "F");
123 break;
124 }
125 }
126 }
127 }
128
129}