JaCoCo 0.8.14 version reduces the test coverage results for switch statement (parameter type String) when used with forEach
JaCoCo version: 0.8.14 JDK version: 25 OS: Mac Tools: Maven Github: https://github.com/Sofiya-Sundaramoorthy/jacoco-0.8.14-switch-statement Brief description: When upgrading the JaCoCo version from 0.8.12 to 0.8.14 to support JDK25 upgrades, I noticed that the test coverage dropped for a switch statement in combination with forEach.
checkData method takes List<String> as parameter which then loops using forEach to pass data to a switch statement
// method
protected String checkData(List<String> datas) {
datas.forEach(data -> {
switch(data) {
case "a" -> System.out.println("first data");
case "b" -> System.out.println("second data");
case "c" -> System.out.println("third data");
default -> System.out.println("default data");
};
});
return null;
};
//testcase
@Test
void testData() {
var application = new SwitchStatementApplication();
var result1 = application.checkData(List.of("a", "b", "c", "d"));
assertNull(result1);
}
The minimal reproducible code is in the github repo https://github.com/Sofiya-Sundaramoorthy/jacoco-0.8.14-switch-statement
Note: The switch statement takes parameter of type String which gives 78% test coverage. However, when passing parameter type of Int the coverage is 100%
Expected behaviour: The combination of forEach + switch (parameter type as String) should produce 100% test coverage
Actual behaviour: The combination of forEach + switch (parameter type as String) produces 78% test coverage
Please refer the screenshots
JaCoCo 0.8.12 with JDK21
JaCoCo 0.8.14 with JDK25
First of all thank you for the reproducer! ❤️
Should be noted that this is not a regression in JaCoCo, but change in javac compiler in JDK 24:
for src/Example.java
import java.util.List;
public class Example {
String checkData(List<String> datas) {
datas.forEach(data -> {
switch(data) {
case "a" -> System.out.println("first data");
case "b" -> System.out.println("second data");
case "c" -> System.out.println("third data");
default -> System.out.println("default data");
};
});
return null;
};
public static void main(String[] args) {
new Example().checkData(List.of("a", "b", "c", "d"));
}
}
using JaCoCo version 0.8.12 execution of
javac --release 21 -g -d classes src/Example.java
java -javaagent:jacoco-0.8.12/lib/jacocoagent.jar -cp classes Example
java -jar jacoco-0.8.12/lib/jacococli.jar \
report jacoco.exec \
--classfiles classes \
--sourcefiles src \
--html report
with javac 23.0.2
produces expected result
All 4 branches covered.
whereas
with javac 24.0.2
produces unexpected result
3 of 14 branches missed.
For these two versions execution of
javap -v -p classes/Example.class
produces two different outputs
LocalVariableTable:
Start Length Slot Name Signature
+ 2 143 1 s0$ Ljava/lang/String;
+ 4 141 2 tmp1$ I
0 146 0 data Ljava/lang/String;
showing change of LocalVariableTable in method lambda$checkData$0 that contains body of the lambda.
Which affects
https://github.com/jacoco/jacoco/blob/2eb248366f0eb63fd964fc7a81804b27229a6edd/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java#L60-L62