Skip to content

Commit 2588785

Browse files
Verify mock correctness and selection a little more careful #2074 (#2153)
Co-authored-by: Alexey Menshutin <alex.menshutin99@gmail.com>
1 parent 41a1009 commit 2588785

File tree

5 files changed

+67
-30
lines changed

5 files changed

+67
-30
lines changed

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import org.utbot.framework.plugin.api.UtModel
2828
import org.utbot.framework.plugin.api.UtNullModel
2929
import org.utbot.framework.plugin.api.UtPrimitiveModel
3030
import org.utbot.framework.plugin.api.getIdOrThrow
31+
import org.utbot.framework.plugin.api.id
3132
import org.utbot.framework.plugin.api.util.fieldId
3233
import org.utbot.framework.plugin.api.util.id
3334
import org.utbot.framework.plugin.api.util.objectArrayClassId
@@ -208,7 +209,10 @@ class RangeModifiableUnlimitedArrayWrapper : WrapperInterface {
208209
?: OBJECT_TYPE
209210

210211
val resultObject = if (valueType is RefType) {
211-
createObject(addr, valueType, useConcreteType = false)
212+
val mockInfoGenerator = UtMockInfoGenerator { mockAddr ->
213+
UtObjectMockInfo(valueType.id, mockAddr)
214+
}
215+
createObject(addr, valueType, useConcreteType = false, mockInfoGenerator)
212216
} else {
213217
require(valueType is ArrayType) {
214218
"Unexpected Primitive Type $valueType in generic parameter for RangeModifiableUnlimitedArray $wrapper"
@@ -431,7 +435,9 @@ class AssociativeArrayWrapper : WrapperInterface {
431435
with(traverser) {
432436
val value = getStorageArrayExpression(wrapper).select(parameters[0].addr)
433437
val addr = UtAddrExpression(value)
434-
val resultObject = createObject(addr, OBJECT_TYPE, useConcreteType = false)
438+
// TODO it is probably a bug, what mock generator should we provide here?
439+
// Seems like we don't know anything about its type here
440+
val resultObject = createObject(addr, OBJECT_TYPE, useConcreteType = false, mockInfoGenerator = null)
435441

436442
val typeIndex = wrapper.asWrapperOrNull?.selectOperationTypeIndex
437443
?: error("Wrapper was expected, got $wrapper")

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,12 @@ data class ThrowableWrapper(val throwable: Throwable) : WrapperInterface {
381381
workaround(MAKE_SYMBOLIC) {
382382
listOf(
383383
MethodResult(
384-
createConst(method.returnType, typeRegistry.findNewSymbolicReturnValueName())
384+
createConst(
385+
method.returnType,
386+
typeRegistry.findNewSymbolicReturnValueName(),
387+
// we don't want to mock anything returned from a throwable instance's methods
388+
mockInfoGenerator = null
389+
)
385390
)
386391
)
387392
}

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

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -292,8 +292,11 @@ class Resolver(
292292
// Associates mock infos by concrete addresses
293293
// Sometimes we might have two mocks with the same concrete address, and here we group their mockInfos
294294
// Then we should merge executables for mocks with the same concrete addresses with respect to the calls order
295-
val mocks = memory
296-
.mocks()
295+
val memoryMocks = memory.mocks()
296+
// TODO add a comment about why is it impossible to have nulls here
297+
.filter { holder.concreteAddr(it.mockInfo.addr) != SYMBOLIC_NULL_ADDR }
298+
299+
val mocks = memoryMocks
297300
.groupBy { enriched -> holder.concreteAddr(enriched.mockInfo.addr) }
298301
.map { (address, mockInfos) -> address to mockInfos.mergeExecutables() }
299302

@@ -303,7 +306,7 @@ class Resolver(
303306
val staticMethodMocks = mutableMapOf<MethodId, List<UtModel>>()
304307

305308
// Enriches mock info with information from callsToMocks
306-
memory.mocks().forEach { (mockInfo, executables) ->
309+
memoryMocks.forEach { (mockInfo, executables) ->
307310
when (mockInfo) {
308311
// Collects static field mocks differently
309312
is UtFieldMockInfo -> if (mockInfo.ownerAddr == null) {
@@ -319,7 +322,7 @@ class Resolver(
319322
}
320323

321324
// Collects instrumentation
322-
val newInstancesInstrumentation = memory.mocks()
325+
val newInstancesInstrumentation = memoryMocks
323326
.map { it.mockInfo }
324327
.filterIsInstance<UtNewInstanceMockInfo>()
325328
.groupBy { it.classId }
@@ -1219,7 +1222,8 @@ fun Traverser.toMethodResult(value: Any?, sootType: Type): MethodResult {
12191222
return when (value) {
12201223
null -> asMethodResult {
12211224
if (sootType is RefType) {
1222-
createObject(nullObjectAddr, sootType, useConcreteType = true)
1225+
// We don't want to mock values we took from a concrete environment
1226+
createObject(nullObjectAddr, sootType, useConcreteType = true, mockInfoGenerator = null)
12231227
} else {
12241228
createArray(nullObjectAddr, sootType as ArrayType, useConcreteType = true)
12251229
}
@@ -1262,7 +1266,8 @@ fun Traverser.toMethodResult(value: Any?, sootType: Type): MethodResult {
12621266
?.let { type -> type to true }
12631267
?: (elementType to false)
12641268

1265-
createObject(addr, type, useConcreteType)
1269+
// We don't want to mock values we took from a concrete environment
1270+
createObject(addr, type, useConcreteType, mockInfoGenerator = null)
12661271
} else {
12671272
require(elementType is ArrayType)
12681273
// We cannot use concrete types since we do not receive
@@ -1296,7 +1301,8 @@ fun Traverser.toMethodResult(value: Any?, sootType: Type): MethodResult {
12961301
?.let { type -> type to true }
12971302
?: (sootType as RefType to false)
12981303

1299-
createObject(addr, type, useConcreteType)
1304+
// We don't want to mock values we took from a concrete environment
1305+
createObject(addr, type, useConcreteType, mockInfoGenerator = null)
13001306
}
13011307
}
13021308
}

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

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -776,8 +776,16 @@ class Traverser(
776776

777777
private fun TraversalContext.skipVerticesForThrowableCreation(current: JAssignStmt) {
778778
val rightType = current.rightOp.type as RefType
779-
val exceptionType = Scene.v().getSootClass(rightType.className).type
780-
val createdException = createObject(findNewAddr(), exceptionType, true)
779+
val exceptionType = Scene.v().getRefType(rightType.className)
780+
val mockInfoGenerator = UtMockInfoGenerator { mockAddr ->
781+
UtNewInstanceMockInfo(exceptionType.id, mockAddr, environment.method.declaringClass.id)
782+
}
783+
val createdException = createObject(
784+
findNewAddr(),
785+
exceptionType,
786+
useConcreteType = true,
787+
mockInfoGenerator = mockInfoGenerator
788+
)
781789
val currentExceptionJimpleLocal = current.leftOp as JimpleLocal
782790

783791
queuedSymbolicStateUpdates += localMemoryUpdate(currentExceptionJimpleLocal.variable to createdException)
@@ -1017,10 +1025,8 @@ class Traverser(
10171025
}
10181026
is StaticFieldRef -> {
10191027
val declaringClassType = fieldRef.field.declaringClass.type
1020-
val fieldTypeId = fieldRef.field.type.classId
10211028
val generator = UtMockInfoGenerator { mockAddr ->
1022-
val fieldId = FieldId(declaringClassType.id, fieldRef.field.name)
1023-
UtFieldMockInfo(fieldTypeId, mockAddr, fieldId, ownerAddr = null)
1029+
UtStaticObjectMockInfo(declaringClassType.id, mockAddr)
10241030
}
10251031
findOrCreateStaticObject(declaringClassType, generator)
10261032
}
@@ -1375,7 +1381,7 @@ class Traverser(
13751381
addr: UtAddrExpression,
13761382
type: RefType,
13771383
useConcreteType: Boolean,
1378-
mockInfoGenerator: UtMockInfoGenerator? = null
1384+
mockInfoGenerator: UtMockInfoGenerator?
13791385
): ObjectValue {
13801386
touchAddress(addr)
13811387
val nullEqualityConstraint = mkEq(addr, nullObjectAddr)
@@ -1422,10 +1428,10 @@ class Traverser(
14221428

14231429
// add typeConstraint for mocked object. It's a declared type of the object.
14241430
val typeConstraint = typeRegistry.typeConstraint(addr, mockedObject.typeStorage).all()
1425-
val isMockConstraint = mkEq(typeRegistry.isMock(mockedObject.addr), UtTrue)
1431+
val isMockConstraint = typeRegistry.isMockConstraint(mockedObject.addr)
14261432

14271433
queuedSymbolicStateUpdates += typeConstraint.asHardConstraint()
1428-
queuedSymbolicStateUpdates += mkOr(isMockConstraint, nullEqualityConstraint).asHardConstraint()
1434+
queuedSymbolicStateUpdates += isMockConstraint.asHardConstraint()
14291435

14301436
return mockedObject
14311437
}
@@ -1505,7 +1511,7 @@ class Traverser(
15051511
}
15061512

15071513
val concreteImplementation: Concrete? = when (applicationContext.typeReplacementMode) {
1508-
AnyImplementor -> findConcreteImplementation(addr, type, typeHardConstraint, nullEqualityConstraint)
1514+
AnyImplementor -> findConcreteImplementation(addr, type, typeHardConstraint)
15091515

15101516
// If our type is not abstract, both in `KnownImplementors` and `NoImplementors` mode,
15111517
// we should just still use concrete implementation that represents itself
@@ -1521,7 +1527,7 @@ class Traverser(
15211527
KnownImplementor,
15221528
NoImplementors -> {
15231529
if (!type.isAbstractType) {
1524-
findConcreteImplementation(addr, type, typeHardConstraint, nullEqualityConstraint)
1530+
findConcreteImplementation(addr, type, typeHardConstraint)
15251531
} else {
15261532
mockInfoGenerator?.let {
15271533
return createMockedObject(addr, type, it, nullEqualityConstraint)
@@ -1540,12 +1546,11 @@ class Traverser(
15401546
addr: UtAddrExpression,
15411547
type: RefType,
15421548
typeHardConstraint: HardConstraint,
1543-
nullEqualityConstraint: UtBoolExpression,
15441549
): Concrete? {
15451550
val isMockConstraint = mkEq(typeRegistry.isMock(addr), UtFalse)
15461551

15471552
queuedSymbolicStateUpdates += typeHardConstraint
1548-
queuedSymbolicStateUpdates += mkOr(isMockConstraint, nullEqualityConstraint).asHardConstraint()
1553+
queuedSymbolicStateUpdates += isMockConstraint.asHardConstraint()
15491554

15501555
// If we have this$0 with UtArrayList type, we have to create such instance.
15511556
// We should create an object with typeStorage of all possible real types and concrete implementation
@@ -1583,10 +1588,10 @@ class Traverser(
15831588

15841589
// add typeConstraint for mocked object. It's a declared type of the object.
15851590
val typeConstraint = typeRegistry.typeConstraint(addr, mockedObject.typeStorage).all()
1586-
val isMockConstraint = mkEq(typeRegistry.isMock(mockedObject.addr), UtTrue)
1591+
val isMockConstraint = typeRegistry.isMockConstraint(mockedObject.addr)
15871592

15881593
queuedSymbolicStateUpdates += typeConstraint.asHardConstraint()
1589-
queuedSymbolicStateUpdates += mkOr(isMockConstraint, nullEqualityConstraint).asHardConstraint()
1594+
queuedSymbolicStateUpdates += isMockConstraint.asHardConstraint()
15901595

15911596
return mockedObject
15921597
}
@@ -1606,7 +1611,8 @@ class Traverser(
16061611
// instead of it we create an unbounded symbolic variable
16071612
workaround(HACK) {
16081613
offerState(environment.state.withLabel(StateLabel.CONCRETE))
1609-
createObject(addr, refType, useConcreteType = true)
1614+
// We don't need to mock a string constant creation
1615+
createObject(addr, refType, useConcreteType = true, mockInfoGenerator = null)
16101616
}
16111617
} else {
16121618
val typeStorage = TypeStorage.constructTypeStorageWithSingleType(refType)
@@ -2254,7 +2260,7 @@ class Traverser(
22542260
addr: UtAddrExpression,
22552261
fieldType: Type,
22562262
chunkId: ChunkId,
2257-
mockInfoGenerator: UtMockInfoGenerator? = null
2263+
mockInfoGenerator: UtMockInfoGenerator?
22582264
): SymbolicValue {
22592265
val descriptor = MemoryChunkDescriptor(chunkId, objectType, fieldType)
22602266
val array = memory.findArray(descriptor)
@@ -2395,10 +2401,10 @@ class Traverser(
23952401
* Since createConst called only for objects from outside at the beginning of the analysis,
23962402
* we can set Le(addr, NULL_ADDR) for all RefValue objects.
23972403
*/
2398-
private fun Value.createConst(pName: String, mockInfoGenerator: UtMockInfoGenerator? = null): SymbolicValue =
2404+
private fun Value.createConst(pName: String, mockInfoGenerator: UtMockInfoGenerator?): SymbolicValue =
23992405
createConst(type, pName, mockInfoGenerator)
24002406

2401-
fun createConst(type: Type, pName: String, mockInfoGenerator: UtMockInfoGenerator? = null): SymbolicValue =
2407+
fun createConst(type: Type, pName: String, mockInfoGenerator: UtMockInfoGenerator?): SymbolicValue =
24022408
when (type) {
24032409
is ByteType -> mkBVConst(pName, UtByteSort).toByteValue()
24042410
is ShortType -> mkBVConst(pName, UtShortSort).toShortValue()
@@ -3460,9 +3466,9 @@ class Traverser(
34603466

34613467
private fun unboundedVariable(name: String, method: SootMethod): MethodResult {
34623468
val value = when (val returnType = method.returnType) {
3463-
is RefType -> createObject(findNewAddr(), returnType, useConcreteType = true)
3469+
is RefType -> createObject(findNewAddr(), returnType, useConcreteType = true, mockInfoGenerator = null)
34643470
is ArrayType -> createArray(findNewAddr(), returnType, useConcreteType = true)
3465-
else -> createConst(returnType, "$name${unboundedConstCounter++}")
3471+
else -> createConst(returnType, "$name${unboundedConstCounter++}", mockInfoGenerator = null)
34663472
}
34673473

34683474
return MethodResult(value)

utbot-framework/src/main/kotlin/org/utbot/engine/types/TypeRegistry.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,20 @@ class TypeRegistry {
199199
*/
200200
fun isMock(addr: UtAddrExpression) = isMockArray.select(addr)
201201

202+
private fun mockCorrectnessConstraint(addr: UtAddrExpression) =
203+
mkOr(
204+
mkEq(isMock(addr), UtFalse),
205+
mkNot(mkEq(addr, nullObjectAddr))
206+
)
207+
208+
fun isMockConstraint(addr: UtAddrExpression) = mkAnd(
209+
mkOr(
210+
mkEq(isMock(addr), UtTrue),
211+
mkEq(addr, nullObjectAddr)
212+
),
213+
mockCorrectnessConstraint(addr)
214+
)
215+
202216
/**
203217
* Makes the numbers of dimensions for every object in the program equal to zero by default
204218
*/

0 commit comments

Comments
 (0)