Jacoco has a missing branch on a safe call with an elvis operator in Kotlin

Viewed 88

Here's some code:

data class House(val line1: String)
data class Street(val house: House)
fun mapCheck(key : String) : House {

    val map = mapOf("A" to Street(House("10 London Road")))

    val street = map[key]
    return street?.house ?: throw IllegalArgumentException("unknown key")

}

and here's a test for it (using Kotest and Junit 5)

 @Test
fun mapTest() {
    val factory = dpsServiceFactory()
    factory.mapCheck("A").line1 shouldBe "10 London Road"
    shouldThrow<java.lang.IllegalArgumentException> { factory.mapCheck("V")  }
}

For this line return street?.house ?: throw IllegalArgumentException("unknown key") my jacoco coverage report says I only have 3 out of 4 conditions covered.

I'm confused by this. I can only see two conditions, the two I have catered for in the test. What's the condition I'm not testing for ?

Update - this only occurs in Kotlin 1.7.10, Jacoco reports full coverage in Kotlin 1.6.10.

1 Answers

I have tested your code with JaCoCo: 0.8.8, Kotest: 5.1.0, Kotlin: 1.6.10, JDK: 11.0.12. The report indicates that all 4 branches covered with 100%. Your test should cover all cases. I don't know why our results differ.

JaCoCo Branches

"JaCoCo also calculates branch coverage for all if and switch statements. This metric counts the total number of such branches in a method and determines the number of executed or missed branches."

https://www.eclemma.org/jacoco/trunk/doc/counters.html

*Your code under test is *

return street?.house ?: throw IllegalArgumentException("unknown key")

When we decompile it, it would be like the code as follows.

if (street != null) { // Branch (1)
     House var10000 = street.getHouse();
     if (var10000 != null) { // Branch (3)
            return var10000;
     } 
     else { // Branch (4)
     }
}
else { // Branch (2)
}

throw (Throwable)(new IllegalArgumentException("unknown key"));

JaCoCo counts all branches and all missed branches. Empty else branches are not considered missed.

Related