@@ -116,11 +116,14 @@ import org.utbot.framework.UtSettings
116116import org.utbot.framework.UtSettings.maximizeCoverageUsingReflection
117117import org.utbot.framework.UtSettings.preferredCexOption
118118import org.utbot.framework.UtSettings.substituteStaticsWithSymbolicVariable
119- import org.utbot.framework.plugin.api.StandardApplicationContext
119+ import org.utbot.framework.plugin.api.ApplicationContext
120120import org.utbot.framework.plugin.api.ClassId
121121import org.utbot.framework.plugin.api.ExecutableId
122122import org.utbot.framework.plugin.api.FieldId
123123import 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
124127import org.utbot.framework.plugin.api.classId
125128import org.utbot.framework.plugin.api.id
126129import org.utbot.framework.plugin.api.util.executable
@@ -239,7 +242,7 @@ class Traverser(
239242 internal val typeResolver : TypeResolver ,
240243 private val globalGraph : InterProceduralUnitGraph ,
241244 private val mocker : Mocker ,
242- private val applicationContext : StandardApplicationContext ? ,
245+ private val applicationContext : ApplicationContext ,
243246) : UtContextInitializer() {
244247
245248 private val visitedStmts: MutableSet <Stmt > = mutableSetOf ()
@@ -1364,7 +1367,7 @@ class Traverser(
13641367 traverseException(current, symException)
13651368 }
13661369
1367- // TODO HACK violation of encapsulation
1370+ // TODO: HACK violation of encapsulation
13681371 fun createObject (
13691372 addr : UtAddrExpression ,
13701373 type : RefType ,
@@ -1373,6 +1376,27 @@ class Traverser(
13731376 ): ObjectValue {
13741377 touchAddress(addr)
13751378
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+
13761400 val nullEqualityConstraint = mkEq(addr, nullObjectAddr)
13771401
13781402 if (mockInfoGenerator != null ) {
@@ -1475,48 +1499,79 @@ class Traverser(
14751499 " but there is no mock info generator provided to construct a mock value."
14761500 }
14771501
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
14921516 }
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+ }
14931529
1494- if (mockedObjectInfo is UnexpectedMock ) {
1495- return mockedObject
1530+ queuedSymbolicStateUpdates + = mkFalse().asHardConstraint()
1531+ null
14961532 }
1533+ }
14971534
1498- queuedSymbolicStateUpdates + = MemoryUpdate (mockInfos = persistentListOf(MockInfoEnriched (mockInfo)))
1535+ return ObjectValue (typeStorage, addr, concreteImplementation)
1536+ }
14991537
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)
15031544
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()
15061556
1557+ mockedObjectInfo.value
1558+ }
1559+ }
1560+
1561+ if (mockedObjectInfo is UnexpectedMock ) {
15071562 return mockedObject
15081563 }
15091564
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 )
15151570
1516- queuedSymbolicStateUpdates + = typeHardConstraint
1571+ queuedSymbolicStateUpdates + = typeConstraint.asHardConstraint()
15171572 queuedSymbolicStateUpdates + = mkOr(isMockConstraint, nullEqualityConstraint).asHardConstraint()
15181573
1519- return ObjectValue (typeStorage, addr, concreteImplementation)
1574+ return mockedObject
15201575 }
15211576
15221577 private fun TraversalContext.resolveConstant (constant : Constant ): SymbolicValue =
0 commit comments