@@ -1376,14 +1376,19 @@ class Traverser(
1376
1376
): ObjectValue {
1377
1377
touchAddress(addr)
1378
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.
1379
1384
val replacedClassId = when (applicationContext.typeReplacementMode) {
1380
1385
KnownImplementor -> applicationContext.replaceTypeIfNeeded(type)
1381
1386
AnyImplementor ,
1382
1387
NoImplementors -> null
1383
1388
}
1384
1389
1385
1390
replacedClassId?.let {
1386
- val sootType = typeResolver.classOrDefault( it.canonicalName)
1391
+ val sootType = Scene .v().getSootClass( it.canonicalName).type
1387
1392
val typeStorage = typeResolver.constructTypeStorage(sootType, useConcreteType = false )
1388
1393
1389
1394
val typeHardConstraint = typeRegistry.typeConstraint(addr, typeStorage).all().asHardConstraint()
@@ -1494,36 +1499,7 @@ class Traverser(
1494
1499
" but there is no mock info generator provided to construct a mock value."
1495
1500
}
1496
1501
1497
- val mockInfo = mockInfoGenerator.generate(addr)
1498
- val mockedObjectInfo = mocker.forceMock(type, mockInfoGenerator.generate(addr))
1499
-
1500
- val mockedObject: ObjectValue = when (mockedObjectInfo) {
1501
- is NoMock -> error(" Value must be mocked after the force mock" )
1502
- is ExpectedMock -> mockedObjectInfo.value
1503
- is UnexpectedMock -> {
1504
- // if mock occurs, but it is unexpected due to some reasons
1505
- // (e.g. we do not have mock framework installed),
1506
- // we can only generate a test that uses null value for mocked object
1507
- queuedSymbolicStateUpdates + = nullEqualityConstraint.asHardConstraint()
1508
-
1509
- mockedObjectInfo.value
1510
- }
1511
- }
1512
-
1513
- if (mockedObjectInfo is UnexpectedMock ) {
1514
- return mockedObject
1515
- }
1516
-
1517
- queuedSymbolicStateUpdates + = MemoryUpdate (mockInfos = persistentListOf(MockInfoEnriched (mockInfo)))
1518
-
1519
- // add typeConstraint for mocked object. It's a declared type of the object.
1520
- val typeConstraint = typeRegistry.typeConstraint(addr, mockedObject.typeStorage).all()
1521
- val isMockConstraint = mkEq(typeRegistry.isMock(mockedObject.addr), UtTrue )
1522
-
1523
- queuedSymbolicStateUpdates + = typeConstraint.asHardConstraint()
1524
- queuedSymbolicStateUpdates + = mkOr(isMockConstraint, nullEqualityConstraint).asHardConstraint()
1525
-
1526
- return mockedObject
1502
+ return createMockedObject(addr, type, mockInfoGenerator)
1527
1503
}
1528
1504
1529
1505
val concreteImplementation = when (applicationContext.typeReplacementMode) {
@@ -1538,10 +1514,19 @@ class Traverser(
1538
1514
// Otherwise we'd have either a wrong type in the resolver, or missing method like 'preconditionCheck'.
1539
1515
wrapperToClass[type]?.first()?.let { wrapper(it, addr) }?.concrete
1540
1516
}
1541
- // In case of known implementor we should have already tried to replace type using `replaceTypeIfNeeded`.
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.
1542
1524
KnownImplementor ,
1543
- // If no implementors are allowed, we should have already generated a mock object.
1544
1525
NoImplementors -> {
1526
+ mockInfoGenerator?.let {
1527
+ return createMockedObject(addr, type, it)
1528
+ }
1529
+
1545
1530
queuedSymbolicStateUpdates + = mkFalse().asHardConstraint()
1546
1531
null
1547
1532
}
@@ -1550,6 +1535,45 @@ class Traverser(
1550
1535
return ObjectValue (typeStorage, addr, concreteImplementation)
1551
1536
}
1552
1537
1538
+ private fun createMockedObject (
1539
+ addr : UtAddrExpression ,
1540
+ type : RefType ,
1541
+ mockInfoGenerator : UtMockInfoGenerator ,
1542
+ ): ObjectValue {
1543
+ val nullEqualityConstraint = mkEq(addr, nullObjectAddr)
1544
+
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()
1556
+
1557
+ mockedObjectInfo.value
1558
+ }
1559
+ }
1560
+
1561
+ if (mockedObjectInfo is UnexpectedMock ) {
1562
+ return mockedObject
1563
+ }
1564
+
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 )
1570
+
1571
+ queuedSymbolicStateUpdates + = typeConstraint.asHardConstraint()
1572
+ queuedSymbolicStateUpdates + = mkOr(isMockConstraint, nullEqualityConstraint).asHardConstraint()
1573
+
1574
+ return mockedObject
1575
+ }
1576
+
1553
1577
private fun TraversalContext.resolveConstant (constant : Constant ): SymbolicValue =
1554
1578
when (constant) {
1555
1579
is IntConstant -> constant.value.toPrimitiveValue()
0 commit comments