From 25a63baab8d26524f3e48af75c71c954bdf0335e Mon Sep 17 00:00:00 2001 From: Zhaohua Zeng Date: Mon, 4 Mar 2024 14:23:53 -0800 Subject: [PATCH 1/3] Add fix in --- .../kotlin/io/mockk/core/ValueClassSupport.kt | 46 +++++++++++++------ .../kotlin/io/mockk/it/ValueClassTest.kt | 39 +++++++++++++--- 2 files changed, 65 insertions(+), 20 deletions(-) diff --git a/modules/mockk-core/src/jvmMain/kotlin/io/mockk/core/ValueClassSupport.kt b/modules/mockk-core/src/jvmMain/kotlin/io/mockk/core/ValueClassSupport.kt index cf7097250..d84c7bdb0 100644 --- a/modules/mockk-core/src/jvmMain/kotlin/io/mockk/core/ValueClassSupport.kt +++ b/modules/mockk-core/src/jvmMain/kotlin/io/mockk/core/ValueClassSupport.kt @@ -2,14 +2,15 @@ package io.mockk.core import java.lang.reflect.Method import kotlin.reflect.KClass +import kotlin.reflect.KProperty import kotlin.reflect.KProperty1 import kotlin.reflect.full.declaredMemberProperties +import kotlin.reflect.jvm.internal.KotlinReflectionInternalError import kotlin.reflect.jvm.isAccessible import kotlin.reflect.jvm.javaField -import kotlin.reflect.jvm.internal.KotlinReflectionInternalError +import kotlin.reflect.jvm.javaGetter import kotlin.reflect.jvm.kotlinFunction - actual object ValueClassSupport { /** @@ -23,20 +24,38 @@ actual object ValueClassSupport { if (!resultType.isValue_safe) { return this } - val kFunction = method.kotlinFunction ?: return this - - // Only unbox a value class if the method's return type is actually the type of the inlined property. - // For example, in a normal case where a value class `Foo` with underlying `Int` property is inlined: - // method.returnType == int (the actual representation of inlined property on JVM) - // method.kotlinFunction.returnType.classifier == Foo - val expectedReturnType = kFunction.returnType.classifier - return if (resultType == expectedReturnType) { - this.boxedValue + val kFunction = method.kotlinFunction + if (kFunction != null) { + // Only unbox a value class if the method's return type is actually the type of the inlined property. + // For example, in a normal case where a value class `Foo` with underlying `Int` property is inlined: + // method.returnType == int (the actual representation of inlined property on JVM) + // method.kotlinFunction.returnType.classifier == Foo + val expectedReturnType = kFunction.returnType.classifier + return if (resultType == expectedReturnType) { + this.boxedValue + } else { + this + } + } + // It is possible that the method is a getter for a property, in which case we can check the property's return + // type in kotlin. + val kProperty = findMatchingPropertyWithJavaGetter(method) + if (kProperty == null) { + return this } else { - this + val expectedReturnType = kProperty.returnType.classifier + return if (resultType == expectedReturnType) { + this.boxedValue + } else { + this + } } } + private fun findMatchingPropertyWithJavaGetter(method: Method): KProperty<*>? { + return method.declaringClass.kotlin.declaredMemberProperties.find { it.javaGetter == method } + } + /** * Underlying property value of a **`value class`** or self. * @@ -92,8 +111,7 @@ actual object ValueClassSupport { false } catch (_: UnsupportedOperationException) { false - } catch (_: AbstractMethodError) { + } catch (e: AbstractMethodError) { false } - } diff --git a/modules/mockk/src/commonTest/kotlin/io/mockk/it/ValueClassTest.kt b/modules/mockk/src/commonTest/kotlin/io/mockk/it/ValueClassTest.kt index aadccdd6d..a972cec37 100644 --- a/modules/mockk/src/commonTest/kotlin/io/mockk/it/ValueClassTest.kt +++ b/modules/mockk/src/commonTest/kotlin/io/mockk/it/ValueClassTest.kt @@ -1,10 +1,13 @@ package io.mockk.it -import io.mockk.* +import io.mockk.every +import io.mockk.mockk +import io.mockk.slot +import io.mockk.spyk +import io.mockk.verify import org.junit.jupiter.api.assertTimeoutPreemptively import java.time.Duration import java.util.UUID -import kotlin.jvm.JvmInline import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals @@ -31,6 +34,17 @@ class ValueClassTest { verify { mock.argValueClassReturnValueClass(dummyValueClassArg) } } + @Test + fun `field is ValueClass, returns ValueClass`() { + val mock = mockk { + every { valueClassField } returns dummyValueClassReturn + } + + assertEquals(dummyValueClassReturn, mock.valueClassField) + + verify { mock.valueClassField } + } + @Test fun `arg is any(ValueClass), returns ValueClass`() { val mock = mockk { @@ -121,7 +135,10 @@ class ValueClassTest { every { argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) } returns dummyComplexValueClassReturn } - assertEquals(dummyComplexValueClassReturn, mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg)) + assertEquals( + dummyComplexValueClassReturn, + mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) + ) verify { mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) } } @@ -132,7 +149,10 @@ class ValueClassTest { every { argComplexValueClassReturnComplexValueClass(any()) } returns dummyComplexValueClassReturn } - assertEquals(dummyComplexValueClassReturn, mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg)) + assertEquals( + dummyComplexValueClassReturn, + mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) + ) verify { mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) } } @@ -159,7 +179,10 @@ class ValueClassTest { every { argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) } answers { dummyComplexValueClassReturn } } - assertEquals(dummyComplexValueClassReturn, mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg)) + assertEquals( + dummyComplexValueClassReturn, + mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) + ) verify { mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) } } @@ -170,7 +193,10 @@ class ValueClassTest { every { argComplexValueClassReturnComplexValueClass(any()) } answers { dummyComplexValueClassReturn } } - assertEquals(dummyComplexValueClassReturn, mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg)) + assertEquals( + dummyComplexValueClassReturn, + mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) + ) verify { mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) } } @@ -625,6 +651,7 @@ class ValueClassTest { @Suppress("UNUSED_PARAMETER") class DummyService { + val valueClassField = DummyValue(0) fun argWrapperReturnWrapper(wrapper: DummyValueWrapper): DummyValueWrapper = DummyValueWrapper(DummyValue(0)) From 7ce6d35888201f794e7d201ccd811e09c81f77f8 Mon Sep 17 00:00:00 2001 From: Zhaohua Zeng Date: Mon, 4 Mar 2024 14:27:17 -0800 Subject: [PATCH 2/3] fix styles --- .../kotlin/io/mockk/core/ValueClassSupport.kt | 2 +- .../kotlin/io/mockk/it/ValueClassTest.kt | 20 ++++--------------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/modules/mockk-core/src/jvmMain/kotlin/io/mockk/core/ValueClassSupport.kt b/modules/mockk-core/src/jvmMain/kotlin/io/mockk/core/ValueClassSupport.kt index d84c7bdb0..393d72a65 100644 --- a/modules/mockk-core/src/jvmMain/kotlin/io/mockk/core/ValueClassSupport.kt +++ b/modules/mockk-core/src/jvmMain/kotlin/io/mockk/core/ValueClassSupport.kt @@ -111,7 +111,7 @@ actual object ValueClassSupport { false } catch (_: UnsupportedOperationException) { false - } catch (e: AbstractMethodError) { + } catch (_: AbstractMethodError) { false } } diff --git a/modules/mockk/src/commonTest/kotlin/io/mockk/it/ValueClassTest.kt b/modules/mockk/src/commonTest/kotlin/io/mockk/it/ValueClassTest.kt index a972cec37..b1628af82 100644 --- a/modules/mockk/src/commonTest/kotlin/io/mockk/it/ValueClassTest.kt +++ b/modules/mockk/src/commonTest/kotlin/io/mockk/it/ValueClassTest.kt @@ -135,10 +135,7 @@ class ValueClassTest { every { argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) } returns dummyComplexValueClassReturn } - assertEquals( - dummyComplexValueClassReturn, - mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) - ) + assertEquals(dummyComplexValueClassReturn, mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg)) verify { mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) } } @@ -149,10 +146,7 @@ class ValueClassTest { every { argComplexValueClassReturnComplexValueClass(any()) } returns dummyComplexValueClassReturn } - assertEquals( - dummyComplexValueClassReturn, - mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) - ) + assertEquals(dummyComplexValueClassReturn, mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg)) verify { mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) } } @@ -179,10 +173,7 @@ class ValueClassTest { every { argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) } answers { dummyComplexValueClassReturn } } - assertEquals( - dummyComplexValueClassReturn, - mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) - ) + assertEquals(dummyComplexValueClassReturn, mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg)) verify { mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) } } @@ -193,10 +184,7 @@ class ValueClassTest { every { argComplexValueClassReturnComplexValueClass(any()) } answers { dummyComplexValueClassReturn } } - assertEquals( - dummyComplexValueClassReturn, - mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) - ) + assertEquals(dummyComplexValueClassReturn, mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg)) verify { mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) } } From 31ee980e72fe03df5550b32b45afe35f9c884745 Mon Sep 17 00:00:00 2001 From: Zhaohua Zeng Date: Mon, 4 Mar 2024 14:55:47 -0800 Subject: [PATCH 3/3] Trigger Build