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}