CoverageBuilder.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 *    Marc R. Hoffmann - initial API and implementation
   10 *    
   11 * $Id: $
   12 *******************************************************************************/
   13package org.jacoco.core.analysis;
   14
   15import java.util.ArrayList;
   16import java.util.Collection;
   17import java.util.Collections;
   18import java.util.HashMap;
   19import java.util.Map;
   20
   21import org.jacoco.core.data.ExecutionDataStore;
   22import org.jacoco.core.data.IClassStructureVisitor;
   23import org.jacoco.core.data.IMethodStructureVisitor;
   24import org.jacoco.core.data.IStructureVisitor;
   25
   26/**
   27 * Builder for hierarchical {@link ICoverageNode} structures based on execution
   28 * and structure information. The builder is constructed for a given
   29 * {@link ExecutionDataStore} and then feed with class structure information
   30 * through its {@link IStructureVisitor} interface. Afterwards the collected
   31 * data can be obtained with {@link #getClasses()}, {@link #getSourceFiles()} or
   32 * {@link #getBundle(String)}.
   33 * 
   34 * @author Marc R. Hoffmann
   35 * @version $Revision: $
   36 */
   37public class CoverageBuilder implements IStructureVisitor {
   38
   39    private final ExecutionDataStore executionData;
   40
   41    private final Map<Long, ClassCoverage> classes;
   42
   43    private final Map<String, SourceFileCoverage> sourcefiles;
   44
   45    /**
   46     * Create a new builder based on the given execution data.
   47     * 
   48     * @param executionData
   49     *            execution data
   50     */
   51    public CoverageBuilder(final ExecutionDataStore executionData) {
   52        this.executionData = executionData;
   53        this.classes = new HashMap<Long, ClassCoverage>();
   54        this.sourcefiles = new HashMap<String, SourceFileCoverage>();
   55    }
   56
   57    /**
   58     * Returns all class nodes currently contained in this builder.
   59     * 
   60     * @return all class nodes
   61     */
   62    public Collection<ClassCoverage> getClasses() {
   63        return Collections.unmodifiableCollection(classes.values());
   64    }
   65
   66    /**
   67     * Returns all source file nodes currently contained in this builder.
   68     * 
   69     * @return all source file nodes
   70     */
   71    public Collection<SourceFileCoverage> getSourceFiles() {
   72        return Collections.unmodifiableCollection(sourcefiles.values());
   73    }
   74
   75    /**
   76     * Creates a bundle from all nodes currently contained in this bundle.
   77     * 
   78     * @param name
   79     *            Name of the bundle
   80     * @return bundle containing all classes and source files
   81     */
   82    public BundleCoverage getBundle(final String name) {
   83        return new BundleCoverage(name, classes.values(), sourcefiles.values());
   84    }
   85
   86    // === IStructureVisitor ===
   87
   88    public IClassStructureVisitor visitClassStructure(final long id) {
   89        final boolean[] covered = executionData.getData(id);
   90        final Collection<MethodCoverage> methods = new ArrayList<MethodCoverage>();
   91        return new IClassStructureVisitor() {
   92            String name;
   93            String signature;
   94            String superName;
   95            String[] interfaces;
   96            String sourcename;
   97
   98            public void visit(final String name, final String signature,
   99                    final String superName, final String[] interfaces) {
  100                this.name = name;
  101                this.signature = signature;
  102                this.superName = superName;
  103                this.interfaces = interfaces;
  104            }
  105
  106            public void visitSourceFile(final String name) {
  107                sourcename = name;
  108            }
  109
  110            public IMethodStructureVisitor visitMethodStructure(
  111                    final String name, final String desc, final String signature) {
  112                return createMethodVisitor(name, desc, signature, methods,
  113                        covered);
  114            }
  115
  116            public void visitEnd() {
  117                final ClassCoverage classData = new ClassCoverage(name,
  118                        signature, superName, interfaces, sourcename, methods);
  119                // Only consider classes that actually contain code:
  120                if (classData.getInstructionCounter().getTotalCount() > 0) {
  121                    classes.put(Long.valueOf(id), classData);
  122                    if (sourcename != null) {
  123                        final SourceFileCoverage sourceFile = getSourceFile(
  124                                sourcename, classData.getPackageName());
  125                        sourceFile.increment(classData);
  126                    }
  127                }
  128            }
  129        };
  130    }
  131
  132    private IMethodStructureVisitor createMethodVisitor(final String name,
  133            final String desc, final String signature,
  134            final Collection<MethodCoverage> container, final boolean[] covered) {
  135        final MethodCoverage method = new MethodCoverage(name, desc, signature);
  136        return new IMethodStructureVisitor() {
  137            public void block(final int id, final int instructions,
  138                    final int[] lineNumbers) {
  139                final boolean c = covered == null ? false : covered[id];
  140                method.addBlock(instructions, lineNumbers, c);
  141            }
  142
  143            public void visitEnd() {
  144                container.add(method);
  145            }
  146        };
  147    }
  148
  149    private SourceFileCoverage getSourceFile(final String filename,
  150            final String packagename) {
  151        final String key = packagename + '/' + filename;
  152        SourceFileCoverage sourcefile = sourcefiles.get(key);
  153        if (sourcefile == null) {
  154            sourcefile = new SourceFileCoverage(filename, packagename);
  155            sourcefiles.put(key, sourcefile);
  156        }
  157        return sourcefile;
  158    }
  159
  160}