From 37a6e34fe104253179519ff27c276042e801aede Mon Sep 17 00:00:00 2001 From: fesc7420 <17569373+Pfoerd@users.noreply.github.com> Date: Wed, 2 Mar 2022 09:26:51 +0100 Subject: [PATCH] Add support for scope linking in checkModules on-behalf-of: @e-solutions-GmbH --- .../kotlin/org/koin/test/CheckModulesTest.kt | 36 ++++++++++++++++++- .../test/kotlin/org/koin/test/Components.kt | 3 ++ .../org/koin/test/check/CheckModules.kt | 22 +++++++----- .../org/koin/test/check/CheckModulesDSL.kt | 5 +++ docs/reference/koin-test/checkmodules.md | 27 ++++++++++++++ 5 files changed, 83 insertions(+), 10 deletions(-) diff --git a/core/koin-test-junit4/src/test/kotlin/org/koin/test/CheckModulesTest.kt b/core/koin-test-junit4/src/test/kotlin/org/koin/test/CheckModulesTest.kt index 766b9cc70..41359e715 100644 --- a/core/koin-test-junit4/src/test/kotlin/org/koin/test/CheckModulesTest.kt +++ b/core/koin-test-junit4/src/test/kotlin/org/koin/test/CheckModulesTest.kt @@ -27,6 +27,12 @@ class CheckModulesTest { single { p -> Simple.ComponentB(p.get()) } single(named("param")) { p -> Simple.MyString(p.get()) } single { Simple.MyString(getProperty("aValue")) } + scope(named("scope1")) { + scoped { Simple.ComponentD() } + } + scope(named("scope2")) { + scoped { Simple.ComponentE(get()) } + } } koinApplication { @@ -36,6 +42,7 @@ class CheckModulesTest { // withInstance("a_parameter") withParameter { "a_parameter" } withProperty("aValue", "string_value") + withScopeLink(named("scope2"), named("scope1")) } } } @@ -46,12 +53,19 @@ class CheckModulesTest { single { p -> Simple.ComponentB(p.get()) } single(named("param")) { p -> Simple.MyString(p.get()) } single { Simple.MyString(getProperty("aValue")) } + scope(named("scope1")) { + scoped { Simple.ComponentD() } + } + scope(named("scope2")) { + scoped { Simple.ComponentE(get()) } + } } checkKoinModules(listOf(modules)) { withInstance() withParameter { "a_parameter" } withProperty("aValue", "string_value") + withScopeLink(named("scope2"), named("scope1")) } } @@ -276,7 +290,7 @@ class CheckModulesTest { } ) }.checkModules() - fail("should not pass with borken definitions") + fail("should not pass with broken definitions") } catch (e: Exception) { e.printStackTrace() } @@ -504,4 +518,24 @@ class CheckModulesTest { } } } + + @Test + fun `check a module with linked scopes`() { + koinApplication { + printLogger(Level.DEBUG) + properties(hashMapOf("aValue" to "value")) + modules( + module { + scope { + scoped { Simple.ComponentD() } + } + scope { + scoped { Simple.ComponentE(get()) } + } + } + ) + }.checkModules { + withScopeLink() + } + } } \ No newline at end of file diff --git a/core/koin-test-junit4/src/test/kotlin/org/koin/test/Components.kt b/core/koin-test-junit4/src/test/kotlin/org/koin/test/Components.kt index dd5e87d77..e58b6620d 100644 --- a/core/koin-test-junit4/src/test/kotlin/org/koin/test/Components.kt +++ b/core/koin-test-junit4/src/test/kotlin/org/koin/test/Components.kt @@ -8,11 +8,14 @@ class Simple { class ComponentA class ComponentB(val a: ComponentA) class ComponentC(val b: ComponentB) + class ComponentD() + class ComponentE(val d: ComponentD) class MyString(val s: String) class UUIDComponent { fun getUUID() = UUID.randomUUID().toString() } + } object UpperCase : Qualifier { diff --git a/core/koin-test/src/commonMain/kotlin/org/koin/test/check/CheckModules.kt b/core/koin-test/src/commonMain/kotlin/org/koin/test/check/CheckModules.kt index 86a78dc89..44ddeff1f 100644 --- a/core/koin-test/src/commonMain/kotlin/org/koin/test/check/CheckModules.kt +++ b/core/koin-test/src/commonMain/kotlin/org/koin/test/check/CheckModules.kt @@ -111,19 +111,23 @@ private fun Koin.declareParameterCreators(parametersDefinition: CheckParameters? @OptIn(KoinInternalApi::class) private fun Koin.checkAllDefinitions(allParameters: ParametersBinding) { + val scopes: List = instantiateAllScopes(allParameters) + allParameters.scopeLinks.forEach { scopeLink -> + val linkTargets = scopes.filter { it.scopeQualifier == scopeLink.value } + scopes.filter { it.scopeQualifier == scopeLink.key } + .forEach { scope -> linkTargets.forEach { linkTarget -> scope.linkTo(linkTarget) } } + } instanceRegistry.instances.values.toSet().forEach { factory -> - check(factory,allParameters) + checkDefinition(allParameters, factory.beanDefinition, scopes.first { it.scopeQualifier == factory.beanDefinition.scopeQualifier }) } } -private fun Koin.check( - factory: InstanceFactory<*>, - allParameters: ParametersBinding -) { - val qualifier = factory.beanDefinition.scopeQualifier - val sourceScopeValue = mockSourceValue(qualifier) - val scope = getOrCreateScope(qualifier.value, qualifier, sourceScopeValue) - checkDefinition(allParameters,factory.beanDefinition,scope) +@OptIn(KoinInternalApi::class) +private fun Koin.instantiateAllScopes(allParameters: ParametersBinding): List { + return scopeRegistry.scopeDefinitions.map { qualifier -> + val sourceScopeValue = mockSourceValue(qualifier) + getOrCreateScope(qualifier.value, qualifier, sourceScopeValue) + } } private fun mockSourceValue(qualifier: Qualifier): Any? { diff --git a/core/koin-test/src/commonMain/kotlin/org/koin/test/check/CheckModulesDSL.kt b/core/koin-test/src/commonMain/kotlin/org/koin/test/check/CheckModulesDSL.kt index 05c912760..37c9bb3c7 100644 --- a/core/koin-test/src/commonMain/kotlin/org/koin/test/check/CheckModulesDSL.kt +++ b/core/koin-test/src/commonMain/kotlin/org/koin/test/check/CheckModulesDSL.kt @@ -19,6 +19,7 @@ import org.koin.core.Koin import org.koin.core.parameter.ParametersHolder import org.koin.core.parameter.parametersOf import org.koin.core.qualifier.Qualifier +import org.koin.core.qualifier.qualifier import org.koin.mp.KoinPlatformTools import org.koin.test.mock.MockProvider import kotlin.reflect.KClass @@ -29,6 +30,7 @@ class ParametersBinding(val koin: Koin) { val parametersCreators = mutableMapOf() val defaultValues = mutableMapOf() + val scopeLinks = mutableMapOf() @Deprecated("use withParameter() instead", ReplaceWith("withParameters(qualifier,creator)")) inline fun create(qualifier: Qualifier? = null, noinline creator: ParametersCreator) = @@ -62,6 +64,9 @@ class ParametersBinding(val koin: Koin) { defaultValues.put(KoinPlatformTools.getClassName(T::class), MockProvider.makeMock()) fun withProperty(key: String, value: Any) = koin.setProperty(key, value) + inline fun withScopeLink() = withScopeLink(qualifier(), qualifier()) + inline fun withScopeLink(scopeQualifier: Qualifier, targetScopeQualifier: Qualifier) = + scopeLinks.put(scopeQualifier, targetScopeQualifier) } typealias ParametersCreator = (Qualifier?) -> ParametersHolder diff --git a/docs/reference/koin-test/checkmodules.md b/docs/reference/koin-test/checkmodules.md index 79a8c6835..7afc35687 100644 --- a/docs/reference/koin-test/checkmodules.md +++ b/docs/reference/koin-test/checkmodules.md @@ -226,3 +226,30 @@ fun `test DI modules`(){ } } ``` + +#### Providing Scope Links + +You can link scopes by using `withScopeLink` function in`checkModules` block to inject instances from another scope's definitions: + +```kotlin +val myModule = module { + scope(named("scope1")) { + scoped { ComponentA() } + } + scope(named("scope2")) { + scoped { ComponentB(get()) } + } +} +``` + +```kotlin +@Test +fun `test DI modules`(){ + koinApplication { + modules(myModule) + checkModules(){ + withScopeLink(named("scope2"), named("scope1")) + } + } +} +```