From e92818496930a2592f42fcc7c069011484d9c28e Mon Sep 17 00:00:00 2001 From: iliyangermanov Date: Sun, 25 Aug 2024 20:52:20 +0300 Subject: [PATCH] Add support for `Lazy` --- .../commonMain/kotlin/ivy/di/DiContainer.kt | 9 +- di/src/commonTest/kotlin/ivy/di/LazyTest.kt | 102 ++++++++++++++++++ 2 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 di/src/commonTest/kotlin/ivy/di/LazyTest.kt diff --git a/di/src/commonMain/kotlin/ivy/di/DiContainer.kt b/di/src/commonMain/kotlin/ivy/di/DiContainer.kt index 490c32d..9602a4c 100644 --- a/di/src/commonMain/kotlin/ivy/di/DiContainer.kt +++ b/di/src/commonMain/kotlin/ivy/di/DiContainer.kt @@ -48,9 +48,14 @@ object Di { register { get(named = named) } } + inline fun getLazy(named: Any? = null): Lazy { + factoryOrThrow(T::class, named) // ensure that factory exists + return lazy { get(named) } + } + inline fun get(named: Any? = null): T { val classKey = T::class - val (scope, factory) = factory(classKey, named) + val (scope, factory) = factoryOrThrow(classKey, named) val depKey = DependencyKey(scope, classKey, named) return if (classKey in singletons) { if (depKey in singletonInstances) { @@ -69,7 +74,7 @@ object Di { } } - fun factory( + fun factoryOrThrow( classKey: KClass<*>, named: Any?, ): Pair = scopes diff --git a/di/src/commonTest/kotlin/ivy/di/LazyTest.kt b/di/src/commonTest/kotlin/ivy/di/LazyTest.kt new file mode 100644 index 0000000..d0ebc47 --- /dev/null +++ b/di/src/commonTest/kotlin/ivy/di/LazyTest.kt @@ -0,0 +1,102 @@ +package ivy.di + +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.shouldBe +import ivy.di.Di.register +import ivy.di.Di.singleton +import kotlin.test.BeforeTest +import kotlin.test.Test + +private var initialized = false + +class Counter(var x: Int) { + init { + initialized = true + } +} + +class CountManager(private val counter: Lazy) { + fun increment() { + counter.value.x++ + } +} + +class LazyTest { + + @BeforeTest + fun setup() { + Di.reset() + initialized = false + } + + @Test + fun lazyInitialization() { + // Given + Di.appScope { + register { Counter(x = 42) } + } + + // When + val lazyCounter = Di.getLazy() + + // Initially the lazy counter isn't initialized + initialized shouldBe false + + // When the lazy value is accessed + val counter = lazyCounter.value + + // Then + initialized shouldBe true + counter.x shouldBe 42 + } + + @Test + fun lazySingletonInitialization() { + // Given + Di.appScope { + singleton { Counter(x = 0) } + } + + // When + val lazyCounter = Di.getLazy() + + // Initially the lazy counter isn't initialized + initialized shouldBe false + + // When the lazy value is accessed and modified + lazyCounter.value.x shouldBe 0 + lazyCounter.value.x = 42 + + // Then + initialized shouldBe true + Di.getLazy().value.x shouldBe 42 + } + + @Test + fun missingFactory() { + // When-Then + shouldThrow { + Di.getLazy() + } + } + + @Test + fun realWorldScenario() { + // Given + Di.appScope { + singleton { Counter(x = 0) } + register { CountManager(Di.getLazy()) } + } + val manager = Di.get() + + // Initially the lazy counter isn't initialized + initialized shouldBe false + + // When + manager.increment() + + // Then + initialized shouldBe true + Di.get().x shouldBe 1 + } +} \ No newline at end of file