Home | History | Annotate | Download | only in analysis
      1 /*******************************************************************************
      2  * Copyright (c) 2009, 2018 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  *******************************************************************************/
     12 package org.jacoco.core.analysis;
     13 
     14 import java.util.ArrayList;
     15 import java.util.Collection;
     16 import java.util.Collections;
     17 import java.util.HashMap;
     18 import java.util.Map;
     19 
     20 import org.jacoco.core.internal.analysis.BundleCoverageImpl;
     21 import org.jacoco.core.internal.analysis.SourceFileCoverageImpl;
     22 
     23 /**
     24  * Builder for hierarchical {@link ICoverageNode} structures from single
     25  * {@link IClassCoverage} nodes. The nodes are feed into the builder through its
     26  * {@link ICoverageVisitor} interface. Afterwards the aggregated data can be
     27  * obtained with {@link #getClasses()}, {@link #getSourceFiles()} or
     28  * {@link #getBundle(String)} in the following hierarchy:
     29  *
     30  * <pre>
     31  * {@link IBundleCoverage}
     32  * +-- {@link IPackageCoverage}*
     33  *     +-- {@link IClassCoverage}*
     34  *     +-- {@link ISourceFileCoverage}*
     35  * </pre>
     36  */
     37 public class CoverageBuilder implements ICoverageVisitor {
     38 
     39 	private final Map<String, IClassCoverage> classes;
     40 
     41 	private final Map<String, ISourceFileCoverage> sourcefiles;
     42 
     43 	/**
     44 	 * Create a new builder.
     45 	 *
     46 	 */
     47 	public CoverageBuilder() {
     48 		this.classes = new HashMap<String, IClassCoverage>();
     49 		this.sourcefiles = new HashMap<String, ISourceFileCoverage>();
     50 	}
     51 
     52 	/**
     53 	 * Returns all class nodes currently contained in this builder.
     54 	 *
     55 	 * @return all class nodes
     56 	 */
     57 	public Collection<IClassCoverage> getClasses() {
     58 		return Collections.unmodifiableCollection(classes.values());
     59 	}
     60 
     61 	/**
     62 	 * Returns all source file nodes currently contained in this builder.
     63 	 *
     64 	 * @return all source file nodes
     65 	 */
     66 	public Collection<ISourceFileCoverage> getSourceFiles() {
     67 		return Collections.unmodifiableCollection(sourcefiles.values());
     68 	}
     69 
     70 	/**
     71 	 * Creates a bundle from all nodes currently contained in this bundle.
     72 	 *
     73 	 * @param name
     74 	 *            Name of the bundle
     75 	 * @return bundle containing all classes and source files
     76 	 */
     77 	public IBundleCoverage getBundle(final String name) {
     78 		return new BundleCoverageImpl(name, classes.values(),
     79 				sourcefiles.values());
     80 	}
     81 
     82 	/**
     83 	 * Returns all classes for which execution data does not match.
     84 	 *
     85 	 * @see IClassCoverage#isNoMatch()
     86 	 * @return collection of classes with non-matching execution data
     87 	 */
     88 	public Collection<IClassCoverage> getNoMatchClasses() {
     89 		final Collection<IClassCoverage> result = new ArrayList<IClassCoverage>();
     90 		for (final IClassCoverage c : classes.values()) {
     91 			if (c.isNoMatch()) {
     92 				result.add(c);
     93 			}
     94 		}
     95 		return result;
     96 	}
     97 
     98 	// === IStructureVisitor ===
     99 
    100 	public void visitCoverage(final IClassCoverage coverage) {
    101 		// Only consider classes that actually contain code:
    102 		if (coverage.getInstructionCounter().getTotalCount() > 0) {
    103 			final String name = coverage.getName();
    104 			final IClassCoverage dup = classes.put(name, coverage);
    105 			if (dup != null) {
    106 				if (dup.getId() != coverage.getId()) {
    107 					throw new IllegalStateException(
    108 							"Can't add different class with same name: "
    109 									+ name);
    110 				}
    111 			} else {
    112 				final String source = coverage.getSourceFileName();
    113 				if (source != null) {
    114 					final SourceFileCoverageImpl sourceFile = getSourceFile(
    115 							source, coverage.getPackageName());
    116 					sourceFile.increment(coverage);
    117 				}
    118 			}
    119 		}
    120 	}
    121 
    122 	private SourceFileCoverageImpl getSourceFile(final String filename,
    123 			final String packagename) {
    124 		final String key = packagename + '/' + filename;
    125 		SourceFileCoverageImpl sourcefile = (SourceFileCoverageImpl) sourcefiles
    126 				.get(key);
    127 		if (sourcefile == null) {
    128 			sourcefile = new SourceFileCoverageImpl(filename, packagename);
    129 			sourcefiles.put(key, sourcefile);
    130 		}
    131 		return sourcefile;
    132 	}
    133 
    134 }
    135