Skip to content

Add support for resolving Kotlin inline value class parameters #5081

@TWiStErRob

Description

@TWiStErRob

Note: this might generalize to Kotlin value classes?

Steps to reproduce

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
import org.junit.jupiter.params.provider.MethodSource

class ResultTest {
    /**
     * This test passes.
     * Good pass: .getOrThrow() returns the expected type and value.
     */
    @Test
    fun normal() {
        val result: Result<String> = Result.success("something")
        val actual = result.getOrThrow()
        assertEquals("something", actual)
    }

    /**
     * This test passes.
     * Good pass: the cast is invalid and therefore .getOrThrow() should throw as it does.
     */
    @Test
    fun cast() {
        val result: Result<String> = Result.success("something")

        @Suppress("UNCHECKED_CAST")
        val castResult = result as Result<Result<String>>
        assertThrows<ClassCastException> {
            val actual = castResult.getOrThrow()
        }
    }

    /**
     * This test passes.
     * Good pass: direct calling the method returns the right type.
     * This to me proves that the issue is somewhere inside @ParameterizedTest handling.
     */
    @Test
    fun direct() {
        val args = valueProviderFull()
        @Suppress("UNCHECKED_CAST")
        val result: Result<String> = args.single().get().single() as Result<String>
        val actual = result.getOrThrow()
        assertEquals("something", actual)
    }

    /**
     * This test passes.
     * Good pass: the type of the parameter matches the type of the value provided as the argument from method source.
     */
    @MethodSource("valueProviderRaw")
    @ParameterizedTest
    fun parameterizedRaw(value: String) {
        val result: Result<String> = Result.success(value)
        val actual = result.getOrThrow()
        assertEquals("something", actual)
    }

    /**
     * This test errors with:
     * > java.lang.ClassCastException: class kotlin.Result cannot be cast to class java.lang.String.
     * This test should pass, because the argument from the method source is a Result<String>.
     */
    @MethodSource("valueProviderFull")
    @ParameterizedTest
    fun parameterizedFull(result: Result<String>) {
        val actual = result.getOrThrow()
        assertEquals("something", actual)
    }

    /**
     * This test passes.
     * This test should fail when trying to call `castResult.getOrThrow()`.
     */
    @MethodSource("valueProviderFull")
    @ParameterizedTest
    fun parameterizedFullCast(result: Result<String>) {
        @Suppress("UNCHECKED_CAST")
        val castResult = result as Result<Result<String>>
        val actual = castResult.getOrThrow()
        assertEquals(Result.success("something"), actual)
        assertEquals("something", actual.getOrThrow())
    }

    /**
     * This test passes.
     * This test should fail when trying to call `result.getOrThrow()`,
     * because the provided argument is a Result<String>.
     */
    @MethodSource("valueProviderFull")
    @ParameterizedTest
    fun parameterizedFullMistyped(result: Result<Result<String>>) {
        val actual = result.getOrThrow()
        assertEquals(Result.success("something"), actual)
        assertEquals("something", actual.getOrThrow())
    }

    companion object {
        @JvmStatic
        fun valueProviderRaw() = listOf(
            Arguments.of("something"),
        )

        @JvmStatic
        fun valueProviderFull() = listOf(
            Arguments.of(Result.success("something")),
        )
    }
}

Context

  • Used versions (Jupiter/Vintage/Platform): 5.12.0, 5.13.0, 5.14.0, 6.0.0
  • Build Tool/IDE: Gradle
  • JVM: 17, 21
  • Kotlin: 2.0.0, 2.1.0, 2.2.20

Deliverables

  • Tests should fail/pass as indicated in comments.

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions