Skip to content

Commit b929fee

Browse files
Add nullable types to random provider type generator (#62)
1 parent 668a98a commit b929fee

File tree

2 files changed

+59
-5
lines changed

2 files changed

+59
-5
lines changed

core/src/main/kotlin/io/github/serpro69/kfaker/provider/RandomProvider.kt

+20-5
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,17 @@ class RandomProvider internal constructor(random: Random) {
7575
} ?: throw NoSuchElementException("No suitable constructor found for $this")
7676

7777
val params = constructor.parameters
78-
.map { it.type.classifier as KClass<*> }
78+
.map { it.type }
7979
.map {
80-
it.predefinedTypeOrNull(config)
81-
?: it.randomPrimitiveOrNull()
82-
?: it.randomEnumOrNull()
83-
?: it.randomClassInstance(config)
80+
val klass = it.classifier as KClass<*>
81+
if (it.isMarkedNullable && config.nullableGenerators.containsKey(klass)) {
82+
config.nullableGenerators[klass]?.invoke()
83+
} else {
84+
klass.predefinedTypeOrNull(config)
85+
?: klass.randomPrimitiveOrNull()
86+
?: klass.randomEnumOrNull()
87+
?: klass.randomClassInstance(config)
88+
}
8489
}
8590
.toTypedArray()
8691

@@ -140,12 +145,22 @@ class RandomProviderConfig @PublishedApi internal constructor() {
140145
@PublishedApi
141146
internal val predefinedGenerators = mutableMapOf<KClass<*>, () -> Any>()
142147

148+
@PublishedApi
149+
internal val nullableGenerators = mutableMapOf<KClass<*>, () -> Any?>()
150+
143151
/**
144152
* Configures generation for a specific type. It can override internal generators (for primitives, for example)
145153
*/
146154
inline fun <reified K : Any> typeGenerator(noinline generator: () -> K) {
147155
predefinedGenerators[K::class] = generator
148156
}
157+
158+
/**
159+
* Configures generation for a specific nullable type. It can override internal generators (for primitives, for example)
160+
*/
161+
inline fun <reified K : Any?> nullableTypeGenerator(noinline generator: () -> K?) {
162+
nullableGenerators[K::class] = generator
163+
}
149164
}
150165

151166
enum class FallbackStrategy {

core/src/test/kotlin/io/github/serpro69/kfaker/provider/RandomProviderTest.kt

+39
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,45 @@ class RandomProviderTest : DescribeSpec({
154154
}
155155
}
156156

157+
describe("a TestClass with non-empty constructor for nullable custom type generators") {
158+
class Foo(val int: Int?)
159+
class TestClass(
160+
val id: UUID,
161+
val int: Int?,
162+
val nullableLong: Long?,
163+
val notNullLong: Long,
164+
val foo: Foo
165+
)
166+
167+
val givenUuid = UUID.fromString("00000000-0000-0000-0000-000000000000")
168+
val givenInt = 1
169+
val givenNullableLong: Long? = null
170+
val givenLong = 1L
171+
172+
context("creating a random instance of the class with nullable custom generators") {
173+
val testClass: TestClass = randomProvider.randomClassInstance {
174+
@Suppress("RemoveExplicitTypeArguments")
175+
typeGenerator<UUID> { givenUuid }
176+
@Suppress("RemoveExplicitTypeArguments")
177+
typeGenerator<Int> { givenInt } // use the not-null type generator and verify it is used for Int?
178+
nullableTypeGenerator<Long?> { givenNullableLong }
179+
@Suppress("RemoveExplicitTypeArguments")
180+
typeGenerator<Long> { givenLong }
181+
}
182+
183+
it("it should be a predefined UUID and primitives with nulls") {
184+
assertSoftly {
185+
testClass shouldBe instanceOf(TestClass::class)
186+
testClass.id shouldBe givenUuid
187+
testClass.int shouldBe givenInt
188+
testClass.nullableLong shouldBe givenNullableLong
189+
testClass.notNullLong shouldBe givenLong
190+
testClass.foo.int shouldBe givenInt
191+
}
192+
}
193+
}
194+
}
195+
157196
describe("a TestClass with 3 non-default constructors") {
158197

159198
class Foo

0 commit comments

Comments
 (0)