Skip to content

UtAssembleModel refactor #812 #970

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Sep 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -471,26 +471,52 @@ data class UtArrayModel(
/**
* Model for complex objects with assemble instructions.
*
* @param instantiationChain is a chain of [UtStatementModel] to instantiate represented object
* @param modificationsChain is a chain of [UtStatementModel] to construct object state
* The default constructor is made private to enforce using a safe constructor.
*
* @param instantiationCall is an [UtExecutableCallModel] to instantiate represented object. It **must** not return `null`.
* @param modificationsChain is a chain of [UtStatementModel] to construct object state.
*/
data class UtAssembleModel(
data class UtAssembleModel private constructor(
override val id: Int?,
override val classId: ClassId,
override val modelName: String,
val instantiationChain: List<UtStatementModel> = emptyList(),
val modificationsChain: List<UtStatementModel> = emptyList(),
val origin: UtCompositeModel? = null
val instantiationCall: UtExecutableCallModel,
val modificationsChain: List<UtStatementModel>,
val origin: UtCompositeModel?
) : UtReferenceModel(id, classId, modelName) {
val allStatementsChain
get() = instantiationChain + modificationsChain
val finalInstantiationModel
get() = instantiationChain.lastOrNull()

/**
* Creates a new [UtAssembleModel].
*
* Please note, that it's the caller responsibility to properly cache [UtModel]s to prevent an infinite recursion.
* The order of the calling:
* 1. [instantiationCall]
* 2. [constructor]
* 3. [modificationsChainProvider]. Possible caching should be made at the beginning of this method.
*
* @param instantiationCall defines the single instruction, which provides a [UtAssembleModel]. It could be a
* constructor or a method of another class, which returns the object of the [classId] type.
*
* @param modificationsChainProvider used for creating modifying statements. Its receiver corresponds to newly
* created [UtAssembleModel], so you can use it for caching and for creating [UtExecutableCallModel]s with it
* as [UtExecutableCallModel.instance].
*/
constructor(
id: Int?,
classId: ClassId,
modelName: String,
instantiationCall: UtExecutableCallModel,
origin: UtCompositeModel? = null,
modificationsChainProvider: UtAssembleModel.() -> List<UtStatementModel> = { emptyList() }
) : this(id, classId, modelName, instantiationCall, mutableListOf(), origin) {
val modificationChainStatements = modificationsChainProvider()
(modificationsChain as MutableList<UtStatementModel>).addAll(modificationChainStatements)
}

override fun toString() = withToStringThreadLocalReentrancyGuard {
buildString {
append("UtAssembleModel(${classId.simpleName} $modelName) ")
append(instantiationChain.joinToString(" "))
append(instantiationCall)
if (modificationsChain.isNotEmpty()) {
append(" ")
append(modificationsChain.joinToString(" "))
Expand Down Expand Up @@ -562,13 +588,13 @@ sealed class UtStatementModel(
* Step of assemble instruction that calls executable.
*
* Contains executable to call, call parameters and an instance model before call.
* Return value is used for tracking objects and call others methods with these tracking objects as parameters.
*
* @param [instance] **must be** `null` for static methods and constructors
*/
data class UtExecutableCallModel(
override val instance: UtReferenceModel?,
val executable: ExecutableId,
val params: List<UtModel>,
val returnValue: UtReferenceModel? = null,
) : UtStatementModel(instance) {
override fun toString() = withToStringThreadLocalReentrancyGuard {
buildString {
Expand All @@ -578,9 +604,7 @@ data class UtExecutableCallModel(
is MethodId -> executable.name
}

if (returnValue != null) {
append("val ${returnValue.modelName} = ")
} else if (instance != null) {
if (instance != null) {
append("${instance.modelName}.")
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package org.utbot.examples.codegen.deepequals

import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test
import org.utbot.tests.infrastructure.DoNotCalculate
import org.utbot.tests.infrastructure.UtValueTestCaseChecker
import org.utbot.framework.plugin.api.CodegenLanguage
import org.utbot.testcheckers.eq
import org.utbot.tests.infrastructure.CodeGeneration
import org.utbot.tests.infrastructure.DoNotCalculate
import org.utbot.tests.infrastructure.UtValueTestCaseChecker

class ClassWithCrossReferenceRelationshipTest : UtValueTestCaseChecker(
testClass = ClassWithCrossReferenceRelationship::class,
Expand All @@ -16,8 +15,6 @@ class ClassWithCrossReferenceRelationshipTest : UtValueTestCaseChecker(
CodeGenerationLanguageLastStage(CodegenLanguage.KOTLIN, CodeGeneration)
)
) {
// TODO: The test is disabled due to [https://github.com/UnitTestBot/UTBotJava/issues/812]
@Disabled
@Test
fun testClassWithCrossReferenceRelationship() {
check(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ internal class ModelsIdEqualityChecker : UtModelTestCaseChecker(

private fun UtReferenceModel.findFieldId(): Int? {
this as UtAssembleModel
val fieldModel = this.allStatementsChain
val fieldModel = this.modificationsChain
.filterIsInstance<UtDirectSetFieldModel>()
.single()
.fieldModel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ class AssembleModelGeneratorTests {
val firstExpectedRepresentation = printExpectedModel(testClassId.simpleName, v1, statementsChain.toList())

statementsChain.clear()
statementsChain.add("val $v2 = ${innerClassId.canonicalName}()")
statementsChain.add("${innerClassId.canonicalName}()")
statementsChain.add("$v2." + addExpectedSetter("a", 2))
statementsChain.add("$v2." + ("b" `=` 4))
val secondExpectedRepresentation = printExpectedModel(innerClassId.simpleName, v2, statementsChain.toList())
Expand Down Expand Up @@ -238,7 +238,7 @@ class AssembleModelGeneratorTests {
val firstExpectedRepresentation = printExpectedModel(listClassId.simpleName, v1, statementsChain.toList())

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

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

statementsChain.clear()
statementsChain.add("val $v2 = ${listClassId.canonicalName}()")
statementsChain.add("${listClassId.canonicalName}()")
statementsChain.add("$v2." + addExpectedSetter("value", 2))
statementsChain.add("$v2." + addExpectedSetter("next", v3))
val secondExpectedRepresentation = printExpectedModel(listClassId.simpleName, v2, statementsChain.toList())

statementsChain.clear()
statementsChain.add("val $v3 = ${listClassId.canonicalName}()")
statementsChain.add("${listClassId.canonicalName}()")
statementsChain.add("$v3." + addExpectedSetter("value", 3))
statementsChain.add("$v3." + addExpectedSetter("next", v1))
val thirdExpectedRepresentation = printExpectedModel(listClassId.simpleName, v3, statementsChain.toList())
Expand Down Expand Up @@ -989,7 +989,7 @@ class AssembleModelGeneratorTests {
val firstExpectedRepresentation = printExpectedModel(listClassId.simpleName, v1, statementsChain.toList())

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

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

statementsChain.clear()
statementsChain.add("val $v2 = ${listClassId.canonicalName}()")
statementsChain.add("${listClassId.canonicalName}()")
statementsChain.add("$v2." + addExpectedSetter("value", 2))
statementsChain.add("$v2." + addExpectedSetter("next", v1))
val secondExpectedRepresentation = printExpectedModel(listClassId.simpleName, v2, statementsChain)
Expand Down Expand Up @@ -1140,7 +1140,7 @@ class AssembleModelGeneratorTests {
statementsChain.add(
"$v1." + ("array" `=` "[" +
"null, " +
"UtAssembleModel(${innerClassId.simpleName} $v2) val $v2 = ${innerClassId.canonicalName}() $v2.setA(5), " +
"UtAssembleModel(${innerClassId.simpleName} $v2) ${innerClassId.canonicalName}() $v2.setA(5), " +
"null" +
"]")
)
Expand Down Expand Up @@ -1240,8 +1240,8 @@ class AssembleModelGeneratorTests {
val v3 = createExpectedVariableName<PrimitiveFields>()
statementsChain.add(
"$v1." + ("array" `=` "[" +
"[UtAssembleModel(${innerClassId.simpleName} $v2) val $v2 = ${innerClassId.canonicalName}() $v2.setA(5), ${null}], " +
"[UtAssembleModel(${innerClassId.simpleName} $v3) val $v3 = ${innerClassId.canonicalName}() $v3.b = 4, ${null}]" +
"[UtAssembleModel(${innerClassId.simpleName} $v2) ${innerClassId.canonicalName}() $v2.setA(5), ${null}], " +
"[UtAssembleModel(${innerClassId.simpleName} $v3) ${innerClassId.canonicalName}() $v3.b = 4, ${null}]" +
"]")
)

Expand Down Expand Up @@ -1480,7 +1480,7 @@ class AssembleModelGeneratorTests {
val varName = createExpectedVariableName<T>()

val paramString = if (params.any()) params.joinToString(", ") else ""
this.add("val $varName = $fqn($paramString)")
this.add("$fqn($paramString)")

return varName
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,22 +119,15 @@ abstract class BaseContainerWrapper(containerClassName: String) : BaseOverridden

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

val instantiationChain = mutableListOf<UtStatementModel>()
val modificationsChain = mutableListOf<UtStatementModel>()

UtAssembleModel(addr, classId, modelName, instantiationChain, modificationsChain)
.apply {
instantiationChain += UtExecutableCallModel(
instance = null,
executable = constructorId(classId),
params = emptyList(),
returnValue = this
)
val instantiationCall = UtExecutableCallModel(
instance = null,
executable = constructorId(classId),
params = emptyList()
)

modificationsChain += parameterModels.map {
UtExecutableCallModel(this, modificationMethodId, it)
}
}
UtAssembleModel(addr, classId, modelName, instantiationCall) {
parameterModels.map { UtExecutableCallModel(this, modificationMethodId, it) }
}
}

/**
Expand Down
23 changes: 10 additions & 13 deletions utbot-framework/src/main/kotlin/org/utbot/engine/ObjectWrappers.kt
Original file line number Diff line number Diff line change
Expand Up @@ -241,18 +241,15 @@ data class ThrowableWrapper(val throwable: Throwable) : WrapperInterface {
val addr = resolver.holder.concreteAddr(wrapper.addr)
val modelName = nextModelName(throwable.javaClass.simpleName.decapitalize())

val instantiationChain = mutableListOf<UtStatementModel>()
return UtAssembleModel(addr, classId, modelName, instantiationChain)
.apply {
instantiationChain += when (val message = throwable.message) {
null -> UtExecutableCallModel(null, constructorId(classId), emptyList(), this)
else -> UtExecutableCallModel(
null,
constructorId(classId, stringClassId),
listOf(UtPrimitiveModel(message)),
this,
)
}
}
val instantiationCall = when (val message = throwable.message) {
null -> UtExecutableCallModel(instance = null, constructorId(classId), emptyList())
else -> UtExecutableCallModel(
instance = null,
constructorId(classId, stringClassId),
listOf(UtPrimitiveModel(message))
)
}

return UtAssembleModel(addr, classId, modelName, instantiationCall)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,11 @@ class OptionalWrapper(private val utOptionalClass: UtOptionalClass) : BaseOverri
val addr = holder.concreteAddr(wrapper.addr)
val modelName = nextModelName(baseModelName)

val instantiationChain = mutableListOf<UtStatementModel>()
val modificationsChain = mutableListOf<UtStatementModel>()
return UtAssembleModel(addr, classId, modelName, instantiationChain, modificationsChain)
.apply {
instantiationChain += instantiationFactoryCallModel(classId, wrapper, this)
}
val instantiationCall = instantiationFactoryCallModel(classId, wrapper)
return UtAssembleModel(addr, classId, modelName, instantiationCall)
}

private fun Resolver.instantiationFactoryCallModel(classId: ClassId, wrapper: ObjectValue, model: UtAssembleModel) : UtExecutableCallModel {
private fun Resolver.instantiationFactoryCallModel(classId: ClassId, wrapper: ObjectValue) : UtExecutableCallModel {
val valueField = FieldId(overriddenClass.id, "value")
val isPresentFieldId = FieldId(overriddenClass.id, "isPresent")
val values = collectFieldModels(wrapper.addr, overriddenClass.type)
Expand All @@ -110,21 +106,23 @@ class OptionalWrapper(private val utOptionalClass: UtOptionalClass) : BaseOverri
}
return if (!isPresent) {
UtExecutableCallModel(
null, MethodId(
instance = null,
MethodId(
classId,
"empty",
classId,
emptyList()
), emptyList(), model
), emptyList()
)
} else {
UtExecutableCallModel(
null, MethodId(
instance = null,
MethodId(
classId,
"of",
classId,
listOf(utOptionalClass.elementClassId)
), listOf(valueModel), model
), listOf(valueModel)
)
}
}
Expand Down
7 changes: 2 additions & 5 deletions utbot-framework/src/main/kotlin/org/utbot/engine/Resolver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -550,11 +550,8 @@ class Resolver(
val baseModelName = primitiveClassId.name
val constructorId = constructorId(classId, primitiveClassId)
val valueModel = fields[FieldId(classId, "value")] ?: primitiveClassId.defaultValueModel()
val instantiationChain = mutableListOf<UtExecutableCallModel>()
UtAssembleModel(addr, classId, nextModelName(baseModelName), instantiationChain)
.apply {
instantiationChain += UtExecutableCallModel(null, constructorId, listOf(valueModel), this)
}
val instantiationCall = UtExecutableCallModel(instance = null, constructorId, listOf(valueModel))
UtAssembleModel(addr, classId, nextModelName(baseModelName), instantiationCall)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package org.utbot.engine

import org.utbot.engine.overrides.security.UtSecurityManager
import org.utbot.framework.plugin.api.UtAssembleModel
import org.utbot.framework.plugin.api.UtExecutableCallModel
import org.utbot.framework.plugin.api.UtModel
import org.utbot.framework.plugin.api.UtStatementModel
import org.utbot.framework.plugin.api.classId
import org.utbot.framework.plugin.api.util.executableId
import org.utbot.framework.util.nextModelName
import soot.Scene
import soot.SootClass
Expand All @@ -27,9 +28,13 @@ class SecurityManagerWrapper : BaseOverriddenWrapper(utSecurityManagerClass.name
val addr = holder.concreteAddr(wrapper.addr)
val modelName = nextModelName(baseModelName)

val instantiationChain = mutableListOf<UtStatementModel>()
val modificationChain = mutableListOf<UtStatementModel>()
return UtAssembleModel(addr, classId, modelName, instantiationChain, modificationChain)
val instantiationCall = UtExecutableCallModel(
instance = null,
System::getSecurityManager.executableId,
emptyList()
)

return UtAssembleModel(addr, classId, modelName, instantiationCall)
}

companion object {
Expand Down
31 changes: 13 additions & 18 deletions utbot-framework/src/main/kotlin/org/utbot/engine/StreamWrappers.kt
Original file line number Diff line number Diff line change
Expand Up @@ -61,24 +61,19 @@ abstract class StreamWrapper(
val modelName = nextModelName(baseModelName)
val parametersArrayModel = resolveElementsAsArrayModel(wrapper)

val instantiationChain = mutableListOf<UtStatementModel>()
val modificationsChain = emptyList<UtStatementModel>()

UtAssembleModel(addr, utStreamClass.overriddenStreamClassId, modelName, instantiationChain, modificationsChain)
.apply {
val (builder, params) = if (parametersArrayModel == null || parametersArrayModel.length == 0) {
streamEmptyMethodId to emptyList()
} else {
streamOfMethodId to listOf(parametersArrayModel)
}

instantiationChain += UtExecutableCallModel(
instance = null,
executable = builder,
params = params,
returnValue = this
)
}
val (builder, params) = if (parametersArrayModel == null || parametersArrayModel.length == 0) {
streamEmptyMethodId to emptyList()
} else {
streamOfMethodId to listOf(parametersArrayModel)
}

val instantiationCall = UtExecutableCallModel(
instance = null,
executable = builder,
params = params
)

UtAssembleModel(addr, utStreamClass.overriddenStreamClassId, modelName, instantiationCall)
}

override fun chooseClassIdWithConstructor(classId: ClassId): ClassId = error("No constructor for Stream")
Expand Down
Loading