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