diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt index 979f6c01c0..c5b3474254 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt @@ -576,9 +576,20 @@ data class UtArrayModel( override fun hashCode(): Int = id } -interface UtModelWithOrigin { - val origin: UtCompositeModel? -} +/** + * Wrapper of [origin] model, that can be handled in a different + * way in some situations (e.g. during value construction). + */ +sealed class UtModelWithCompositeOrigin( + id: Int?, + classId: ClassId, + modelName: String = id.toString(), + open val origin: UtCompositeModel?, +) : UtReferenceModel( + id = id, + classId = classId, + modelName = modelName +) /** * Model for complex objects with assemble instructions. @@ -595,7 +606,7 @@ data class UtAssembleModel private constructor( val instantiationCall: UtStatementCallModel, val modificationsChain: List, override val origin: UtCompositeModel? -) : UtReferenceModel(id, classId, modelName), UtModelWithOrigin { +) : UtModelWithCompositeOrigin(id, classId, modelName, origin) { /** * Creates a new [UtAssembleModel]. @@ -737,11 +748,11 @@ class UtLambdaModel( * Common parent of all framework-specific models (e.g. Spring-specific models) */ abstract class UtCustomModel( - override val origin: UtCompositeModel? = null, id: Int?, classId: ClassId, - modelName: String = id.toString() -) : UtReferenceModel(id, classId, modelName), UtModelWithOrigin + modelName: String = id.toString(), + override val origin: UtCompositeModel? = null, +) : UtModelWithCompositeOrigin(id, classId, modelName, origin) object UtSpringContextModel : UtCustomModel( id = null, diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/SpringModelUtils.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/SpringModelUtils.kt index dc826f0e60..4bb8326466 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/SpringModelUtils.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/SpringModelUtils.kt @@ -109,7 +109,7 @@ object SpringModelUtils { private val mockMvcRequestBuildersClassId = ClassId("org.springframework.test.web.servlet.request.MockMvcRequestBuilders") private val requestBuilderClassId = ClassId("org.springframework.test.web.servlet.RequestBuilder") val resultActionsClassId = ClassId("org.springframework.test.web.servlet.ResultActions") - private val mockMvcClassId = ClassId("org.springframework.test.web.servlet.MockMvc") + val mockMvcClassId = ClassId("org.springframework.test.web.servlet.MockMvc") private val mvcResultClassId = ClassId("org.springframework.test.web.servlet.MvcResult") private val resultHandlerClassId = ClassId("org.springframework.test.web.servlet.ResultHandler") val mockMvcResultHandlersClassId = ClassId("org.springframework.test.web.servlet.result.MockMvcResultHandlers") diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgClassFieldManager.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgClassFieldManager.kt index 9102daaf5e..45b028a545 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgClassFieldManager.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgClassFieldManager.kt @@ -11,7 +11,7 @@ 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 -import org.utbot.framework.plugin.api.UtModelWithOrigin +import org.utbot.framework.plugin.api.UtModelWithCompositeOrigin import org.utbot.framework.plugin.api.isMockModel import org.utbot.framework.plugin.api.util.SpringModelUtils.autowiredClassId import org.utbot.framework.plugin.api.util.SpringModelUtils.isAutowiredFromContext @@ -48,7 +48,7 @@ class CgInjectingMocksFieldsManager(val context: CgContext) : CgClassFieldManage override fun constructVariableForField(model: UtModel, modelVariable: CgValue): CgValue { val modelFields = when (model) { is UtCompositeModel -> model.fields - is UtModelWithOrigin -> model.origin?.fields + is UtModelWithCompositeOrigin -> model.origin?.fields else -> null } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgMethodConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgMethodConstructor.kt index 54b7a9c9d7..2fddec0c3c 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgMethodConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgMethodConstructor.kt @@ -100,7 +100,7 @@ import org.utbot.framework.plugin.api.UtExecutionSuccess import org.utbot.framework.plugin.api.UtExplicitlyThrownException import org.utbot.framework.plugin.api.UtLambdaModel import org.utbot.framework.plugin.api.UtModel -import org.utbot.framework.plugin.api.UtModelWithOrigin +import org.utbot.framework.plugin.api.UtModelWithCompositeOrigin import org.utbot.framework.plugin.api.UtNewInstanceInstrumentation import org.utbot.framework.plugin.api.UtNullModel import org.utbot.framework.plugin.api.UtOverflowFailure @@ -1069,7 +1069,7 @@ open class CgMethodConstructor(val context: CgContext) : CgContextOwner by conte when (model) { is UtCompositeModel -> collectExecutionsResultFieldsRecursively(model, 0) - is UtModelWithOrigin -> model.origin?.let { + is UtModelWithCompositeOrigin -> model.origin?.let { collectExecutionsResultFieldsRecursively(it, 0) } @@ -1109,7 +1109,7 @@ open class CgMethodConstructor(val context: CgContext) : CgContextOwner by conte when (fieldModel) { is UtCompositeModel -> collectExecutionsResultFieldsRecursively(fieldModel, depth + 1) - is UtModelWithOrigin -> fieldModel.origin?.let { + is UtModelWithCompositeOrigin -> fieldModel.origin?.let { collectExecutionsResultFieldsRecursively(it, depth + 1) } @@ -1201,7 +1201,10 @@ open class CgMethodConstructor(val context: CgContext) : CgContextOwner by conte expectedVariableName: String = "expected", emptyLineIfNeeded: Boolean = false, ) { - if (expected !is UtCustomModel || !customAssertConstructor.tryConstructCustomAssert(expected, actual)) { + val successfullyConstructedCustomAssert = expected is UtCustomModel && + customAssertConstructor.tryConstructCustomAssert(expected, actual) + + if (!successfullyConstructedCustomAssert) { val expectedVariable = variableConstructor.getOrCreateVariable(expected, expectedVariableName) if (emptyLineIfNeeded) emptyLineIfNeeded() assertEquality(expectedVariable, actual) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgMockMvcResultActionsAssertConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgMockMvcResultActionsAssertConstructor.kt index d40e359164..963eabdf3b 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgMockMvcResultActionsAssertConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgMockMvcResultActionsAssertConstructor.kt @@ -2,14 +2,12 @@ package org.utbot.framework.codegen.tree import org.utbot.framework.codegen.domain.context.CgContext import org.utbot.framework.codegen.domain.context.CgContextOwner -import org.utbot.framework.codegen.domain.models.AnnotationTarget import org.utbot.framework.codegen.domain.models.CgVariable import org.utbot.framework.codegen.services.access.CgCallableAccessManager import org.utbot.framework.codegen.services.access.CgCallableAccessManagerImpl import org.utbot.framework.codegen.tree.CgComponents.getStatementConstructorBy import org.utbot.framework.plugin.api.UtCustomModel import org.utbot.framework.plugin.api.UtSpringMockMvcResultActionsModel -import org.utbot.framework.plugin.api.util.SpringModelUtils.autoConfigureMockMvcClassId import org.utbot.framework.plugin.api.util.SpringModelUtils.contentMatchersStringMethodId import org.utbot.framework.plugin.api.util.SpringModelUtils.mockMvcResultHandlersClassId import org.utbot.framework.plugin.api.util.SpringModelUtils.mockMvcResultMatchersClassId @@ -34,20 +32,18 @@ class CgMockMvcResultActionsAssertConstructor( CgCallableAccessManager by CgCallableAccessManagerImpl(context) { override fun tryConstructCustomAssert(expected: UtCustomModel, actual: CgVariable): Boolean { if (expected is UtSpringMockMvcResultActionsModel) { - addAnnotation(autoConfigureMockMvcClassId, AnnotationTarget.Class) - var expr = actual[resultActionsAndDoMethodId](mockMvcResultHandlersClassId[resultHandlersPrintMethodId]()) - expr = expr[resultActionsAndExpectMethodId]( + +actual[resultActionsAndDoMethodId](mockMvcResultHandlersClassId[resultHandlersPrintMethodId]()) + +actual[resultActionsAndExpectMethodId]( mockMvcResultMatchersClassId[resultMatchersStatusMethodId]()[statusMatchersIsMethodId](expected.status) ) expected.viewName?.let { viewName -> - expr = expr[resultActionsAndExpectMethodId]( + +actual[resultActionsAndExpectMethodId]( mockMvcResultMatchersClassId[resultMatchersViewMethodId]()[viewMatchersNameMethodId](viewName) ) } - expr = expr[resultActionsAndExpectMethodId]( + +actual[resultActionsAndExpectMethodId]( mockMvcResultMatchersClassId[resultMatchersContentMethodId]()[contentMatchersStringMethodId](expected.contentAsString) ) - +expr return true } else return delegateAssertConstructor.tryConstructCustomAssert(expected, actual) 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 743f6114ed..ff217b2a8a 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 @@ -17,6 +17,7 @@ import org.utbot.framework.plugin.api.ConcreteContextLoadingResult import org.utbot.framework.plugin.api.SpringSettings.* import org.utbot.framework.plugin.api.SpringConfiguration.* import org.utbot.framework.plugin.api.util.IndentUtil.TAB +import org.utbot.framework.plugin.api.util.SpringModelUtils import org.utbot.framework.plugin.api.util.SpringModelUtils.activeProfilesClassId import org.utbot.framework.plugin.api.util.SpringModelUtils.autoConfigureTestDbClassId import org.utbot.framework.plugin.api.util.SpringModelUtils.bootstrapWithClassId @@ -25,6 +26,7 @@ import org.utbot.framework.plugin.api.util.SpringModelUtils.crudRepositoryClassI import org.utbot.framework.plugin.api.util.SpringModelUtils.dirtiesContextClassId import org.utbot.framework.plugin.api.util.SpringModelUtils.dirtiesContextClassModeClassId import org.utbot.framework.plugin.api.util.SpringModelUtils.extendWithClassId +import org.utbot.framework.plugin.api.util.SpringModelUtils.mockMvcClassId import org.utbot.framework.plugin.api.util.SpringModelUtils.runWithClassId import org.utbot.framework.plugin.api.util.SpringModelUtils.springBootTestClassId import org.utbot.framework.plugin.api.util.SpringModelUtils.springBootTestContextBootstrapperClassId @@ -47,7 +49,7 @@ class CgSpringIntegrationTestClassConstructor( } override fun constructTestClass(testClassModel: SpringTestClassModel): CgClass { - addNecessarySpringSpecificAnnotations() + addNecessarySpringSpecificAnnotations(testClassModel) return super.constructTestClass(testClassModel) } @@ -102,7 +104,7 @@ class CgSpringIntegrationTestClassConstructor( .map { it.escapeControlChars() } ) - private fun addNecessarySpringSpecificAnnotations() { + private fun addNecessarySpringSpecificAnnotations(testClassModel: SpringTestClassModel) { val isSpringBootTestAccessible = utContext.classLoader.tryLoadClass(springBootTestClassId.name) != null if (isSpringBootTestAccessible) { addAnnotation(springBootTestClassId, Class) @@ -193,5 +195,8 @@ class CgSpringIntegrationTestClassConstructor( // generated tests will fail with `ClassNotFoundException: org.springframework.dao.DataAccessException`. if (utContext.classLoader.tryLoadClass(crudRepositoryClassId.name) != null) addAnnotation(autoConfigureTestDbClassId, Class) + + if (mockMvcClassId in testClassModel.springSpecificInformation.autowiredFromContextModels) + addAnnotation(SpringModelUtils.autoConfigureMockMvcClassId, Class) } } \ 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 c78749d873..e25f5ab6b5 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 @@ -1,5 +1,6 @@ package org.utbot.framework.codegen.tree +import mu.KotlinLogging import org.utbot.common.isStatic import org.utbot.framework.codegen.domain.builtin.forName import org.utbot.framework.codegen.domain.builtin.setArrayElement @@ -68,6 +69,10 @@ open class CgVariableConstructor(val context: CgContext) : CgCallableAccessManager by getCallableAccessManagerBy(context), CgStatementConstructor by getStatementConstructorBy(context) { + companion object { + private val logger = KotlinLogging.logger {} + } + private val nameGenerator = getNameGeneratorBy(context) val mockFrameworkManager = getMockFrameworkManagerBy(context) @@ -99,7 +104,7 @@ open class CgVariableConstructor(val context: CgContext) : constructValueByModel(model, name) } - open fun constructValueByModel(model: UtModel, name: String?): CgValue { + private fun constructValueByModel(model: UtModel, name: String?): CgValue { // name could be taken from existing names, or be specified manually, or be created from generator val baseName = name ?: nameGenerator.nameFrom(model.classId) @@ -112,7 +117,12 @@ open class CgVariableConstructor(val context: CgContext) : is UtLambdaModel -> constructLambda(model, baseName) is UtNullModel -> nullLiteral() is UtPrimitiveModel -> CgLiteral(model.classId, model.value) - is UtCustomModel -> constructValueByModel(model.origin ?: error("Can't construct value for custom model without origin [$model]"), name) + is UtCustomModel -> { + logger.error { "Unexpected behaviour: value for UtCustomModel [$model] is constructed by base CgVariableConstructor" } + constructValueByModel( + model.origin ?: error("Can't construct value for UtCustomModel without origin [$model]"), name + ) + } is UtReferenceModel -> error("Unexpected UtReferenceModel: ${model::class}") is UtVoidModel -> error("Unexpected UtVoidModel: ${model::class}") else -> error("Unexpected UtModel: ${model::class}") diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/fields/ExecutionStateAnalyzer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/fields/ExecutionStateAnalyzer.kt index e8fcb7f8ab..46466eb945 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/fields/ExecutionStateAnalyzer.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/fields/ExecutionStateAnalyzer.kt @@ -15,7 +15,7 @@ import org.utbot.framework.plugin.api.UtEnumConstantModel import org.utbot.framework.plugin.api.UtExecution import org.utbot.framework.plugin.api.UtLambdaModel import org.utbot.framework.plugin.api.UtModel -import org.utbot.framework.plugin.api.UtModelWithOrigin +import org.utbot.framework.plugin.api.UtModelWithCompositeOrigin import org.utbot.framework.plugin.api.UtNullModel import org.utbot.framework.plugin.api.UtPrimitiveModel import org.utbot.framework.plugin.api.UtReferenceModel @@ -106,7 +106,7 @@ class ExecutionStateAnalyzer(val execution: UtExecution) { var modelBefore = before if (before::class != after::class) { - if (before is UtModelWithOrigin && after is UtModelWithOrigin && before.origin != null) { + if (before is UtModelWithCompositeOrigin && after is UtModelWithCompositeOrigin && before.origin != null) { modelBefore = before.origin ?: unreachableBranch("We have already checked the origin for a null value") } else { doNotRun { @@ -114,7 +114,7 @@ class ExecutionStateAnalyzer(val execution: UtExecution) { // modelAfter (constructed by concrete executor) will consist all these fields, // therefore, AssembleModelGenerator won't be able to transform the given composite model - val reason = if (before is UtModelWithOrigin && after is UtCompositeModel) { + val reason = if (before is UtModelWithCompositeOrigin && after is UtCompositeModel) { "ModelBefore is an UtModelWithOrigin and ModelAfter " + "is a CompositeModel, but modelBefore doesn't have an origin model." } else { diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/SimpleUtExecutionInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/SimpleUtExecutionInstrumentation.kt index 4c3ba7775d..adaec0ab1a 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/SimpleUtExecutionInstrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/SimpleUtExecutionInstrumentation.kt @@ -131,7 +131,7 @@ class SimpleUtExecutionInstrumentation( delegateInstrumentation.getStaticField(fieldId).map { value -> UtModelConstructor.createOnlyUserClassesConstructor( pathsToUserClasses = pathsToUserClasses, - utCustomModelConstructorFinder = instrumentationContext::findUtCustomModelConstructor + utModelWithCompositeOriginConstructorFinder = instrumentationContext::findUtModelWithCompositeOriginConstructor ).construct(value, fieldId.type) } diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/JavaStdLibCustomModelConstructors.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/JavaStdLibCustomModelConstructors.kt index 148bb3e059..72419f9c49 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/JavaStdLibCustomModelConstructors.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/JavaStdLibCustomModelConstructors.kt @@ -4,7 +4,7 @@ import org.utbot.framework.plugin.api.util.jClass import org.utbot.framework.plugin.api.util.primitiveWrappers import org.utbot.framework.plugin.api.util.voidWrapperClassId -val javaStdLibCustomModelConstructors: Map, () -> UtCustomModelConstructor> = +val javaStdLibModelWithCompositeOriginConstructors: Map, () -> UtModelWithCompositeOriginConstructor> = mutableMapOf, () -> UtAssembleModelConstructorBase>( /** * Optionals diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/UtAssembleModelConstructors.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/UtAssembleModelConstructors.kt index cc6c4d87e2..f6acd29bba 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/UtAssembleModelConstructors.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/UtAssembleModelConstructors.kt @@ -18,8 +18,8 @@ internal fun findStreamConstructor(stream: BaseStream<*, *>): UtAssembleModelCon else -> BaseStreamConstructor() } -internal abstract class UtAssembleModelConstructorBase : UtCustomModelConstructor { - override fun constructCustomModel( +internal abstract class UtAssembleModelConstructorBase : UtModelWithCompositeOriginConstructor { + override fun constructModelWithCompositeOrigin( internalConstructor: UtModelConstructorInterface, value: Any, valueClassId: ClassId, diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/UtCustomModelConstructor.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/UtCustomModelConstructor.kt deleted file mode 100644 index 93e1db1b28..0000000000 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/UtCustomModelConstructor.kt +++ /dev/null @@ -1,19 +0,0 @@ -package org.utbot.instrumentation.instrumentation.execution.constructors - -import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.UtCompositeModel -import org.utbot.framework.plugin.api.UtModel - -/** - * Responsible for constructing [UtModel]s of some specific type, that are more human-readable - * when rendered by the code generation compared to [UtCompositeModel]s. - */ -interface UtCustomModelConstructor { - fun constructCustomModel( - internalConstructor: UtModelConstructorInterface, - value: Any, - valueClassId: ClassId, - id: Int?, - saveToCache: (UtModel) -> Unit - ): UtModel -} \ No newline at end of file diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/UtModelConstructor.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/UtModelConstructor.kt index f2950aa27f..dd5de775c6 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/UtModelConstructor.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/UtModelConstructor.kt @@ -17,13 +17,6 @@ interface UtModelConstructorInterface { * Constructs a UtModel from a concrete [value] with a specific [classId]. */ fun construct(value: Any?, classId: ClassId): UtModel - - /** - * Constructs UtCompositeModel. - * - * Uses runtime javaClass to collect ALL fields, except final static fields, and builds this model recursively. - */ - fun constructCompositeModel(value: Any): UtCompositeModel } /** @@ -39,7 +32,7 @@ interface UtModelConstructorInterface { */ class UtModelConstructor( private val objectToModelCache: IdentityHashMap, - private val utCustomModelConstructorFinder: (ClassId) -> UtCustomModelConstructor?, + private val utModelWithCompositeOriginConstructorFinder: (ClassId) -> UtModelWithCompositeOriginConstructor?, private val compositeModelStrategy: UtCompositeModelStrategy = AlwaysConstructStrategy, private val maxDepth: Long = DEFAULT_MAX_DEPTH ) : UtModelConstructorInterface { @@ -56,13 +49,13 @@ class UtModelConstructor( fun createOnlyUserClassesConstructor( pathsToUserClasses: Set, - utCustomModelConstructorFinder: (ClassId) -> UtCustomModelConstructor? + utModelWithCompositeOriginConstructorFinder: (ClassId) -> UtModelWithCompositeOriginConstructor? ): UtModelConstructor { val cache = IdentityHashMap() val strategy = ConstructOnlyUserClassesOrCachedObjectsStrategy( pathsToUserClasses, cache ) - return UtModelConstructor(cache, utCustomModelConstructorFinder, strategy) + return UtModelConstructor(cache, utModelWithCompositeOriginConstructorFinder, strategy) } } @@ -280,7 +273,7 @@ class UtModelConstructor( val streamConstructor = findStreamConstructor(stream) try { - streamConstructor.constructCustomModel(this, stream, valueToClassId(stream), handleId(stream)) { + streamConstructor.constructModelWithCompositeOrigin(this, stream, valueToClassId(stream), handleId(stream)) { constructedObjects[stream] = it } } catch (e: Exception) { @@ -305,9 +298,9 @@ class UtModelConstructor( * Uses runtime class of [value]. */ private fun tryConstructCustomModel(value: Any, remainingDepth: Long): UtModel? = - utCustomModelConstructorFinder(value::class.java.id)?.let { modelConstructor -> + utModelWithCompositeOriginConstructorFinder(value::class.java.id)?.let { modelConstructor -> try { - modelConstructor.constructCustomModel( + modelConstructor.constructModelWithCompositeOrigin( internalConstructor = this.withMaxDepth(remainingDepth - 1), value = value, valueClassId = valueToClassId(value), @@ -321,11 +314,11 @@ class UtModelConstructor( } } - override fun constructCompositeModel(value: Any): UtCompositeModel = constructCompositeModel( - value, - remainingDepth = maxDepth - ) - + /** + * Constructs UtCompositeModel. + * + * Uses runtime javaClass to collect ALL fields, except final static fields, and builds this model recursively. + */ private fun constructCompositeModel(value: Any, remainingDepth: Long): UtCompositeModel { // value can be mock only if it was previously constructed from UtCompositeModel val isMock = objectToModelCache[value]?.isMockModel() ?: false @@ -357,9 +350,6 @@ class UtModelConstructor( private fun withMaxDepth(newMaxDepth: Long) = object : UtModelConstructorInterface { override fun construct(value: Any?, classId: ClassId): UtModel = construct(value, classId, newMaxDepth) - - override fun constructCompositeModel(value: Any): UtCompositeModel = - constructCompositeModel(value, newMaxDepth) } } diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/UtModelWithCompositeOriginConstructor.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/UtModelWithCompositeOriginConstructor.kt new file mode 100644 index 0000000000..034f7a2306 --- /dev/null +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/UtModelWithCompositeOriginConstructor.kt @@ -0,0 +1,30 @@ +package org.utbot.instrumentation.instrumentation.execution.constructors + +import org.utbot.framework.plugin.api.ClassId +import org.utbot.framework.plugin.api.UtCompositeModel +import org.utbot.framework.plugin.api.UtModel +import org.utbot.framework.plugin.api.UtModelWithCompositeOrigin + +/** + * Responsible for constructing [UtModelWithCompositeOrigin]s of some specific type, that are more human-readable + * when rendered by the code generation compared to [UtCompositeModel]s. + */ +interface UtModelWithCompositeOriginConstructor { + + /** + * @param internalConstructor constructor to use for constructing child models + * (e.g. when [value] is a list, [internalConstructor] is used for constructing list elements) + * @param value object to construct model for + * @param valueClassId [ClassId] to use for constructed model + * @param saveToCache function that should be called on the returned model right after constructing it, + * but before adding any modifications, so [internalConstructor] doesn't have to reconstruct it for every modification + * and recursive values (e.g. list containing itself) are constructed correctly + */ + fun constructModelWithCompositeOrigin( + internalConstructor: UtModelConstructorInterface, + value: Any, + valueClassId: ClassId, + id: Int?, + saveToCache: (UtModel) -> Unit + ): UtModelWithCompositeOrigin +} \ No newline at end of file diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/context/InstrumentationContext.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/context/InstrumentationContext.kt index b4f2906481..e2f818d64b 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/context/InstrumentationContext.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/context/InstrumentationContext.kt @@ -3,7 +3,7 @@ package org.utbot.instrumentation.instrumentation.execution.context import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.UtConcreteValue import org.utbot.framework.plugin.api.UtModel -import org.utbot.instrumentation.instrumentation.execution.constructors.UtCustomModelConstructor +import org.utbot.instrumentation.instrumentation.execution.constructors.UtModelWithCompositeOriginConstructor import java.lang.reflect.Method import java.util.IdentityHashMap import org.utbot.instrumentation.instrumentation.mock.computeKeyForMethod @@ -28,7 +28,11 @@ interface InstrumentationContext { */ fun constructContextDependentValue(model: UtModel): UtConcreteValue<*>? - fun findUtCustomModelConstructor(classId: ClassId): UtCustomModelConstructor? + /** + * Finds [UtModelWithCompositeOriginConstructor] that should be used to + * construct models for instances of specified [class][classId]. + */ + fun findUtModelWithCompositeOriginConstructor(classId: ClassId): UtModelWithCompositeOriginConstructor? object MockGetter { data class MockContainer(private val values: List<*>) { diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/context/SimpleInstrumentationContext.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/context/SimpleInstrumentationContext.kt index ef6f24594c..51e08ae816 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/context/SimpleInstrumentationContext.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/context/SimpleInstrumentationContext.kt @@ -4,8 +4,8 @@ import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.UtConcreteValue import org.utbot.framework.plugin.api.UtModel import org.utbot.framework.plugin.api.util.jClass -import org.utbot.instrumentation.instrumentation.execution.constructors.UtCustomModelConstructor -import org.utbot.instrumentation.instrumentation.execution.constructors.javaStdLibCustomModelConstructors +import org.utbot.instrumentation.instrumentation.execution.constructors.UtModelWithCompositeOriginConstructor +import org.utbot.instrumentation.instrumentation.execution.constructors.javaStdLibModelWithCompositeOriginConstructors /** * Simple instrumentation context, that is used for pure JVM projects without @@ -19,6 +19,6 @@ class SimpleInstrumentationContext : InstrumentationContext { */ override fun constructContextDependentValue(model: UtModel): UtConcreteValue<*>? = null - override fun findUtCustomModelConstructor(classId: ClassId): UtCustomModelConstructor? = - javaStdLibCustomModelConstructors[classId.jClass]?.invoke() + override fun findUtModelWithCompositeOriginConstructor(classId: ClassId): UtModelWithCompositeOriginConstructor? = + javaStdLibModelWithCompositeOriginConstructors[classId.jClass]?.invoke() } \ No newline at end of file diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/ModelConstructionPhase.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/ModelConstructionPhase.kt index f68f723374..20f6dac2e3 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/ModelConstructionPhase.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/ModelConstructionPhase.kt @@ -9,7 +9,7 @@ import org.utbot.instrumentation.instrumentation.et.ExplicitThrowInstruction import org.utbot.instrumentation.instrumentation.et.TraceHandler import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult import org.utbot.instrumentation.instrumentation.execution.constructors.UtCompositeModelStrategy -import org.utbot.instrumentation.instrumentation.execution.constructors.UtCustomModelConstructor +import org.utbot.instrumentation.instrumentation.execution.constructors.UtModelWithCompositeOriginConstructor import org.utbot.instrumentation.instrumentation.execution.constructors.UtModelConstructor import java.security.AccessControlException import java.util.* @@ -19,7 +19,7 @@ import java.util.* */ class ModelConstructionPhase( private val traceHandler: TraceHandler, - private val utCustomModelConstructorFinder: (ClassId) -> UtCustomModelConstructor?, + private val utModelWithCompositeOriginConstructorFinder: (ClassId) -> UtModelWithCompositeOriginConstructor?, ) : ExecutionPhase { override fun wrapError(e: Throwable): ExecutionPhaseException { @@ -46,7 +46,7 @@ class ModelConstructionPhase( block() constructor = UtModelConstructor( objectToModelCache = cache, - utCustomModelConstructorFinder = utCustomModelConstructorFinder, + utModelWithCompositeOriginConstructorFinder = utModelWithCompositeOriginConstructorFinder, compositeModelStrategy = strategy, ) } diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/PhasesController.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/PhasesController.kt index a552bcbd83..53d4e6fc0f 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/PhasesController.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/phases/PhasesController.kt @@ -33,7 +33,7 @@ class PhasesController( val modelConstructionPhase = ModelConstructionPhase( traceHandler = traceHandler, - utCustomModelConstructorFinder = instrumentationContext::findUtCustomModelConstructor + utModelWithCompositeOriginConstructorFinder = instrumentationContext::findUtModelWithCompositeOriginConstructor ) val postprocessingPhase = PostprocessingPhase() diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringInstrumentationContext.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringInstrumentationContext.kt index fe24cdfc9a..79c9209772 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringInstrumentationContext.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringInstrumentationContext.kt @@ -9,7 +9,7 @@ import org.utbot.framework.plugin.api.UtSpringContextModel import org.utbot.framework.plugin.api.util.SpringModelUtils.resultActionsClassId import org.utbot.framework.plugin.api.util.isSubtypeOf import org.utbot.framework.plugin.api.util.utContext -import org.utbot.instrumentation.instrumentation.execution.constructors.UtCustomModelConstructor +import org.utbot.instrumentation.instrumentation.execution.constructors.UtModelWithCompositeOriginConstructor import org.utbot.instrumentation.instrumentation.execution.context.InstrumentationContext import org.utbot.spring.api.SpringApi import org.utbot.spring.api.provider.SpringApiProviderFacade @@ -49,7 +49,7 @@ class SpringInstrumentationContext( else -> delegateInstrumentationContext.constructContextDependentValue(model) } - override fun findUtCustomModelConstructor(classId: ClassId): UtCustomModelConstructor? = + override fun findUtModelWithCompositeOriginConstructor(classId: ClassId): UtModelWithCompositeOriginConstructor? = if (classId.isSubtypeOf(resultActionsClassId)) UtMockMvcResultActionsModelConstructor() - else delegateInstrumentationContext.findUtCustomModelConstructor(classId) + else delegateInstrumentationContext.findUtModelWithCompositeOriginConstructor(classId) } \ No newline at end of file diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringUtExecutionInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringUtExecutionInstrumentation.kt index 2a6808b694..bdc9feedae 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringUtExecutionInstrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/SpringUtExecutionInstrumentation.kt @@ -101,7 +101,7 @@ class SpringUtExecutionInstrumentation( val bean = springApi.getBean(beanName) return UtModelConstructor.createOnlyUserClassesConstructor( pathsToUserClasses = classpathToConstruct, - utCustomModelConstructorFinder = instrumentationContext::findUtCustomModelConstructor + utModelWithCompositeOriginConstructorFinder = instrumentationContext::findUtModelWithCompositeOriginConstructor ).construct(bean, bean::class.java.id) } @@ -152,6 +152,9 @@ class SpringUtExecutionInstrumentation( targetDirectoryName = "spring-commons" ).path + // TODO may be we can use some alternative sandbox that has more permissions + // (at the very least we need `ReflectPermission("suppressAccessChecks")` + // to let Jackson work with private fields when `@RequestBody` is used) override val forceDisableSandbox: Boolean get() = true diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/UtMockMvcResultActionsModelConstructor.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/UtMockMvcResultActionsModelConstructor.kt index 6064e8e88f..05f307a373 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/UtMockMvcResultActionsModelConstructor.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/spring/UtMockMvcResultActionsModelConstructor.kt @@ -13,24 +13,24 @@ import org.utbot.framework.plugin.api.util.SpringModelUtils.responseGetStatusMet import org.utbot.framework.plugin.api.util.SpringModelUtils.resultActionsAndReturnMethodId import org.utbot.framework.plugin.api.util.mapClassId import org.utbot.framework.plugin.api.util.method -import org.utbot.instrumentation.instrumentation.execution.constructors.UtCustomModelConstructor +import org.utbot.instrumentation.instrumentation.execution.constructors.UtModelWithCompositeOriginConstructor import org.utbot.instrumentation.instrumentation.execution.constructors.UtModelConstructorInterface -class UtMockMvcResultActionsModelConstructor : UtCustomModelConstructor { - override fun constructCustomModel( +class UtMockMvcResultActionsModelConstructor : UtModelWithCompositeOriginConstructor { + override fun constructModelWithCompositeOrigin( internalConstructor: UtModelConstructorInterface, value: Any, valueClassId: ClassId, id: Int?, saveToCache: (UtModel) -> Unit - ): UtModel { + ): UtSpringMockMvcResultActionsModel { val mvcResult = resultActionsAndReturnMethodId.method.invoke(value) val response = mvcResultGetResponseMethodId.method.invoke(mvcResult) val modelAndView = mvcResultGetModelAndViewMethodId.method.invoke(mvcResult) return UtSpringMockMvcResultActionsModel( id = id, - origin = internalConstructor.constructCompositeModel(value), + origin = null, // replace with actual origin if needed status = responseGetStatusMethodId.method.invoke(response) as Int, errorMessage = responseGetErrorMessageMethodId.method.invoke(response) as String?, contentAsString = responseGetContentAsStringMethodId.method.invoke(response) as String, diff --git a/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/BaseConstructorTest.kt b/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/BaseConstructorTest.kt index 318a12eb7c..afc147be72 100644 --- a/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/BaseConstructorTest.kt +++ b/utbot-instrumentation/src/test/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/BaseConstructorTest.kt @@ -27,7 +27,7 @@ abstract class BaseConstructorTest { protected fun computeReconstructed(value: T): T { val model = UtModelConstructor( objectToModelCache = IdentityHashMap(), - utCustomModelConstructorFinder = ::findUtCustomModelConstructor + utModelWithCompositeOriginConstructorFinder = ::findUtCustomModelConstructor ).construct(value, value::class.java.id) Assertions.assertTrue(model is UtAssembleModel) @@ -36,6 +36,6 @@ abstract class BaseConstructorTest { return ValueConstructor().construct(listOf(model)).single().value as T } - protected open fun findUtCustomModelConstructor(classId: ClassId): UtCustomModelConstructor? = - javaStdLibCustomModelConstructors[classId.jClass]?.invoke() + protected open fun findUtCustomModelConstructor(classId: ClassId): UtModelWithCompositeOriginConstructor? = + javaStdLibModelWithCompositeOriginConstructors[classId.jClass]?.invoke() } \ No newline at end of file diff --git a/utbot-js/src/main/kotlin/api/JsUtModelConstructor.kt b/utbot-js/src/main/kotlin/api/JsUtModelConstructor.kt index aaf51d5a61..09c5b74af3 100644 --- a/utbot-js/src/main/kotlin/api/JsUtModelConstructor.kt +++ b/utbot-js/src/main/kotlin/api/JsUtModelConstructor.kt @@ -21,11 +21,11 @@ import org.utbot.framework.plugin.api.UtExecutableCallModel import org.utbot.framework.plugin.api.UtModel import org.utbot.instrumentation.instrumentation.execution.constructors.UtModelConstructorInterface -class JsUtModelConstructor { +class JsUtModelConstructor : UtModelConstructorInterface { // TODO SEVERE: Requires substantial expansion to other types @Suppress("NAME_SHADOWING") - fun construct(value: Any?, classId: ClassId): UtModel { + override fun construct(value: Any?, classId: ClassId): UtModel { val classId = classId as JsClassId if (classId == jsErrorClassId) return UtModel(jsErrorClassId) return when (value) { diff --git a/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgMethodConstructor.kt b/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgMethodConstructor.kt index 685c62e612..38102712da 100644 --- a/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgMethodConstructor.kt +++ b/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgMethodConstructor.kt @@ -38,7 +38,7 @@ class JsCgMethodConstructor(ctx: CgContext) : CgMethodConstructor(ctx) { } // build arguments for ((index, param) in execution.stateBefore.parameters.withIndex()) { - val name = paramNames[execution.executableToCall ?: testSet.executableUnderTest]?.get(index) + val name = paramNames[testSet.executableUnderTest]?.get(index) methodArguments += variableConstructor.getOrCreateVariable(param, name) } recordActualResult() @@ -61,7 +61,7 @@ class JsCgMethodConstructor(ctx: CgContext) : CgMethodConstructor(ctx) { override fun generateResultAssertions() { emptyLineIfNeeded() val currentExecution = currentExecution!! - val method = currentExecutableToCall as MethodId + val method = currentExecutableUnderTest as MethodId // build assertions currentExecution.result .onSuccess { result -> @@ -80,7 +80,7 @@ class JsCgMethodConstructor(ctx: CgContext) : CgMethodConstructor(ctx) { private fun processExecutionFailure(execution: UtExecution, exception: Throwable) { val methodInvocationBlock = { - with(currentExecutableToCall) { + with(currentExecutableUnderTest) { when (this) { is MethodId -> thisInstance[this](*methodArguments.toTypedArray()).intercepted() is ConstructorId -> this(*methodArguments.toTypedArray()).intercepted() diff --git a/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/constructor/tree/PythonCgMethodConstructor.kt b/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/constructor/tree/PythonCgMethodConstructor.kt index 1325e9ed23..659d282553 100644 --- a/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/constructor/tree/PythonCgMethodConstructor.kt +++ b/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/constructor/tree/PythonCgMethodConstructor.kt @@ -123,11 +123,7 @@ class PythonCgMethodConstructor(context: CgContext) : CgMethodConstructor(contex generateResultAssertions() if (methodType == CgTestMethodType.PASSED_EXCEPTION) { - generateFieldStateAssertions( - stateAssertions, - assertThisObject, - execution.executableToCall ?: testSet.executableUnderTest - ) + generateFieldStateAssertions(stateAssertions, assertThisObject, testSet.executableUnderTest) } }