Skip to content

Commit e0fde47

Browse files
committed
Move ApplicationContext and SpringApplicationContext to utbot-framework
1 parent 5e086d2 commit e0fde47

File tree

11 files changed

+244
-211
lines changed

11 files changed

+244
-211
lines changed

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

Lines changed: 0 additions & 208 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
package org.utbot.framework.plugin.api
1010

11-
import mu.KotlinLogging
1211
import org.utbot.common.FileUtil
1312
import org.utbot.common.isDefaultValue
1413
import org.utbot.common.withToStringThreadLocalReentrancyGuard
@@ -56,17 +55,8 @@ import java.io.File
5655
import kotlin.contracts.ExperimentalContracts
5756
import kotlin.contracts.contract
5857
import org.utbot.common.isAbstract
59-
import org.utbot.common.isStatic
60-
import org.utbot.framework.isFromTrustedLibrary
61-
import org.utbot.framework.plugin.api.TypeReplacementMode.*
6258
import org.utbot.framework.plugin.api.util.SpringModelUtils
63-
import org.utbot.framework.plugin.api.util.allDeclaredFieldIds
64-
import org.utbot.framework.plugin.api.util.allSuperTypes
65-
import org.utbot.framework.plugin.api.util.fieldId
66-
import org.utbot.framework.plugin.api.util.isSubtypeOf
67-
import org.utbot.framework.plugin.api.util.utContext
6859
import org.utbot.framework.process.OpenModulesContainer
69-
import soot.SootField
7060
import soot.SootMethod
7161

7262
const val SYMBOLIC_NULL_ADDR: Int = 0
@@ -1332,71 +1322,6 @@ interface SpringCodeGenerationContext : CodeGenerationContext {
13321322
val springContextLoadingResult: SpringContextLoadingResult?
13331323
}
13341324

1335-
/**
1336-
* A context to use when no specific data is required.
1337-
*
1338-
* @param mockFrameworkInstalled shows if we have installed framework dependencies
1339-
* @param staticsMockingIsConfigured shows if we have installed static mocking tools
1340-
*/
1341-
open class ApplicationContext(
1342-
val mockFrameworkInstalled: Boolean = true,
1343-
staticsMockingIsConfigured: Boolean = true,
1344-
) : CodeGenerationContext {
1345-
var staticsMockingIsConfigured = staticsMockingIsConfigured
1346-
private set
1347-
1348-
init {
1349-
/**
1350-
* Situation when mock framework is not installed but static mocking is configured is semantically incorrect.
1351-
*
1352-
* However, it may be obtained in real application after this actions:
1353-
* - fully configure mocking (dependency installed + resource file created)
1354-
* - remove mockito-core dependency from project
1355-
* - forget to remove mock-maker file from resource directory
1356-
*
1357-
* Here we transform this configuration to semantically correct.
1358-
*/
1359-
if (!mockFrameworkInstalled && staticsMockingIsConfigured) {
1360-
this.staticsMockingIsConfigured = false
1361-
}
1362-
}
1363-
1364-
/**
1365-
* Shows if there are any restrictions on type implementors.
1366-
*/
1367-
open val typeReplacementMode: TypeReplacementMode = AnyImplementor
1368-
1369-
/**
1370-
* Finds a type to replace the original abstract type
1371-
* if it is guided with some additional information.
1372-
*/
1373-
open fun replaceTypeIfNeeded(type: RefType): ClassId? = null
1374-
1375-
/**
1376-
* Sets the restrictions on speculative not null
1377-
* constraints in current application context.
1378-
*
1379-
* @see docs/SpeculativeFieldNonNullability.md for more information.
1380-
*/
1381-
open fun avoidSpeculativeNotNullChecks(field: SootField): Boolean =
1382-
UtSettings.maximizeCoverageUsingReflection || !field.declaringClass.isFromTrustedLibrary()
1383-
1384-
/**
1385-
* Checks whether accessing [field] (with a method invocation or field access) speculatively
1386-
* cannot produce [NullPointerException] (according to its finality or accessibility).
1387-
*
1388-
* @see docs/SpeculativeFieldNonNullability.md for more information.
1389-
*/
1390-
open fun speculativelyCannotProduceNullPointerException(
1391-
field: SootField,
1392-
classUnderTest: ClassId,
1393-
): Boolean = field.isFinal || !field.isPublic
1394-
1395-
open fun preventsFurtherTestGeneration(): Boolean = false
1396-
1397-
open fun getErrors(): List<UtError> = emptyList()
1398-
}
1399-
14001325
sealed class SpringConfiguration(val fullDisplayName: String) {
14011326
class JavaConfiguration(val classBinaryName: String) : SpringConfiguration(classBinaryName)
14021327
class XMLConfiguration(val absolutePath: String) : SpringConfiguration(absolutePath)
@@ -1429,139 +1354,6 @@ class SpringContextLoadingResult(
14291354
val exceptions: List<Throwable>
14301355
)
14311356

1432-
/**
1433-
* Data we get from Spring application context
1434-
* to manage engine and code generator behaviour.
1435-
*
1436-
* @param beanDefinitions describes bean definitions (bean name, type, some optional additional data)
1437-
* @param shouldUseImplementors describes it we want to replace interfaces with injected types or not
1438-
*/
1439-
// TODO move this class to utbot-framework so we can use it as abstract factory
1440-
// to get rid of numerous `when`s and polymorphically create things like:
1441-
// - Instrumentation<UtConcreteExecutionResult>
1442-
// - FuzzedType (to get rid of thisInstanceFuzzedTypeWrapper)
1443-
// - JavaValueProvider
1444-
// - CgVariableConstructor
1445-
// - CodeGeneratorResult (generateForSpringClass)
1446-
// Right now this refactoring is blocked because some interfaces need to get extracted and moved to utbot-framework-api
1447-
// As an alternative we can just move ApplicationContext itself to utbot-framework
1448-
class SpringApplicationContext(
1449-
mockInstalled: Boolean,
1450-
staticsMockingIsConfigured: Boolean,
1451-
val beanDefinitions: List<BeanDefinitionData> = emptyList(),
1452-
private val shouldUseImplementors: Boolean,
1453-
override val springTestType: SpringTestType,
1454-
override val springSettings: SpringSettings,
1455-
): ApplicationContext(mockInstalled, staticsMockingIsConfigured), SpringCodeGenerationContext {
1456-
1457-
override var springContextLoadingResult: SpringContextLoadingResult? = null
1458-
1459-
companion object {
1460-
private val logger = KotlinLogging.logger {}
1461-
}
1462-
1463-
private var areInjectedClassesInitialized : Boolean = false
1464-
private var areAllInjectedTypesInitialized: Boolean = false
1465-
1466-
// Classes representing concrete types that are actually used in Spring application
1467-
private val springInjectedClasses: Set<ClassId>
1468-
get() {
1469-
if (!areInjectedClassesInitialized) {
1470-
for (beanTypeName in beanDefinitions.map { it.beanTypeName }) {
1471-
try {
1472-
val beanClass = utContext.classLoader.loadClass(beanTypeName)
1473-
if (!beanClass.isAbstract && !beanClass.isInterface &&
1474-
!beanClass.isLocalClass && (!beanClass.isMemberClass || beanClass.isStatic)) {
1475-
springInjectedClassesStorage += beanClass.id
1476-
}
1477-
} catch (e: Throwable) {
1478-
// For some Spring beans (e.g. with anonymous classes)
1479-
// it is possible to have problems with classes loading.
1480-
when (e) {
1481-
is ClassNotFoundException, is NoClassDefFoundError, is IllegalAccessError ->
1482-
logger.warn { "Failed to load bean class for $beanTypeName (${e.message})" }
1483-
1484-
else -> throw e
1485-
}
1486-
}
1487-
}
1488-
1489-
// This is done to be sure that this storage is not empty after the first class loading iteration.
1490-
// So, even if all loaded classes were filtered out, we will not try to load them again.
1491-
areInjectedClassesInitialized = true
1492-
}
1493-
1494-
return springInjectedClassesStorage
1495-
}
1496-
1497-
private val allInjectedTypes: Set<ClassId>
1498-
get() {
1499-
if (!areAllInjectedTypesInitialized) {
1500-
allInjectedTypesStorage = springInjectedClasses.flatMap { it.allSuperTypes() }.toSet()
1501-
areAllInjectedTypesInitialized = true
1502-
}
1503-
1504-
return allInjectedTypesStorage
1505-
}
1506-
1507-
// imitates `by lazy` (we can't use actual `by lazy` because communication via RD breaks it)
1508-
private var allInjectedTypesStorage: Set<ClassId> = emptySet()
1509-
1510-
// This is a service field to model the lazy behavior of [springInjectedClasses].
1511-
// Do not call it outside the getter.
1512-
//
1513-
// Actually, we should just call [springInjectedClasses] with `by lazy`, but we had problems
1514-
// with a strange `kotlin.UNINITIALIZED_VALUE` in `speculativelyCannotProduceNullPointerException` method call.
1515-
private val springInjectedClassesStorage = mutableSetOf<ClassId>()
1516-
1517-
override val typeReplacementMode: TypeReplacementMode =
1518-
if (shouldUseImplementors) KnownImplementor else NoImplementors
1519-
1520-
/**
1521-
* Replaces an interface type with its implementor type
1522-
* if there is the unique implementor in bean definitions.
1523-
*/
1524-
override fun replaceTypeIfNeeded(type: RefType): ClassId? =
1525-
if (type.isAbstractType) {
1526-
springInjectedClasses.singleOrNull { it.isSubtypeOf(type.id) }
1527-
} else {
1528-
null
1529-
}
1530-
1531-
override fun avoidSpeculativeNotNullChecks(field: SootField): Boolean = false
1532-
1533-
/**
1534-
* In Spring applications we can mark as speculatively not null
1535-
* fields if they are mocked and injecting into class under test so on.
1536-
*
1537-
* Fields are not mocked if their actual type is obtained from [springInjectedClasses].
1538-
*
1539-
*/
1540-
override fun speculativelyCannotProduceNullPointerException(
1541-
field: SootField,
1542-
classUnderTest: ClassId,
1543-
): Boolean = field.fieldId in classUnderTest.allDeclaredFieldIds && field.type.classId !in allInjectedTypes
1544-
1545-
override fun preventsFurtherTestGeneration(): Boolean =
1546-
super.preventsFurtherTestGeneration() || springContextLoadingResult?.contextLoaded == false
1547-
1548-
override fun getErrors(): List<UtError> =
1549-
springContextLoadingResult?.exceptions?.map { exception ->
1550-
UtError(
1551-
"Failed to load Spring application context",
1552-
exception
1553-
)
1554-
}.orEmpty() + super.getErrors()
1555-
1556-
fun getBeansAssignableTo(classId: ClassId): List<BeanDefinitionData> = beanDefinitions.filter { beanDef ->
1557-
// some bean classes may fail to load
1558-
runCatching {
1559-
val beanClass = ClassId(beanDef.beanTypeName).jClass
1560-
classId.jClass.isAssignableFrom(beanClass)
1561-
}.getOrElse { false }
1562-
}
1563-
}
1564-
15651357
enum class SpringTestType(
15661358
override val id: String,
15671359
override val displayName: String,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import kotlinx.collections.immutable.persistentListOf
1919
import org.utbot.common.nameOfPackage
2020
import org.utbot.engine.types.OBJECT_TYPE
2121
import org.utbot.engine.util.mockListeners.MockListenerController
22-
import org.utbot.framework.plugin.api.ApplicationContext
22+
import org.utbot.framework.context.ApplicationContext
2323
import org.utbot.framework.plugin.api.util.isInaccessibleViaReflection
2424
import soot.BooleanType
2525
import soot.RefType

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ import org.utbot.framework.UtSettings
116116
import org.utbot.framework.UtSettings.preferredCexOption
117117
import org.utbot.framework.UtSettings.substituteStaticsWithSymbolicVariable
118118
import org.utbot.framework.isFromTrustedLibrary
119-
import org.utbot.framework.plugin.api.ApplicationContext
119+
import org.utbot.framework.context.ApplicationContext
120120
import org.utbot.framework.plugin.api.ClassId
121121
import org.utbot.framework.plugin.api.ExecutableId
122122
import org.utbot.framework.plugin.api.FieldId

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ import org.utbot.framework.UtSettings.pathSelectorStepsLimit
3333
import org.utbot.framework.UtSettings.pathSelectorType
3434
import org.utbot.framework.UtSettings.processUnknownStatesDuringConcreteExecution
3535
import org.utbot.framework.UtSettings.useDebugVisualization
36+
import org.utbot.framework.context.ApplicationContext
37+
import org.utbot.framework.context.SpringApplicationContext
3638
import org.utbot.framework.plugin.api.*
3739
import org.utbot.framework.plugin.api.Step
3840
import org.utbot.framework.plugin.api.util.*
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package org.utbot.framework.context
2+
3+
import org.utbot.framework.UtSettings
4+
import org.utbot.framework.isFromTrustedLibrary
5+
import org.utbot.framework.plugin.api.ClassId
6+
import org.utbot.framework.plugin.api.CodeGenerationContext
7+
import org.utbot.framework.plugin.api.TypeReplacementMode
8+
import org.utbot.framework.plugin.api.UtError
9+
import soot.RefType
10+
import soot.SootField
11+
12+
/**
13+
* A context to use when no specific data is required.
14+
*
15+
* @param mockFrameworkInstalled shows if we have installed framework dependencies
16+
* @param staticsMockingIsConfigured shows if we have installed static mocking tools
17+
*/
18+
open class ApplicationContext(
19+
val mockFrameworkInstalled: Boolean = true,
20+
staticsMockingIsConfigured: Boolean = true,
21+
) : CodeGenerationContext {
22+
var staticsMockingIsConfigured = staticsMockingIsConfigured
23+
private set
24+
25+
init {
26+
/**
27+
* Situation when mock framework is not installed but static mocking is configured is semantically incorrect.
28+
*
29+
* However, it may be obtained in real application after this actions:
30+
* - fully configure mocking (dependency installed + resource file created)
31+
* - remove mockito-core dependency from project
32+
* - forget to remove mock-maker file from resource directory
33+
*
34+
* Here we transform this configuration to semantically correct.
35+
*/
36+
if (!mockFrameworkInstalled && staticsMockingIsConfigured) {
37+
this.staticsMockingIsConfigured = false
38+
}
39+
}
40+
41+
/**
42+
* Shows if there are any restrictions on type implementors.
43+
*/
44+
open val typeReplacementMode: TypeReplacementMode = TypeReplacementMode.AnyImplementor
45+
46+
/**
47+
* Finds a type to replace the original abstract type
48+
* if it is guided with some additional information.
49+
*/
50+
open fun replaceTypeIfNeeded(type: RefType): ClassId? = null
51+
52+
/**
53+
* Sets the restrictions on speculative not null
54+
* constraints in current application context.
55+
*
56+
* @see docs/SpeculativeFieldNonNullability.md for more information.
57+
*/
58+
open fun avoidSpeculativeNotNullChecks(field: SootField): Boolean =
59+
UtSettings.maximizeCoverageUsingReflection || !field.declaringClass.isFromTrustedLibrary()
60+
61+
/**
62+
* Checks whether accessing [field] (with a method invocation or field access) speculatively
63+
* cannot produce [NullPointerException] (according to its finality or accessibility).
64+
*
65+
* @see docs/SpeculativeFieldNonNullability.md for more information.
66+
*/
67+
open fun speculativelyCannotProduceNullPointerException(
68+
field: SootField,
69+
classUnderTest: ClassId,
70+
): Boolean = field.isFinal || !field.isPublic
71+
72+
open fun preventsFurtherTestGeneration(): Boolean = false
73+
74+
open fun getErrors(): List<UtError> = emptyList()
75+
}

0 commit comments

Comments
 (0)