Skip to content

Commit

Permalink
Add collection element type gen for random class instance
Browse files Browse the repository at this point in the history
  • Loading branch information
serpro69 committed Jun 16, 2024
1 parent 20c85c5 commit bdc1bbd
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ class RandomClassProvider {
?: klass.randomPrimitiveOrNull()
?: klass.randomEnumOrNull()
?: klass.randomSealedClassOrNull(config)
?: klass.randomCollectionOrNull(it.type, config)
?: klass.randomCollectionOrNull(it.type, config, pInfo)
?: klass.randomClassInstance(config)
}
}
Expand Down Expand Up @@ -219,21 +219,27 @@ class RandomClassProvider {
return if (isSealed) randomService.randomValue(sealedSubclasses).randomClassInstance(config) else null
}

private fun KClass<*>.randomCollectionOrNull(kType: KType, config: RandomProviderConfig): Any? {
private fun KClass<*>.randomCollectionOrNull(kType: KType, config: RandomProviderConfig, pInfo: ParameterInfo): Any? {
val instance: (el: KClass<*>) -> Any? = {
when {
config.collectionTypeGenerators.containsKey(it) -> config.collectionTypeGenerators[it]?.invoke(pInfo)
else -> it.randomClassInstance(config)
}
}
return when (this) {
List::class -> {
val elementType = kType.arguments[0].type?.classifier as KClass<*>
List(config.collectionsSize) { elementType.randomClassInstance(config) }
List(config.collectionsSize) { instance(elementType) }
}
Set::class -> {
val elementType = kType.arguments[0].type?.classifier as KClass<*>
List(config.collectionsSize) { elementType.randomClassInstance(config) }.toSet()
List(config.collectionsSize) { instance(elementType) }.toSet()
}
Map::class -> {
val keyElementType = kType.arguments[0].type?.classifier as KClass<*>
val valElementType = kType.arguments[1].type?.classifier as KClass<*>
val keys = List(config.collectionsSize) { keyElementType.randomClassInstance(config) }
val values = List(config.collectionsSize) { valElementType.randomClassInstance(config) }
val values = List(config.collectionsSize) { instance(valElementType) }
keys.zip(values).associate { (k, v) -> k to v }
}
else -> null
Expand Down Expand Up @@ -274,8 +280,12 @@ class RandomProviderConfig @PublishedApi internal constructor() {
@PublishedApi
internal val nullableGenerators = mutableMapOf<KClass<*>, (pInfo: ParameterInfo) -> Any?>()

@PublishedApi
internal val collectionTypeGenerators = mutableMapOf<KClass<*>, (pInfo: ParameterInfo) -> Any?>()

/**
* Configures generation for a specific named parameter. Overrides all other generators
* Configures generation for a specific named constructor parameter.
* Overrides all other generators.
*/
inline fun <reified K : Any> namedParameterGenerator(
parameterName: String,
Expand All @@ -285,18 +295,24 @@ class RandomProviderConfig @PublishedApi internal constructor() {
}

/**
* Configures generation for a specific type. It can override internal generators (for primitives, for example)
* Configures generation for a specific type of constructor parameter.
* It can override internal generators (for primitives, for example)
*/
inline fun <reified K : Any> typeGenerator(noinline generator: (pInfo: ParameterInfo) -> K) {
predefinedGenerators[K::class] = generator
}

/**
* Configures generation for a specific nullable type. It can override internal generators (for primitives, for example)
* Configures generation for a specific nullable type of constructor parameter.
* It can override internal generators (for primitives, for example)
*/
inline fun <reified K : Any?> nullableTypeGenerator(noinline generator: (pInfo: ParameterInfo) -> K?) {
nullableGenerators[K::class] = generator
}

inline fun <reified K : Any?> collectionTypeGenerator(noinline generator: (pInfo: ParameterInfo) -> K?) {
collectionTypeGenerators[K::class] = generator
}
}

private fun RandomProviderConfig.reset() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import io.kotest.matchers.string.shouldHaveLength
import io.kotest.matchers.types.instanceOf
import io.kotest.matchers.types.shouldNotBeSameInstanceAs
import org.junit.jupiter.api.assertThrows
import java.util.*
import java.util.Random
import java.util.UUID
import kotlin.reflect.full.declaredMemberProperties

@Suppress("unused")
Expand Down Expand Up @@ -437,6 +438,7 @@ class RandomClassProviderTest : DescribeSpec({
// enum-key based map can only have up to 3 entries in this case, depending on the randomness of the generated key
testClass.enumMap.size shouldBeInRange 1..3
}

it("should generate Collections with pre-configured type generation") {
val testClass = randomProvider.randomClassInstance<TestClass> {
typeGenerator<List<Foo>> { listOf() }
Expand All @@ -453,6 +455,35 @@ class RandomClassProviderTest : DescribeSpec({
testClass.enumSet shouldHaveSize 1
testClass.enumMap shouldHaveSize 1
}

it("should generate elements in a collection with predefined collection generator") {
val foo = Foo()
val bar = Bar(42)
val baz = Baz(foo, "foo")
val testClass = randomProvider.randomClassInstance<TestClass> {
collectionTypeGenerator<Foo> { foo }
collectionTypeGenerator<Bar> { bar }
collectionTypeGenerator<Baz> { baz }
collectionTypeGenerator<String> { "string" }
collectionTypeGenerator<Char> { 'c' }
collectionTypeGenerator<Boolean> { true }
collectionTypeGenerator<Int> { 42 }
collectionTypeGenerator<Byte> { Byte.MAX_VALUE }
collectionTypeGenerator<TestEnum> { TestEnum.GO }
}
testClass.set shouldHaveSize 1
testClass.set.first() shouldBe bar
testClass.map.all { it.value == baz } shouldBe true
testClass.charList.all { it == 'c' } shouldBe true
testClass.intSet shouldHaveSize 1
testClass.intSet.first() shouldBe 42
testClass.boolMap.all { it.value == Byte.MAX_VALUE } shouldBe true
testClass.enumList.all { it == TestEnum.GO } shouldBe true
testClass.enumSet shouldHaveSize 1
testClass.enumSet.all { it == TestEnum.GO } shouldBe true
testClass.enumMap shouldHaveSize 1
testClass.enumMap.all { it.value == TestEnum.GO } shouldBe true
}
}

describe("a TestClass with with abstract type constructor parameter") {
Expand Down

0 comments on commit bdc1bbd

Please sign in to comment.