Skip to content

Commit 701fb39

Browse files
committed
Support mock strategies and type replacement in Spring unit test fuzzing
1 parent 0587302 commit 701fb39

19 files changed

+161
-53
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1397,7 +1397,7 @@ class Traverser(
13971397
// from Spring bean definitions, for example), we can just create a symbolic object
13981398
// with hard constraint on the mentioned type.
13991399
val replacedClassId = when (typeReplacer.typeReplacementMode) {
1400-
KnownImplementor -> typeReplacer.replaceTypeIfNeeded(type)
1400+
KnownImplementor -> typeReplacer.replaceTypeIfNeeded(type.id)
14011401
AnyImplementor,
14021402
NoImplementors -> null
14031403
}

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,6 @@ class UtBotSymbolicEngine(
423423
* Run fuzzing flow.
424424
*
425425
* @param until is used by fuzzer to cancel all tasks if the current time is over this value
426-
* @param transform provides model values for a method
427426
*/
428427
fun fuzzing(until: Long = Long.MAX_VALUE) = flow {
429428
val isFuzzable = methodUnderTest.parameters.all { classId ->
@@ -440,7 +439,12 @@ class UtBotSymbolicEngine(
440439
var testEmittedByFuzzer = 0
441440

442441
val fuzzingContext = try {
443-
concreteExecutionContext.tryCreateFuzzingContext(concreteExecutor, classUnderTest, defaultIdGenerator)
442+
concreteExecutionContext.tryCreateFuzzingContext(
443+
concreteExecutor,
444+
classUnderTest,
445+
mockStrategy,
446+
defaultIdGenerator,
447+
)
444448
} catch (e: Exception) {
445449
emit(UtError(e.message ?: "Failed to create ValueProvider", e))
446450
return@flow

utbot-framework/src/main/kotlin/org/utbot/framework/context/ConcreteExecutionContext.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.utbot.framework.context
22

3+
import org.utbot.engine.MockStrategy
34
import org.utbot.framework.plugin.api.ClassId
45
import org.utbot.framework.plugin.api.ConcreteContextLoadingResult
56
import org.utbot.framework.plugin.api.UtExecution
@@ -23,6 +24,7 @@ interface ConcreteExecutionContext {
2324
fun tryCreateFuzzingContext(
2425
concreteExecutor: ConcreteExecutor<UtConcreteExecutionResult, UtExecutionInstrumentation>,
2526
classUnderTest: ClassId,
27+
mockStrategy: MockStrategy,
2628
idGenerator: IdentityPreservingIdGenerator<Int>,
2729
): JavaFuzzingContext
2830
}

utbot-framework/src/main/kotlin/org/utbot/framework/context/JavaFuzzingContext.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.utbot.framework.context
22

3+
import org.utbot.engine.MockStrategy
34
import org.utbot.framework.plugin.api.ClassId
45
import org.utbot.framework.plugin.api.EnvironmentModels
56
import org.utbot.framework.plugin.api.ExecutableId
@@ -11,6 +12,7 @@ import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionRe
1112

1213
interface JavaFuzzingContext {
1314
val classUnderTest: ClassId
15+
val mockStrategy: MockStrategy
1416
val idGenerator: IdentityPreservingIdGenerator<Int>
1517
val valueProvider: JavaValueProvider
1618

utbot-framework/src/main/kotlin/org/utbot/framework/context/TypeReplacer.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package org.utbot.framework.context
22

33
import org.utbot.framework.plugin.api.ClassId
44
import org.utbot.framework.plugin.api.TypeReplacementMode
5-
import soot.RefType
65

76
interface TypeReplacer {
87
/**
@@ -14,5 +13,5 @@ interface TypeReplacer {
1413
* Finds a type to replace the original abstract type
1514
* if it is guided with some additional information.
1615
*/
17-
fun replaceTypeIfNeeded(type: RefType): ClassId?
16+
fun replaceTypeIfNeeded(classId: ClassId): ClassId?
1817
}

utbot-framework/src/main/kotlin/org/utbot/framework/context/custom/MockingJavaFuzzingContext.kt

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,48 @@ package org.utbot.framework.context.custom
22

33
import org.utbot.framework.context.JavaFuzzingContext
44
import org.utbot.fuzzing.JavaValueProvider
5+
import org.utbot.fuzzing.providers.AnyDepthNullValueProvider
56
import org.utbot.fuzzing.providers.MapValueProvider
67
import org.utbot.fuzzing.spring.unit.MockValueProvider
78
import org.utbot.fuzzing.providers.NullValueProvider
89
import org.utbot.fuzzing.providers.ObjectValueProvider
910
import org.utbot.fuzzing.providers.StringValueProvider
11+
import org.utbot.fuzzing.providers.anyObjectValueProvider
12+
import org.utbot.fuzzing.spring.decorators.filterTypes
1013
import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult
1114

1215
/**
13-
* Makes fuzzer mock all types that don't have *specific* [JavaValueProvider],
14-
* like [MapValueProvider] or [StringValueProvider].
16+
* Allows fuzzer to use mocks in accordance with [JavaFuzzingContext.mockStrategy].
1517
*
16-
* NOTE: the caller is responsible for providing some *specific* [JavaValueProvider]
17-
* that can create values for class under test (otherwise it will be mocked),
18-
* [ObjectValueProvider] and [NullValueProvider] do not count as *specific*.
18+
* NOTE:
19+
* - fuzzer won't mock types, that have *specific* value providers (e.g. [MapValueProvider] and [StringValueProvider])
20+
* - [ObjectValueProvider] and [NullValueProvider] do not count as *specific* value providers
1921
*/
20-
fun JavaFuzzingContext.mockAllTypesWithoutSpecificValueProvider() =
22+
fun JavaFuzzingContext.allowMocks() =
2123
MockingJavaFuzzingContext(delegateContext = this)
2224

2325
class MockingJavaFuzzingContext(
24-
val delegateContext: JavaFuzzingContext
26+
val delegateContext: JavaFuzzingContext,
2527
) : JavaFuzzingContext by delegateContext {
2628
private val mockValueProvider = MockValueProvider(delegateContext.idGenerator)
2729

2830
override val valueProvider: JavaValueProvider =
29-
// NOTE: we first remove `NullValueProvider` from `delegateContext.valueProvider` and then
30-
// add it back as a part of our `withFallback` so it has the same priority as
31-
// `mockValueProvider`, otherwise mocks will never be used where `null` can be used.
31+
// NOTE: we first remove `NullValueProvider` and `ObjectValueProvider` from `delegateContext.valueProvider`
32+
// and then add them back as a part of our `withFallback` so they have the same priority as
33+
// `mockValueProvider`, otherwise mocks will never be used where `null` or new object can be used.
3234
delegateContext.valueProvider
3335
.except { it is NullValueProvider }
3436
.except { it is ObjectValueProvider }
3537
.withFallback(
3638
mockValueProvider
39+
.filterTypes { type ->
40+
mockStrategy.eligibleToMock(
41+
classToMock = type.classId,
42+
classUnderTest = classUnderTest
43+
)
44+
}
45+
.with(anyObjectValueProvider(idGenerator))
46+
.withFallback(mockValueProvider.with(AnyDepthNullValueProvider))
3747
.with(NullValueProvider)
3848
)
3949

utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleConcreteExecutionContext.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.utbot.framework.context.simple
22

3+
import org.utbot.engine.MockStrategy
34
import org.utbot.framework.context.ConcreteExecutionContext
45
import org.utbot.framework.context.JavaFuzzingContext
56
import org.utbot.framework.plugin.api.ClassId
@@ -28,6 +29,7 @@ class SimpleConcreteExecutionContext(fullClassPath: String) : ConcreteExecutionC
2829
override fun tryCreateFuzzingContext(
2930
concreteExecutor: ConcreteExecutor<UtConcreteExecutionResult, UtExecutionInstrumentation>,
3031
classUnderTest: ClassId,
32+
mockStrategy: MockStrategy,
3133
idGenerator: IdentityPreservingIdGenerator<Int>
32-
): JavaFuzzingContext = SimpleJavaFuzzingContext(classUnderTest, idGenerator)
34+
): JavaFuzzingContext = SimpleJavaFuzzingContext(classUnderTest, mockStrategy, idGenerator)
3335
}

utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleJavaFuzzingContext.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.utbot.framework.context.simple
22

3+
import org.utbot.engine.MockStrategy
34
import org.utbot.framework.context.JavaFuzzingContext
45
import org.utbot.framework.plugin.api.ClassId
56
import org.utbot.framework.plugin.api.EnvironmentModels
@@ -14,6 +15,7 @@ import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionRe
1415

1516
class SimpleJavaFuzzingContext(
1617
override val classUnderTest: ClassId,
18+
override val mockStrategy: MockStrategy,
1719
override val idGenerator: IdentityPreservingIdGenerator<Int>,
1820
) : JavaFuzzingContext {
1921
override val valueProvider: JavaValueProvider =

utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleTypeReplacer.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ package org.utbot.framework.context.simple
33
import org.utbot.framework.context.TypeReplacer
44
import org.utbot.framework.plugin.api.ClassId
55
import org.utbot.framework.plugin.api.TypeReplacementMode
6-
import soot.RefType
76

87
class SimpleTypeReplacer : TypeReplacer {
98
override val typeReplacementMode: TypeReplacementMode = TypeReplacementMode.AnyImplementor
109

11-
override fun replaceTypeIfNeeded(type: RefType): ClassId? = null
10+
override fun replaceTypeIfNeeded(classId: ClassId): ClassId? = null
1211
}

utbot-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import org.utbot.framework.context.ConcreteExecutionContext
1111
import org.utbot.framework.context.NonNullSpeculator
1212
import org.utbot.framework.context.TypeReplacer
1313
import org.utbot.framework.context.custom.CoverageFilteringConcreteExecutionContext
14-
import org.utbot.framework.context.custom.mockAllTypesWithoutSpecificValueProvider
14+
import org.utbot.framework.context.custom.allowMocks
1515
import org.utbot.framework.context.utils.transformJavaFuzzingContext
16-
import org.utbot.framework.context.utils.withValueProvider
16+
import org.utbot.framework.context.utils.transformValueProvider
1717
import org.utbot.framework.plugin.api.BeanDefinitionData
1818
import org.utbot.framework.plugin.api.ClassId
1919
import org.utbot.framework.plugin.api.ConcreteContextLoadingResult
@@ -24,7 +24,9 @@ import org.utbot.framework.plugin.api.util.allSuperTypes
2424
import org.utbot.framework.plugin.api.util.id
2525
import org.utbot.framework.plugin.api.util.jClass
2626
import org.utbot.framework.plugin.api.util.utContext
27+
import org.utbot.fuzzing.spring.decorators.replaceTypes
2728
import org.utbot.fuzzing.spring.unit.InjectMockValueProvider
29+
import org.utbot.fuzzing.toFuzzerType
2830

2931
class SpringApplicationContextImpl(
3032
private val delegateContext: ApplicationContext,
@@ -64,13 +66,20 @@ class SpringApplicationContextImpl(
6466
return when (springTestType) {
6567
SpringTestType.UNIT_TEST -> delegateConcreteExecutionContext.transformJavaFuzzingContext { fuzzingContext ->
6668
fuzzingContext
67-
.withValueProvider(
69+
.allowMocks()
70+
.transformValueProvider { origValueProvider ->
6871
InjectMockValueProvider(
6972
idGenerator = fuzzingContext.idGenerator,
7073
classToUseCompositeModelFor = fuzzingContext.classUnderTest
7174
)
72-
)
73-
.mockAllTypesWithoutSpecificValueProvider()
75+
.withFallback(origValueProvider)
76+
.replaceTypes { description, type ->
77+
typeReplacer.replaceTypeIfNeeded(type.classId)?.let { replacement ->
78+
// TODO infer generic type
79+
toFuzzerType(replacement.jClass, description.typeCache)
80+
} ?: type
81+
}
82+
}
7483
}
7584
SpringTestType.INTEGRATION_TEST -> SpringIntegrationTestConcreteExecutionContext(
7685
delegateConcreteExecutionContext,

0 commit comments

Comments
 (0)