Skip to content

Commit

Permalink
Merge pull request #1192 from re-gmbh/master
Browse files Browse the repository at this point in the history
Support value classes for non-primitive types
  • Loading branch information
Raibaz committed Dec 22, 2023
2 parents 1626ac7 + f4c51fe commit 5fb2636
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 0 deletions.
90 changes: 90 additions & 0 deletions modules/mockk/src/commonTest/kotlin/io/mockk/it/ValueClassTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.mockk.it
import io.mockk.*
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
Expand All @@ -14,7 +15,9 @@ class ValueClassTest {
private val dummyValueWrapperReturn get() = DummyValueWrapper(DummyValue(99))

private val dummyValueClassArg get() = DummyValue(101)
private val dummyComplexValueClassArg get() = ComplexValue(UUID.fromString("4d19b22c-7754-4c55-ba4d-f80109708a1f"))
private val dummyValueClassReturn get() = DummyValue(202)
private val dummyComplexValueClassReturn get() = ComplexValue(UUID.fromString("25581db2-4cdb-48cd-a6c9-e087aee31f0b"))

//<editor-fold desc="arg=Value Class, return=ValueClass">
@Test
Expand Down Expand Up @@ -95,6 +98,85 @@ class ValueClassTest {
}
//</editor-fold>

//<editor-fold desc="arg=Complex Value Class, return=ComplexValueClass">
@Test
fun `arg is ComplexValueClass, returns ComplexValueClass`() {
val mock = mockk<DummyService> {
every { argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) } returns dummyComplexValueClassReturn
}

assertEquals(dummyComplexValueClassReturn, mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg))

verify { mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) }
}

@Test
fun `arg is any(ComplexValueClass), returns ComplexValueClass`() {
val mock = mockk<DummyService> {
every { argComplexValueClassReturnComplexValueClass(any()) } returns dummyComplexValueClassReturn
}

assertEquals(dummyComplexValueClassReturn, mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg))

verify { mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) }
}

@Test
fun `arg is slot(ComplexValueClass), returns ComplexValueClass`() {
val slot = slot<ComplexValue>()
val mock = mockk<DummyService> {
every { argComplexValueClassReturnComplexValueClass(capture(slot)) } returns dummyComplexValueClassReturn
}

val result = mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg)

assertEquals(dummyComplexValueClassReturn, result)

assertEquals(dummyComplexValueClassArg, slot.captured)

verify { mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) }
}

@Test
fun `arg is ComplexValueClass, answers ComplexValueClass`() {
val mock = mockk<DummyService> {
every { argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) } answers { dummyComplexValueClassReturn }
}

assertEquals(dummyComplexValueClassReturn, mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg))

verify { mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) }
}

@Test
fun `arg is any(ComplexValueClass), answers ComplexValueClass`() {
val mock = mockk<DummyService> {
every { argComplexValueClassReturnComplexValueClass(any()) } answers { dummyComplexValueClassReturn }
}

assertEquals(dummyComplexValueClassReturn, mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg))

verify { mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) }
}

@Test
fun `arg is slot(ComplexValueClass), answers ComplexValueClass`() {
val slot = slot<ComplexValue>()

val mock = mockk<DummyService> {
every { argComplexValueClassReturnComplexValueClass(capture(slot)) } answers { dummyComplexValueClassReturn }
}

val result = mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg)

assertEquals(dummyComplexValueClassReturn, result)

assertEquals(dummyComplexValueClassArg, slot.captured)

verify { mock.argComplexValueClassReturnComplexValueClass(dummyComplexValueClassArg) }
}
//</editor-fold>

//<editor-fold desc="arg=Value Class, return=Wrapper">
@Test
@Ignore // TODO support nested value classes https://github.com/mockk/mockk/issues/859
Expand Down Expand Up @@ -511,6 +593,11 @@ class ValueClassTest {
val text: String get() = value.toString()
}

@JvmInline
value class ComplexValue(val value: UUID) {
val text: String get() = value.toString()
}

@JvmInline
value class DummyValueWrapper(val value: DummyValue)

Expand All @@ -529,6 +616,9 @@ class ValueClassTest {
fun argValueClassReturnValueClass(valueClass: DummyValue): DummyValue =
DummyValue(0)

fun argComplexValueClassReturnComplexValueClass(complexValue: ComplexValue): ComplexValue =
ComplexValue(UUID.fromString("7dea337b-ce0b-4e25-9788-79e708aadc33"))

fun returnValueClass(): DummyValue =
DummyValue(0)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,14 @@ actual object InternalPlatform {

actual fun <K, V> synchronizedMutableMap(): MutableMap<K, V> = synchronizedMap(hashMapOf())

// UnsupportedOperationException is thrown for some internal classes generated by the Kotlin compiler
private fun isValueClass(clazz: KClass<*>) =
try { clazz.isValue } catch (_: UnsupportedOperationException) { false }

actual fun packRef(arg: Any?): Any? {
return when {
arg == null -> null
isValueClass(arg::class) -> packRef(arg.boxedValue)
isPassedByValue(arg::class.boxedClass) -> arg.boxedValue
else -> ref(arg)
}
Expand Down

0 comments on commit 5fb2636

Please sign in to comment.