[Kotlin] @JvmInline value class field loses its set value when a pre-built object is set into a parent via set()/setExp()

Open
#1,285 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
64/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Quiet
Tech stack
kotlin
Domain
testing-qa

Research direction

Start by running the FmValueClassReproTest reproduction with fixture-monkey-starter-kotlin, focusing on giveMeKotlinBuilder, set()/setExp(), and the difference between 1.1.15 and 1.1.16. Trace how a pre-built Child is handled when assigned to Parent, then verify that its Code("FIXED") value is preserved without requiring Values.just(child), while the plain name field remains preserved.

Written by the indexing model from the issue text.

Description

bug

Describe the bug

When a pre-built object (created via giveMeKotlinBuilder(...).sample()) is assigned to a
parent's property using set() / setExp(), Fixture Monkey decomposes and regenerates that
object. As a result, a @JvmInline value class field loses the value that was fixed on it
— it is regenerated to a random value — while plain (non-value-class) fields of the same object
are preserved.

This is a behavior change: it works as expected on 1.1.15 and breaks starting from 1.1.16
(still reproduces on 1.1.20). It does not appear to be mentioned in the release notes.

Wrapping the value with Values.just(...) works around it, but the change silently breaks
existing tests that relied on the previous "use the instance as-is" behavior.

Your environment

  • Fixture Monkey: 1.1.16 (first broken version; also reproduces on 1.1.20). Works correctly on 1.1.14, 1.1.15. Artifact: fixture-monkey-starter-kotlin
  • Kotlin: 2.1.10
  • Java/JVM target: 17

Steps to reproduce

Run the following Kotlin test. The failure is deterministic (the value class field is always
regenerated), so it reproduces on every run regardless of seed.

import com.navercorp.fixturemonkey.FixtureMonkeyBuilder
import com.navercorp.fixturemonkey.kotlin.KotlinPlugin
import com.navercorp.fixturemonkey.kotlin.giveMeKotlinBuilder
import kotlin.test.assertEquals
import org.junit.Test

class FmValueClassReproTest {

    @JvmInline
    value class Code(val value: String)

    data class Child(val code: Code, val name: String)
    data class Parent(val child: Child)

    private val fm = FixtureMonkeyBuilder().plugin(KotlinPlugin()).build()

    // A) set & assert the VALUE CLASS field
    @Test
    fun valueClassField() {
        val fixedCode = Code("FIXED")
        val child = fm.giveMeKotlinBuilder<Child>()
            .setExp(Child::code, fixedCode)
            .sample()
        assertEquals(fixedCode, child.code) // standalone
        val parent = fm.giveMeKotlinBuilder<Parent>()
            .setExp(Parent::child, child)
            .sample()
        println("Check. parent.child: ${parent.child}, child: $child")
        assertEquals(fixedCode, parent.child.code) // hypothesis: FAIL on 1.1.16
    }

    // B) set & assert a PLAIN field (object still contains a value class field)
    @Test
    fun plainFieldInValueClassObject() {
        val child = fm.giveMeKotlinBuilder<Child>().setExp(Child::name, "FIXED").sample()
        val parent = fm.giveMeKotlinBuilder<Parent>().setExp(Parent::child, child).sample()
        println("DIAG name=${parent.child.name}")
        assertEquals("FIXED", parent.child.name)
    }
}
Image Image

Expected behaviour

parent.child.code should remain Code("FIXED") — the value fixed on the injected instance's
value class field should be preserved when the object is set into a parent (as it was in 1.1.15,
and as plain fields still are in 1.1.16+).

Actual behaviour

parent.child.code is regenerated to a random Code(...), so the assertion fails. Only the
@JvmInline value class field is affected; plain fields (e.g. name) of the same object are
preserved. Wrapping with Values.just(child) restores the correct value.

Dominant language
Java
Stars
699
Forks
124
Avg merge
24m
Merged PRs (30d)
7

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from naver/fixture-monkey

All issues in naver/fixture-monkey

Similar issues

More Java issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.