Skip to content

Commit 3d4e9d0

Browse files
authored
Code Coverage Integration (#95)
* Added jacoco plugin and parser * Coverage reporter impl * Updated coverage report parser * Removing redundant empty line * Refactored the parse function
1 parent a4fcfa6 commit 3d4e9d0

File tree

2 files changed

+202
-0
lines changed

2 files changed

+202
-0
lines changed

pom.xml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,64 @@
226226
</plugins>
227227
</build>
228228
</profile>
229+
<profile>
230+
<id>code-coverage</id>
231+
<activation>
232+
<property>
233+
<name>jacoco</name>
234+
</property>
235+
</activation>
236+
<build>
237+
<plugins>
238+
<plugin>
239+
<groupId>org.jacoco</groupId>
240+
<artifactId>jacoco-maven-plugin</artifactId>
241+
<version>0.7.9</version>
242+
<executions>
243+
<execution>
244+
<id>pre-unit-test</id>
245+
<goals>
246+
<goal>prepare-agent</goal>
247+
</goals>
248+
</execution>
249+
<execution>
250+
<id>post-unit-test</id>
251+
<phase>test</phase>
252+
<goals>
253+
<goal>report</goal>
254+
</goals>
255+
<configuration>
256+
<!-- Sets the path to the file which contains the execution data. -->
257+
<dataFile>target/jacoco.exec</dataFile>
258+
<!-- Sets the output directory for the code coverage report. -->
259+
<outputDirectory>target/jacoco-ut</outputDirectory>
260+
</configuration>
261+
</execution>
262+
</executions>
263+
</plugin>
264+
<plugin>
265+
<groupId>org.codehaus.mojo</groupId>
266+
<artifactId>exec-maven-plugin</artifactId>
267+
<version>1.6.0</version>
268+
<executions>
269+
<execution>
270+
<phase>test</phase>
271+
<goals>
272+
<goal>java</goal>
273+
</goals>
274+
</execution>
275+
</executions>
276+
<configuration>
277+
<mainClass>com.google.firebase.CodeCoverageReporter</mainClass>
278+
<arguments>
279+
<argument>target/jacoco-ut/jacoco.csv</argument>
280+
</arguments>
281+
<classpathScope>test</classpathScope>
282+
</configuration>
283+
</plugin>
284+
</plugins>
285+
</build>
286+
</profile>
229287
</profiles>
230288

231289
<build>
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/*
2+
* Copyright 2017 Google Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.firebase;
18+
19+
import static com.google.common.base.Preconditions.checkArgument;
20+
21+
import com.google.common.base.Strings;
22+
import java.io.BufferedReader;
23+
import java.io.FileReader;
24+
import java.io.IOException;
25+
import java.util.Collection;
26+
import java.util.Map;
27+
import java.util.TreeMap;
28+
29+
/**
30+
* A simple executable for parsing the code coverage reports produced by Jacoco.
31+
*/
32+
public class CodeCoverageReporter {
33+
34+
public static void main(String[] args) {
35+
if (args.length != 1) {
36+
System.err.println("Invalid invocation of the CodeCoverageReporter.");
37+
System.out.println("Usage: CodeCoverageReporter <path>");
38+
return;
39+
}
40+
41+
System.out.println();
42+
System.out.println("-------------------------------------------------------------------------");
43+
System.out.println(" Jacoco Coverage Report");
44+
System.out.println("-------------------------------------------------------------------------");
45+
46+
Map<String, CoverageInfo> coverageData = new TreeMap<>();
47+
try (BufferedReader reader = new BufferedReader(new FileReader(args[0]))) {
48+
String line;
49+
while ((line = reader.readLine()) != null) {
50+
if (line.startsWith("GROUP")) {
51+
// Skip the header line
52+
continue;
53+
}
54+
CoverageInfo info = CoverageInfo.parse(line);
55+
String packageName = info.getPackage();
56+
CoverageInfo existing = coverageData.get(packageName);
57+
if (existing != null) {
58+
coverageData.put(packageName, existing.aggregate(info, packageName));
59+
} else {
60+
coverageData.put(packageName, info);
61+
}
62+
}
63+
printStats(coverageData);
64+
} catch (IOException e) {
65+
e.printStackTrace();
66+
}
67+
}
68+
69+
private static void printStats(Map<String, CoverageInfo> coverageData) {
70+
int titleLength = findLongest(coverageData.keySet()) + 1;
71+
CoverageInfo overall = null;
72+
for (Map.Entry<String, CoverageInfo> entry : coverageData.entrySet()) {
73+
CoverageInfo info = entry.getValue();
74+
if (overall == null) {
75+
overall = info;
76+
} else {
77+
overall = overall.aggregate(info, "Overall");
78+
}
79+
System.out.println(info.getFormattedString(titleLength));
80+
}
81+
82+
if (overall != null) {
83+
System.out.println();
84+
System.out.println(overall.getFormattedString(titleLength));
85+
}
86+
System.out.println();
87+
}
88+
89+
private static int findLongest(Collection<String> keys) {
90+
int longest = 0;
91+
for (String key : keys) {
92+
if (key.length() > longest) {
93+
longest = key.length();
94+
}
95+
}
96+
return longest;
97+
}
98+
99+
private static class CoverageInfo {
100+
101+
private final String pkg;
102+
private final long instructionsCovered;
103+
private final long totalInstructions;
104+
105+
CoverageInfo(String pkg, long instructionsCovered, long totalInstructions) {
106+
this.pkg = pkg;
107+
this.instructionsCovered = instructionsCovered;
108+
this.totalInstructions = totalInstructions;
109+
}
110+
111+
static CoverageInfo parse(String line) {
112+
checkArgument(!Strings.isNullOrEmpty(line));
113+
String[] segments = line.split(",");
114+
return new CoverageInfo(
115+
segments[1],
116+
Long.parseLong(segments[4]),
117+
Long.parseLong(segments[3]) + Long.parseLong(segments[4]));
118+
}
119+
120+
String getPackage() {
121+
return pkg;
122+
}
123+
124+
private double getCoverage() {
125+
if (totalInstructions == 0) {
126+
return 0;
127+
}
128+
return ((double) instructionsCovered / totalInstructions) * 100.0;
129+
}
130+
131+
CoverageInfo aggregate(CoverageInfo other, String name) {
132+
return new CoverageInfo(
133+
name,
134+
this.instructionsCovered + other.instructionsCovered,
135+
this.totalInstructions + other.totalInstructions);
136+
}
137+
138+
String getFormattedString(int titleLength) {
139+
String ratio = this.instructionsCovered + "/" + this.totalInstructions;
140+
return String.format(
141+
"%-" + titleLength + "s %12s %8.2f%%", this.pkg, ratio, this.getCoverage());
142+
}
143+
}
144+
}

0 commit comments

Comments
 (0)