diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt index 755ad82928..6759311300 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt @@ -404,13 +404,10 @@ fun UtModel.isMockModel() = this is UtCompositeModel && isMock * Checks that this [UtModel] must be constructed with @Spy annotation in generated tests. * Used only for construct variables with @Spy annotation. */ -fun UtModel.canBeSpied(): Boolean { - val javaClass = this.classId.jClass +fun UtModel.canBeSpied(): Boolean = + this is UtAssembleModel && spiedTypes.any { type -> type.isAssignableFrom(this.classId.jClass)} - return this is UtAssembleModel && - (Collection::class.java.isAssignableFrom(javaClass) - || Map::class.java.isAssignableFrom(javaClass)) -} +val spiedTypes = setOf(Collection::class.java, Map::class.java) /** * Get model id (symbolic null value for UtNullModel) diff --git a/utbot-spring-framework/src/main/kotlin/org/utbot/framework/codegen/tree/fieldmanager/CgSpiedFieldsManager.kt b/utbot-spring-framework/src/main/kotlin/org/utbot/framework/codegen/tree/fieldmanager/CgSpiedFieldsManager.kt index 4fdab3e496..6c37ff3602 100644 --- a/utbot-spring-framework/src/main/kotlin/org/utbot/framework/codegen/tree/fieldmanager/CgSpiedFieldsManager.kt +++ b/utbot-spring-framework/src/main/kotlin/org/utbot/framework/codegen/tree/fieldmanager/CgSpiedFieldsManager.kt @@ -1,5 +1,6 @@ package org.utbot.framework.codegen.tree.fieldmanager +import org.utbot.framework.codegen.domain.UtModelWrapper import org.utbot.framework.codegen.domain.builtin.spyClassId import org.utbot.framework.codegen.domain.context.CgContext import org.utbot.framework.codegen.domain.models.CgFieldDeclaration @@ -12,6 +13,8 @@ import org.utbot.framework.plugin.api.UtAssembleModel import org.utbot.framework.plugin.api.UtModel import org.utbot.framework.plugin.api.canBeSpied import org.utbot.framework.plugin.api.isMockModel +import org.utbot.framework.plugin.api.spiedTypes +import org.utbot.framework.plugin.api.util.jClass class CgSpiedFieldsManager(context: CgContext) : CgAbstractClassFieldManager(context) { @@ -38,10 +41,10 @@ class CgSpiedFieldsManager(context: CgContext) : CgAbstractClassFieldManager(con cgModel !in dependentMockModels } - return constructFieldsWithAnnotation(dependentSpyModels) + val suitableSpyModels = getSuitableSpyModels(dependentSpyModels) + return constructFieldsWithAnnotation(suitableSpyModels) } - private val spyFrameworkManager = SpyFrameworkManager(context) override fun useVariableForModel(model: UtModel, variable: CgValue) { @@ -57,4 +60,29 @@ class CgSpiedFieldsManager(context: CgContext) : CgAbstractClassFieldManager(con classId.canBeInjectedByTypeInto(classUnderTest) override fun constructBaseVarName(model: UtModel): String = super.constructBaseVarName(model) + "Spy" + + private fun getSuitableSpyModels(potentialSpyModels: MutableSet): Set = + spiedTypes.fold(setOf()) { spyModels, type -> + spyModels + getSuitableSpyModelsOfType(type, potentialSpyModels) + } + + /* + * Filters out cases when different tests use different [clazz] + * implementations and hence we need to inject different types. + * + * This limitation is reasoned by @InjectMocks behaviour. + * Otherwise, injection may be misleading: + * for example, several spies may be injected into one field. + */ + private fun getSuitableSpyModelsOfType( + clazz: Class<*>, + potentialSpyModels: MutableSet + ): Set { + val spyModelsAssignableFrom = potentialSpyModels + .filter { clazz.isAssignableFrom(it.model.classId.jClass) } + .toSet() + val spyModelsTypesCount = spyModelsAssignableFrom.map { it.model.classId }.toSet().size + + return if (spyModelsTypesCount == 1) spyModelsAssignableFrom else emptySet() + } } \ No newline at end of file