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}