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

kotlinx.datetime.Instant relaxed mock yields null java.time.Instant value #1220

Open
3 tasks done
grepory opened this issue Feb 19, 2024 · 0 comments
Open
3 tasks done

Comments

@grepory
Copy link

grepory commented Feb 19, 2024

Prerequisites

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

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

Expected Behavior

When I used a relaxed mock of a class with a property of type kotlinx.datetime.Instant, a reasonable value is returned for that property.

Current Behavior

Given a class that has a property that returns a kotlinx.datetime.Instant, a relaxed mockk of that class will return an invalid instance of Instant.

Failure Information (for bugs)

Please help provide information about the failure if this is a bug. If it is not a bug, please remove the rest of this template.

Steps to Reproduce

Please provide detailed steps for reproducing the issue.

  1. relaxed mock a kotlinx.datetime.Instant

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.13.9
  • OS: macOS 14.2.1
  • Kotlin version: 1.9.22
  • JDK version: 17
  • JUnit version: 5.8.0
  • Type of test: unit test

Minimal reproducible code (the gist of this issue)

kx.d.Instant has an internal property, value, that holds its java.time.Instant. the j.t.Instant in the mocked kx.d.Instant is somehow null. That shouldn't be possible as kx.d.Instant only has a single internal constructor that requires a non-null value for a java.time.Instant.

public actual class Instant internal constructor(internal val value: jtInstant) : Comparable<Instant> {

So when I do something like this:

class HasInstantProperty(val Instant: instant)

And write a test for it with a mockk:

    @Test fun mockInstant() {
        val mock = mockk<InstantReturner>(relaxed = true)
        assertNotNull(mock.instant)
    }

What I will see when debugging is:

image

This is not so great, because if that j.t.Instant is null, then things can get spooky. We discovered this when SQL Exposed started throwing ClassCastExceptions during tests.

java.lang.ClassCastException: class java.lang.Object cannot be cast to class java.time.chrono.Chronology (java.lang.Object and java.time.chrono.Chronology are in module java.base of loader 'bootstrap')
	at java.base/java.time.format.DateTimePrintContext.adjust(DateTimePrintContext.java:132)
	at java.base/java.time.format.DateTimePrintContext.<init>(DateTimePrintContext.java:119)
	at java.base/java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1847)
	at java.base/java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1823)
	at org.jetbrains.exposed.sql.kotlin.datetime.KotlinInstantColumnType.nonNullValueToString(KotlinDateColumnType.kt:284)
...

We got around this by simply not using a relaxed mock, but if someone has an idea of why this is the way it is and if anything can be done about it... or at least can explain what's happening in detail so that I can understand... I would sincerely appreciate it.

// -----------------------[ GRADLE DEFINITIONS ] -----------------------
dependencies {
    testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
    testImplementation("io.kotest:kotest-runner-junit5:5.8.0")
    testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.1")
    testImplementation("io.mockk:mockk:1.13.9")
    implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.5.0")
}
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

1 participant