spekframework / spek

A specification framework for Kotlin
Other
2.23k stars 179 forks source link

Kotlin 1.5.0 - TestSuiteExecutionException testing function with "when" and enum #967

Open ryanelliott-wk opened 3 years ago

ryanelliott-wk commented 3 years ago

Tests fail unexpectedly with a TestSuiteExecutionException after upgrading to Kotlin v1.5.0 using Spek v2.0.15. This happens when using an Enum and a when statement. Here is an example to reproduce:

enum class Letters {
    A,
    B,
    C
}

inline fun <T> doMadLib(letter: Letters, sentenceNeedingNoun: (String) -> T): T =
    when (letter) {
        Letters.A -> sentenceNeedingNoun("apple")
        Letters.B -> sentenceNeedingNoun("banana")
        Letters.C -> sentenceNeedingNoun("carrot")
    }

and the test:

object MadLibTest : Spek({
    test("does the madlib") {
        assertEquals(doMadLib(Letters.A) { "I love $it" }, "I love apple")
    }
})

Which produces this exception:

Click to expand ``` org.gradle.api.internal.tasks.testing.TestSuiteExecutionException: Could not execute test class 'com.myorg.myservice.unit.MadLibTest$1$1$invoke$$inlined$doMadLib$1$wm$MadLibKt$WhenMappings'. at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:53) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33) at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94) at com.sun.proxy.$Proxy2.processTestClass(Unknown Source) at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:119) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182) at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164) at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56) at java.base/java.lang.Thread.run(Thread.java:834) Caused by: java.lang.IncompatibleClassChangeError: com.myorg.myservice.utils.MadLibKt and com.myorg.myservice.unit.MadLibTest$1$1$invoke$$inlined$doMadLib$1$wm$MadLibKt$WhenMappings disagree on InnerClasses attribute at java.base/java.lang.Class.getDeclaringClass0(Native Method) at java.base/java.lang.Class.getEnclosingClass(Class.java:1517) at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.isInnerClass(JUnitPlatformTestClassProcessor.java:104) at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.access$200(JUnitPlatformTestClassProcessor.java:54) at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.execute(JUnitPlatformTestClassProcessor.java:90) at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.execute(JUnitPlatformTestClassProcessor.java:79) at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62) at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51) ... 25 more ```

The function works as expected without any errors when called in the application. It also works just fine in a kotlin-test:

internal class MadLibTest {
    @Test
    fun doesAMadLib() {
        assertEquals(doMadLib(Letters.A) { "I love $it" }, "I love apple")
    }
}

I can convert the when statement to an if statement as a workaround.

raniejade commented 3 years ago

Weird and interesting at the same time. Have you tried disabling the new IR backend compiler?

ryanelliott-wk commented 3 years ago

@raniejade is the IR compiler just for targeting JS? I am using JVM

raniejade commented 3 years ago

@ryanelliott-wk There's an IR backend for JVM as well which was made the default in Kotlin 1.5

ryanelliott-wk commented 3 years ago

I see the same exception with useIR=false

Here are my compiler options:

compileKotlin {
    kotlinOptions {
        useIR = false
    }
}

compileTestKotlin {
    kotlinOptions {
        // Needed for runBlocking test coroutine dispatcher
        freeCompilerArgs += "-Xuse-experimental=kotlin.Experimental"
        freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
        useIR = false
    }
}
ntoskrnl commented 3 years ago

I just run the test you provided with Kotlin 1.5.0 – works fine for me...

raniejade commented 3 years ago

Interesting thanks @ntoskrnl! Maybe some caching issues? Have you tried doing a clean build @ryanelliott-wk ?

ryanelliott-wk commented 3 years ago

Thanks for trying it out @ntoskrnl!

@raniejade I'm still having the issue with a clean build. I'll try to do a more standalone reproduction - maybe there is another dependency somewhere in my project that is contributing to the issue.

rocketraman commented 3 years ago

Likely https://youtrack.jetbrains.com/issue/KT-47475