diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModel.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModel.kt index 893c7e1946..8dfabf8832 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModel.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModel.kt @@ -22,15 +22,17 @@ class SimpleTestClassModel( /** * Extended [SimpleTestClassModel] for Spring analysis reasons - * - * @param injectingMocksClass a class to inject other mocks into - * @param mockedClasses variables of test class to represent mocked instances */ class SpringTestClassModel( classUnderTest: ClassId, methodTestSets: List, nestedClasses: List, - val thisInstanceModels: TypedModelWrappers = mapOf(), - val thisInstanceDependentMocks: TypedModelWrappers = mapOf(), + val springSpecificInformation: SpringSpecificInformation, ): TestClassModel(classUnderTest, methodTestSets, nestedClasses) + +class SpringSpecificInformation( + val thisInstanceModels: TypedModelWrappers = mapOf(), + val thisInstanceDependentMocks: TypedModelWrappers = mapOf(), + val applicationContextModels: TypedModelWrappers = mapOf(), +) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SpringTestClassModelBuilder.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SpringTestClassModelBuilder.kt index b911b8b882..23453f9ca3 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SpringTestClassModelBuilder.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SpringTestClassModelBuilder.kt @@ -3,6 +3,7 @@ package org.utbot.framework.codegen.domain.models.builders import org.utbot.framework.codegen.domain.UtModelWrapper import org.utbot.framework.codegen.domain.context.CgContext import org.utbot.framework.codegen.domain.models.CgMethodTestSet +import org.utbot.framework.codegen.domain.models.SpringSpecificInformation import org.utbot.framework.codegen.domain.models.SpringTestClassModel import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.UtArrayModel @@ -11,7 +12,6 @@ import org.utbot.framework.plugin.api.UtClassRefModel import org.utbot.framework.plugin.api.UtCompositeModel import org.utbot.framework.plugin.api.UtDirectSetFieldModel import org.utbot.framework.plugin.api.UtEnumConstantModel -import org.utbot.framework.plugin.api.UtExecutableCallModel import org.utbot.framework.plugin.api.UtLambdaModel import org.utbot.framework.plugin.api.UtModel import org.utbot.framework.plugin.api.UtNullModel @@ -27,20 +27,20 @@ class SpringTestClassModelBuilder(val context: CgContext): TestClassModelBuilder override fun createTestClassModel(classUnderTest: ClassId, testSets: List): SpringTestClassModel { val baseModel = SimpleTestClassModelBuilder(context).createTestClassModel(classUnderTest, testSets) - val (thisInstanceModels, dependentMockModels) = collectThisInstanceAndDependentModels(testSets) + val springSpecificInformation = collectSpecificModelsForClassVariables(testSets) return SpringTestClassModel( classUnderTest = baseModel.classUnderTest, methodTestSets = baseModel.methodTestSets, nestedClasses = baseModel.nestedClasses, - thisInstanceModels = thisInstanceModels, - thisInstanceDependentMocks = dependentMockModels + springSpecificInformation = springSpecificInformation ) } - private fun collectThisInstanceAndDependentModels(testSets: List): Pair { + private fun collectSpecificModelsForClassVariables(testSets: List): SpringSpecificInformation { val thisInstanceModels = mutableSetOf() val thisInstancesDependentModels = mutableSetOf() + val stateBeforeDependentModels = mutableSetOf() with(context) { for ((testSetIndex, testSet) in testSets.withIndex()) { @@ -51,8 +51,13 @@ class SpringTestClassModelBuilder(val context: CgContext): TestClassModelBuilder .filterNotNull() .forEach { model -> thisInstanceModels += model.wrap() - thisInstancesDependentModels += collectByThisInstanceModel(model) + thisInstancesDependentModels += collectByModel(model) + } + + (execution.stateBefore.parameters + execution.stateBefore.thisInstance) + .filterNotNull() + .forEach { model -> stateBeforeDependentModels += collectByModel(model) } } } } @@ -65,10 +70,18 @@ class SpringTestClassModelBuilder(val context: CgContext): TestClassModelBuilder cgModel.model.isMockModel() && cgModel !in thisInstanceModels } - return thisInstanceModels.groupByClassId() to dependentMockModels.groupByClassId() + val applicationContextModels = stateBeforeDependentModels + .filter { it.model is UtSpringContextModel } + .toSet() + + return SpringSpecificInformation( + thisInstanceModels.groupByClassId(), + dependentMockModels.groupByClassId(), + applicationContextModels.groupByClassId(), + ) } - private fun collectByThisInstanceModel(model: UtModel): Set { + private fun collectByModel(model: UtModel): Set { val dependentModels = mutableSetOf() collectRecursively(model, dependentModels) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgAbstractSpringTestClassConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgAbstractSpringTestClassConstructor.kt index fcfe2c0b72..6510fefc16 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgAbstractSpringTestClassConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgAbstractSpringTestClassConstructor.kt @@ -85,17 +85,9 @@ abstract class CgAbstractSpringTestClassConstructor(context: CgContext): abstract fun constructAdditionalMethods(): CgMethodsCluster protected fun constructFieldsWithAnnotation( + annotationClassId: ClassId, groupedModelsByClassId: TypedModelWrappers, - annotationClassId: ClassId ): List { - require( - annotationClassId == injectMocksClassId || - annotationClassId == mockClassId || - annotationClassId == autowiredClassId - ) { - error("Unexpected annotation classId -- $annotationClassId") - } - val annotation = statementConstructor.annotation(annotationClassId) val constructedDeclarations = mutableListOf() @@ -111,10 +103,8 @@ abstract class CgAbstractSpringTestClassConstructor(context: CgContext): valueByUtModelWrapper[key] = createdVariable } - when (annotationClassId) { - injectMocksClassId -> variableConstructor.injectedMocksModelsVariables += listOfUtModels - mockClassId -> variableConstructor.mockedModelsVariables += listOfUtModels - } + variableConstructor.annotatedModelVariables + .getOrPut(annotationClassId) { mutableSetOf() } += listOfUtModels } return constructedDeclarations @@ -130,12 +120,8 @@ abstract class CgAbstractSpringTestClassConstructor(context: CgContext): * related side effects and just creating a variable definition, * but it will take very long time to do it now. */ - protected fun clearUnwantedVariableModels() { - val whiteListOfModels = - listOf( - variableConstructor.mockedModelsVariables, - variableConstructor.injectedMocksModelsVariables - ).flatten() + private fun clearUnwantedVariableModels() { + val whiteListOfModels = variableConstructor.annotatedModelVariables.values.flatten() valueByUtModelWrapper .filter { it.key !in whiteListOfModels } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringIntegrationTestClassConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringIntegrationTestClassConstructor.kt index 1a19342d68..db134a3464 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringIntegrationTestClassConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringIntegrationTestClassConstructor.kt @@ -9,7 +9,8 @@ import org.utbot.framework.codegen.domain.models.SpringTestClassModel class CgSpringIntegrationTestClassConstructor(context: CgContext) : CgAbstractSpringTestClassConstructor(context) { override fun constructClassFields(testClassModel: SpringTestClassModel): List { - return constructFieldsWithAnnotation(testClassModel.thisInstanceModels, autowiredClassId) + val applicationContextModels = testClassModel.springSpecificInformation.applicationContextModels + return constructFieldsWithAnnotation(autowiredClassId, applicationContextModels) } override fun constructAdditionalMethods() = CgMethodsCluster( diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringUnitTestClassConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringUnitTestClassConstructor.kt index 25474ed26b..09e54b0c82 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringUnitTestClassConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringUnitTestClassConstructor.kt @@ -27,10 +27,12 @@ class CgSpringUnitTestClassConstructor(context: CgContext) : CgAbstractSpringTes override fun constructClassFields(testClassModel: SpringTestClassModel): List { val fields = mutableListOf() + val thisInstances = testClassModel.springSpecificInformation.thisInstanceModels + val mocks = testClassModel.springSpecificInformation.thisInstanceDependentMocks - if (testClassModel.thisInstanceDependentMocks.isNotEmpty()) { - val mockedFields = constructFieldsWithAnnotation(testClassModel.thisInstanceDependentMocks, mockClassId) - val injectingMocksFields = constructFieldsWithAnnotation(testClassModel.thisInstanceModels, injectMocksClassId) + if (mocks.isNotEmpty()) { + val mockedFields = constructFieldsWithAnnotation(mockClassId, mocks) + val injectingMocksFields = constructFieldsWithAnnotation(injectMocksClassId, thisInstances) fields += injectingMocksFields fields += mockedFields diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringVariableConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringVariableConstructor.kt index 03f9a04ead..08c3bf1e3d 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringVariableConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringVariableConstructor.kt @@ -1,9 +1,13 @@ package org.utbot.framework.codegen.tree import org.utbot.framework.codegen.domain.UtModelWrapper +import org.utbot.framework.codegen.domain.builtin.autowiredClassId +import org.utbot.framework.codegen.domain.builtin.injectMocksClassId +import org.utbot.framework.codegen.domain.builtin.mockClassId import org.utbot.framework.codegen.domain.context.CgContext import org.utbot.framework.codegen.domain.models.CgValue import org.utbot.framework.codegen.domain.models.CgVariable +import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.UtAssembleModel import org.utbot.framework.plugin.api.UtCompositeModel import org.utbot.framework.plugin.api.UtModel @@ -11,16 +15,10 @@ import org.utbot.framework.plugin.api.UtSpringContextModel import org.utbot.framework.plugin.api.isMockModel class CgSpringVariableConstructor(context: CgContext) : CgVariableConstructor(context) { - val injectedMocksModelsVariables: MutableSet = mutableSetOf() - val mockedModelsVariables: MutableSet = mutableSetOf() + val annotatedModelVariables: MutableMap> = mutableMapOf() override fun getOrCreateVariable(model: UtModel, name: String?): CgValue { - if (model is UtSpringContextModel) { - // TODO also, properly render corresponding @Autowired field(s), and make sure name isn't taken - return CgVariable(model.modelName, model.classId) - } - - val alreadyCreatedInjectMocks = findCgValueByModel(model, injectedMocksModelsVariables) + val alreadyCreatedInjectMocks = findCgValueByModel(model, annotatedModelVariables[injectMocksClassId]) if (alreadyCreatedInjectMocks != null) { val fields: Collection = when (model) { is UtCompositeModel -> model.fields.values @@ -33,7 +31,7 @@ class CgSpringVariableConstructor(context: CgContext) : CgVariableConstructor(co return alreadyCreatedInjectMocks } - val alreadyCreatedMock = findCgValueByModel(model, mockedModelsVariables) + val alreadyCreatedMock = findCgValueByModel(model, annotatedModelVariables[mockClassId]) if (alreadyCreatedMock != null) { if (model.isMockModel()) { mockFrameworkManager.createMockForVariable( @@ -45,11 +43,26 @@ class CgSpringVariableConstructor(context: CgContext) : CgVariableConstructor(co return alreadyCreatedMock } - return super.getOrCreateVariable(model, name) + val alreadyCreatedAutowired = findCgValueByModel(model, annotatedModelVariables[autowiredClassId]) + if (alreadyCreatedAutowired != null) { + return alreadyCreatedAutowired + } + + return when (model) { + is UtSpringContextModel -> constructSpringContext(model, name) + else -> super.getOrCreateVariable(model, name) + } + } + + private fun constructSpringContext(model: UtSpringContextModel, baseName: String?): CgValue { + val obj = newVar(model.classId, baseName) { utilsClassId[createInstance](model.classId.name) } + + valueByUtModelWrapper[model.wrap()] = obj + return obj } - private fun findCgValueByModel(model: UtModel, setOfModels: Set): CgValue? { - val key = setOfModels.find { it == model.wrap() } + private fun findCgValueByModel(model: UtModel, setOfModels: Set?): CgValue? { + val key = setOfModels?.find { it == model.wrap() } ?: return null return valueByUtModelWrapper[key] } } \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgVariableConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgVariableConstructor.kt index ebb3fd3244..17d743d733 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgVariableConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgVariableConstructor.kt @@ -52,6 +52,7 @@ import org.utbot.framework.plugin.api.UtModel import org.utbot.framework.plugin.api.UtNullModel import org.utbot.framework.plugin.api.UtPrimitiveModel import org.utbot.framework.plugin.api.UtReferenceModel +import org.utbot.framework.plugin.api.UtSpringContextModel import org.utbot.framework.plugin.api.UtStatementCallModel import org.utbot.framework.plugin.api.UtVoidModel import org.utbot.framework.plugin.api.util.classClassId