Skip to content

Commit 36d3be5

Browse files
committed
Try to apply fixes after review
1 parent 07fdbd9 commit 36d3be5

File tree

2 files changed

+94
-50
lines changed
  • utbot-framework/src/main/kotlin/org/utbot/engine
  • utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api

2 files changed

+94
-50
lines changed

utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ import kotlin.contracts.ExperimentalContracts
5656
import kotlin.contracts.contract
5757
import org.utbot.common.isAbstract
5858
import org.utbot.common.isStatic
59+
import org.utbot.framework.plugin.api.TypeReplacementMode.*
5960
import org.utbot.framework.plugin.api.util.isSubtypeOf
6061
import org.utbot.framework.plugin.api.util.utContext
6162
import org.utbot.framework.process.OpenModulesContainer
@@ -1151,6 +1152,27 @@ open class TypeParameters(val parameters: List<ClassId> = emptyList())
11511152

11521153
class WildcardTypeParameter : TypeParameters(emptyList())
11531154

1155+
/**
1156+
* Describes the way to replace abstract types with concrete implementors.
1157+
*/
1158+
enum class TypeReplacementMode {
1159+
/**
1160+
* Any possible implementor may be used.
1161+
*/
1162+
AnyImplementor,
1163+
1164+
/**
1165+
* There is a known implementor to be used.
1166+
* For example, it is found in Spring bean definitions.
1167+
*/
1168+
KnownImplementor,
1169+
1170+
/**
1171+
* Using implementors is not allowed.
1172+
*/
1173+
NoImplementors,
1174+
}
1175+
11541176
/**
11551177
* A context to use when no specific data is required.
11561178
*
@@ -1181,8 +1203,13 @@ open class ApplicationContext(
11811203
}
11821204

11831205
/**
1184-
* Finds a type to replace the original during symbolic
1185-
* analysis if it is guided with some additional information.
1206+
* Shows if there are any restrictions on type implementors.
1207+
*/
1208+
open val typeReplacementMode: TypeReplacementMode = AnyImplementor
1209+
1210+
/**
1211+
* Finds a type to replace the original abstract type
1212+
* if it is guided with some additional information.
11861213
*/
11871214
open fun replaceTypeIfNeeded(type: RefType): ClassId? = null
11881215
}
@@ -1197,8 +1224,8 @@ open class ApplicationContext(
11971224
class SpringApplicationContext(
11981225
mockInstalled: Boolean,
11991226
staticsMockingIsConfigured: Boolean,
1200-
val beanQualifiedNames: List<String> = emptyList(),
1201-
val shouldUseImplementors: Boolean,
1227+
private val beanQualifiedNames: List<String> = emptyList(),
1228+
private val shouldUseImplementors: Boolean,
12021229
): ApplicationContext(mockInstalled, staticsMockingIsConfigured) {
12031230

12041231
private val springInjectedClasses: List<ClassId> by lazy {
@@ -1208,13 +1235,15 @@ class SpringApplicationContext(
12081235
.map { it.id }
12091236
}
12101237

1238+
override val typeReplacementMode: TypeReplacementMode
1239+
get() = if (shouldUseImplementors) KnownImplementor else NoImplementors
1240+
12111241
/**
12121242
* Replaces an interface type with its implementor type
12131243
* if there is the unique implementor in bean definitions.
12141244
*/
12151245
override fun replaceTypeIfNeeded(type: RefType): ClassId? =
1216-
if (shouldUseImplementors &&
1217-
(type.sootClass.isInterface || type.sootClass.isAbstract)) {
1246+
if (type.sootClass.isInterface || type.sootClass.isAbstract) {
12181247
springInjectedClasses.singleOrNull { it.isSubtypeOf(type.id) }
12191248
} else {
12201249
null

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

Lines changed: 59 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,9 @@ import org.utbot.framework.plugin.api.ClassId
121121
import org.utbot.framework.plugin.api.ExecutableId
122122
import org.utbot.framework.plugin.api.FieldId
123123
import org.utbot.framework.plugin.api.MethodId
124-
import org.utbot.framework.plugin.api.SpringApplicationContext
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
125127
import org.utbot.framework.plugin.api.classId
126128
import org.utbot.framework.plugin.api.id
127129
import org.utbot.framework.plugin.api.util.executable
@@ -1365,7 +1367,7 @@ class Traverser(
13651367
traverseException(current, symException)
13661368
}
13671369

1368-
// TODO HACK violation of encapsulation
1370+
// TODO: HACK violation of encapsulation
13691371
fun createObject(
13701372
addr: UtAddrExpression,
13711373
type: RefType,
@@ -1374,8 +1376,13 @@ class Traverser(
13741376
): ObjectValue {
13751377
touchAddress(addr)
13761378

1377-
val concreteClassId = applicationContext.replaceTypeIfNeeded(type)
1378-
concreteClassId?.let {
1379+
val replacedClassId = when (applicationContext.typeReplacementMode) {
1380+
KnownImplementor -> applicationContext.replaceTypeIfNeeded(type)
1381+
AnyImplementor,
1382+
NoImplementors -> null
1383+
}
1384+
1385+
replacedClassId?.let {
13791386
val sootType = typeResolver.classOrDefault(it.canonicalName)
13801387
val typeStorage = typeResolver.constructTypeStorage(sootType, useConcreteType = false)
13811388

@@ -1481,58 +1488,66 @@ class Traverser(
14811488
return it
14821489
}
14831490

1484-
// In Spring application we may rely on concrete types obtained from bean definitions only,
1485-
// and this potential replacement has already been suggested in the beginning of the method
1486-
val useConcreteTypes = applicationContext !is SpringApplicationContext
1487-
1488-
if (useConcreteTypes && typeStorage.possibleConcreteTypes.any()) {
1489-
// If we have this$0 with UtArrayList type, we have to create such instance.
1490-
// We should create an object with typeStorage of all possible real types and concrete implementation
1491-
// Otherwise we'd have either a wrong type in the resolver, or missing method like 'preconditionCheck'.
1492-
val concreteImplementation = wrapperToClass[type]?.first()?.let { wrapper(it, addr) }?.concrete
1493-
val isMockConstraint = mkEq(typeRegistry.isMock(addr), UtFalse)
1494-
1495-
queuedSymbolicStateUpdates += typeHardConstraint
1496-
queuedSymbolicStateUpdates += mkOr(isMockConstraint, nullEqualityConstraint).asHardConstraint()
1491+
if (typeStorage.possibleConcreteTypes.isEmpty()) {
1492+
requireNotNull(mockInfoGenerator) {
1493+
"An object with $addr and $type doesn't have concrete possible types," +
1494+
"but there is no mock info generator provided to construct a mock value."
1495+
}
14971496

1498-
return ObjectValue(typeStorage, addr, concreteImplementation)
1499-
}
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+
}
15001512

1501-
requireNotNull(mockInfoGenerator) {
1502-
"An object with $addr and $type doesn't have concrete possible types," +
1503-
"but there is no mock info generator provided to construct a mock value."
1504-
}
1513+
if (mockedObjectInfo is UnexpectedMock) {
1514+
return mockedObject
1515+
}
15051516

1506-
val mockInfo = mockInfoGenerator.generate(addr)
1507-
val mockedObjectInfo = mocker.forceMock(type, mockInfoGenerator.generate(addr))
1517+
queuedSymbolicStateUpdates += MemoryUpdate(mockInfos = persistentListOf(MockInfoEnriched(mockInfo)))
15081518

1509-
val mockedObject: ObjectValue = when (mockedObjectInfo) {
1510-
is NoMock -> error("Value must be mocked after the force mock")
1511-
is ExpectedMock -> mockedObjectInfo.value
1512-
is UnexpectedMock -> {
1513-
// if mock occurs, but it is unexpected due to some reasons
1514-
// (e.g. we do not have mock framework installed),
1515-
// we can only generate a test that uses null value for mocked object
1516-
queuedSymbolicStateUpdates += nullEqualityConstraint.asHardConstraint()
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)
15171522

1518-
mockedObjectInfo.value
1519-
}
1520-
}
1523+
queuedSymbolicStateUpdates += typeConstraint.asHardConstraint()
1524+
queuedSymbolicStateUpdates += mkOr(isMockConstraint, nullEqualityConstraint).asHardConstraint()
15211525

1522-
if (mockedObjectInfo is UnexpectedMock) {
15231526
return mockedObject
15241527
}
15251528

1526-
queuedSymbolicStateUpdates += MemoryUpdate(mockInfos = persistentListOf(MockInfoEnriched(mockInfo)))
1529+
val concreteImplementation = when (applicationContext.typeReplacementMode) {
1530+
AnyImplementor -> {
1531+
val isMockConstraint = mkEq(typeRegistry.isMock(addr), UtFalse)
15271532

1528-
// add typeConstraint for mocked object. It's a declared type of the object.
1529-
val typeConstraint = typeRegistry.typeConstraint(addr, mockedObject.typeStorage).all()
1530-
val isMockConstraint = mkEq(typeRegistry.isMock(mockedObject.addr), UtTrue)
1533+
queuedSymbolicStateUpdates += typeHardConstraint
1534+
queuedSymbolicStateUpdates += mkOr(isMockConstraint, nullEqualityConstraint).asHardConstraint()
15311535

1532-
queuedSymbolicStateUpdates += typeConstraint.asHardConstraint()
1533-
queuedSymbolicStateUpdates += mkOr(isMockConstraint, nullEqualityConstraint).asHardConstraint()
1536+
// If we have this$0 with UtArrayList type, we have to create such instance.
1537+
// We should create an object with typeStorage of all possible real types and concrete implementation
1538+
// Otherwise we'd have either a wrong type in the resolver, or missing method like 'preconditionCheck'.
1539+
wrapperToClass[type]?.first()?.let { wrapper(it, addr) }?.concrete
1540+
}
1541+
// In case of known implementor we should have already tried to replace type using `replaceTypeIfNeeded`.
1542+
KnownImplementor,
1543+
// If no implementors are allowed, we should have already generated a mock object.
1544+
NoImplementors -> {
1545+
queuedSymbolicStateUpdates += mkFalse().asHardConstraint()
1546+
null
1547+
}
1548+
}
15341549

1535-
return mockedObject
1550+
return ObjectValue(typeStorage, addr, concreteImplementation)
15361551
}
15371552

15381553

0 commit comments

Comments
 (0)