@@ -116,11 +116,14 @@ import org.utbot.framework.UtSettings
116
116
import org.utbot.framework.UtSettings.maximizeCoverageUsingReflection
117
117
import org.utbot.framework.UtSettings.preferredCexOption
118
118
import org.utbot.framework.UtSettings.substituteStaticsWithSymbolicVariable
119
- import org.utbot.framework.plugin.api.StandardApplicationContext
119
+ import org.utbot.framework.plugin.api.ApplicationContext
120
120
import org.utbot.framework.plugin.api.ClassId
121
121
import org.utbot.framework.plugin.api.ExecutableId
122
122
import org.utbot.framework.plugin.api.FieldId
123
123
import org.utbot.framework.plugin.api.MethodId
124
+ import org.utbot.framework.plugin.api.TypeReplacementMode.AnyImplementor
125
+ import org.utbot.framework.plugin.api.TypeReplacementMode.KnownImplementor
126
+ import org.utbot.framework.plugin.api.TypeReplacementMode.NoImplementors
124
127
import org.utbot.framework.plugin.api.classId
125
128
import org.utbot.framework.plugin.api.id
126
129
import org.utbot.framework.plugin.api.util.executable
@@ -239,7 +242,7 @@ class Traverser(
239
242
internal val typeResolver : TypeResolver ,
240
243
private val globalGraph : InterProceduralUnitGraph ,
241
244
private val mocker : Mocker ,
242
- private val applicationContext : StandardApplicationContext ? ,
245
+ private val applicationContext : ApplicationContext ,
243
246
) : UtContextInitializer() {
244
247
245
248
private val visitedStmts: MutableSet <Stmt > = mutableSetOf ()
@@ -1364,7 +1367,7 @@ class Traverser(
1364
1367
traverseException(current, symException)
1365
1368
}
1366
1369
1367
- // TODO HACK violation of encapsulation
1370
+ // TODO: HACK violation of encapsulation
1368
1371
fun createObject (
1369
1372
addr : UtAddrExpression ,
1370
1373
type : RefType ,
@@ -1373,6 +1376,27 @@ class Traverser(
1373
1376
): ObjectValue {
1374
1377
touchAddress(addr)
1375
1378
1379
+ // Some types (e.g., interfaces) need to be mocked or replaced with the concrete implementor.
1380
+ // Typically, this implementor is selected by SMT solver later.
1381
+ // However, if we have the restriction on implementor type (it may be obtained
1382
+ // from Spring bean definitions, for example), we can just create a symbolic object
1383
+ // with hard constraint on the mentioned type.
1384
+ val replacedClassId = when (applicationContext.typeReplacementMode) {
1385
+ KnownImplementor -> applicationContext.replaceTypeIfNeeded(type)
1386
+ AnyImplementor ,
1387
+ NoImplementors -> null
1388
+ }
1389
+
1390
+ replacedClassId?.let {
1391
+ val sootType = Scene .v().getRefType(it.canonicalName)
1392
+ val typeStorage = typeResolver.constructTypeStorage(sootType, useConcreteType = false )
1393
+
1394
+ val typeHardConstraint = typeRegistry.typeConstraint(addr, typeStorage).all().asHardConstraint()
1395
+ queuedSymbolicStateUpdates + = typeHardConstraint
1396
+
1397
+ return ObjectValue (typeStorage, addr)
1398
+ }
1399
+
1376
1400
val nullEqualityConstraint = mkEq(addr, nullObjectAddr)
1377
1401
1378
1402
if (mockInfoGenerator != null ) {
@@ -1475,48 +1499,79 @@ class Traverser(
1475
1499
" but there is no mock info generator provided to construct a mock value."
1476
1500
}
1477
1501
1478
- val mockInfo = mockInfoGenerator.generate(addr )
1479
- val mockedObjectInfo = mocker.forceMock(type, mockInfoGenerator.generate(addr))
1480
-
1481
- val mockedObject : ObjectValue = when (mockedObjectInfo ) {
1482
- is NoMock -> error( " Value must be mocked after the force mock " )
1483
- is ExpectedMock -> mockedObjectInfo.value
1484
- is UnexpectedMock -> {
1485
- // if mock occurs, but it is unexpected due to some reasons
1486
- // (e.g. we do not have mock framework installed),
1487
- // we can only generate a test that uses null value for mocked object
1488
- queuedSymbolicStateUpdates + = nullEqualityConstraint.asHardConstraint()
1489
-
1490
- mockedObjectInfo.value
1491
- }
1502
+ return createMockedObject(addr, type, mockInfoGenerator)
1503
+ }
1504
+
1505
+ val concreteImplementation = when (applicationContext.typeReplacementMode ) {
1506
+ AnyImplementor -> {
1507
+ val isMockConstraint = mkEq(typeRegistry.isMock(addr), UtFalse )
1508
+
1509
+ queuedSymbolicStateUpdates + = typeHardConstraint
1510
+ queuedSymbolicStateUpdates + = mkOr(isMockConstraint, nullEqualityConstraint).asHardConstraint()
1511
+
1512
+ // If we have this$0 with UtArrayList type, we have to create such instance.
1513
+ // We should create an object with typeStorage of all possible real types and concrete implementation
1514
+ // Otherwise we'd have either a wrong type in the resolver, or missing method like 'preconditionCheck'.
1515
+ wrapperToClass[type]?.first()?. let { wrapper(it, addr) }?.concrete
1492
1516
}
1517
+ // In case of `KnownImplementor` mode we should have already tried to replace type using `replaceTypeIfNeeded`.
1518
+ // However, this replacement attempt might be unsuccessful even if some possible concrete types are present.
1519
+ // For example, we may have two concrete implementors present in Spring bean definitions, so we do not know
1520
+ // which one to use. In such case we try to mock this type, if it is possible, or prune branch as unsatisfiable.
1521
+ //
1522
+ // In case of `NoImplementors` mode we should try to mock this type or prune branch as unsatisfiable.
1523
+ // Mocking can be impossible here as there are no guaranties that `mockInfoGenerator` is instantiated.
1524
+ KnownImplementor ,
1525
+ NoImplementors -> {
1526
+ mockInfoGenerator?.let {
1527
+ return createMockedObject(addr, type, it)
1528
+ }
1493
1529
1494
- if (mockedObjectInfo is UnexpectedMock ) {
1495
- return mockedObject
1530
+ queuedSymbolicStateUpdates + = mkFalse().asHardConstraint()
1531
+ null
1496
1532
}
1533
+ }
1497
1534
1498
- queuedSymbolicStateUpdates + = MemoryUpdate (mockInfos = persistentListOf(MockInfoEnriched (mockInfo)))
1535
+ return ObjectValue (typeStorage, addr, concreteImplementation)
1536
+ }
1499
1537
1500
- // add typeConstraint for mocked object. It's a declared type of the object.
1501
- val typeConstraint = typeRegistry.typeConstraint(addr, mockedObject.typeStorage).all()
1502
- val isMockConstraint = mkEq(typeRegistry.isMock(mockedObject.addr), UtTrue )
1538
+ private fun createMockedObject (
1539
+ addr : UtAddrExpression ,
1540
+ type : RefType ,
1541
+ mockInfoGenerator : UtMockInfoGenerator ,
1542
+ ): ObjectValue {
1543
+ val nullEqualityConstraint = mkEq(addr, nullObjectAddr)
1503
1544
1504
- queuedSymbolicStateUpdates + = typeConstraint.asHardConstraint()
1505
- queuedSymbolicStateUpdates + = mkOr(isMockConstraint, nullEqualityConstraint).asHardConstraint()
1545
+ val mockInfo = mockInfoGenerator.generate(addr)
1546
+ val mockedObjectInfo = mocker.forceMock(type, mockInfoGenerator.generate(addr))
1547
+
1548
+ val mockedObject: ObjectValue = when (mockedObjectInfo) {
1549
+ is NoMock -> error(" Value must be mocked after the force mock" )
1550
+ is ExpectedMock -> mockedObjectInfo.value
1551
+ is UnexpectedMock -> {
1552
+ // if mock occurs, but it is unexpected due to some reasons
1553
+ // (e.g. we do not have mock framework installed),
1554
+ // we can only generate a test that uses null value for mocked object
1555
+ queuedSymbolicStateUpdates + = nullEqualityConstraint.asHardConstraint()
1506
1556
1557
+ mockedObjectInfo.value
1558
+ }
1559
+ }
1560
+
1561
+ if (mockedObjectInfo is UnexpectedMock ) {
1507
1562
return mockedObject
1508
1563
}
1509
1564
1510
- // If we have this$0 with UtArrayList type, we have to create such instance.
1511
- // We should create an object with typeStorage of all possible real types and concrete implementation
1512
- // Otherwise we'd have either a wrong type in the resolver, or missing method like 'preconditionCheck' .
1513
- val concreteImplementation = wrapperToClass[type]?.first()?. let { wrapper(it, addr) }?.concrete
1514
- val isMockConstraint = mkEq(typeRegistry.isMock(addr), UtFalse )
1565
+ queuedSymbolicStateUpdates + = MemoryUpdate (mockInfos = persistentListOf( MockInfoEnriched (mockInfo)))
1566
+
1567
+ // add typeConstraint for mocked object. It's a declared type of the object .
1568
+ val typeConstraint = typeRegistry.typeConstraint(addr, mockedObject.typeStorage).all()
1569
+ val isMockConstraint = mkEq(typeRegistry.isMock(mockedObject. addr), UtTrue )
1515
1570
1516
- queuedSymbolicStateUpdates + = typeHardConstraint
1571
+ queuedSymbolicStateUpdates + = typeConstraint.asHardConstraint()
1517
1572
queuedSymbolicStateUpdates + = mkOr(isMockConstraint, nullEqualityConstraint).asHardConstraint()
1518
1573
1519
- return ObjectValue (typeStorage, addr, concreteImplementation)
1574
+ return mockedObject
1520
1575
}
1521
1576
1522
1577
private fun TraversalContext.resolveConstant (constant : Constant ): SymbolicValue =
0 commit comments