From 3b0ca177376ff38c5d8480026e958300b42b3294 Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Fri, 17 Nov 2023 23:27:01 +0300 Subject: [PATCH 1/5] Fix compilation after USVM update (jvm-instrumentation-persistent-descriptors) --- .../contest/usvm/JcToUtModelConverter.kt | 31 +------------------ .../contest/usvm/UTestValueDescriptorUtils.kt | 3 +- 2 files changed, 2 insertions(+), 32 deletions(-) diff --git a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/JcToUtModelConverter.kt b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/JcToUtModelConverter.kt index 70f46029f8..f5499a0c58 100644 --- a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/JcToUtModelConverter.kt +++ b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/JcToUtModelConverter.kt @@ -68,7 +68,7 @@ class JcToUtModelConverter( model } - is UTestArrayDescriptor.Array -> { + is UTestArrayDescriptor -> { val stores = mutableMapOf() val model = UtArrayModel( @@ -88,15 +88,6 @@ class JcToUtModelConverter( model } - is UTestArrayDescriptor.BooleanArray -> constructPrimitiveArray(valueDescriptor, valueDescriptor.value.toList()) - is UTestArrayDescriptor.ByteArray -> constructPrimitiveArray(valueDescriptor, valueDescriptor.value.toList()) - is UTestArrayDescriptor.CharArray -> constructPrimitiveArray(valueDescriptor, valueDescriptor.value.toList()) - is UTestArrayDescriptor.DoubleArray -> constructPrimitiveArray(valueDescriptor, valueDescriptor.value.toList()) - is UTestArrayDescriptor.FloatArray -> constructPrimitiveArray(valueDescriptor, valueDescriptor.value.toList()) - is UTestArrayDescriptor.IntArray -> constructPrimitiveArray(valueDescriptor, valueDescriptor.value.toList()) - is UTestArrayDescriptor.LongArray -> constructPrimitiveArray(valueDescriptor, valueDescriptor.value.toList()) - is UTestArrayDescriptor.ShortArray -> constructPrimitiveArray(valueDescriptor, valueDescriptor.value.toList()) - is UTestClassDescriptor -> UtClassRefModel( id = idGenerator.createId(), classId = classClassId, @@ -138,26 +129,6 @@ class JcToUtModelConverter( } } - private fun constructPrimitiveArray(valueDescriptor: UTestArrayDescriptor<*>, arrayContent: List): UtArrayModel { - val stores = mutableMapOf() - - val model = UtArrayModel( - id = idGenerator.createId(), - classId = valueDescriptor.type.classId, - length = valueDescriptor.length, - constModel = UtNullModel(valueDescriptor.elementType.classId), - stores = stores, - ) - - descriptorToModelCache[valueDescriptor] = model - - arrayContent - .map { elemValue -> UtPrimitiveModel(elemValue) } - .forEachIndexed { index, elemModel -> stores += index to elemModel } - - return model - } - private fun constructString(valueDescriptorValue: String): UtModel { if(valueDescriptorValue == nameForExistingButNullString){ return UtNullModel(stringClassId) diff --git a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/UTestValueDescriptorUtils.kt b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/UTestValueDescriptorUtils.kt index ba7dc42ee7..cd96782def 100644 --- a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/UTestValueDescriptorUtils.kt +++ b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/UTestValueDescriptorUtils.kt @@ -13,14 +13,13 @@ fun UTestValueDescriptor.dropStaticFields( cache: MutableMap ): UTestValueDescriptor = cache.getOrPut(this) { when (this) { - is UTestArrayDescriptor.Array -> UTestArrayDescriptor.Array( + is UTestArrayDescriptor -> UTestArrayDescriptor( elementType = elementType, length = length, value = value.map { it.dropStaticFields(cache) }, refId = refId ) - is UTestArrayDescriptor<*> -> this is UTestClassDescriptor -> this is UTestConstantDescriptor -> this is UTestCyclicReferenceDescriptor -> this From 482e35d2250e79e454ca48740e5a3c104756328f Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Fri, 17 Nov 2023 23:33:58 +0300 Subject: [PATCH 2/5] Make `JcToUtModelConverter` construct `UtCompositeModel.origin` and assign same id to `stateBefore` and `stateAfter` models that describe same object --- .../contest/usvm/EnvironmentStateKind.kt | 5 ++ .../contest/usvm/JcToUtExecutionConverter.kt | 24 +++--- .../contest/usvm/JcToUtModelConverter.kt | 82 ++++++++++++++----- 3 files changed, 82 insertions(+), 29 deletions(-) create mode 100644 utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/EnvironmentStateKind.kt diff --git a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/EnvironmentStateKind.kt b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/EnvironmentStateKind.kt new file mode 100644 index 0000000000..0c275c4152 --- /dev/null +++ b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/EnvironmentStateKind.kt @@ -0,0 +1,5 @@ +package org.utbot.contest.usvm + +enum class EnvironmentStateKind { + INITIAL, FINAL +} \ No newline at end of file diff --git a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/JcToUtExecutionConverter.kt b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/JcToUtExecutionConverter.kt index 2e200e36d3..94429b5249 100644 --- a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/JcToUtExecutionConverter.kt +++ b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/JcToUtExecutionConverter.kt @@ -68,17 +68,19 @@ class JcToUtExecutionConverter( val utUsvmExecution: UtUsvmExecution = when (val executionResult = jcExecution.uTestExecutionResult) { is UTestExecutionSuccessResult -> UtUsvmExecution( - stateBefore = convertState(executionResult.initialState, jcExecution.method, jcToUtModelConverter), - stateAfter = convertState(executionResult.resultState, jcExecution.method, jcToUtModelConverter), + stateBefore = convertState(executionResult.initialState, EnvironmentStateKind.INITIAL, jcExecution.method), + stateAfter = convertState(executionResult.resultState, EnvironmentStateKind.FINAL, jcExecution.method), // TODO usvm-sbft: ask why `UTestExecutionSuccessResult.result` is nullable - result = UtExecutionSuccess(executionResult.result?.let { jcToUtModelConverter.convert(it) } ?: UtVoidModel), + result = UtExecutionSuccess(executionResult.result?.let { + jcToUtModelConverter.convert(it, EnvironmentStateKind.FINAL) + } ?: UtVoidModel), coverage = coverage, instrumentation = instrumentation, ) is UTestExecutionExceptionResult -> { UtUsvmExecution( - stateBefore = convertState(executionResult.initialState, jcExecution.method, jcToUtModelConverter), - stateAfter = convertState(executionResult.resultState, jcExecution.method, jcToUtModelConverter), + stateBefore = convertState(executionResult.initialState, EnvironmentStateKind.INITIAL, jcExecution.method), + stateAfter = convertState(executionResult.resultState, EnvironmentStateKind.FINAL, jcExecution.method), result = createExecutionFailureResult( executionResult.cause, jcExecution.method, @@ -160,18 +162,20 @@ class JcToUtExecutionConverter( private fun convertState( state: UTestExecutionState, + stateKind: EnvironmentStateKind, method: JcTypedMethod, - modelConverter: JcToUtModelConverter, - ): EnvironmentModels { + ): EnvironmentModels { val thisInstance = if (method.isStatic) null else if (method.method.isConstructor) null - else modelConverter.convert(state.instanceDescriptor ?: error("Unexpected null instanceDescriptor")) - val parameters = state.argsDescriptors.map { modelConverter.convert(it ?: error("Unexpected null argDescriptor")) } + else jcToUtModelConverter.convert(state.instanceDescriptor ?: error("Unexpected null instanceDescriptor"), stateKind) + val parameters = state.argsDescriptors.map { + jcToUtModelConverter.convert(it ?: error("Unexpected null argDescriptor"), stateKind) + } val statics = state.statics .entries .associate { (jcField, uTestDescr) -> - jcField.fieldId to modelConverter.convert(uTestDescr) + jcField.fieldId to jcToUtModelConverter.convert(uTestDescr, stateKind) } val executableId: ExecutableId = method.method.toExecutableId(jcClasspath) return EnvironmentModels(thisInstance, parameters, statics, executableId) diff --git a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/JcToUtModelConverter.kt b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/JcToUtModelConverter.kt index f5499a0c58..9f79379732 100644 --- a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/JcToUtModelConverter.kt +++ b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/JcToUtModelConverter.kt @@ -2,6 +2,7 @@ package org.utbot.contest.usvm import org.jacodb.api.JcClasspath import org.usvm.instrumentation.testcase.api.UTestExpression +import org.usvm.instrumentation.testcase.api.UTestMock import org.usvm.instrumentation.testcase.descriptor.UTestArrayDescriptor import org.usvm.instrumentation.testcase.descriptor.UTestClassDescriptor import org.usvm.instrumentation.testcase.descriptor.UTestConstantDescriptor @@ -14,18 +15,19 @@ import org.usvm.instrumentation.testcase.descriptor.UTestValueDescriptor import org.usvm.instrumentation.util.InstrumentationModuleConstants.nameForExistingButNullString import org.utbot.framework.plugin.api.FieldId import org.utbot.framework.plugin.api.UtArrayModel +import org.utbot.framework.plugin.api.UtAssembleModel import org.utbot.framework.plugin.api.UtClassRefModel import org.utbot.framework.plugin.api.UtCompositeModel import org.utbot.framework.plugin.api.UtEnumConstantModel import org.utbot.framework.plugin.api.UtModel import org.utbot.framework.plugin.api.UtNullModel import org.utbot.framework.plugin.api.UtPrimitiveModel +import org.utbot.framework.plugin.api.UtReferenceModel import org.utbot.framework.plugin.api.util.classClassId import org.utbot.framework.plugin.api.util.id import org.utbot.framework.plugin.api.util.jClass import org.utbot.framework.plugin.api.util.stringClassId import org.utbot.fuzzer.IdGenerator -import java.lang.Throwable class JcToUtModelConverter( private val idGenerator: IdGenerator, @@ -33,22 +35,57 @@ class JcToUtModelConverter( private val instToUtModelConverter: UTestInst2UtModelConverter, ) { private val descriptorToModelCache = mutableMapOf() - private val refIdToDescriptorCache = mutableMapOf() + private val refIdAndStateKindToDescriptorCache = + mutableMapOf, UTestValueDescriptor>() + + fun convert( + valueDescriptor: UTestValueDescriptor, + stateKind: EnvironmentStateKind, + ): UtModel = descriptorToModelCache.getOrPut(valueDescriptor) { + if (stateKind == EnvironmentStateKind.INITIAL || valueDescriptor.origin is UTestMock) + valueDescriptor.origin?.let { originExpr -> + val model = instToUtModelConverter.findModelByInst(originExpr as UTestExpression) + if (model is UtAssembleModel && model.origin == null) { + val compositeOrigin = convertIgnoringOriginExprForThisModel( + valueDescriptor = valueDescriptor, + stateKind = stateKind, + curModelId = model.id ?: idGenerator.createId(), + ) + if (compositeOrigin is UtCompositeModel) + return@getOrPut model.copy(origin = compositeOrigin) + } + return@getOrPut model + } - fun convert(valueDescriptor: UTestValueDescriptor): UtModel = descriptorToModelCache.getOrPut(valueDescriptor) { - valueDescriptor.origin?.let { originExpr -> - return instToUtModelConverter.findModelByInst(originExpr as UTestExpression) - } + val previousStateModel = + if (stateKind == EnvironmentStateKind.FINAL && valueDescriptor is UTestRefDescriptor) { + (getModelByRefIdAndStateKind(valueDescriptor.refId, EnvironmentStateKind.INITIAL) as? UtReferenceModel) + } else { + null + } - if (valueDescriptor is UTestRefDescriptor) - refIdToDescriptorCache[valueDescriptor.refId] = valueDescriptor + return@getOrPut convertIgnoringOriginExprForThisModel( + valueDescriptor, + stateKind, + curModelId = previousStateModel?.id ?: idGenerator.createId() + ) + } + + private fun convertIgnoringOriginExprForThisModel( + valueDescriptor: UTestValueDescriptor, + stateKind: EnvironmentStateKind, + curModelId: Int, + ): UtModel = descriptorToModelCache.getOrPut(valueDescriptor) { + if (valueDescriptor is UTestRefDescriptor) { + refIdAndStateKindToDescriptorCache[valueDescriptor.refId to stateKind] = valueDescriptor + } return when (valueDescriptor) { is UTestObjectDescriptor -> { val fields = mutableMapOf() val model = UtCompositeModel( - id = idGenerator.createId(), + id = curModelId, classId = valueDescriptor.type.classId, isMock = false, mocks = mutableMapOf(), @@ -61,7 +98,7 @@ class JcToUtModelConverter( .entries .associate { (jcField, fieldDescr) -> val fieldId = FieldId(jcField.enclosingClass.classId, jcField.name) - val fieldModel = convert(fieldDescr) + val fieldModel = convert(fieldDescr, stateKind) fieldId to fieldModel } @@ -72,7 +109,7 @@ class JcToUtModelConverter( val stores = mutableMapOf() val model = UtArrayModel( - id = idGenerator.createId(), + id = curModelId, classId = valueDescriptor.type.classId, length = valueDescriptor.length, constModel = UtNullModel(valueDescriptor.elementType.classId), @@ -82,17 +119,17 @@ class JcToUtModelConverter( descriptorToModelCache[valueDescriptor] = model valueDescriptor.value - .map { elemDescr -> convert(elemDescr) } + .map { elemDescr -> convert(elemDescr, stateKind) } .forEachIndexed { index, elemModel -> stores += index to elemModel } model } is UTestClassDescriptor -> UtClassRefModel( - id = idGenerator.createId(), + id = curModelId, classId = classClassId, value = valueDescriptor.classType.classId, - ) + ) is UTestConstantDescriptor.Null -> UtNullModel(valueDescriptor.type.classId) @@ -106,11 +143,11 @@ class JcToUtModelConverter( is UTestConstantDescriptor.Short -> UtPrimitiveModel(valueDescriptor.value) is UTestConstantDescriptor.String -> constructString(valueDescriptor.value) - is UTestCyclicReferenceDescriptor -> descriptorToModelCache.getValue( - refIdToDescriptorCache.getValue(valueDescriptor.refId) - ) + is UTestCyclicReferenceDescriptor -> getModelByRefIdAndStateKind(valueDescriptor.refId, stateKind) + ?: error("Invalid UTestCyclicReferenceDescriptor: $valueDescriptor") + is UTestEnumValueDescriptor -> UtEnumConstantModel( - id = idGenerator.createId(), + id = curModelId, classId = valueDescriptor.type.classId, value = valueDescriptor.type.classId.jClass.enumConstants.find { // [valueDescriptor.enumValueName] is the enum value to which toString() was applied @@ -118,7 +155,7 @@ class JcToUtModelConverter( } as Enum<*> ) is UTestExceptionDescriptor -> UtCompositeModel( - id = idGenerator.createId(), + id = curModelId, classId = valueDescriptor.type.classId, isMock = false, fields = mutableMapOf( @@ -136,4 +173,11 @@ class JcToUtModelConverter( return UtPrimitiveModel(valueDescriptorValue) } + private fun getModelByRefIdAndStateKind( + refId: Int, + stateKind: EnvironmentStateKind + ): UtModel? = + refIdAndStateKindToDescriptorCache[refId to stateKind]?.let { + descriptorToModelCache[it] + } } \ No newline at end of file From 1762b968ab0778fcc0570c072d7cc370182cef83 Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Fri, 17 Nov 2023 23:37:16 +0300 Subject: [PATCH 3/5] Adapt `ExecutionStateAnalyzer` to deal with absence of `refId` in USVM descriptors for classes, enums, and throwables --- .../org/utbot/framework/fields/ExecutionStateAnalyzer.kt | 9 +++++++++ 1 file changed, 9 insertions(+) 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 46466eb945..4cc02dcb36 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 @@ -21,6 +21,8 @@ import org.utbot.framework.plugin.api.UtPrimitiveModel import org.utbot.framework.plugin.api.UtReferenceModel import org.utbot.framework.plugin.api.UtSymbolicExecution import org.utbot.framework.plugin.api.UtVoidModel +import org.utbot.framework.plugin.api.util.id +import org.utbot.framework.plugin.api.util.isSubtypeOf import org.utbot.framework.util.UtModelVisitor import org.utbot.framework.util.hasThisInstance import org.utbot.fuzzer.UtFuzzedExecution @@ -260,6 +262,13 @@ private class FieldStateVisitor : UtModelVisitor() { // sometimes we don't have initial state of the field, e.g. if it is static and we didn't `touch` it // during the analysis, but the concrete executor included it in the modelAfter val initial = previousFields[path] ?: return false + + // TODO usvm-sbft: In USVM descriptors for classes, enums, and throwables don't implement `UTestRefDescriptor` + // and don't have `refId`, which causes `UtReferenceModel.id` to diverge in `stateBefore` and `stateAfter` + if (initial is UtClassRefModel) return initial.value != ((model as? UtClassRefModel)?.value) + if (initial is UtEnumConstantModel) return initial.value != ((model as? UtEnumConstantModel)?.value) + if (initial.classId isSubtypeOf java.lang.Throwable::class.id) return initial.classId != model.classId + return initial != model } } From f46c9e4a7bde46dcbb42dea7068f10beca82120b Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Fri, 17 Nov 2023 23:38:33 +0300 Subject: [PATCH 4/5] Adapt `ExecutionStateAnalyzer` to deal with `UtAssembleModel`s with `origin` --- .../fields/ExecutionStateAnalyzer.kt | 36 ++++++++----------- 1 file changed, 14 insertions(+), 22 deletions(-) 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 4cc02dcb36..a8731dc14d 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 @@ -106,31 +106,23 @@ class ExecutionStateAnalyzer(val execution: UtExecution) { initialPath: FieldPath = FieldPath() ): FieldStatesInfo { var modelBefore = before + var modelAfter = after if (before::class != after::class) { - 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 { - // it is ok because we might have modelBefore with some absent fields (i.e. statics), but - // 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 UtModelWithCompositeOrigin && after is UtCompositeModel) { - "ModelBefore is an UtModelWithOrigin and ModelAfter " + - "is a CompositeModel, but modelBefore doesn't have an origin model." - } else { - "The model before and the model after have different types: " + - "model before is ${before::class}, but model after is ${after::class}." - } + if (before is UtModelWithCompositeOrigin) + modelBefore = before.origin ?: before + if (after is UtModelWithCompositeOrigin) + modelAfter = after.origin ?: after + } - error("Cannot analyze fields modification. $reason") - } + if (modelBefore::class != modelAfter::class) { + doNotRun { + error("Cannot analyze model fields modification, before: [$before], after: [$after]") + } - // remove it when we will fix assemble models in the resolver JIRA:1464 - workaround(WorkaroundReason.IGNORE_MODEL_TYPES_INEQUALITY) { - return FieldStatesInfo(fieldsBefore = emptyMap(), fieldsAfter = emptyMap()) - } + // remove it when we will fix assemble models in the resolver JIRA:1464 + workaround(WorkaroundReason.IGNORE_MODEL_TYPES_INEQUALITY) { + return FieldStatesInfo(fieldsBefore = emptyMap(), fieldsAfter = emptyMap()) } } @@ -141,7 +133,7 @@ class ExecutionStateAnalyzer(val execution: UtExecution) { modelBefore.accept(FieldStateVisitor(), dataBefore) val dataAfter = FieldData(FieldsVisitorMode.AFTER, fieldsAfter, initialPath, previousFields = fieldsBefore) - after.accept(FieldStateVisitor(), dataAfter) + modelAfter.accept(FieldStateVisitor(), dataAfter) return FieldStatesInfo(fieldsBefore, fieldsAfter) } From fdc4ae4eef150528f7de864442d9160fd2b1dafb Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Fri, 17 Nov 2023 23:41:31 +0300 Subject: [PATCH 5/5] Replace `UtAssembleModel`s that only use reflection with `UtCompositeModel`s, improve `constModel` for `UtArrayModel` --- .../plugin/api/mapper/UtModelDeepMapper.kt | 3 +- .../contest/usvm/JcToUtExecutionConverter.kt | 33 ++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/mapper/UtModelDeepMapper.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/mapper/UtModelDeepMapper.kt index 85e590aaf8..1d207f118d 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/mapper/UtModelDeepMapper.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/mapper/UtModelDeepMapper.kt @@ -12,6 +12,7 @@ import org.utbot.framework.plugin.api.UtNullModel import org.utbot.framework.plugin.api.UtPrimitiveModel import org.utbot.framework.plugin.api.UtReferenceModel import org.utbot.framework.plugin.api.UtVoidModel +import java.util.IdentityHashMap /** * Performs deep mapping of [UtModel]s. @@ -30,7 +31,7 @@ class UtModelDeepMapper private constructor( * Values are models that have been deeply mapped by this [UtModelDeepMapper]. * Models are only associated with models of the same type (i.e. the cache type is actually `MutableMap`) */ - private val cache = mutableMapOf() + private val cache = IdentityHashMap() private val allInputtedModels get() = cache.keys private val allOutputtedModels get() = cache.values diff --git a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/JcToUtExecutionConverter.kt b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/JcToUtExecutionConverter.kt index 94429b5249..88d872f41e 100644 --- a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/JcToUtExecutionConverter.kt +++ b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/JcToUtExecutionConverter.kt @@ -25,6 +25,7 @@ import org.utbot.framework.plugin.api.Coverage import org.utbot.framework.plugin.api.EnvironmentModels import org.utbot.framework.plugin.api.ExecutableId import org.utbot.framework.plugin.api.Instruction +import org.utbot.framework.plugin.api.UtArrayModel import org.utbot.framework.plugin.api.UtAssembleModel import org.utbot.framework.plugin.api.UtExecutableCallModel import org.utbot.framework.plugin.api.UtExecution @@ -34,12 +35,14 @@ import org.utbot.framework.plugin.api.UtExplicitlyThrownException import org.utbot.framework.plugin.api.UtImplicitlyThrownException import org.utbot.framework.plugin.api.UtInstrumentation import org.utbot.framework.plugin.api.UtPrimitiveModel +import org.utbot.framework.plugin.api.UtStatementCallModel import org.utbot.framework.plugin.api.UtVoidModel import org.utbot.framework.plugin.api.mapper.UtModelDeepMapper import org.utbot.framework.plugin.api.util.executableId import org.utbot.framework.plugin.api.util.jClass import org.utbot.framework.plugin.api.util.utContext import org.utbot.fuzzer.IdGenerator +import java.util.IdentityHashMap private val logger = KotlinLogging.logger {} @@ -110,7 +113,10 @@ class JcToUtExecutionConverter( } } ?: return null - return utUsvmExecution.mapModels(constructAssemblingMapper()) + return utUsvmExecution + .mapModels(constructAssemblingMapper()) + .mapModels(constructAssembleToCompositeModelMapper()) + .mapModels(constructConstArrayModelMapper()) } private fun constructAssemblingMapper(): UtModelDeepMapper = UtModelDeepMapper { model -> @@ -147,6 +153,31 @@ class JcToUtExecutionConverter( } ?: model } + private fun constructConstArrayModelMapper(): UtModelDeepMapper = UtModelDeepMapper { model -> + if (model is UtArrayModel) { + val storeGroups = model.stores.entries.groupByTo(IdentityHashMap()) { it.value } + val mostCommonStore = storeGroups.maxBy { it.value.size } + if (mostCommonStore.value.size > 1) { + model.constModel = mostCommonStore.key + mostCommonStore.value.forEach { (index, _) -> model.stores.remove(index) } + } + } + model + } + + private fun constructAssembleToCompositeModelMapper(): UtModelDeepMapper = UtModelDeepMapper { model -> + if (model is UtAssembleModel + && utilMethodProvider.createInstanceMethodId == model.instantiationCall.statement + && model.modificationsChain.all { + utilMethodProvider.setFieldMethodId == (it as? UtStatementCallModel)?.statement + } + ) { + model.origin ?: model + } else { + model + } + } + private fun convertException(exceptionDescriptor: UTestExceptionDescriptor): Throwable = toValueConverter.buildObjectFromDescriptor(exceptionDescriptor.dropStaticFields( cache = mutableMapOf()