All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.org.koin.test.check.CheckModules.kt Maven / Gradle / Ivy

/*
 * Copyright 2017-Present the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
@file:Suppress("UNUSED_PARAMETER")
@file:OptIn(KoinInternalApi::class)

package org.koin.test.check

import org.koin.core.Koin
import org.koin.core.KoinApplication
import org.koin.core.annotation.KoinInternalApi
import org.koin.core.context.startKoin
import org.koin.core.context.stopKoin
import org.koin.core.definition.BeanDefinition
import org.koin.core.logger.Level
import org.koin.core.module.Module
import org.koin.core.parameter.ParametersHolder
import org.koin.core.qualifier.Qualifier
import org.koin.core.qualifier.TypeQualifier
import org.koin.core.scope.Scope
import org.koin.dsl.KoinAppDeclaration
import org.koin.mp.KoinPlatformTools
import org.koin.test.mock.MockProvider
import org.koin.test.parameter.MockParameter

//TODO TO BE DEPRECATED in 4.0

/**
 * Check all definition's dependencies - start all modules and check if definitions can run
 */
@Deprecated(
    message = "Migrate to verify() API",
    replaceWith = ReplaceWith("org.koin.test.verify.Verify")
)
fun KoinApplication.checkModules(parameters: CheckParameters? = null) = koin.checkModules(parameters)

/**
 * Verify Modules by running each definition
 *
 * @param level - Log level
 * @param parameters - parameter setup
 * @param appDeclaration - koin Application
 */
@Deprecated(
    message = "Migrate to verify() API",
    replaceWith = ReplaceWith("org.koin.test.verify.Verify")
)
fun checkModules(level: Level = Level.INFO, parameters: CheckParameters? = null, appDeclaration: KoinAppDeclaration) {
    startKoin(appDeclaration)
        .logger(KoinPlatformTools.defaultLogger(level))
        .checkModules(parameters)
}

/**
 * Check given modules directly
 *
 * @param modules - list of modules
 * @param appDeclaration - Koin app config if needed
 * @param parameters - Check parameters DSL
 */
@Deprecated(
    message = "Migrate to verify() API",
    replaceWith = ReplaceWith("modules.verifyAll()", "org.koin.test.verify.verifyAll")
)
fun checkKoinModules(modules: List, appDeclaration: KoinAppDeclaration = {}, parameters: CheckParameters? = null) {
    startKoin(appDeclaration)
        .modules(modules)
        .checkModules(parameters)
    stopKoin()
}

/**
 * @see checkModules
 *
 * Deprecated
 */
@Deprecated("use instead checkKoinModules(modules : List, appDeclaration: KoinAppDeclaration = {}, parameters: CheckParameters? = null)")
fun checkKoinModules(level: Level = Level.INFO, parameters: CheckParameters? = null, appDeclaration: KoinAppDeclaration) {
    startKoin(appDeclaration)
        .logger(KoinPlatformTools.defaultLogger(level))
        .checkModules(parameters)
    stopKoin()
}

/**
 * @see checkKoinModules
 *
 * Deprecated
 */
@Deprecated("use instead checkKoinModules(modules : List, appDeclaration: KoinAppDeclaration = {}, parameters: CheckParameters? = null)")
fun checkKoinModules(vararg modules: Module, level: Level = Level.INFO, parameters: CheckParameters? = null) {
    startKoin({})
        .logger(KoinPlatformTools.defaultLogger(level))
        .checkModules(parameters)
    stopKoin()
}

/**
 * Check all definition's dependencies - start all modules and check if definitions can run
 */
@Deprecated(
    message = "Migrate to verify() API",
    replaceWith = ReplaceWith("org.koin.test.verify.Verify")
)
fun Koin.checkModules(parametersDefinition: CheckParameters? = null) {
    logger.info("[Check] checking modules ...")

    checkAllDefinitions(
        declareParameterCreators(parametersDefinition),
    )

    logger.info("[Check] All checked")
    close()
}

private fun Koin.declareParameterCreators(parametersDefinition: CheckParameters?) =
    ParametersBinding(this).also { binding -> parametersDefinition?.invoke(binding) }

@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 ->
        checkDefinition(allParameters, factory.beanDefinition, scopes.first { it.scopeQualifier == factory.beanDefinition.scopeQualifier })
    }
}

@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? {
    return if (qualifier is TypeQualifier) {
        MockProvider.makeMock(qualifier.type)
    } else {
        null
    }
}

private fun Koin.checkDefinition(
    allParameters: ParametersBinding,
    definition: BeanDefinition<*>,
    scope: Scope,
) {
    val parameters: ParametersHolder = allParameters.parametersCreators[
        CheckedComponent(
            definition.qualifier,
            definition.primaryType,
        ),
    ]?.invoke(
        definition.qualifier,
    ) ?: MockParameter(scope, allParameters.defaultValues)

    logger.info("[Check] definition: $definition")
    scope.get(definition.primaryType, definition.qualifier) { parameters }

    for (secondaryType in definition.secondaryTypes) {
        val valueAsSecondary = scope.get(secondaryType, definition.qualifier) { parameters }
        require(secondaryType.isInstance(valueAsSecondary)) {
            "instance of ${valueAsSecondary::class} is not inheritable from $secondaryType"
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy