CoverageBuilder.java

    1/*******************************************************************************
    2 * Copyright (c) 2009 Mountainminds GmbH & Co. KG and others
    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 String name) {
   90        final boolean[] covered = executionData.getData(id);
   91        final Collection<MethodCoverage> methods = new ArrayList<MethodCoverage>();
   92        final String[] sourcename = new String[1];
   93        return new IClassStructureVisitor() {
   94            public void visitSourceFile(final String name) {
   95                sourcename[0] = name;
   96            }
   97
   98            public IMethodStructureVisitor visitMethodStructure(
   99                    final String name, final String desc, final String signature) {
  100                return createMethodVisitor(name, desc, signature, methods,
  101                        covered);
  102            }
  103
  104            public void visitEnd() {
  105                final ClassCoverage classData = new ClassCoverage(name,
  106                        sourcename[0], methods);
  107                classes.put(Long.valueOf(id), classData);
  108                if (sourcename[0] != null) {
  109                    final SourceFileCoverage sourceFile = getSourceFile(
  110                            sourcename[0], classData.getPackageName());
  111                    sourceFile.increment(classData);
  112                }
  113            }
  114        };
  115    }
  116
  117    private IMethodStructureVisitor createMethodVisitor(final String name,
  118            final String desc, final String signature,
  119            final Collection<MethodCoverage> container, final boolean[] covered) {
  120        final MethodCoverage method = new MethodCoverage(name, desc, signature);
  121        return new IMethodStructureVisitor() {
  122            public void block(final int id, final int instructions,
  123                    final int[] lineNumbers) {
  124                final boolean c = covered == null ? false : covered[id];
  125                method.addBlock(instructions, lineNumbers, c);
  126            }
  127
  128            public void visitEnd() {
  129                container.add(method);
  130            }
  131        };
  132    }
  133
  134    private SourceFileCoverage getSourceFile(final String filename,
  135            final String packagename) {
  136        final String key = packagename + '/' + filename;
  137        SourceFileCoverage sourcefile = sourcefiles.get(key);
  138        if (sourcefile == null) {
  139            sourcefile = new SourceFileCoverage(filename, packagename);
  140            sourcefiles.put(key, sourcefile);
  141        }
  142        return sourcefile;
  143    }
  144
  145}