Skip to content

Commit 14aef84

Browse files
UtAssembleModel refactor #812 (#970)
1 parent aa8f7a9 commit 14aef84

File tree

28 files changed

+348
-359
lines changed

28 files changed

+348
-359
lines changed

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

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -471,26 +471,52 @@ data class UtArrayModel(
471471
/**
472472
* Model for complex objects with assemble instructions.
473473
*
474-
* @param instantiationChain is a chain of [UtStatementModel] to instantiate represented object
475-
* @param modificationsChain is a chain of [UtStatementModel] to construct object state
474+
* The default constructor is made private to enforce using a safe constructor.
475+
*
476+
* @param instantiationCall is an [UtExecutableCallModel] to instantiate represented object. It **must** not return `null`.
477+
* @param modificationsChain is a chain of [UtStatementModel] to construct object state.
476478
*/
477-
data class UtAssembleModel(
479+
data class UtAssembleModel private constructor(
478480
override val id: Int?,
479481
override val classId: ClassId,
480482
override val modelName: String,
481-
val instantiationChain: List<UtStatementModel> = emptyList(),
482-
val modificationsChain: List<UtStatementModel> = emptyList(),
483-
val origin: UtCompositeModel? = null
483+
val instantiationCall: UtExecutableCallModel,
484+
val modificationsChain: List<UtStatementModel>,
485+
val origin: UtCompositeModel?
484486
) : UtReferenceModel(id, classId, modelName) {
485-
val allStatementsChain
486-
get() = instantiationChain + modificationsChain
487-
val finalInstantiationModel
488-
get() = instantiationChain.lastOrNull()
487+
488+
/**
489+
* Creates a new [UtAssembleModel].
490+
*
491+
* Please note, that it's the caller responsibility to properly cache [UtModel]s to prevent an infinite recursion.
492+
* The order of the calling:
493+
* 1. [instantiationCall]
494+
* 2. [constructor]
495+
* 3. [modificationsChainProvider]. Possible caching should be made at the beginning of this method.
496+
*
497+
* @param instantiationCall defines the single instruction, which provides a [UtAssembleModel]. It could be a
498+
* constructor or a method of another class, which returns the object of the [classId] type.
499+
*
500+
* @param modificationsChainProvider used for creating modifying statements. Its receiver corresponds to newly
501+
* created [UtAssembleModel], so you can use it for caching and for creating [UtExecutableCallModel]s with it
502+
* as [UtExecutableCallModel.instance].
503+
*/
504+
constructor(
505+
id: Int?,
506+
classId: ClassId,
507+
modelName: String,
508+
instantiationCall: UtExecutableCallModel,
509+
origin: UtCompositeModel? = null,
510+
modificationsChainProvider: UtAssembleModel.() -> List<UtStatementModel> = { emptyList() }
511+
) : this(id, classId, modelName, instantiationCall, mutableListOf(), origin) {
512+
val modificationChainStatements = modificationsChainProvider()
513+
(modificationsChain as MutableList<UtStatementModel>).addAll(modificationChainStatements)
514+
}
489515

490516
override fun toString() = withToStringThreadLocalReentrancyGuard {
491517
buildString {
492518
append("UtAssembleModel(${classId.simpleName} $modelName) ")
493-
append(instantiationChain.joinToString(" "))
519+
append(instantiationCall)
494520
if (modificationsChain.isNotEmpty()) {
495521
append(" ")
496522
append(modificationsChain.joinToString(" "))
@@ -562,13 +588,13 @@ sealed class UtStatementModel(
562588
* Step of assemble instruction that calls executable.
563589
*
564590
* Contains executable to call, call parameters and an instance model before call.
565-
* Return value is used for tracking objects and call others methods with these tracking objects as parameters.
591+
*
592+
* @param [instance] **must be** `null` for static methods and constructors
566593
*/
567594
data class UtExecutableCallModel(
568595
override val instance: UtReferenceModel?,
569596
val executable: ExecutableId,
570597
val params: List<UtModel>,
571-
val returnValue: UtReferenceModel? = null,
572598
) : UtStatementModel(instance) {
573599
override fun toString() = withToStringThreadLocalReentrancyGuard {
574600
buildString {
@@ -578,9 +604,7 @@ data class UtExecutableCallModel(
578604
is MethodId -> executable.name
579605
}
580606

581-
if (returnValue != null) {
582-
append("val ${returnValue.modelName} = ")
583-
} else if (instance != null) {
607+
if (instance != null) {
584608
append("${instance.modelName}.")
585609
}
586610

utbot-framework-test/src/test/kotlin/org/utbot/examples/codegen/deepequals/ClassWithCrossReferenceRelationshipTest.kt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
package org.utbot.examples.codegen.deepequals
22

3-
import org.junit.jupiter.api.Disabled
43
import org.junit.jupiter.api.Test
5-
import org.utbot.tests.infrastructure.DoNotCalculate
6-
import org.utbot.tests.infrastructure.UtValueTestCaseChecker
74
import org.utbot.framework.plugin.api.CodegenLanguage
85
import org.utbot.testcheckers.eq
96
import org.utbot.tests.infrastructure.CodeGeneration
7+
import org.utbot.tests.infrastructure.DoNotCalculate
8+
import org.utbot.tests.infrastructure.UtValueTestCaseChecker
109

1110
class ClassWithCrossReferenceRelationshipTest : UtValueTestCaseChecker(
1211
testClass = ClassWithCrossReferenceRelationship::class,
@@ -16,8 +15,6 @@ class ClassWithCrossReferenceRelationshipTest : UtValueTestCaseChecker(
1615
CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration)
1716
)
1817
) {
19-
// TODO: The test is disabled due to [https://github.com/UnitTestBot/UTBotJava/issues/812]
20-
@Disabled
2118
@Test
2219
fun testClassWithCrossReferenceRelationship() {
2320
check(

utbot-framework-test/src/test/kotlin/org/utbot/examples/models/ModelsIdEqualityChecker.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ internal class ModelsIdEqualityChecker : UtModelTestCaseChecker(
129129

130130
private fun UtReferenceModel.findFieldId(): Int? {
131131
this as UtAssembleModel
132-
val fieldModel = this.allStatementsChain
132+
val fieldModel = this.modificationsChain
133133
.filterIsInstance<UtDirectSetFieldModel>()
134134
.single()
135135
.fieldModel

utbot-framework-test/src/test/kotlin/org/utbot/framework/assemble/AssembleModelGeneratorTests.kt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ class AssembleModelGeneratorTests {
184184
val firstExpectedRepresentation = printExpectedModel(testClassId.simpleName, v1, statementsChain.toList())
185185

186186
statementsChain.clear()
187-
statementsChain.add("val $v2 = ${innerClassId.canonicalName}()")
187+
statementsChain.add("${innerClassId.canonicalName}()")
188188
statementsChain.add("$v2." + addExpectedSetter("a", 2))
189189
statementsChain.add("$v2." + ("b" `=` 4))
190190
val secondExpectedRepresentation = printExpectedModel(innerClassId.simpleName, v2, statementsChain.toList())
@@ -238,7 +238,7 @@ class AssembleModelGeneratorTests {
238238
val firstExpectedRepresentation = printExpectedModel(listClassId.simpleName, v1, statementsChain.toList())
239239

240240
statementsChain.clear()
241-
statementsChain.add("val $v2 = ${listClassId.canonicalName}()")
241+
statementsChain.add("${listClassId.canonicalName}()")
242242
statementsChain.add("$v2." + addExpectedSetter("value", 2))
243243
val secondExpectedRepresentation = printExpectedModel(listClassId.simpleName, v2, statementsChain.toList())
244244

@@ -268,13 +268,13 @@ class AssembleModelGeneratorTests {
268268
val firstExpectedRepresentation = printExpectedModel(listClassId.simpleName, v1, statementsChain.toList())
269269

270270
statementsChain.clear()
271-
statementsChain.add("val $v2 = ${listClassId.canonicalName}()")
271+
statementsChain.add("${listClassId.canonicalName}()")
272272
statementsChain.add("$v2." + addExpectedSetter("value", 2))
273273
statementsChain.add("$v2." + addExpectedSetter("next", v3))
274274
val secondExpectedRepresentation = printExpectedModel(listClassId.simpleName, v2, statementsChain.toList())
275275

276276
statementsChain.clear()
277-
statementsChain.add("val $v3 = ${listClassId.canonicalName}()")
277+
statementsChain.add("${listClassId.canonicalName}()")
278278
statementsChain.add("$v3." + addExpectedSetter("value", 3))
279279
statementsChain.add("$v3." + addExpectedSetter("next", v1))
280280
val thirdExpectedRepresentation = printExpectedModel(listClassId.simpleName, v3, statementsChain.toList())
@@ -989,7 +989,7 @@ class AssembleModelGeneratorTests {
989989
val firstExpectedRepresentation = printExpectedModel(listClassId.simpleName, v1, statementsChain.toList())
990990

991991
statementsChain.clear()
992-
statementsChain.add("val $v2 = ${listClassId.canonicalName}()")
992+
statementsChain.add("${listClassId.canonicalName}()")
993993
statementsChain.add("$v2." + addExpectedSetter("value", 2))
994994
val secondExpectedRepresentation = printExpectedModel(listClassId.simpleName, v2, statementsChain.toList())
995995

@@ -1017,7 +1017,7 @@ class AssembleModelGeneratorTests {
10171017
val firstExpectedRepresentation = printExpectedModel(listClassId.simpleName, v1, statementsChain.toList())
10181018

10191019
statementsChain.clear()
1020-
statementsChain.add("val $v2 = ${listClassId.canonicalName}()")
1020+
statementsChain.add("${listClassId.canonicalName}()")
10211021
statementsChain.add("$v2." + addExpectedSetter("value", 2))
10221022
statementsChain.add("$v2." + addExpectedSetter("next", v1))
10231023
val secondExpectedRepresentation = printExpectedModel(listClassId.simpleName, v2, statementsChain)
@@ -1140,7 +1140,7 @@ class AssembleModelGeneratorTests {
11401140
statementsChain.add(
11411141
"$v1." + ("array" `=` "[" +
11421142
"null, " +
1143-
"UtAssembleModel(${innerClassId.simpleName} $v2) val $v2 = ${innerClassId.canonicalName}() $v2.setA(5), " +
1143+
"UtAssembleModel(${innerClassId.simpleName} $v2) ${innerClassId.canonicalName}() $v2.setA(5), " +
11441144
"null" +
11451145
"]")
11461146
)
@@ -1240,8 +1240,8 @@ class AssembleModelGeneratorTests {
12401240
val v3 = createExpectedVariableName<PrimitiveFields>()
12411241
statementsChain.add(
12421242
"$v1." + ("array" `=` "[" +
1243-
"[UtAssembleModel(${innerClassId.simpleName} $v2) val $v2 = ${innerClassId.canonicalName}() $v2.setA(5), ${null}], " +
1244-
"[UtAssembleModel(${innerClassId.simpleName} $v3) val $v3 = ${innerClassId.canonicalName}() $v3.b = 4, ${null}]" +
1243+
"[UtAssembleModel(${innerClassId.simpleName} $v2) ${innerClassId.canonicalName}() $v2.setA(5), ${null}], " +
1244+
"[UtAssembleModel(${innerClassId.simpleName} $v3) ${innerClassId.canonicalName}() $v3.b = 4, ${null}]" +
12451245
"]")
12461246
)
12471247

@@ -1480,7 +1480,7 @@ class AssembleModelGeneratorTests {
14801480
val varName = createExpectedVariableName<T>()
14811481

14821482
val paramString = if (params.any()) params.joinToString(", ") else ""
1483-
this.add("val $varName = $fqn($paramString)")
1483+
this.add("$fqn($paramString)")
14841484

14851485
return varName
14861486
}

utbot-framework/src/main/kotlin/org/utbot/engine/CollectionWrappers.kt

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -119,22 +119,15 @@ abstract class BaseContainerWrapper(containerClassName: String) : BaseOverridden
119119

120120
val classId = chooseClassIdWithConstructor(wrapper.type.sootClass.id)
121121

122-
val instantiationChain = mutableListOf<UtStatementModel>()
123-
val modificationsChain = mutableListOf<UtStatementModel>()
124-
125-
UtAssembleModel(addr, classId, modelName, instantiationChain, modificationsChain)
126-
.apply {
127-
instantiationChain += UtExecutableCallModel(
128-
instance = null,
129-
executable = constructorId(classId),
130-
params = emptyList(),
131-
returnValue = this
132-
)
122+
val instantiationCall = UtExecutableCallModel(
123+
instance = null,
124+
executable = constructorId(classId),
125+
params = emptyList()
126+
)
133127

134-
modificationsChain += parameterModels.map {
135-
UtExecutableCallModel(this, modificationMethodId, it)
136-
}
137-
}
128+
UtAssembleModel(addr, classId, modelName, instantiationCall) {
129+
parameterModels.map { UtExecutableCallModel(this, modificationMethodId, it) }
130+
}
138131
}
139132

140133
/**

utbot-framework/src/main/kotlin/org/utbot/engine/ObjectWrappers.kt

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -241,18 +241,15 @@ data class ThrowableWrapper(val throwable: Throwable) : WrapperInterface {
241241
val addr = resolver.holder.concreteAddr(wrapper.addr)
242242
val modelName = nextModelName(throwable.javaClass.simpleName.decapitalize())
243243

244-
val instantiationChain = mutableListOf<UtStatementModel>()
245-
return UtAssembleModel(addr, classId, modelName, instantiationChain)
246-
.apply {
247-
instantiationChain += when (val message = throwable.message) {
248-
null -> UtExecutableCallModel(null, constructorId(classId), emptyList(), this)
249-
else -> UtExecutableCallModel(
250-
null,
251-
constructorId(classId, stringClassId),
252-
listOf(UtPrimitiveModel(message)),
253-
this,
254-
)
255-
}
256-
}
244+
val instantiationCall = when (val message = throwable.message) {
245+
null -> UtExecutableCallModel(instance = null, constructorId(classId), emptyList())
246+
else -> UtExecutableCallModel(
247+
instance = null,
248+
constructorId(classId, stringClassId),
249+
listOf(UtPrimitiveModel(message))
250+
)
251+
}
252+
253+
return UtAssembleModel(addr, classId, modelName, instantiationCall)
257254
}
258255
}

utbot-framework/src/main/kotlin/org/utbot/engine/OptionalWrapper.kt

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -90,15 +90,11 @@ class OptionalWrapper(private val utOptionalClass: UtOptionalClass) : BaseOverri
9090
val addr = holder.concreteAddr(wrapper.addr)
9191
val modelName = nextModelName(baseModelName)
9292

93-
val instantiationChain = mutableListOf<UtStatementModel>()
94-
val modificationsChain = mutableListOf<UtStatementModel>()
95-
return UtAssembleModel(addr, classId, modelName, instantiationChain, modificationsChain)
96-
.apply {
97-
instantiationChain += instantiationFactoryCallModel(classId, wrapper, this)
98-
}
93+
val instantiationCall = instantiationFactoryCallModel(classId, wrapper)
94+
return UtAssembleModel(addr, classId, modelName, instantiationCall)
9995
}
10096

101-
private fun Resolver.instantiationFactoryCallModel(classId: ClassId, wrapper: ObjectValue, model: UtAssembleModel) : UtExecutableCallModel {
97+
private fun Resolver.instantiationFactoryCallModel(classId: ClassId, wrapper: ObjectValue) : UtExecutableCallModel {
10298
val valueField = FieldId(overriddenClass.id, "value")
10399
val isPresentFieldId = FieldId(overriddenClass.id, "isPresent")
104100
val values = collectFieldModels(wrapper.addr, overriddenClass.type)
@@ -110,21 +106,23 @@ class OptionalWrapper(private val utOptionalClass: UtOptionalClass) : BaseOverri
110106
}
111107
return if (!isPresent) {
112108
UtExecutableCallModel(
113-
null, MethodId(
109+
instance = null,
110+
MethodId(
114111
classId,
115112
"empty",
116113
classId,
117114
emptyList()
118-
), emptyList(), model
115+
), emptyList()
119116
)
120117
} else {
121118
UtExecutableCallModel(
122-
null, MethodId(
119+
instance = null,
120+
MethodId(
123121
classId,
124122
"of",
125123
classId,
126124
listOf(utOptionalClass.elementClassId)
127-
), listOf(valueModel), model
125+
), listOf(valueModel)
128126
)
129127
}
130128
}

utbot-framework/src/main/kotlin/org/utbot/engine/Resolver.kt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -550,11 +550,8 @@ class Resolver(
550550
val baseModelName = primitiveClassId.name
551551
val constructorId = constructorId(classId, primitiveClassId)
552552
val valueModel = fields[FieldId(classId, "value")] ?: primitiveClassId.defaultValueModel()
553-
val instantiationChain = mutableListOf<UtExecutableCallModel>()
554-
UtAssembleModel(addr, classId, nextModelName(baseModelName), instantiationChain)
555-
.apply {
556-
instantiationChain += UtExecutableCallModel(null, constructorId, listOf(valueModel), this)
557-
}
553+
val instantiationCall = UtExecutableCallModel(instance = null, constructorId, listOf(valueModel))
554+
UtAssembleModel(addr, classId, nextModelName(baseModelName), instantiationCall)
558555
}
559556
}
560557

utbot-framework/src/main/kotlin/org/utbot/engine/SecurityManagerWrapper.kt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ package org.utbot.engine
22

33
import org.utbot.engine.overrides.security.UtSecurityManager
44
import org.utbot.framework.plugin.api.UtAssembleModel
5+
import org.utbot.framework.plugin.api.UtExecutableCallModel
56
import org.utbot.framework.plugin.api.UtModel
6-
import org.utbot.framework.plugin.api.UtStatementModel
77
import org.utbot.framework.plugin.api.classId
8+
import org.utbot.framework.plugin.api.util.executableId
89
import org.utbot.framework.util.nextModelName
910
import soot.Scene
1011
import soot.SootClass
@@ -27,9 +28,13 @@ class SecurityManagerWrapper : BaseOverriddenWrapper(utSecurityManagerClass.name
2728
val addr = holder.concreteAddr(wrapper.addr)
2829
val modelName = nextModelName(baseModelName)
2930

30-
val instantiationChain = mutableListOf<UtStatementModel>()
31-
val modificationChain = mutableListOf<UtStatementModel>()
32-
return UtAssembleModel(addr, classId, modelName, instantiationChain, modificationChain)
31+
val instantiationCall = UtExecutableCallModel(
32+
instance = null,
33+
System::getSecurityManager.executableId,
34+
emptyList()
35+
)
36+
37+
return UtAssembleModel(addr, classId, modelName, instantiationCall)
3338
}
3439

3540
companion object {

utbot-framework/src/main/kotlin/org/utbot/engine/StreamWrappers.kt

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -61,24 +61,19 @@ abstract class StreamWrapper(
6161
val modelName = nextModelName(baseModelName)
6262
val parametersArrayModel = resolveElementsAsArrayModel(wrapper)
6363

64-
val instantiationChain = mutableListOf<UtStatementModel>()
65-
val modificationsChain = emptyList<UtStatementModel>()
66-
67-
UtAssembleModel(addr, utStreamClass.overriddenStreamClassId, modelName, instantiationChain, modificationsChain)
68-
.apply {
69-
val (builder, params) = if (parametersArrayModel == null || parametersArrayModel.length == 0) {
70-
streamEmptyMethodId to emptyList()
71-
} else {
72-
streamOfMethodId to listOf(parametersArrayModel)
73-
}
74-
75-
instantiationChain += UtExecutableCallModel(
76-
instance = null,
77-
executable = builder,
78-
params = params,
79-
returnValue = this
80-
)
81-
}
64+
val (builder, params) = if (parametersArrayModel == null || parametersArrayModel.length == 0) {
65+
streamEmptyMethodId to emptyList()
66+
} else {
67+
streamOfMethodId to listOf(parametersArrayModel)
68+
}
69+
70+
val instantiationCall = UtExecutableCallModel(
71+
instance = null,
72+
executable = builder,
73+
params = params
74+
)
75+
76+
UtAssembleModel(addr, utStreamClass.overriddenStreamClassId, modelName, instantiationCall)
8277
}
8378

8479
override fun chooseClassIdWithConstructor(classId: ClassId): ClassId = error("No constructor for Stream")

0 commit comments

Comments
 (0)