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