Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.12.5 every fails when kotlin.time.Duration should be returned #869

Closed
eliasmueller opened this issue Jul 28, 2022 · 14 comments
Closed

1.12.5 every fails when kotlin.time.Duration should be returned #869

eliasmueller opened this issue Jul 28, 2022 · 14 comments

Comments

@eliasmueller
Copy link

eliasmueller commented Jul 28, 2022

Prerequisites

Please answer the following questions for yourself before submitting an issue.

  • [ x] I am running the latest version
  • [ x] I checked the documentation and found no answer
  • [ x] I checked to make sure that this issue has not already been filed

Expected Behavior

Calling the every method succeeds and returns the correct an object of kotlin.time.Duration when called

Current Behavior

The method calls fails and throws a java.lang.ClassCastException

Failure Information (for bugs)

Steps to Reproduce

In mockk 1.12.4 I was able to use the every mocking method and return a value on a method call from a method that returns kotlin.time.Duration
1.12.5 seems to have broken this and tries to cast the kotlin.time.Duration into a java.lang.Long unsuccessfully.

Code below.

Context

Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.

  • MockK version: 1.12.5
  • OS: macOS X 12.4 (x86)
  • Kotlin version: 1.7.10
  • JDK version: 17
  • JUnit version: JUnit Jupiter 5.8.2
  • Type of test: unit test

Stack trace

/Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home/bin/java -ea -Didea.test.cyclic.buffer.size=1048576 -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=49646:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Users/Elias/.m2/repository/org/junit/platform/junit-platform-launcher/1.8.2/junit-platform-launcher-1.8.2.jar:/Users/Elias/.m2/repository/org/junit/vintage/junit-vintage-engine/5.8.2/junit-vintage-engine-5.8.2.jar:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar:/Applications/IntelliJ IDEA.app/Contents/plugins/junit/lib/junit5-rt.jar:/Applications/IntelliJ IDEA.app/Contents/plugins/junit/lib/junit-rt.jar:/Users/Elias/Desktop/duration-mock-error/target/test-classes:/Users/Elias/Desktop/duration-mock-error/target/classes:/Users/Elias/.m2/repository/org/jetbrains/kotlin/kotlin-test-junit/1.7.10/kotlin-test-junit-1.7.10.jar:/Users/Elias/.m2/repository/org/jetbrains/kotlin/kotlin-test/1.7.10/kotlin-test-1.7.10.jar:/Users/Elias/.m2/repository/junit/junit/4.13.2/junit-4.13.2.jar:/Users/Elias/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar:/Users/Elias/.m2/repository/org/junit/jupiter/junit-jupiter-engine/5.8.2/junit-jupiter-engine-5.8.2.jar:/Users/Elias/.m2/repository/org/junit/platform/junit-platform-engine/1.8.2/junit-platform-engine-1.8.2.jar:/Users/Elias/.m2/repository/org/opentest4j/opentest4j/1.2.0/opentest4j-1.2.0.jar:/Users/Elias/.m2/repository/org/junit/platform/junit-platform-commons/1.8.2/junit-platform-commons-1.8.2.jar:/Users/Elias/.m2/repository/org/junit/jupiter/junit-jupiter-api/5.8.2/junit-jupiter-api-5.8.2.jar:/Users/Elias/.m2/repository/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar:/Users/Elias/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.7.10/kotlin-stdlib-jdk8-1.7.10.jar:/Users/Elias/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib/1.7.10/kotlin-stdlib-1.7.10.jar:/Users/Elias/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-common/1.7.10/kotlin-stdlib-common-1.7.10.jar:/Users/Elias/.m2/repository/org/jetbrains/annotations/13.0/annotations-13.0.jar:/Users/Elias/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.7.10/kotlin-stdlib-jdk7-1.7.10.jar:/Users/Elias/.m2/repository/io/mockk/mockk/1.12.5/mockk-1.12.5.jar:/Users/Elias/.m2/repository/io/mockk/mockk-common/1.12.5/mockk-common-1.12.5.jar:/Users/Elias/.m2/repository/io/mockk/mockk-dsl/1.12.5/mockk-dsl-1.12.5.jar:/Users/Elias/.m2/repository/io/mockk/mockk-dsl-jvm/1.12.5/mockk-dsl-jvm-1.12.5.jar:/Users/Elias/.m2/repository/io/mockk/mockk-agent-jvm/1.12.5/mockk-agent-jvm-1.12.5.jar:/Users/Elias/.m2/repository/io/mockk/mockk-agent-api/1.12.5/mockk-agent-api-1.12.5.jar:/Users/Elias/.m2/repository/io/mockk/mockk-agent-common/1.12.5/mockk-agent-common-1.12.5.jar:/Users/Elias/.m2/repository/org/objenesis/objenesis/3.2/objenesis-3.2.jar:/Users/Elias/.m2/repository/net/bytebuddy/byte-buddy/1.12.6/byte-buddy-1.12.6.jar:/Users/Elias/.m2/repository/net/bytebuddy/byte-buddy-agent/1.12.6/byte-buddy-agent-1.12.6.jar:/Users/Elias/.m2/repository/org/jetbrains/kotlin/kotlin-reflect/1.7.10/kotlin-reflect-1.7.10.jar com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit5 ConfigTest
Java HotSpot(TM) 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended

io.mockk.MockKException: Class cast exception happened.
Probably type information was erased.
In this case use `hint` before call to specify exact return type of a method.


	at io.mockk.impl.InternalPlatform.prettifyRecordingException(InternalPlatform.kt:74)
	at io.mockk.impl.eval.RecordedBlockEvaluator.record(RecordedBlockEvaluator.kt:66)
	at io.mockk.impl.eval.EveryBlockEvaluator.every(EveryBlockEvaluator.kt:30)
	at io.mockk.MockKDsl.internalEvery(API.kt:93)
	at io.mockk.MockKKt.every(MockK.kt:98)
	at ConfigTest.testAnything(ConfigTest.kt:16)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ClassCastException: class kotlin.time.Duration cannot be cast to class java.lang.Long (kotlin.time.Duration is in unnamed module of loader 'app'; java.lang.Long is in module java.base of loader 'bootstrap')
	at Config.getDurationInSeconds-UwyO8pc(Config.kt:4)
	at ConfigTest$testAnything$1.invoke-5sfh64U(ConfigTest.kt:16)
	at ConfigTest$testAnything$1.invoke(ConfigTest.kt:16)
	at io.mockk.impl.eval.RecordedBlockEvaluator$record$block$1.invoke(RecordedBlockEvaluator.kt:25)
	at io.mockk.impl.eval.RecordedBlockEvaluator$enhanceWithRethrow$1.invoke(RecordedBlockEvaluator.kt:78)
	at io.mockk.impl.recording.JvmAutoHinter.autoHint(JvmAutoHinter.kt:23)
	at io.mockk.impl.eval.RecordedBlockEvaluator.record(RecordedBlockEvaluator.kt:40)
	... 73 more


Process finished with exit code 255

Minimal reproducible code (the gist of this issue)

import kotlin.time.Duration.Companion.seconds

class Config {
    fun getDurationInSeconds() = 0.seconds
}

import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.junit5.MockKExtension
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import kotlin.time.Duration

@ExtendWith(MockKExtension::class)
class ConfigTest {

    @MockK
    private lateinit var config: Config

    @Test
    fun testAnything() {
        every { config.getDurationInSeconds() } returns Duration.ZERO
    }
}
@qoomon
Copy link
Contributor

qoomon commented Jul 30, 2022

Should be fixed by #872

@qoomon
Copy link
Contributor

qoomon commented Aug 23, 2022

It was fixed with recent version 1.12.6

@Raibaz Raibaz closed this as completed Aug 25, 2022
@naivekook
Copy link

I still have this error in a similar setup with mockk 1.12.7.

@qoomon
Copy link
Contributor

qoomon commented Sep 9, 2022

@naivekook Could you provide a simple test to reproduce the error?

@NinoDLC
Copy link

NinoDLC commented Dec 9, 2022

If the Duration type is nullable ?, it no longer works. Example:

Foo.kt

class Foo(private val bar: Bar) {
    fun run(): String {
        return "Execution of bar with id ${bar.id} took ${bar.duration?.toString() ?: "an unknown time"}"
    }
}

Bar.kt

import kotlin.time.Duration

data class Bar(
    val id: String,
    val duration: Duration?
)

FooTest.kt

import io.mockk.every
import io.mockk.mockk
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test

class FooTest {

    private val bar: Bar = mockk {
        every { id } returns "ID"
        every { duration } returns null
    }

    @Test
    fun `this test doesn't works`() {
        assertEquals("Execution of bar with id ID took an unknown time", Foo(bar).run())
    }
}

By the way, if in my test I use a mock like this, it still doesn't work (same class cast error):

private val bar: Bar = mockk {
    every { id } returns "ID"
    every { duration } returns 5.minutes
}

Github project: https://github.com/NinoDLC/MockK_Duration_Bug

@glockbender
Copy link

glockbender commented Feb 6, 2023

The issue is still relevant (version 1.13.4). Example of code:

"DelayMode function should invoke" {
    val exception = RuntimeException("test")
    val mockCall: () -> String = mockk()
    every { mockCall() } throws exception andThen "test"
    val delayFunc: (RetryAttemptInput) -> kotlin.time.Duration = mockk()
    every { delayFunc.invoke(any()) }.returns(1.milliseconds) // HERE THE EXCEPTION
}

Exception: Caused by: java.lang.ClassCastException: class java.lang.Long cannot be cast to class kotlin.time.Duration (java.lang.Long is in module java.base of loader 'bootstrap'; kotlin.time.Duration is in unnamed module of loader 'app')

@glockbender
Copy link

@Raibaz are there any plans to fix the issue?

@antoniofpnmartins
Copy link

Still getting the exception when using Duration? (nullable Duration). @Raibaz can we reopen this issue? Or maybe create a new one for nullable Duration?

@Raibaz
Copy link
Collaborator

Raibaz commented Jan 7, 2024

I'd rather open a new one for the nullable Duration

@alexxRizz
Copy link

The issue is still relevant (version 1.13.4). Example of code:

"DelayMode function should invoke" {
    val exception = RuntimeException("test")
    val mockCall: () -> String = mockk()
    every { mockCall() } throws exception andThen "test"
    val delayFunc: (RetryAttemptInput) -> kotlin.time.Duration = mockk()
    every { delayFunc.invoke(any()) }.returns(1.milliseconds) // HERE THE EXCEPTION
}

Exception: Caused by: java.lang.ClassCastException: class java.lang.Long cannot be cast to class kotlin.time.Duration (java.lang.Long is in module java.base of loader 'bootstrap'; kotlin.time.Duration is in unnamed module of loader 'app')

Very annoying issue. Because of this bug i have to use mockito as a workaround for mocking interfaces with methods which return value classes, Duration for example. For other cases i'm using mockk.

@glockbender
Copy link

@Raibaz could you reopen the issue? Or should we create a new one?

@Raibaz
Copy link
Collaborator

Raibaz commented Jan 31, 2024

See above, I'd rather have a new one.

@bboschrek
Copy link

bboschrek commented Mar 28, 2024

Same happened when I verifying value in match expression in coEvery:

awsS3Client.getFileTemporaryUrl(
     bucket = match { it shouldBe "imagesS3Bucket"; true },
     key = match { it shouldBe imageId; true },
     validFor = match { it shouldBe 1.hours; true }
)

validFor is Kotlin Duration

@ghackett
Copy link
Contributor

Looks like this issue has regressed in v1.13.10.

interface DurationProvider {
  val myDuration: Duration
}

val mockProvider = mockk<DurationProvider> {
  every { myDuration } returns 5.minutes
}

runTest {
  delay(mockProvider.myDuration) // works fin on 1.13.9, class cast exception on 1.13.10
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants