Kotlin / kotlinx-kover

Apache License 2.0
1.37k stars 53 forks source link

Reified T - Invalid Code Coverage #638

Open gibarrola-mdt opened 5 months ago

gibarrola-mdt commented 5 months ago

Kover 0.8.1 and previous versions are incorrectly calculating the branch % for some reified extensions. Below is a snippet on how to reproduce the observed error:

Internal Function:

internal inline fun <reified T> sizeOf() : Int where T : Number =
    when(T::class)
    {
       Byte::class -> Byte.SIZE_BYTES
       Short::class -> Short.SIZE_BYTES
       Int::class -> Int.SIZE_BYTES
       Long::class -> Long.SIZE_BYTES
       Float::class -> Float.SIZE_BYTES
       Double::class -> Double.SIZE_BYTES
       else -> throw Exception("Unsupported type")
    }

Unit Test - results in partial "Branch, %" coverage although the "Instruction, %" is 100%:

@Test
fun sizeOfTest() {
    assertEquals(1, sizeOf<Byte>())
    assertEquals(2, sizeOf<Short>())
    assertEquals(4, sizeOf<Int>())
    assertEquals(8, sizeOf<Long>())
    assertEquals(4, sizeOf<Float>())
    assertEquals(8, sizeOf<Double>())

    assertFailsWith<Exception> {
       sizeOf<InvalidNumberClass>()
    }
}

private class InvalidNumberClass(private val number: Number): Number() {
    override fun toByte() = number.toByte()
    override fun toShort() = number.toShort()
    override fun toInt() = number.toInt()
    override fun toLong() = number.toLong()
    override fun toFloat() = number.toFloat()
    override fun toDouble(): Double = number.toDouble()
}

image

Environment

shanshin commented 5 months ago

@zuevmaxim, locally reproduced

Image

zuevmaxim commented 5 months ago

@shanshin For the last inlined call, the compiler replaced previously used IFEQ with IFNE instruction, so the coverage agent tracks the first branch as covered twice, and the second one as not covered at all.