Skip to content

Commit 8227e23

Browse files
Introduce autowired class variables #2240 (#2248)
1 parent d7319b0 commit 8227e23

File tree

7 files changed

+66
-48
lines changed

7 files changed

+66
-48
lines changed

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/TestClassModel.kt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,17 @@ class SimpleTestClassModel(
2222

2323
/**
2424
* Extended [SimpleTestClassModel] for Spring analysis reasons
25-
*
26-
* @param injectingMocksClass a class to inject other mocks into
27-
* @param mockedClasses variables of test class to represent mocked instances
2825
*/
2926
class SpringTestClassModel(
3027
classUnderTest: ClassId,
3128
methodTestSets: List<CgMethodTestSet>,
3229
nestedClasses: List<SimpleTestClassModel>,
33-
val thisInstanceModels: TypedModelWrappers = mapOf(),
34-
val thisInstanceDependentMocks: TypedModelWrappers = mapOf(),
30+
val springSpecificInformation: SpringSpecificInformation,
3531
): TestClassModel(classUnderTest, methodTestSets, nestedClasses)
3632

33+
34+
class SpringSpecificInformation(
35+
val thisInstanceModels: TypedModelWrappers = mapOf(),
36+
val thisInstanceDependentMocks: TypedModelWrappers = mapOf(),
37+
val applicationContextModels: TypedModelWrappers = mapOf(),
38+
)

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/models/builders/SpringTestClassModelBuilder.kt

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package org.utbot.framework.codegen.domain.models.builders
33
import org.utbot.framework.codegen.domain.UtModelWrapper
44
import org.utbot.framework.codegen.domain.context.CgContext
55
import org.utbot.framework.codegen.domain.models.CgMethodTestSet
6+
import org.utbot.framework.codegen.domain.models.SpringSpecificInformation
67
import org.utbot.framework.codegen.domain.models.SpringTestClassModel
78
import org.utbot.framework.plugin.api.ClassId
89
import org.utbot.framework.plugin.api.UtArrayModel
@@ -11,7 +12,6 @@ import org.utbot.framework.plugin.api.UtClassRefModel
1112
import org.utbot.framework.plugin.api.UtCompositeModel
1213
import org.utbot.framework.plugin.api.UtDirectSetFieldModel
1314
import org.utbot.framework.plugin.api.UtEnumConstantModel
14-
import org.utbot.framework.plugin.api.UtExecutableCallModel
1515
import org.utbot.framework.plugin.api.UtLambdaModel
1616
import org.utbot.framework.plugin.api.UtModel
1717
import org.utbot.framework.plugin.api.UtNullModel
@@ -27,20 +27,20 @@ class SpringTestClassModelBuilder(val context: CgContext): TestClassModelBuilder
2727

2828
override fun createTestClassModel(classUnderTest: ClassId, testSets: List<CgMethodTestSet>): SpringTestClassModel {
2929
val baseModel = SimpleTestClassModelBuilder(context).createTestClassModel(classUnderTest, testSets)
30-
val (thisInstanceModels, dependentMockModels) = collectThisInstanceAndDependentModels(testSets)
30+
val springSpecificInformation = collectSpecificModelsForClassVariables(testSets)
3131

3232
return SpringTestClassModel(
3333
classUnderTest = baseModel.classUnderTest,
3434
methodTestSets = baseModel.methodTestSets,
3535
nestedClasses = baseModel.nestedClasses,
36-
thisInstanceModels = thisInstanceModels,
37-
thisInstanceDependentMocks = dependentMockModels
36+
springSpecificInformation = springSpecificInformation
3837
)
3938
}
4039

41-
private fun collectThisInstanceAndDependentModels(testSets: List<CgMethodTestSet>): Pair<TypedModelWrappers, TypedModelWrappers> {
40+
private fun collectSpecificModelsForClassVariables(testSets: List<CgMethodTestSet>): SpringSpecificInformation {
4241
val thisInstanceModels = mutableSetOf<UtModelWrapper>()
4342
val thisInstancesDependentModels = mutableSetOf<UtModelWrapper>()
43+
val stateBeforeDependentModels = mutableSetOf<UtModelWrapper>()
4444

4545
with(context) {
4646
for ((testSetIndex, testSet) in testSets.withIndex()) {
@@ -51,8 +51,13 @@ class SpringTestClassModelBuilder(val context: CgContext): TestClassModelBuilder
5151
.filterNotNull()
5252
.forEach { model ->
5353
thisInstanceModels += model.wrap()
54-
thisInstancesDependentModels += collectByThisInstanceModel(model)
54+
thisInstancesDependentModels += collectByModel(model)
55+
5556
}
57+
58+
(execution.stateBefore.parameters + execution.stateBefore.thisInstance)
59+
.filterNotNull()
60+
.forEach { model -> stateBeforeDependentModels += collectByModel(model) }
5661
}
5762
}
5863
}
@@ -65,10 +70,18 @@ class SpringTestClassModelBuilder(val context: CgContext): TestClassModelBuilder
6570
cgModel.model.isMockModel() && cgModel !in thisInstanceModels
6671
}
6772

68-
return thisInstanceModels.groupByClassId() to dependentMockModels.groupByClassId()
73+
val applicationContextModels = stateBeforeDependentModels
74+
.filter { it.model is UtSpringContextModel }
75+
.toSet()
76+
77+
return SpringSpecificInformation(
78+
thisInstanceModels.groupByClassId(),
79+
dependentMockModels.groupByClassId(),
80+
applicationContextModels.groupByClassId(),
81+
)
6982
}
7083

71-
private fun collectByThisInstanceModel(model: UtModel): Set<UtModelWrapper> {
84+
private fun collectByModel(model: UtModel): Set<UtModelWrapper> {
7285
val dependentModels = mutableSetOf<UtModelWrapper>()
7386
collectRecursively(model, dependentModels)
7487

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgAbstractSpringTestClassConstructor.kt

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -85,17 +85,9 @@ abstract class CgAbstractSpringTestClassConstructor(context: CgContext):
8585
abstract fun constructAdditionalMethods(): CgMethodsCluster
8686

8787
protected fun constructFieldsWithAnnotation(
88+
annotationClassId: ClassId,
8889
groupedModelsByClassId: TypedModelWrappers,
89-
annotationClassId: ClassId
9090
): List<CgFieldDeclaration> {
91-
require(
92-
annotationClassId == injectMocksClassId ||
93-
annotationClassId == mockClassId ||
94-
annotationClassId == autowiredClassId
95-
) {
96-
error("Unexpected annotation classId -- $annotationClassId")
97-
}
98-
9991
val annotation = statementConstructor.annotation(annotationClassId)
10092

10193
val constructedDeclarations = mutableListOf<CgFieldDeclaration>()
@@ -111,10 +103,8 @@ abstract class CgAbstractSpringTestClassConstructor(context: CgContext):
111103
valueByUtModelWrapper[key] = createdVariable
112104
}
113105

114-
when (annotationClassId) {
115-
injectMocksClassId -> variableConstructor.injectedMocksModelsVariables += listOfUtModels
116-
mockClassId -> variableConstructor.mockedModelsVariables += listOfUtModels
117-
}
106+
variableConstructor.annotatedModelVariables
107+
.getOrPut(annotationClassId) { mutableSetOf() } += listOfUtModels
118108
}
119109

120110
return constructedDeclarations
@@ -130,12 +120,8 @@ abstract class CgAbstractSpringTestClassConstructor(context: CgContext):
130120
* related side effects and just creating a variable definition,
131121
* but it will take very long time to do it now.
132122
*/
133-
protected fun clearUnwantedVariableModels() {
134-
val whiteListOfModels =
135-
listOf(
136-
variableConstructor.mockedModelsVariables,
137-
variableConstructor.injectedMocksModelsVariables
138-
).flatten()
123+
private fun clearUnwantedVariableModels() {
124+
val whiteListOfModels = variableConstructor.annotatedModelVariables.values.flatten()
139125

140126
valueByUtModelWrapper
141127
.filter { it.key !in whiteListOfModels }

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringIntegrationTestClassConstructor.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import org.utbot.framework.codegen.domain.models.SpringTestClassModel
99
class CgSpringIntegrationTestClassConstructor(context: CgContext) : CgAbstractSpringTestClassConstructor(context) {
1010

1111
override fun constructClassFields(testClassModel: SpringTestClassModel): List<CgFieldDeclaration> {
12-
return constructFieldsWithAnnotation(testClassModel.thisInstanceModels, autowiredClassId)
12+
val applicationContextModels = testClassModel.springSpecificInformation.applicationContextModels
13+
return constructFieldsWithAnnotation(autowiredClassId, applicationContextModels)
1314
}
1415

1516
override fun constructAdditionalMethods() = CgMethodsCluster(

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgSpringUnitTestClassConstructor.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ class CgSpringUnitTestClassConstructor(context: CgContext) : CgAbstractSpringTes
2727

2828
override fun constructClassFields(testClassModel: SpringTestClassModel): List<CgFieldDeclaration> {
2929
val fields = mutableListOf<CgFieldDeclaration>()
30+
val thisInstances = testClassModel.springSpecificInformation.thisInstanceModels
31+
val mocks = testClassModel.springSpecificInformation.thisInstanceDependentMocks
3032

31-
if (testClassModel.thisInstanceDependentMocks.isNotEmpty()) {
32-
val mockedFields = constructFieldsWithAnnotation(testClassModel.thisInstanceDependentMocks, mockClassId)
33-
val injectingMocksFields = constructFieldsWithAnnotation(testClassModel.thisInstanceModels, injectMocksClassId)
33+
if (mocks.isNotEmpty()) {
34+
val mockedFields = constructFieldsWithAnnotation(mockClassId, mocks)
35+
val injectingMocksFields = constructFieldsWithAnnotation(injectMocksClassId, thisInstances)
3436

3537
fields += injectingMocksFields
3638
fields += mockedFields
Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,24 @@
11
package org.utbot.framework.codegen.tree
22

33
import org.utbot.framework.codegen.domain.UtModelWrapper
4+
import org.utbot.framework.codegen.domain.builtin.autowiredClassId
5+
import org.utbot.framework.codegen.domain.builtin.injectMocksClassId
6+
import org.utbot.framework.codegen.domain.builtin.mockClassId
47
import org.utbot.framework.codegen.domain.context.CgContext
58
import org.utbot.framework.codegen.domain.models.CgValue
69
import org.utbot.framework.codegen.domain.models.CgVariable
10+
import org.utbot.framework.plugin.api.ClassId
711
import org.utbot.framework.plugin.api.UtAssembleModel
812
import org.utbot.framework.plugin.api.UtCompositeModel
913
import org.utbot.framework.plugin.api.UtModel
1014
import org.utbot.framework.plugin.api.UtSpringContextModel
1115
import org.utbot.framework.plugin.api.isMockModel
1216

1317
class CgSpringVariableConstructor(context: CgContext) : CgVariableConstructor(context) {
14-
val injectedMocksModelsVariables: MutableSet<UtModelWrapper> = mutableSetOf()
15-
val mockedModelsVariables: MutableSet<UtModelWrapper> = mutableSetOf()
18+
val annotatedModelVariables: MutableMap<ClassId, MutableSet<UtModelWrapper>> = mutableMapOf()
1619

1720
override fun getOrCreateVariable(model: UtModel, name: String?): CgValue {
18-
if (model is UtSpringContextModel) {
19-
// TODO also, properly render corresponding @Autowired field(s), and make sure name isn't taken
20-
return CgVariable(model.modelName, model.classId)
21-
}
22-
23-
val alreadyCreatedInjectMocks = findCgValueByModel(model, injectedMocksModelsVariables)
21+
val alreadyCreatedInjectMocks = findCgValueByModel(model, annotatedModelVariables[injectMocksClassId])
2422
if (alreadyCreatedInjectMocks != null) {
2523
val fields: Collection<UtModel> = when (model) {
2624
is UtCompositeModel -> model.fields.values
@@ -33,7 +31,7 @@ class CgSpringVariableConstructor(context: CgContext) : CgVariableConstructor(co
3331
return alreadyCreatedInjectMocks
3432
}
3533

36-
val alreadyCreatedMock = findCgValueByModel(model, mockedModelsVariables)
34+
val alreadyCreatedMock = findCgValueByModel(model, annotatedModelVariables[mockClassId])
3735
if (alreadyCreatedMock != null) {
3836
if (model.isMockModel()) {
3937
mockFrameworkManager.createMockForVariable(
@@ -45,11 +43,26 @@ class CgSpringVariableConstructor(context: CgContext) : CgVariableConstructor(co
4543
return alreadyCreatedMock
4644
}
4745

48-
return super.getOrCreateVariable(model, name)
46+
val alreadyCreatedAutowired = findCgValueByModel(model, annotatedModelVariables[autowiredClassId])
47+
if (alreadyCreatedAutowired != null) {
48+
return alreadyCreatedAutowired
49+
}
50+
51+
return when (model) {
52+
is UtSpringContextModel -> constructSpringContext(model, name)
53+
else -> super.getOrCreateVariable(model, name)
54+
}
55+
}
56+
57+
private fun constructSpringContext(model: UtSpringContextModel, baseName: String?): CgValue {
58+
val obj = newVar(model.classId, baseName) { utilsClassId[createInstance](model.classId.name) }
59+
60+
valueByUtModelWrapper[model.wrap()] = obj
61+
return obj
4962
}
5063

51-
private fun findCgValueByModel(model: UtModel, setOfModels: Set<UtModelWrapper>): CgValue? {
52-
val key = setOfModels.find { it == model.wrap() }
64+
private fun findCgValueByModel(model: UtModel, setOfModels: Set<UtModelWrapper>?): CgValue? {
65+
val key = setOfModels?.find { it == model.wrap() } ?: return null
5366
return valueByUtModelWrapper[key]
5467
}
5568
}

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgVariableConstructor.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import org.utbot.framework.plugin.api.UtModel
5252
import org.utbot.framework.plugin.api.UtNullModel
5353
import org.utbot.framework.plugin.api.UtPrimitiveModel
5454
import org.utbot.framework.plugin.api.UtReferenceModel
55+
import org.utbot.framework.plugin.api.UtSpringContextModel
5556
import org.utbot.framework.plugin.api.UtStatementCallModel
5657
import org.utbot.framework.plugin.api.UtVoidModel
5758
import org.utbot.framework.plugin.api.util.classClassId

0 commit comments

Comments
 (0)