From d0d5f6c45b33b89570d09da09a13d8f4276ee2dc Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Mon, 27 Nov 2023 18:11:21 +0300 Subject: [PATCH 1/2] Update `JcTestExecutor` to resolve mocks --- .../utbot/contest/usvm/jc/JcTestExecutor.kt | 79 ++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/jc/JcTestExecutor.kt b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/jc/JcTestExecutor.kt index 7e630626da..46ac4279c8 100644 --- a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/jc/JcTestExecutor.kt +++ b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/jc/JcTestExecutor.kt @@ -3,14 +3,25 @@ package org.utbot.contest.usvm.jc import kotlinx.coroutines.runBlocking import org.jacodb.api.JcClassType import org.jacodb.api.JcClasspath +import org.jacodb.api.JcField +import org.jacodb.api.JcMethod import org.jacodb.api.JcType import org.jacodb.api.JcTypedMethod +import org.jacodb.api.ext.findTypeOrNull +import org.jacodb.api.ext.methods import org.jacodb.api.ext.objectType +import org.jacodb.api.ext.toType +import org.jacodb.approximation.JcEnrichedVirtualField +import org.jacodb.approximation.JcEnrichedVirtualMethod import org.usvm.UConcreteHeapRef import org.usvm.UExpr +import org.usvm.UHeapRef +import org.usvm.UIndexedMethodReturnValue +import org.usvm.UMockSymbol import org.usvm.api.JcCoverage import org.usvm.api.JcTest import org.usvm.api.util.JcTestStateResolver +import org.usvm.collection.field.UFieldLValue import org.usvm.instrumentation.executor.UTestConcreteExecutor import org.usvm.instrumentation.testcase.UTest import org.usvm.instrumentation.testcase.api.UTestAllocateMemoryCall @@ -18,10 +29,12 @@ import org.usvm.instrumentation.testcase.api.UTestExecutionExceptionResult import org.usvm.instrumentation.testcase.api.UTestExecutionSuccessResult import org.usvm.instrumentation.testcase.api.UTestExpression import org.usvm.instrumentation.testcase.api.UTestMethodCall +import org.usvm.instrumentation.testcase.api.UTestMockObject import org.usvm.instrumentation.testcase.api.UTestNullExpression import org.usvm.instrumentation.testcase.api.UTestStaticMethodCall import org.usvm.machine.JcContext import org.usvm.machine.state.JcMethodResult +import org.usvm.machine.JcMocker import org.usvm.machine.state.JcState import org.usvm.machine.state.localIdx import org.usvm.memory.ULValue @@ -47,7 +60,14 @@ class JcTestExecutor( val ctx = state.ctx - val memoryScope = MemoryScope(ctx, model, model, stringConstants, method) + val mocker = state.memory.mocker as JcMocker +// val staticMethodMocks = mocker.statics TODO global mocks????????????????????????? + val methodMocks = mocker.symbols + + val resolvedMethodMocks = methodMocks.entries.groupBy({ model.eval(it.key) }, { it.value }) + .mapValues { it.value.flatten() } + + val memoryScope = MemoryScope(ctx, model, model, stringConstants, resolvedMethodMocks, method) val uTest = memoryScope.createUTest() @@ -62,7 +82,7 @@ class JcTestExecutor( when (symbolicResult) { is JcMethodResult.JcException -> UTestSymbolicExceptionResult(symbolicResult.type) is JcMethodResult.Success -> { - val resultScope = MemoryScope(ctx, model, state.memory, stringConstants, method) + val resultScope = MemoryScope(ctx, model, state.memory, stringConstants, resolvedMethodMocks, method) val resultExpr = resultScope.resolveExpr(symbolicResult.value, method.returnType) val resultInitializer = resultScope.decoderApi.initializerInstructions() UTestSymbolicSuccessResult(resultInitializer, resultExpr) @@ -95,6 +115,7 @@ class JcTestExecutor( model: UModelBase, memory: UReadOnlyMemory, stringConstants: Map, + private val resolvedMethodMocks: Map>>, method: JcTypedMethod, ) : JcTestStateResolver(ctx, model, memory, stringConstants, method) { @@ -128,5 +149,59 @@ class JcTestExecutor( // todo: looks incorrect override fun allocateString(value: UTestExpression): UTestExpression = value + + override fun resolveObject(ref: UConcreteHeapRef, heapRef: UHeapRef, type: JcClassType): UTestExpression { + if (ref !in resolvedMethodMocks) { + return super.resolveObject(ref, heapRef, type) + } + + val mocks = resolvedMethodMocks.getValue(ref) + + val fieldValues = mutableMapOf() + val methods = mutableMapOf>() + + val instance = UTestMockObject(type, fieldValues, methods) + saveResolvedRef(ref.address, instance) + + val mockedMethodValues = mutableMapOf>>() + mocks.filterIsInstance>().forEach { mockValue -> + var method = mockValue.method + + // Find original method + if (method is JcEnrichedVirtualMethod) { + method = method.enclosingClass.methods + .filter { it !is JcEnrichedVirtualMethod } + .singleOrNull { it.name == method.name && it.description == method.description } + ?: return@forEach + } + + mockedMethodValues.getOrPut(method) { mutableListOf() }.add(mockValue) + } + + mockedMethodValues.forEach { (method, values) -> + val mockedValueType = requireNotNull(ctx.cp.findTypeOrNull(method.returnType)) { + "No such type found: ${method.returnType}" + } + + methods[method] = values + .sortedBy { it.callIndex } + .map { resolveExpr(it, mockedValueType) } + } + + val fields = generateSequence(type.jcClass) { it.superClass } + .map { it.toType() } + .flatMap { it.declaredFields } + .filter { !it.isStatic } + .filterNot { it.field is JcEnrichedVirtualField } + + for (field in fields) { + val lvalue = UFieldLValue(ctx.typeToSort(field.fieldType), heapRef, field.field) + val fieldValue = resolveLValue(lvalue, field.fieldType) + + fieldValues[field.field] = fieldValue + } + + return instance + } } } From b9667276556795bc116a6d599c43011cca38456e Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Tue, 28 Nov 2023 14:25:39 +0300 Subject: [PATCH 2/2] Remove approximations specific methods filter --- .../org/utbot/contest/usvm/jc/JcTestExecutor.kt | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/jc/JcTestExecutor.kt b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/jc/JcTestExecutor.kt index 46ac4279c8..6d0733a9bb 100644 --- a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/jc/JcTestExecutor.kt +++ b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/usvm/jc/JcTestExecutor.kt @@ -8,11 +8,9 @@ import org.jacodb.api.JcMethod import org.jacodb.api.JcType import org.jacodb.api.JcTypedMethod import org.jacodb.api.ext.findTypeOrNull -import org.jacodb.api.ext.methods import org.jacodb.api.ext.objectType import org.jacodb.api.ext.toType import org.jacodb.approximation.JcEnrichedVirtualField -import org.jacodb.approximation.JcEnrichedVirtualMethod import org.usvm.UConcreteHeapRef import org.usvm.UExpr import org.usvm.UHeapRef @@ -165,17 +163,8 @@ class JcTestExecutor( val mockedMethodValues = mutableMapOf>>() mocks.filterIsInstance>().forEach { mockValue -> - var method = mockValue.method - - // Find original method - if (method is JcEnrichedVirtualMethod) { - method = method.enclosingClass.methods - .filter { it !is JcEnrichedVirtualMethod } - .singleOrNull { it.name == method.name && it.description == method.description } - ?: return@forEach - } - - mockedMethodValues.getOrPut(method) { mutableListOf() }.add(mockValue) + // todo: filter out approximations-only methods + mockedMethodValues.getOrPut(mockValue.method) { mutableListOf() }.add(mockValue) } mockedMethodValues.forEach { (method, values) ->