I using Jacoco 0.8.6 and I have an enum with 3 values.
I have this when shown on the image below and I have a test for each branch but Jacoco is still saying that I am missing a branch, also my var is non-null. What is wrong?

I using Jacoco 0.8.6 and I have an enum with 3 values.
I have this when shown on the image below and I have a test for each branch but Jacoco is still saying that I am missing a branch, also my var is non-null. What is wrong?

JaCoCo performs analysis of bytecode. For Example.kt
object Example {
var type: Type = Type.SETUP_LOGIN
set(value) {
field = value
when (value) {
Type.SETUP_LOGIN -> nop()
Type.CHANGE_PIN -> nop()
Type.CHANGE_FINGERPRINT -> nop()
}
}
fun nop() {
}
enum class Type {
SETUP_LOGIN, CHANGE_PIN, CHANGE_FINGERPRINT
}
}
compiled by
kotlinc-1.4.30/bin/kotlinc Example.kt
execution of
java -v -p Example.class
shows following bytecode for setType method
public final void setType(Example$Type);
descriptor: (LExample$Type;)V
flags: ACC_PUBLIC, ACC_FINAL
Code:
stack=2, locals=2, args_size=2
0: aload_1
1: ldc #17 // String value
3: invokestatic #23 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
6: aload_1
7: putstatic #11 // Field type:LExample$Type;
10: aload_1
11: getstatic #29 // Field Example$WhenMappings.$EnumSwitchMapping$0:[I
14: swap
15: invokevirtual #35 // Method Example$Type.ordinal:()I
18: iaload
19: tableswitch { // 1 to 3
1: 44
2: 51
3: 58
default: 65
}
44: aload_0
45: invokevirtual #39 // Method nop:()V
48: goto 65
51: aload_0
52: invokevirtual #39 // Method nop:()V
55: goto 65
58: aload_0
59: invokevirtual #39 // Method nop:()V
62: goto 65
65: return
LineNumberTable:
line 4: 6
line 5: 10
line 6: 44
line 7: 51
line 8: 58
line 9: 65
line 10: 65
where as you can see tableswitch has 4 branches and this is exactly what you see in the JaCoCo report.
Looking at such bytecode only (as like JaCoCo does) there is no way to realize that default branch of tableswitch can't be reached - add one more value to enum, without changing anything else, recompile and you'll see exactly the same bytecode for this setType method.
You can use exhaustive
val <T> T.exhaustive: T
get() = this
then
when (value) {
Type.SETUP_LOGIN -> nop()
Type.CHANGE_PIN -> nop()
Type.CHANGE_FINGERPRINT -> nop()
}.exhaustive