Skip to content

Commit 0587302

Browse files
Better method mutations in Spring fuzzing #2502 (#2541)
1 parent abb6268 commit 0587302

File tree

19 files changed

+250
-149
lines changed

19 files changed

+250
-149
lines changed

utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,11 @@ object UtSettings : AbstractSettings(logger, defaultKeyForSettingsPath, defaultS
241241
*/
242242
var fuzzingImplementationOfAbstractClasses: Boolean by getBooleanProperty(true)
243243

244+
/**
245+
* Use methods to mutate fields of classes different from class under test or not.
246+
*/
247+
var tryMutateOtherClassesFieldsWithMethods: Boolean by getBooleanProperty(false)
248+
244249
/**
245250
* Generate tests that treat possible overflows in arithmetic operations as errors
246251
* that throw Arithmetic Exception.

utbot-framework-test/src/test/kotlin/org/utbot/framework/modificators/UtBotFieldModificatorsTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import org.junit.jupiter.api.BeforeEach
2626
import org.junit.jupiter.api.Test
2727
import org.utbot.framework.plugin.services.JdkInfoDefaultProvider
2828
import org.utbot.framework.util.SootUtils
29-
import org.utbot.modifications.ModificationTransformationMode
29+
import org.utbot.modifications.FieldInvolvementMode
3030

3131
internal class UtBotFieldModificatorsTest {
3232
private lateinit var fieldsModificatorsSearcher: UtBotFieldsModificatorsSearcher
@@ -177,7 +177,7 @@ internal class UtBotFieldModificatorsTest {
177177
jdkInfo = JdkInfoDefaultProvider().info
178178
)
179179
fieldsModificatorsSearcher = UtBotFieldsModificatorsSearcher(
180-
modificationTransformationMode = ModificationTransformationMode.WriteOnly
180+
fieldInvolvementMode = FieldInvolvementMode.WriteOnly
181181
)
182182
}
183183

utbot-framework/src/main/kotlin/org/utbot/external/api/UtBotJavaApi.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import org.utbot.framework.plugin.services.JdkInfoDefaultProvider
3939
import org.utbot.fuzzer.FuzzedType
4040
import org.utbot.fuzzer.FuzzedValue
4141
import org.utbot.fuzzing.FuzzedDescription
42+
import org.utbot.fuzzing.JavaValueProvider
4243
import org.utbot.fuzzing.Seed
4344
import org.utbot.fuzzing.ValueProvider
4445
import org.utbot.instrumentation.ConcreteExecutor
@@ -173,7 +174,7 @@ object UtBotJavaApi {
173174
}
174175
?.map { UtPrimitiveModel(it) } ?: emptySequence()
175176

176-
val customModelProvider = ValueProvider<FuzzedType, FuzzedValue, FuzzedDescription> { _, type ->
177+
val customModelProvider = JavaValueProvider { _, type ->
177178
sequence {
178179
createPrimitiveModels(primitiveValuesSupplier, type.classId).forEach { model ->
179180
yield(Seed.Simple(FuzzedValue(model)))

utbot-framework/src/main/kotlin/org/utbot/framework/assemble/AssembleModelGenerator.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ import org.utbot.framework.plugin.api.util.jClass
4848
import org.utbot.framework.util.nextModelName
4949
import java.lang.reflect.Constructor
5050
import java.util.IdentityHashMap
51-
import org.utbot.modifications.ModificationTransformationMode
51+
import org.utbot.modifications.FieldInvolvementMode
5252

5353
/**
5454
* Creates [UtAssembleModel] from any [UtModel] or it's inner models if possible
@@ -75,7 +75,7 @@ class AssembleModelGenerator(private val basePackageName: String) {
7575

7676
private val modificatorsSearcher =
7777
UtBotFieldsModificatorsSearcher(
78-
modificationTransformationMode = ModificationTransformationMode.WriteOnly
78+
fieldInvolvementMode = FieldInvolvementMode.WriteOnly
7979
)
8080
private val constructorAnalyzer = ConstructorAnalyzer()
8181

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

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ import org.utbot.framework.plugin.api.util.utContext
1717
import org.utbot.fuzzer.IdentityPreservingIdGenerator
1818
import org.utbot.fuzzing.JavaValueProvider
1919
import org.utbot.fuzzing.ValueProvider
20+
import org.utbot.fuzzing.providers.AbstractsObjectValueProvider
2021
import org.utbot.fuzzing.providers.AnyDepthNullValueProvider
22+
import org.utbot.fuzzing.providers.ModifyingWithMethodsProviderWrapper
2123
import org.utbot.fuzzing.providers.ObjectValueProvider
22-
import org.utbot.fuzzing.providers.anyObjectValueProvider
2324
import org.utbot.fuzzing.spring.GeneratedFieldValueProvider
2425
import org.utbot.fuzzing.spring.SpringBeanValueProvider
2526
import org.utbot.fuzzing.spring.preserveProperties
@@ -37,28 +38,37 @@ class SpringIntegrationTestJavaFuzzingContext(
3738
private val logger = KotlinLogging.logger {}
3839
}
3940

40-
override val valueProvider: JavaValueProvider =
41+
private val springBeanValueProvider: JavaValueProvider =
4142
SpringBeanValueProvider(
4243
idGenerator,
4344
beanNameProvider = { classId ->
4445
springApplicationContext.getBeansAssignableTo(classId).map { it.beanName }
4546
},
4647
relevantRepositories = relevantRepositories
4748
)
48-
.withFallback(ValidEntityValueProvider(idGenerator, onlyAcceptWhenValidIsRequired = true))
49+
50+
override val valueProvider: JavaValueProvider =
51+
springBeanValueProvider.withModifyingMethodsBuddy()
52+
.withFallback(ValidEntityValueProvider(idGenerator, onlyAcceptWhenValidIsRequired = true).withModifyingMethodsBuddy())
4953
.withFallback(EmailValueProvider())
5054
.withFallback(NotBlankStringValueProvider())
5155
.withFallback(NotEmptyStringValueProvider())
5256
.withFallback(
5357
delegateContext.valueProvider
54-
.except { p -> p is ObjectValueProvider }
55-
.with(anyObjectValueProvider(idGenerator, shouldMutateWithMethods = true))
56-
.with(ValidEntityValueProvider(idGenerator, onlyAcceptWhenValidIsRequired = false))
58+
.with(ObjectValueProvider(idGenerator).withModifyingMethodsBuddy())
59+
.with(ValidEntityValueProvider(idGenerator, onlyAcceptWhenValidIsRequired = false).withModifyingMethodsBuddy())
5760
.with(createGeneratedFieldValueProviders(relevantRepositories, idGenerator))
5861
.withFallback(AnyDepthNullValueProvider)
5962
)
6063
.preserveProperties()
6164

65+
private fun JavaValueProvider.withModifyingMethodsBuddy(): JavaValueProvider =
66+
with(modifyingMethodsBuddy(this))
67+
68+
private fun modifyingMethodsBuddy(provider: JavaValueProvider): JavaValueProvider =
69+
ModifyingWithMethodsProviderWrapper(classUnderTest, provider)
70+
71+
6272
private fun createGeneratedFieldValueProviders(
6373
relevantRepositories: Set<SpringRepositoryId>,
6474
idGenerator: IdentityPreservingIdGenerator<Int>

utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/JavaLanguage.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ fun defaultValueProviders(idGenerator: IdentityPreservingIdGenerator<Int>) = lis
4242
FloatValueProvider,
4343
StringValueProvider,
4444
NumberValueProvider,
45-
anyObjectValueProvider(idGenerator, shouldMutateWithMethods = false),
45+
anyObjectValueProvider(idGenerator),
4646
ArrayValueProvider(idGenerator),
4747
EnumValueProvider(idGenerator),
4848
ListSetValueProvider(idGenerator),
@@ -59,7 +59,7 @@ suspend fun runJavaFuzzing(
5959
methodUnderTest: ExecutableId,
6060
constants: Collection<FuzzedConcreteValue>,
6161
names: List<String>,
62-
providers: List<ValueProvider<FuzzedType, FuzzedValue, FuzzedDescription>> = defaultValueProviders(idGenerator),
62+
providers: List<JavaValueProvider> = defaultValueProviders(idGenerator),
6363
exec: suspend (thisInstance: FuzzedValue?, description: FuzzedDescription, values: List<FuzzedValue>) -> BaseFeedback<Trie.Node<Instruction>, FuzzedType, FuzzedValue>
6464
) {
6565
val random = Random(0)

utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Arrays.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import org.utbot.fuzzing.*
1111

1212
class ArrayValueProvider(
1313
val idGenerator: IdGenerator<Int>,
14-
) : ValueProvider<FuzzedType, FuzzedValue, FuzzedDescription> {
14+
) : JavaValueProvider {
1515

1616
override fun accept(type: FuzzedType) = type.classId.isArray
1717

utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Collections.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import kotlin.reflect.KClass
1212

1313
class EmptyCollectionValueProvider(
1414
val idGenerator: IdGenerator<Int>
15-
) : ValueProvider<FuzzedType, FuzzedValue, FuzzedDescription> {
15+
) : JavaValueProvider {
1616
private class Info(val classId: ClassId, val methodName: String, val returnType: ClassId = classId)
1717

1818
private val unmodifiableCollections = listOf(
@@ -150,7 +150,7 @@ class ListSetValueProvider(
150150
abstract class CollectionValueProvider(
151151
private val idGenerator: IdGenerator<Int>,
152152
vararg acceptableCollectionTypes: ClassId
153-
) : ValueProvider<FuzzedType, FuzzedValue, FuzzedDescription> {
153+
) : JavaValueProvider {
154154

155155
private val acceptableCollectionTypes = acceptableCollectionTypes.toList()
156156

@@ -216,7 +216,7 @@ abstract class CollectionValueProvider(
216216
}
217217
}
218218

219-
class IteratorValueProvider(val idGenerator: IdGenerator<Int>) : ValueProvider<FuzzedType, FuzzedValue, FuzzedDescription> {
219+
class IteratorValueProvider(val idGenerator: IdGenerator<Int>) : JavaValueProvider {
220220
override fun accept(type: FuzzedType): Boolean {
221221
return type.classId == Iterator::class.id
222222
}

utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Enums.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ import org.utbot.fuzzer.FuzzedValue
88
import org.utbot.fuzzer.IdentityPreservingIdGenerator
99
import org.utbot.fuzzer.fuzzed
1010
import org.utbot.fuzzing.FuzzedDescription
11+
import org.utbot.fuzzing.JavaValueProvider
1112
import org.utbot.fuzzing.Seed
12-
import org.utbot.fuzzing.ValueProvider
1313

1414
class EnumValueProvider(
1515
val idGenerator: IdentityPreservingIdGenerator<Int>,
16-
) : ValueProvider<FuzzedType, FuzzedValue, FuzzedDescription> {
16+
) : JavaValueProvider {
1717
override fun accept(type: FuzzedType) = type.classId.isEnum
1818

1919
override fun generate(
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package org.utbot.fuzzing.providers
2+
3+
import org.utbot.framework.plugin.api.ClassId
4+
import org.utbot.framework.plugin.api.UtAssembleModel
5+
import org.utbot.framework.plugin.api.UtExecutableCallModel
6+
import org.utbot.framework.plugin.api.util.executableId
7+
import org.utbot.fuzzer.FuzzedType
8+
import org.utbot.fuzzer.FuzzedValue
9+
import org.utbot.fuzzing.FuzzedDescription
10+
import org.utbot.fuzzing.JavaValueProvider
11+
import org.utbot.fuzzing.Routine
12+
import org.utbot.fuzzing.Scope
13+
import org.utbot.fuzzing.Seed
14+
15+
/**
16+
* Value provider that is a buddy for another provider
17+
* that keeps all it's functionality and also allows
18+
* to use methods to mutate field states of an object.
19+
*
20+
* NOTE!!!
21+
* Instances represented by [UtAssembleModel] only can be mutated with methods.
22+
*/
23+
class ModifyingWithMethodsProviderWrapper(
24+
private val classUnderTest: ClassId,
25+
private val delegate: JavaValueProvider
26+
) : JavaValueProvider by delegate {
27+
28+
override fun generate(description: FuzzedDescription, type: FuzzedType): Sequence<Seed<FuzzedType, FuzzedValue>> =
29+
delegate
30+
.generate(description, type)
31+
.map { seed ->
32+
if (seed is Seed.Recursive) {
33+
Seed.Recursive(
34+
construct = seed.construct,
35+
modify = seed.modify +
36+
findMethodsToModifyWith(description, type.classId, classUnderTest)
37+
.asSequence()
38+
.map { md ->
39+
Routine.Call(md.parameterTypes) { self, values ->
40+
val model = self.model as UtAssembleModel
41+
model.modificationsChain as MutableList +=
42+
UtExecutableCallModel(
43+
model,
44+
md.method.executableId,
45+
values.map { it.model }
46+
)
47+
}
48+
},
49+
empty = seed.empty,
50+
)
51+
} else seed
52+
}
53+
54+
override fun enrich(description: FuzzedDescription, type: FuzzedType, scope: Scope) =
55+
delegate.enrich(description, type, scope)
56+
57+
override fun accept(type: FuzzedType): Boolean = delegate.accept(type)
58+
}

0 commit comments

Comments
 (0)