Skip to content

Commit

Permalink
Merge pull request #939 from cliffred/sealed-any
Browse files Browse the repository at this point in the history
Fix InstantiationError when using any() where a sealed type is expected
  • Loading branch information
Raibaz committed Oct 25, 2022
2 parents a2421bf + ea5c646 commit 2b9b52f
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 17 deletions.
18 changes: 18 additions & 0 deletions modules/mockk/src/commonTest/kotlin/io/mockk/it/SealedClassTest.kt
Expand Up @@ -2,6 +2,8 @@ package io.mockk.it

import io.mockk.every
import io.mockk.mockk
import org.junit.jupiter.api.condition.DisabledForJreRange
import org.junit.jupiter.api.condition.JRE
import kotlin.test.Test
import kotlin.test.assertEquals

Expand Down Expand Up @@ -30,6 +32,18 @@ class SealedClassTest {
assertEquals(Leaf(1), result)
}

@Test
fun serviceTakesSealedClassAsInput() {
val formattedNode = "Formatted node"
val factory = mockk<Factory> {
every { format(any()) } answers { formattedNode }
}

val result = factory.format(Root(0))

assertEquals(formattedNode, result)
}

companion object {

sealed class Node
Expand All @@ -39,10 +53,14 @@ class SealedClassTest {

interface Factory {
fun create(): Node

fun format(node: Node): String
}

class FactoryImpl : Factory {
override fun create(): Node = Root(0)

override fun format(node: Node): String = node.toString()
}

}
Expand Down
Expand Up @@ -2,6 +2,8 @@ package io.mockk.it

import io.mockk.every
import io.mockk.mockk
import org.junit.jupiter.api.condition.DisabledForJreRange
import org.junit.jupiter.api.condition.JRE
import kotlin.test.Test
import kotlin.test.assertEquals

Expand Down Expand Up @@ -30,6 +32,18 @@ class SealedInterfaceTest {
assertEquals(Leaf(1), result)
}

@Test
fun serviceTakesSealedInterfaceAsInput() {
val formattedNode = "Formatted node"
val factory = mockk<Factory> {
every { format(any()) } answers { formattedNode }
}

val result = factory.format(Root(0))

assertEquals(formattedNode, result)
}

companion object {

sealed interface Node
Expand All @@ -39,10 +53,14 @@ class SealedInterfaceTest {

interface Factory {
fun create(): Node

fun format(node: Node): String
}

class FactoryImpl : Factory {
override fun create(): Node = Root(0)

override fun format(node: Node): String = node.toString()
}

}
Expand Down
Expand Up @@ -24,24 +24,34 @@ class JvmSignatureValueGenerator(val rnd: Random) : SignatureValueGenerator {
return constructor.call(valueSig)
}

return cls.cast(
when (cls) {
java.lang.Boolean::class -> rnd.nextBoolean()
java.lang.Byte::class -> rnd.nextInt().toByte()
java.lang.Short::class -> rnd.nextInt().toShort()
java.lang.Character::class -> rnd.nextInt().toChar()
java.lang.Integer::class -> rnd.nextInt()
java.lang.Long::class -> rnd.nextLong()
java.lang.Float::class -> rnd.nextFloat()
java.lang.Double::class -> rnd.nextDouble()
java.lang.String::class -> rnd.nextLong().toString(16)
return cls.cast(instantiate(cls, anyValueGeneratorProvider, instantiator))
}

private fun <T : Any> instantiate(
cls: KClass<T>,
anyValueGeneratorProvider: () -> AnyValueGenerator,
instantiator: AbstractInstantiator
): Any = when (cls) {
Boolean::class -> rnd.nextBoolean()
Byte::class -> rnd.nextInt().toByte()
Short::class -> rnd.nextInt().toShort()
Character::class -> rnd.nextInt().toChar()
Integer::class -> rnd.nextInt()
Long::class -> rnd.nextLong()
Float::class -> rnd.nextFloat()
Double::class -> rnd.nextDouble()
String::class -> rnd.nextLong().toString(16)

else ->
@Suppress("UNCHECKED_CAST")
anyValueGeneratorProvider().anyValue(cls, isNullable = false) {
instantiator.instantiate(cls)
} as T
else ->
if (cls.isSealed) {
cls.sealedSubclasses.firstNotNullOfOrNull {
instantiate(it, anyValueGeneratorProvider, instantiator)
} ?: error("Unable to create proxy for sealed class $cls, available subclasses: ${cls.sealedSubclasses}")
} else {
@Suppress("UNCHECKED_CAST")
anyValueGeneratorProvider().anyValue(cls, isNullable = false) {
instantiator.instantiate(cls)
} as T
}
)
}
}

0 comments on commit 2b9b52f

Please sign in to comment.