Skip to content

Commit 5d3465f

Browse files
Autowire not applicationContext but actual variables (#2309)
1 parent 7f914af commit 5d3465f

File tree

9 files changed

+67
-50
lines changed

9 files changed

+67
-50
lines changed

utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -711,11 +711,17 @@ class UtLambdaModel(
711711
}
712712
}
713713

714-
class UtSpringContextModel : UtReferenceModel(
714+
object UtSpringContextModel : UtReferenceModel(
715715
id = null,
716716
classId = SpringModelUtils.applicationContextClassId,
717717
modelName = "applicationContext"
718-
)
718+
) {
719+
// NOTE that overriding equals is required just because without it
720+
// we will lose equality for objects after deserialization
721+
override fun equals(other: Any?): Boolean = other is UtSpringContextModel
722+
723+
override fun hashCode(): Int = 0
724+
}
719725

720726
data class SpringRepositoryId(
721727
val repositoryBeanName: String,

utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/SpringModelUtils.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ object SpringModelUtils {
1414
val crudRepositoryClassId = ClassId("org.springframework.data.repository.CrudRepository")
1515
val entityClassId = ClassId("javax.persistence.Entity")
1616

17-
val getBeanMethodId = MethodId(
17+
private val getBeanMethodId = MethodId(
1818
classId = applicationContextClassId,
1919
name = "getBean",
2020
returnType = Any::class.id,
2121
parameters = listOf(String::class.id),
2222
bypassesSandbox = true // TODO may be we can use some alternative sandbox that has more permissions
2323
)
2424

25-
val saveMethodId = MethodId(
25+
private val saveMethodId = MethodId(
2626
classId = crudRepositoryClassId,
2727
name = "save",
2828
returnType = Any::class.id,
@@ -35,7 +35,7 @@ object SpringModelUtils {
3535
classId = classId,
3636
modelName = "@Autowired $beanName",
3737
instantiationCall = UtExecutableCallModel(
38-
instance = UtSpringContextModel(),
38+
instance = UtSpringContextModel,
3939
executable = getBeanMethodId,
4040
params = listOf(UtPrimitiveModel(beanName))
4141
),
@@ -51,4 +51,7 @@ object SpringModelUtils {
5151
executable = saveMethodId,
5252
params = listOf(entityModel)
5353
)
54+
55+
fun UtModel.isAutowiredFromContext(): Boolean =
56+
this is UtAssembleModel && this.instantiationCall.instance is UtSpringContextModel
5457
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,5 @@ class SpringTestClassModel(
3434
class SpringSpecificInformation(
3535
val thisInstanceModels: TypedModelWrappers = mapOf(),
3636
val thisInstanceDependentMocks: TypedModelWrappers = mapOf(),
37-
val applicationContextModels: TypedModelWrappers = mapOf(),
37+
val autowiredFromContextModels: TypedModelWrappers = mapOf(),
3838
)

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import org.utbot.framework.plugin.api.UtSpringContextModel
2020
import org.utbot.framework.plugin.api.UtStatementCallModel
2121
import org.utbot.framework.plugin.api.UtVoidModel
2222
import org.utbot.framework.plugin.api.isMockModel
23+
import org.utbot.framework.plugin.api.util.SpringModelUtils.isAutowiredFromContext
2324

2425
typealias TypedModelWrappers = Map<ClassId, Set<UtModelWrapper>>
2526

@@ -70,14 +71,13 @@ class SpringTestClassModelBuilder(val context: CgContext): TestClassModelBuilder
7071
cgModel.model.isMockModel() && cgModel !in thisInstanceModels
7172
}
7273

73-
val applicationContextModels = stateBeforeDependentModels
74-
.filter { it.model is UtSpringContextModel }
75-
.toSet()
74+
val autowiredFromContextModels =
75+
stateBeforeDependentModels.filterTo(HashSet()) { it.model.isAutowiredFromContext() }
7676

7777
return SpringSpecificInformation(
7878
thisInstanceModels.groupByClassId(),
7979
dependentMockModels.groupByClassId(),
80-
applicationContextModels.groupByClassId(),
80+
autowiredFromContextModels.groupByClassId(),
8181
)
8282
}
8383

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
package org.utbot.framework.codegen.tree
22

33
import org.utbot.framework.codegen.domain.builtin.TestClassUtilMethodProvider
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
74
import org.utbot.framework.codegen.domain.context.CgContext
85
import org.utbot.framework.codegen.domain.models.CgClassBody
96
import org.utbot.framework.codegen.domain.models.CgDeclaration
@@ -19,6 +16,7 @@ import org.utbot.framework.codegen.domain.models.CgVariable
1916
import org.utbot.framework.codegen.domain.models.SpringTestClassModel
2017
import org.utbot.framework.codegen.domain.models.builders.TypedModelWrappers
2118
import org.utbot.framework.plugin.api.ClassId
19+
import org.utbot.framework.plugin.api.UtSpringContextModel
2220
import org.utbot.framework.plugin.api.util.id
2321
import java.lang.Exception
2422

@@ -111,7 +109,7 @@ abstract class CgAbstractSpringTestClassConstructor(context: CgContext):
111109
}
112110

113111
/**
114-
* Clears the results of variable instantiations that occured
112+
* Clears the results of variable instantiations that occurred
115113
* when we create class variables with specific annotations.
116114
* Actually, only mentioned variables should be stored in `valueByModelId`.
117115
*
@@ -121,10 +119,11 @@ abstract class CgAbstractSpringTestClassConstructor(context: CgContext):
121119
* but it will take very long time to do it now.
122120
*/
123121
private fun clearUnwantedVariableModels() {
124-
val whiteListOfModels = variableConstructor.annotatedModelVariables.values.flatten()
122+
val trustedListOfModels =
123+
variableConstructor.annotatedModelVariables.values.flatten() + listOf(UtSpringContextModel.wrap())
125124

126125
valueByUtModelWrapper
127-
.filter { it.key !in whiteListOfModels }
126+
.filterNot { it.key in trustedListOfModels }
128127
.forEach { valueByUtModelWrapper.remove(it.key) }
129128
}
130129

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ import org.utbot.framework.codegen.domain.context.CgContext
55
import org.utbot.framework.codegen.domain.models.CgFieldDeclaration
66
import org.utbot.framework.codegen.domain.models.CgMethodsCluster
77
import org.utbot.framework.codegen.domain.models.SpringTestClassModel
8+
import org.utbot.framework.plugin.api.UtSpringContextModel
89

910
class CgSpringIntegrationTestClassConstructor(context: CgContext) : CgAbstractSpringTestClassConstructor(context) {
1011

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

1617
override fun constructAdditionalMethods() = CgMethodsCluster(

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

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import org.utbot.framework.codegen.domain.builtin.autowiredClassId
55
import org.utbot.framework.codegen.domain.builtin.injectMocksClassId
66
import org.utbot.framework.codegen.domain.builtin.mockClassId
77
import org.utbot.framework.codegen.domain.context.CgContext
8+
import org.utbot.framework.codegen.domain.models.CgLiteral
89
import org.utbot.framework.codegen.domain.models.CgValue
910
import org.utbot.framework.codegen.domain.models.CgVariable
1011
import org.utbot.framework.plugin.api.ClassId
@@ -13,6 +14,9 @@ import org.utbot.framework.plugin.api.UtCompositeModel
1314
import org.utbot.framework.plugin.api.UtModel
1415
import org.utbot.framework.plugin.api.UtSpringContextModel
1516
import org.utbot.framework.plugin.api.isMockModel
17+
import org.utbot.framework.plugin.api.util.SpringModelUtils.applicationContextClassId
18+
import org.utbot.framework.plugin.api.util.SpringModelUtils.isAutowiredFromContext
19+
import org.utbot.framework.plugin.api.util.stringClassId
1620

1721
class CgSpringVariableConstructor(context: CgContext) : CgVariableConstructor(context) {
1822
val annotatedModelVariables: MutableMap<ClassId, MutableSet<UtModelWrapper>> = mutableMapOf()
@@ -45,20 +49,29 @@ class CgSpringVariableConstructor(context: CgContext) : CgVariableConstructor(co
4549

4650
val alreadyCreatedAutowired = findCgValueByModel(model, annotatedModelVariables[autowiredClassId])
4751
if (alreadyCreatedAutowired != null) {
48-
return alreadyCreatedAutowired
52+
return when {
53+
model.isAutowiredFromContext() -> {
54+
super.constructAssembleForVariable(model as UtAssembleModel)
55+
}
56+
else -> error("Trying to autowire model $model but it is not appropriate")
57+
}
4958
}
5059

5160
return when (model) {
52-
is UtSpringContextModel -> constructSpringContext(model, name)
61+
is UtSpringContextModel -> createApplicationContextVariable()
5362
else -> super.getOrCreateVariable(model, name)
5463
}
5564
}
5665

57-
private fun constructSpringContext(model: UtSpringContextModel, baseName: String?): CgValue {
58-
val obj = newVar(model.classId, baseName) { utilsClassId[createInstance](model.classId.name) }
66+
private fun createApplicationContextVariable(): CgValue {
67+
// This is a kind of HACK
68+
// Actually, applicationContext variable is useless as it is not used in the generated code.
69+
// However, this variable existence is required for autowired fields creation process.
70+
val applicationContextVariable = CgLiteral(stringClassId, "applicationContext")
5971

60-
valueByUtModelWrapper[model.wrap()] = obj
61-
return obj
72+
return applicationContextVariable.also {
73+
valueByUtModelWrapper[UtSpringContextModel.wrap()] = it
74+
}
6275
}
6376

6477
private fun findCgValueByModel(model: UtModel, setOfModels: Set<UtModelWrapper>?): CgValue? {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ import kotlin.reflect.KFunction
7272
import kotlin.reflect.jvm.kotlinFunction
7373

7474
interface CgStatementConstructor {
75+
7576
fun newVar(baseType: ClassId, baseName: String? = null, init: () -> CgExpression): CgVariable =
7677
newVar(baseType, model = null, baseName, isMutable = false, init)
7778

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

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ import org.utbot.framework.plugin.api.BuiltinClassId
3737
import org.utbot.framework.plugin.api.ClassId
3838
import org.utbot.framework.plugin.api.CodegenLanguage
3939
import org.utbot.framework.plugin.api.ConstructorId
40-
import org.utbot.framework.plugin.api.DirectFieldAccessId
4140
import org.utbot.framework.plugin.api.MethodId
4241
import org.utbot.framework.plugin.api.UtArrayModel
4342
import org.utbot.framework.plugin.api.UtAssembleModel
@@ -52,7 +51,6 @@ import org.utbot.framework.plugin.api.UtModel
5251
import org.utbot.framework.plugin.api.UtNullModel
5352
import org.utbot.framework.plugin.api.UtPrimitiveModel
5453
import org.utbot.framework.plugin.api.UtReferenceModel
55-
import org.utbot.framework.plugin.api.UtSpringContextModel
5654
import org.utbot.framework.plugin.api.UtStatementCallModel
5755
import org.utbot.framework.plugin.api.UtVoidModel
5856
import org.utbot.framework.plugin.api.util.classClassId
@@ -209,9 +207,27 @@ open class CgVariableConstructor(val context: CgContext) :
209207
}
210208

211209
private fun constructAssemble(model: UtAssembleModel, baseName: String?): CgValue {
212-
val instantiationCall = model.instantiationCall
213-
processInstantiationStatement(model, instantiationCall, baseName)
210+
instantiateAssembleModel(model, baseName)
211+
return constructAssembleForVariable(model)
212+
}
213+
214+
private fun instantiateAssembleModel(model: UtAssembleModel, baseName: String?) {
215+
val statementCall = model.instantiationCall
216+
val executable = statementCall.statement
217+
val params = statementCall.params
218+
219+
// Don't use redundant constructors for primitives and String
220+
val initExpr = if (executable is ConstructorId && isPrimitiveWrapperOrString(model.classId)) {
221+
cgLiteralForWrapper(params)
222+
} else {
223+
createCgExecutableCallFromUtExecutableCall(statementCall)
224+
}
214225

226+
newVar(model.classId, model, baseName) { initExpr }
227+
.also { valueByUtModelWrapper[model.wrap()] = it }
228+
}
229+
230+
protected fun constructAssembleForVariable(model: UtAssembleModel): CgValue {
215231
for (statementModel in model.modificationsChain) {
216232
when (statementModel) {
217233
is UtDirectSetFieldModel -> {
@@ -233,28 +249,6 @@ open class CgVariableConstructor(val context: CgContext) :
233249
return valueByUtModelWrapper.getValue(model.wrap())
234250
}
235251

236-
private fun processInstantiationStatement(
237-
model: UtAssembleModel,
238-
statementCall: UtStatementCallModel,
239-
baseName: String?
240-
) {
241-
val executable = statementCall.statement
242-
val params = statementCall.params
243-
244-
// Don't use redundant constructors for primitives and String
245-
val initExpr = if (executable is ConstructorId && isPrimitiveWrapperOrString(model.classId)) {
246-
cgLiteralForWrapper(params)
247-
} else {
248-
createCgExecutableCallFromUtExecutableCall(statementCall)
249-
}
250-
newVar(model.classId, model, baseName) {
251-
initExpr
252-
}.also {
253-
valueByUtModelWrapper[model.wrap()] = it
254-
}
255-
}
256-
257-
258252
private fun createCgExecutableCallFromUtExecutableCall(statementModel: UtStatementCallModel): CgExecutableCall =
259253
when (statementModel) {
260254
is UtExecutableCallModel -> {

0 commit comments

Comments
 (0)