From c15e5548624fc07e1d11d6231632245479000f61 Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Mon, 28 Aug 2023 11:22:12 +0300 Subject: [PATCH 01/10] Support mock strategies and type replacement in Spring unit test fuzzing --- .../main/kotlin/org/utbot/engine/Traverser.kt | 2 +- .../org/utbot/engine/UtBotSymbolicEngine.kt | 1 - .../framework/context/JavaFuzzingContext.kt | 2 ++ .../utbot/framework/context/TypeReplacer.kt | 3 +- .../custom/MockingJavaFuzzingContext.kt | 30 ++++++++++++------- .../simple/SimpleJavaFuzzingContext.kt | 2 ++ .../context/simple/SimpleTypeReplacer.kt | 3 +- .../kotlin/org/utbot/fuzzing/JavaLanguage.kt | 2 +- .../ModifyingWithMethodsProviderWrapper.kt | 14 ++++----- .../spring/PropertyPreservingValueProvider.kt | 20 +++++-------- .../decorators/FilteredValueProvider.kt | 18 +++++++++++ .../decorators/TypeReplacingValueProvider.kt | 28 +++++++++++++++++ .../decorators/ValueProviderDecorator.kt | 29 ++++++++++++++++++ .../spring/SpringApplicationContextImpl.kt | 19 ++++++++---- .../context/spring/SpringTypeReplacer.kt | 10 +++---- 15 files changed, 134 insertions(+), 49 deletions(-) create mode 100644 utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/FilteredValueProvider.kt create mode 100644 utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/TypeReplacingValueProvider.kt create mode 100644 utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/ValueProviderDecorator.kt diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt index 75e319a943..33d9ca61ce 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt @@ -1397,7 +1397,7 @@ class Traverser( // from Spring bean definitions, for example), we can just create a symbolic object // with hard constraint on the mentioned type. val replacedClassId = when (typeReplacer.typeReplacementMode) { - KnownImplementor -> typeReplacer.replaceTypeIfNeeded(type) + KnownImplementor -> typeReplacer.replaceTypeIfNeeded(type.id) AnyImplementor, NoImplementors -> null } diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt index 670b89839d..3423b4f3a3 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt @@ -424,7 +424,6 @@ class UtBotSymbolicEngine( * Run fuzzing flow. * * @param until is used by fuzzer to cancel all tasks if the current time is over this value - * @param transform provides model values for a method */ fun fuzzing(until: Long = Long.MAX_VALUE) = flow { val isFuzzable = methodUnderTest.parameters.all { classId -> diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/JavaFuzzingContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/JavaFuzzingContext.kt index ee4f57acbf..51bbd22553 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/JavaFuzzingContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/JavaFuzzingContext.kt @@ -1,5 +1,6 @@ package org.utbot.framework.context +import org.utbot.engine.MockStrategy import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.EnvironmentModels import org.utbot.framework.plugin.api.ExecutableId @@ -11,6 +12,7 @@ import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionRe interface JavaFuzzingContext { val classUnderTest: ClassId + val mockStrategy: MockStrategy val idGenerator: IdentityPreservingIdGenerator val valueProvider: JavaValueProvider diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/TypeReplacer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/TypeReplacer.kt index 52c3ee8604..25aec4d025 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/TypeReplacer.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/TypeReplacer.kt @@ -2,7 +2,6 @@ package org.utbot.framework.context import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.TypeReplacementMode -import soot.RefType interface TypeReplacer { /** @@ -14,5 +13,5 @@ interface TypeReplacer { * Finds a type to replace the original abstract type * if it is guided with some additional information. */ - fun replaceTypeIfNeeded(type: RefType): ClassId? + fun replaceTypeIfNeeded(classId: ClassId): ClassId? } \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/custom/MockingJavaFuzzingContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/custom/MockingJavaFuzzingContext.kt index e2e865319a..6f587a68ed 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/custom/MockingJavaFuzzingContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/custom/MockingJavaFuzzingContext.kt @@ -3,38 +3,48 @@ package org.utbot.framework.context.custom import org.utbot.framework.context.JavaFuzzingContext import org.utbot.framework.plugin.api.ExecutableId import org.utbot.fuzzing.JavaValueProvider +import org.utbot.fuzzing.providers.AnyDepthNullValueProvider import org.utbot.fuzzing.providers.MapValueProvider import org.utbot.fuzzing.spring.unit.MockValueProvider import org.utbot.fuzzing.providers.NullValueProvider import org.utbot.fuzzing.providers.ObjectValueProvider import org.utbot.fuzzing.providers.StringValueProvider +import org.utbot.fuzzing.providers.anyObjectValueProvider +import org.utbot.fuzzing.spring.decorators.filterTypes import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult /** - * Makes fuzzer mock all types that don't have *specific* [JavaValueProvider], - * like [MapValueProvider] or [StringValueProvider]. + * Allows fuzzer to use mocks in accordance with [JavaFuzzingContext.mockStrategy]. * - * NOTE: the caller is responsible for providing some *specific* [JavaValueProvider] - * that can create values for class under test (otherwise it will be mocked), - * [ObjectValueProvider] and [NullValueProvider] do not count as *specific*. + * NOTE: + * - fuzzer won't mock types, that have *specific* value providers (e.g. [MapValueProvider] and [StringValueProvider]) + * - [ObjectValueProvider] and [NullValueProvider] do not count as *specific* value providers */ -fun JavaFuzzingContext.mockAllTypesWithoutSpecificValueProvider() = +fun JavaFuzzingContext.allowMocks() = MockingJavaFuzzingContext(delegateContext = this) class MockingJavaFuzzingContext( - val delegateContext: JavaFuzzingContext + val delegateContext: JavaFuzzingContext, ) : JavaFuzzingContext by delegateContext { private val mockValueProvider = MockValueProvider(delegateContext.idGenerator) override val valueProvider: JavaValueProvider = - // NOTE: we first remove `NullValueProvider` from `delegateContext.valueProvider` and then - // add it back as a part of our `withFallback` so it has the same priority as - // `mockValueProvider`, otherwise mocks will never be used where `null` can be used. + // NOTE: we first remove `NullValueProvider` and `ObjectValueProvider` from `delegateContext.valueProvider` + // and then add them back as a part of our `withFallback` so they have the same priority as + // `mockValueProvider`, otherwise mocks will never be used where `null` or new object can be used. delegateContext.valueProvider .except { it is NullValueProvider } .except { it is ObjectValueProvider } .withFallback( mockValueProvider + .filterTypes { type -> + mockStrategy.eligibleToMock( + classToMock = type.classId, + classUnderTest = classUnderTest + ) + } + .with(anyObjectValueProvider(idGenerator)) + .withFallback(mockValueProvider.with(AnyDepthNullValueProvider)) .with(NullValueProvider) ) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleJavaFuzzingContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleJavaFuzzingContext.kt index 8951c65d5e..2c885d5ea0 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleJavaFuzzingContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleJavaFuzzingContext.kt @@ -1,5 +1,6 @@ package org.utbot.framework.context.simple +import org.utbot.engine.MockStrategy import org.utbot.framework.context.JavaFuzzingContext import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.EnvironmentModels @@ -14,6 +15,7 @@ import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionRe class SimpleJavaFuzzingContext( override val classUnderTest: ClassId, + override val mockStrategy: MockStrategy, override val idGenerator: IdentityPreservingIdGenerator, ) : JavaFuzzingContext { override val valueProvider: JavaValueProvider = diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleTypeReplacer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleTypeReplacer.kt index 300aea86e5..3df1f5930e 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleTypeReplacer.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleTypeReplacer.kt @@ -3,10 +3,9 @@ package org.utbot.framework.context.simple import org.utbot.framework.context.TypeReplacer import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.TypeReplacementMode -import soot.RefType class SimpleTypeReplacer : TypeReplacer { override val typeReplacementMode: TypeReplacementMode = TypeReplacementMode.AnyImplementor - override fun replaceTypeIfNeeded(type: RefType): ClassId? = null + override fun replaceTypeIfNeeded(classId: ClassId): ClassId? = null } \ No newline at end of file diff --git a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/JavaLanguage.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/JavaLanguage.kt index 6f3e600788..f5278473c5 100644 --- a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/JavaLanguage.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/JavaLanguage.kt @@ -171,7 +171,7 @@ internal fun FuzzedType.traverseHierarchy(typeCache: MutableMap): FuzzedType { +fun toFuzzerType(type: Type, cache: MutableMap): FuzzedType { return toFuzzerType( type = type, classId = { t -> toClassId(t, cache) }, diff --git a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/ModifyingWithMethodsProviderWrapper.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/ModifyingWithMethodsProviderWrapper.kt index fa3ab0b4cc..c011e14926 100644 --- a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/ModifyingWithMethodsProviderWrapper.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/ModifyingWithMethodsProviderWrapper.kt @@ -9,8 +9,8 @@ import org.utbot.fuzzer.FuzzedValue import org.utbot.fuzzing.FuzzedDescription import org.utbot.fuzzing.JavaValueProvider import org.utbot.fuzzing.Routine -import org.utbot.fuzzing.Scope import org.utbot.fuzzing.Seed +import org.utbot.fuzzing.spring.decorators.ValueProviderDecorator /** * Value provider that is a buddy for another provider @@ -22,8 +22,11 @@ import org.utbot.fuzzing.Seed */ class ModifyingWithMethodsProviderWrapper( private val classUnderTest: ClassId, - private val delegate: JavaValueProvider -) : JavaValueProvider by delegate { + delegate: JavaValueProvider +) : ValueProviderDecorator(delegate) { + + override fun wrap(provider: JavaValueProvider): JavaValueProvider = + ModifyingWithMethodsProviderWrapper(classUnderTest, provider) override fun generate(description: FuzzedDescription, type: FuzzedType): Sequence> = delegate @@ -50,9 +53,4 @@ class ModifyingWithMethodsProviderWrapper( ) } else seed } - - override fun enrich(description: FuzzedDescription, type: FuzzedType, scope: Scope) = - delegate.enrich(description, type, scope) - - override fun accept(type: FuzzedType): Boolean = delegate.accept(type) } \ No newline at end of file diff --git a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/PropertyPreservingValueProvider.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/PropertyPreservingValueProvider.kt index 986d6d2ead..27cf6e2d60 100644 --- a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/PropertyPreservingValueProvider.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/PropertyPreservingValueProvider.kt @@ -6,8 +6,8 @@ import org.utbot.fuzzer.FuzzedValue import org.utbot.fuzzing.FuzzedDescription import org.utbot.fuzzing.JavaValueProvider import org.utbot.fuzzing.Routine -import org.utbot.fuzzing.Scope import org.utbot.fuzzing.Seed +import org.utbot.fuzzing.spring.decorators.ValueProviderDecorator /** * @see preserveProperties @@ -25,14 +25,14 @@ interface PreservableFuzzedTypeProperty : FuzzedTypeProperty fun JavaValueProvider.preserveProperties() : JavaValueProvider = PropertyPreservingValueProvider(this) -class PropertyPreservingValueProvider(private val delegateProvider: JavaValueProvider) : JavaValueProvider { - override fun enrich(description: FuzzedDescription, type: FuzzedType, scope: Scope) = - delegateProvider.enrich(description, type, scope) - - override fun accept(type: FuzzedType): Boolean = delegateProvider.accept(type) +class PropertyPreservingValueProvider( + delegate: JavaValueProvider +) : ValueProviderDecorator(delegate) { + override fun wrap(provider: JavaValueProvider): JavaValueProvider = + provider.preserveProperties() override fun generate(description: FuzzedDescription, type: FuzzedType): Sequence> { - val delegateSeeds = delegateProvider.generate(description, type) + val delegateSeeds = delegate.generate(description, type) val preservedProperties = type.properties.entries .filter { it.property is PreservableFuzzedTypeProperty } @@ -67,10 +67,4 @@ class PropertyPreservingValueProvider(private val delegateProvider: JavaValuePro } } } - - override fun map(transform: (JavaValueProvider) -> JavaValueProvider): JavaValueProvider = - delegateProvider.map(transform).preserveProperties() - - override fun except(filter: (JavaValueProvider) -> Boolean): JavaValueProvider = - delegateProvider.except(filter).preserveProperties() } \ No newline at end of file diff --git a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/FilteredValueProvider.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/FilteredValueProvider.kt new file mode 100644 index 0000000000..faf2178f03 --- /dev/null +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/FilteredValueProvider.kt @@ -0,0 +1,18 @@ +package org.utbot.fuzzing.spring.decorators + +import org.utbot.fuzzing.Description +import org.utbot.fuzzing.ValueProvider + +fun > ValueProvider.filterTypes(predicate: (T) -> Boolean) = + FilteredValueProvider(delegate = this, predicate) + +class FilteredValueProvider>( + delegate: ValueProvider, + private val predicate: (T) -> Boolean +) : ValueProviderDecorator(delegate) { + override fun wrap(provider: ValueProvider): ValueProvider = + provider.filterTypes(predicate) + + override fun accept(type: T): Boolean = + predicate(type) && super.accept(type) +} \ No newline at end of file diff --git a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/TypeReplacingValueProvider.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/TypeReplacingValueProvider.kt new file mode 100644 index 0000000000..2df9984d00 --- /dev/null +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/TypeReplacingValueProvider.kt @@ -0,0 +1,28 @@ +package org.utbot.fuzzing.spring.decorators + +import org.utbot.fuzzing.Description +import org.utbot.fuzzing.Scope +import org.utbot.fuzzing.Seed +import org.utbot.fuzzing.ValueProvider + +fun > ValueProvider.replaceTypes(typeReplacer: (D, T) -> T) = + TypeReplacingValueProvider(delegate = this, typeReplacer) + +class TypeReplacingValueProvider>( + delegate: ValueProvider, + private val typeReplacer: (D, T) -> T +) : ValueProviderDecorator(delegate) { + override fun wrap(provider: ValueProvider): ValueProvider = + provider.replaceTypes(typeReplacer) + + override fun enrich(description: D, type: T, scope: Scope) = + super.enrich(description, typeReplacer(description, type), scope) + + override fun accept(type: T): Boolean = true + + override fun generate(description: D, type: T): Sequence> = + if (super.accept(typeReplacer(description, type))) + super.generate(description, typeReplacer(description, type)) + else + emptySequence() +} diff --git a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/ValueProviderDecorator.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/ValueProviderDecorator.kt new file mode 100644 index 0000000000..030d3bcd81 --- /dev/null +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/ValueProviderDecorator.kt @@ -0,0 +1,29 @@ +package org.utbot.fuzzing.spring.decorators + +import org.utbot.fuzzing.Description +import org.utbot.fuzzing.Scope +import org.utbot.fuzzing.Seed +import org.utbot.fuzzing.ValueProvider + +abstract class ValueProviderDecorator>( + protected val delegate: ValueProvider +) : ValueProvider { + protected abstract fun wrap(provider: ValueProvider): ValueProvider + + override fun enrich(description: D, type: T, scope: Scope) = + delegate.enrich(description, type, scope) + + override fun accept(type: T): Boolean = + delegate.accept(type) + + override fun generate(description: D, type: T): Sequence> = + delegate.generate(description, type) + + override fun except(filter: (ValueProvider) -> Boolean): ValueProvider { + val res = wrap(delegate.except(filter)) + return if (filter(res)) ValueProvider.of(emptyList()) else res + } + + override fun map(transform: (ValueProvider) -> ValueProvider): ValueProvider = + transform(wrap(delegate.map(transform))) +} \ No newline at end of file diff --git a/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt b/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt index 9bddff2a52..bbcd7028ad 100644 --- a/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt +++ b/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt @@ -12,9 +12,9 @@ import org.utbot.framework.context.NonNullSpeculator import org.utbot.framework.context.TypeReplacer import org.utbot.framework.context.custom.CoverageFilteringConcreteExecutionContext import org.utbot.framework.context.custom.RerunningConcreteExecutionContext -import org.utbot.framework.context.custom.mockAllTypesWithoutSpecificValueProvider +import org.utbot.framework.context.custom.allowMocks import org.utbot.framework.context.utils.transformJavaFuzzingContext -import org.utbot.framework.context.utils.withValueProvider +import org.utbot.framework.context.utils.transformValueProvider import org.utbot.framework.plugin.api.BeanDefinitionData import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.ConcreteContextLoadingResult @@ -25,7 +25,9 @@ import org.utbot.framework.plugin.api.util.allSuperTypes import org.utbot.framework.plugin.api.util.id import org.utbot.framework.plugin.api.util.jClass import org.utbot.framework.plugin.api.util.utContext +import org.utbot.fuzzing.spring.decorators.replaceTypes import org.utbot.fuzzing.spring.unit.InjectMockValueProvider +import org.utbot.fuzzing.toFuzzerType class SpringApplicationContextImpl( private val delegateContext: ApplicationContext, @@ -65,13 +67,20 @@ class SpringApplicationContextImpl( return when (springTestType) { SpringTestType.UNIT_TEST -> delegateConcreteExecutionContext.transformJavaFuzzingContext { fuzzingContext -> fuzzingContext - .withValueProvider( + .allowMocks() + .transformValueProvider { origValueProvider -> InjectMockValueProvider( idGenerator = fuzzingContext.idGenerator, classToUseCompositeModelFor = fuzzingContext.classUnderTest ) - ) - .mockAllTypesWithoutSpecificValueProvider() + .withFallback(origValueProvider) + .replaceTypes { description, type -> + typeReplacer.replaceTypeIfNeeded(type.classId)?.let { replacement -> + // TODO infer generic type + toFuzzerType(replacement.jClass, description.typeCache) + } ?: type + } + } } SpringTestType.INTEGRATION_TEST -> RerunningConcreteExecutionContext( diff --git a/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringTypeReplacer.kt b/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringTypeReplacer.kt index 8fca71c751..b8a9e7de77 100644 --- a/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringTypeReplacer.kt +++ b/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringTypeReplacer.kt @@ -3,10 +3,8 @@ package org.utbot.framework.context.spring import org.utbot.framework.context.TypeReplacer import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.TypeReplacementMode -import org.utbot.framework.plugin.api.id -import org.utbot.framework.plugin.api.isAbstractType +import org.utbot.framework.plugin.api.util.isAbstract import org.utbot.framework.plugin.api.util.isSubtypeOf -import soot.RefType class SpringTypeReplacer( private val delegateTypeReplacer: TypeReplacer, @@ -19,7 +17,7 @@ class SpringTypeReplacer( else TypeReplacementMode.NoImplementors - override fun replaceTypeIfNeeded(type: RefType): ClassId? = - if (type.isAbstractType) springApplicationContext.injectedTypes.singleOrNull { it.isSubtypeOf(type.id) } - else delegateTypeReplacer.replaceTypeIfNeeded(type) + override fun replaceTypeIfNeeded(classId: ClassId): ClassId? = + if (classId.isAbstract) springApplicationContext.injectedTypes.singleOrNull { it.isSubtypeOf(classId) } + else delegateTypeReplacer.replaceTypeIfNeeded(classId) } \ No newline at end of file From eea12f17407ad975228b88c75c0443b150d13d04 Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Tue, 29 Aug 2023 13:31:34 +0300 Subject: [PATCH 02/10] Avoid mocking replaced types --- .../org/utbot/fuzzing/spring/unit/Mocks.kt | 6 ++++++ .../spring/SpringApplicationContextImpl.kt | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/unit/Mocks.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/unit/Mocks.kt index 85417456bf..7fa8f0cb13 100644 --- a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/unit/Mocks.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/unit/Mocks.kt @@ -18,11 +18,15 @@ import org.utbot.fuzzing.Routine import org.utbot.fuzzing.Scope import org.utbot.fuzzing.ScopeProperty import org.utbot.fuzzing.Seed +import org.utbot.fuzzing.spring.FuzzedTypeFlag +import org.utbot.fuzzing.spring.properties import org.utbot.fuzzing.spring.utils.jType import org.utbot.fuzzing.spring.utils.toTypeParametrizedByTypeVariables import org.utbot.fuzzing.spring.utils.typeToken import org.utbot.fuzzing.toFuzzerType +object NeverMockFlag : FuzzedTypeFlag + val methodsToMockProperty = ScopeProperty>( description = "Method ids that can be mocked by `MockValueProvider`" ) @@ -37,6 +41,8 @@ class MockValueProvider(private val idGenerator: IdGenerator) : JavaValuePr private val methodsToMock = mutableSetOf() + override fun accept(type: FuzzedType) = NeverMockFlag !in type.properties + override fun enrich(description: FuzzedDescription, type: FuzzedType, scope: Scope) { val publicMethods = type.classId.jClass.methods.map { it.executableId } publicMethods.intersect(methodsToMock).takeIf { it.isNotEmpty() }?.let { diff --git a/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt b/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt index bbcd7028ad..007b31f100 100644 --- a/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt +++ b/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt @@ -1,8 +1,10 @@ package org.utbot.framework.context.spring import mu.KotlinLogging +import org.utbot.common.dynamicPropertiesOf import org.utbot.common.isAbstract import org.utbot.common.isStatic +import org.utbot.common.withValue import org.utbot.framework.codegen.generator.AbstractCodeGenerator import org.utbot.framework.codegen.generator.CodeGeneratorParams import org.utbot.framework.codegen.generator.SpringCodeGenerator @@ -25,8 +27,10 @@ import org.utbot.framework.plugin.api.util.allSuperTypes import org.utbot.framework.plugin.api.util.id import org.utbot.framework.plugin.api.util.jClass import org.utbot.framework.plugin.api.util.utContext +import org.utbot.fuzzing.spring.addProperties import org.utbot.fuzzing.spring.decorators.replaceTypes import org.utbot.fuzzing.spring.unit.InjectMockValueProvider +import org.utbot.fuzzing.spring.unit.NeverMockFlag import org.utbot.fuzzing.toFuzzerType class SpringApplicationContextImpl( @@ -75,10 +79,14 @@ class SpringApplicationContextImpl( ) .withFallback(origValueProvider) .replaceTypes { description, type -> - typeReplacer.replaceTypeIfNeeded(type.classId)?.let { replacement -> - // TODO infer generic type - toFuzzerType(replacement.jClass, description.typeCache) - } ?: type + typeReplacer.replaceTypeIfNeeded(type.classId) + ?.takeIf { it != type.classId } + ?.let { replacement -> + // TODO infer generic type of replacement + toFuzzerType(replacement.jClass, description.typeCache).addProperties( + dynamicPropertiesOf(NeverMockFlag.withValue(Unit)) + ) + } ?: type } } } From badfd3b7a98c9d178a1ab1821a18431791934913 Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Tue, 29 Aug 2023 13:50:43 +0300 Subject: [PATCH 03/10] Only use `InjectMockValueProvider` for `thisInstance` --- .../utbot/fuzzing/spring/unit/InjectMocks.kt | 20 +++++++++++++++++-- .../spring/SpringApplicationContextImpl.kt | 2 +- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/unit/InjectMocks.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/unit/InjectMocks.kt index d6bb17f8b8..3843930e92 100644 --- a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/unit/InjectMocks.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/unit/InjectMocks.kt @@ -13,20 +13,36 @@ import org.utbot.fuzzer.fuzzed import org.utbot.fuzzing.FuzzedDescription import org.utbot.fuzzing.JavaValueProvider import org.utbot.fuzzing.Routine +import org.utbot.fuzzing.Scope +import org.utbot.fuzzing.ScopeProperty import org.utbot.fuzzing.Seed import org.utbot.fuzzing.toFuzzerType +val INJECT_MOCK_FLAG = ScopeProperty( + "INJECT_MOCK_FLAG is present if composite model should be used (i.e. thisInstance is being created)" +) + /** * Models created by this class can be used with `@InjectMock` annotation, because * they are [UtCompositeModel]s similar to the ones created by the symbolic engine. + * + * This class only creates models for thisInstance of type [classUnderTest]. */ class InjectMockValueProvider( private val idGenerator: IdGenerator, - private val classToUseCompositeModelFor: ClassId + private val classUnderTest: ClassId ) : JavaValueProvider { - override fun accept(type: FuzzedType): Boolean = type.classId == classToUseCompositeModelFor + override fun enrich(description: FuzzedDescription, type: FuzzedType, scope: Scope) { + // any value except this + if (description.description.isStatic == false && scope.parameterIndex == 0 && scope.recursionDepth == 1) { + scope.putProperty(INJECT_MOCK_FLAG, Unit) + } + } + + override fun accept(type: FuzzedType): Boolean = type.classId == classUnderTest override fun generate(description: FuzzedDescription, type: FuzzedType): Sequence> { + if (description.scope?.getProperty(INJECT_MOCK_FLAG) == null) return emptySequence() val fields = type.classId.allDeclaredFieldIds.filterNot { it.isStatic && it.isFinal }.toList() return sequenceOf(Seed.Recursive( construct = Routine.Create(types = fields.map { toFuzzerType(it.jField.genericType, description.typeCache) }) { values -> diff --git a/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt b/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt index 007b31f100..af790387e4 100644 --- a/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt +++ b/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt @@ -75,7 +75,7 @@ class SpringApplicationContextImpl( .transformValueProvider { origValueProvider -> InjectMockValueProvider( idGenerator = fuzzingContext.idGenerator, - classToUseCompositeModelFor = fuzzingContext.classUnderTest + classUnderTest = fuzzingContext.classUnderTest ) .withFallback(origValueProvider) .replaceTypes { description, type -> From 3a15ae3b725c6c8a700a38e547a289755fce9eb8 Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Tue, 29 Aug 2023 15:15:41 +0300 Subject: [PATCH 04/10] Disallow non-mocks when mock can be used --- .../custom/MockingJavaFuzzingContext.kt | 19 ++++++++----------- .../org/utbot/fuzzing/spring/unit/Mocks.kt | 6 ------ .../spring/SpringApplicationContextImpl.kt | 17 +++++++++++++---- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/custom/MockingJavaFuzzingContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/custom/MockingJavaFuzzingContext.kt index 6f587a68ed..9b689d33cf 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/custom/MockingJavaFuzzingContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/custom/MockingJavaFuzzingContext.kt @@ -2,6 +2,7 @@ package org.utbot.framework.context.custom import org.utbot.framework.context.JavaFuzzingContext import org.utbot.framework.plugin.api.ExecutableId +import org.utbot.fuzzer.FuzzedType import org.utbot.fuzzing.JavaValueProvider import org.utbot.fuzzing.providers.AnyDepthNullValueProvider import org.utbot.fuzzing.providers.MapValueProvider @@ -14,17 +15,19 @@ import org.utbot.fuzzing.spring.decorators.filterTypes import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult /** - * Allows fuzzer to use mocks in accordance with [JavaFuzzingContext.mockStrategy]. + * Makes fuzzer to use mocks in accordance with [mockPredicate]. * * NOTE: * - fuzzer won't mock types, that have *specific* value providers (e.g. [MapValueProvider] and [StringValueProvider]) * - [ObjectValueProvider] and [NullValueProvider] do not count as *specific* value providers + * - fuzzer may still resort to mocks despite [mockPredicate] if it can't create other non-null values or at runtime */ -fun JavaFuzzingContext.allowMocks() = - MockingJavaFuzzingContext(delegateContext = this) +fun JavaFuzzingContext.useMocks(mockPredicate: (FuzzedType) -> Boolean) = + MockingJavaFuzzingContext(delegateContext = this, mockPredicate) class MockingJavaFuzzingContext( val delegateContext: JavaFuzzingContext, + val mockPredicate: (FuzzedType) -> Boolean, ) : JavaFuzzingContext by delegateContext { private val mockValueProvider = MockValueProvider(delegateContext.idGenerator) @@ -36,14 +39,8 @@ class MockingJavaFuzzingContext( .except { it is NullValueProvider } .except { it is ObjectValueProvider } .withFallback( - mockValueProvider - .filterTypes { type -> - mockStrategy.eligibleToMock( - classToMock = type.classId, - classUnderTest = classUnderTest - ) - } - .with(anyObjectValueProvider(idGenerator)) + mockValueProvider.filterTypes(mockPredicate) + .with(anyObjectValueProvider(idGenerator).filterTypes { !mockPredicate(it) }) .withFallback(mockValueProvider.with(AnyDepthNullValueProvider)) .with(NullValueProvider) ) diff --git a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/unit/Mocks.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/unit/Mocks.kt index 7fa8f0cb13..85417456bf 100644 --- a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/unit/Mocks.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/unit/Mocks.kt @@ -18,15 +18,11 @@ import org.utbot.fuzzing.Routine import org.utbot.fuzzing.Scope import org.utbot.fuzzing.ScopeProperty import org.utbot.fuzzing.Seed -import org.utbot.fuzzing.spring.FuzzedTypeFlag -import org.utbot.fuzzing.spring.properties import org.utbot.fuzzing.spring.utils.jType import org.utbot.fuzzing.spring.utils.toTypeParametrizedByTypeVariables import org.utbot.fuzzing.spring.utils.typeToken import org.utbot.fuzzing.toFuzzerType -object NeverMockFlag : FuzzedTypeFlag - val methodsToMockProperty = ScopeProperty>( description = "Method ids that can be mocked by `MockValueProvider`" ) @@ -41,8 +37,6 @@ class MockValueProvider(private val idGenerator: IdGenerator) : JavaValuePr private val methodsToMock = mutableSetOf() - override fun accept(type: FuzzedType) = NeverMockFlag !in type.properties - override fun enrich(description: FuzzedDescription, type: FuzzedType, scope: Scope) { val publicMethods = type.classId.jClass.methods.map { it.executableId } publicMethods.intersect(methodsToMock).takeIf { it.isNotEmpty() }?.let { diff --git a/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt b/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt index af790387e4..d838816046 100644 --- a/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt +++ b/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt @@ -14,7 +14,7 @@ import org.utbot.framework.context.NonNullSpeculator import org.utbot.framework.context.TypeReplacer import org.utbot.framework.context.custom.CoverageFilteringConcreteExecutionContext import org.utbot.framework.context.custom.RerunningConcreteExecutionContext -import org.utbot.framework.context.custom.allowMocks +import org.utbot.framework.context.custom.useMocks import org.utbot.framework.context.utils.transformJavaFuzzingContext import org.utbot.framework.context.utils.transformValueProvider import org.utbot.framework.plugin.api.BeanDefinitionData @@ -27,10 +27,11 @@ import org.utbot.framework.plugin.api.util.allSuperTypes import org.utbot.framework.plugin.api.util.id import org.utbot.framework.plugin.api.util.jClass import org.utbot.framework.plugin.api.util.utContext +import org.utbot.fuzzing.spring.FuzzedTypeFlag import org.utbot.fuzzing.spring.addProperties import org.utbot.fuzzing.spring.decorators.replaceTypes +import org.utbot.fuzzing.spring.properties import org.utbot.fuzzing.spring.unit.InjectMockValueProvider -import org.utbot.fuzzing.spring.unit.NeverMockFlag import org.utbot.fuzzing.toFuzzerType class SpringApplicationContextImpl( @@ -43,6 +44,8 @@ class SpringApplicationContextImpl( private val logger = KotlinLogging.logger {} } + private object ReplacedFuzzedTypeFlag : FuzzedTypeFlag + override val typeReplacer: TypeReplacer = SpringTypeReplacer(delegateContext.typeReplacer, this) override val nonNullSpeculator: NonNullSpeculator = SpringNonNullSpeculator(delegateContext.nonNullSpeculator, this) @@ -71,7 +74,13 @@ class SpringApplicationContextImpl( return when (springTestType) { SpringTestType.UNIT_TEST -> delegateConcreteExecutionContext.transformJavaFuzzingContext { fuzzingContext -> fuzzingContext - .allowMocks() + .useMocks { type -> + ReplacedFuzzedTypeFlag !in type.properties && + fuzzingContext.mockStrategy.eligibleToMock( + classToMock = type.classId, + classUnderTest = fuzzingContext.classUnderTest + ) + } .transformValueProvider { origValueProvider -> InjectMockValueProvider( idGenerator = fuzzingContext.idGenerator, @@ -84,7 +93,7 @@ class SpringApplicationContextImpl( ?.let { replacement -> // TODO infer generic type of replacement toFuzzerType(replacement.jClass, description.typeCache).addProperties( - dynamicPropertiesOf(NeverMockFlag.withValue(Unit)) + dynamicPropertiesOf(ReplacedFuzzedTypeFlag.withValue(Unit)) ) } ?: type } From cce1616b63ab389f93ed07da0934cb909b2c98df Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Tue, 29 Aug 2023 16:09:33 +0300 Subject: [PATCH 05/10] Move all value provider decorators to one package --- .../decorators}/ModifyingWithMethodsProviderWrapper.kt | 4 ++-- .../{ => decorators}/PropertyPreservingValueProvider.kt | 6 ++++-- .../kotlin/org/utbot/fuzzing/spring/valid/ValidEntity.kt | 2 +- .../spring/SpringIntegrationTestJavaFuzzingContext.kt | 4 ++-- 4 files changed, 9 insertions(+), 7 deletions(-) rename utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/{providers => spring/decorators}/ModifyingWithMethodsProviderWrapper.kt (95%) rename utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/{ => decorators}/PropertyPreservingValueProvider.kt (93%) diff --git a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/ModifyingWithMethodsProviderWrapper.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/ModifyingWithMethodsProviderWrapper.kt similarity index 95% rename from utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/ModifyingWithMethodsProviderWrapper.kt rename to utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/ModifyingWithMethodsProviderWrapper.kt index c011e14926..d94b2ea18a 100644 --- a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/ModifyingWithMethodsProviderWrapper.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/ModifyingWithMethodsProviderWrapper.kt @@ -1,4 +1,4 @@ -package org.utbot.fuzzing.providers +package org.utbot.fuzzing.spring.decorators import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.UtAssembleModel @@ -10,7 +10,7 @@ import org.utbot.fuzzing.FuzzedDescription import org.utbot.fuzzing.JavaValueProvider import org.utbot.fuzzing.Routine import org.utbot.fuzzing.Seed -import org.utbot.fuzzing.spring.decorators.ValueProviderDecorator +import org.utbot.fuzzing.providers.findMethodsToModifyWith /** * Value provider that is a buddy for another provider diff --git a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/PropertyPreservingValueProvider.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/PropertyPreservingValueProvider.kt similarity index 93% rename from utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/PropertyPreservingValueProvider.kt rename to utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/PropertyPreservingValueProvider.kt index 27cf6e2d60..5f52435daa 100644 --- a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/PropertyPreservingValueProvider.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/PropertyPreservingValueProvider.kt @@ -1,4 +1,4 @@ -package org.utbot.fuzzing.spring +package org.utbot.fuzzing.spring.decorators import org.utbot.common.toDynamicProperties import org.utbot.fuzzer.FuzzedType @@ -7,7 +7,9 @@ import org.utbot.fuzzing.FuzzedDescription import org.utbot.fuzzing.JavaValueProvider import org.utbot.fuzzing.Routine import org.utbot.fuzzing.Seed -import org.utbot.fuzzing.spring.decorators.ValueProviderDecorator +import org.utbot.fuzzing.spring.FuzzedTypeProperty +import org.utbot.fuzzing.spring.addProperties +import org.utbot.fuzzing.spring.properties /** * @see preserveProperties diff --git a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/valid/ValidEntity.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/valid/ValidEntity.kt index f21c8e3948..4acc0dce66 100644 --- a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/valid/ValidEntity.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/valid/ValidEntity.kt @@ -32,7 +32,7 @@ import org.utbot.fuzzing.Routine import org.utbot.fuzzing.Seed import org.utbot.fuzzing.providers.findAccessibleModifiableFields import org.utbot.fuzzing.providers.nullRoutine -import org.utbot.fuzzing.spring.PreservableFuzzedTypeProperty +import org.utbot.fuzzing.spring.decorators.PreservableFuzzedTypeProperty import org.utbot.fuzzing.spring.addProperties import org.utbot.fuzzing.spring.properties import org.utbot.fuzzing.utils.hex diff --git a/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringIntegrationTestJavaFuzzingContext.kt b/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringIntegrationTestJavaFuzzingContext.kt index bf4934887a..b391cf009d 100644 --- a/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringIntegrationTestJavaFuzzingContext.kt +++ b/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringIntegrationTestJavaFuzzingContext.kt @@ -21,11 +21,11 @@ import org.utbot.fuzzer.IdentityPreservingIdGenerator import org.utbot.fuzzing.JavaValueProvider import org.utbot.fuzzing.ValueProvider import org.utbot.fuzzing.providers.AnyDepthNullValueProvider -import org.utbot.fuzzing.providers.ModifyingWithMethodsProviderWrapper +import org.utbot.fuzzing.spring.decorators.ModifyingWithMethodsProviderWrapper import org.utbot.fuzzing.providers.ObjectValueProvider import org.utbot.fuzzing.spring.GeneratedFieldValueProvider import org.utbot.fuzzing.spring.SpringBeanValueProvider -import org.utbot.fuzzing.spring.preserveProperties +import org.utbot.fuzzing.spring.decorators.preserveProperties import org.utbot.fuzzing.spring.valid.EmailValueProvider import org.utbot.fuzzing.spring.valid.NotBlankStringValueProvider import org.utbot.fuzzing.spring.valid.NotEmptyStringValueProvider From beef34fbd9cf3cb5a0a89c973cf2919a89b561b0 Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Tue, 29 Aug 2023 16:16:12 +0300 Subject: [PATCH 06/10] Improve adding of `ReplacedFuzzedTypeFlag` --- .../context/spring/SpringApplicationContextImpl.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt b/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt index d838816046..6bf72f78a8 100644 --- a/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt +++ b/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt @@ -89,10 +89,12 @@ class SpringApplicationContextImpl( .withFallback(origValueProvider) .replaceTypes { description, type -> typeReplacer.replaceTypeIfNeeded(type.classId) - ?.takeIf { it != type.classId } - ?.let { replacement -> + ?.let { replacementClassId -> // TODO infer generic type of replacement - toFuzzerType(replacement.jClass, description.typeCache).addProperties( + val replacement = + if (type.classId == replacementClassId) type + else toFuzzerType(replacementClassId.jClass, description.typeCache) + replacement.addProperties( dynamicPropertiesOf(ReplacedFuzzedTypeFlag.withValue(Unit)) ) } ?: type From 9ea8815b3847e3dc13041bd36b3d9cc5c17fe35c Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Mon, 11 Sep 2023 19:28:02 +0300 Subject: [PATCH 07/10] Make `map` and `except` apply transformer/filter to ALL value providers --- .../kotlin/org/utbot/fuzzing/Providers.kt | 25 ++++++++----------- .../decorators/ValueProviderDecorator.kt | 5 ---- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/Providers.kt b/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/Providers.kt index f64fb7d996..0a47c42624 100644 --- a/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/Providers.kt +++ b/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/Providers.kt @@ -92,26 +92,16 @@ fun interface ValueProvider> { } /** - * Removes `anotherValueProviders) -> Boolean): ValueProvider { - return if (this is Combined) { - Combined(providers.map { it.unwrapIfFallback() }.filterNot(filter)) - } else { - Combined(if (filter(unwrapIfFallback())) emptyList() else listOf(this)) - } - } + fun except(filter: (ValueProvider) -> Boolean): ValueProvider = + map { if (filter(it)) Combined(emptyList()) else it } /** * Applies [transform] for current provider */ - fun map(transform: (ValueProvider) -> ValueProvider): ValueProvider { - return if (this is Combined) { - Combined(providers.map(transform)) - } else { - transform(this) - } - } + fun map(transform: (ValueProvider) -> ValueProvider): ValueProvider = + transform(this) /** * Uses fallback value provider in case when 'this' one failed to generate any value. @@ -167,6 +157,8 @@ fun interface ValueProvider> { } } + override fun map(transform: (ValueProvider) -> ValueProvider): ValueProvider = + transform(Fallback(provider.map(transform), fallback.map(transform))) } /** @@ -200,6 +192,9 @@ fun interface ValueProvider> { } } } + + override fun map(transform: (ValueProvider) -> ValueProvider): ValueProvider = + transform(Combined(providers.map { it.map(transform) })) } companion object { diff --git a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/ValueProviderDecorator.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/ValueProviderDecorator.kt index 030d3bcd81..142c6c82d8 100644 --- a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/ValueProviderDecorator.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/ValueProviderDecorator.kt @@ -19,11 +19,6 @@ abstract class ValueProviderDecorator>( override fun generate(description: D, type: T): Sequence> = delegate.generate(description, type) - override fun except(filter: (ValueProvider) -> Boolean): ValueProvider { - val res = wrap(delegate.except(filter)) - return if (filter(res)) ValueProvider.of(emptyList()) else res - } - override fun map(transform: (ValueProvider) -> ValueProvider): ValueProvider = transform(wrap(delegate.map(transform))) } \ No newline at end of file From f64a5b7ae635c4a872daaa864ed05c295104e116 Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Mon, 11 Sep 2023 19:34:27 +0300 Subject: [PATCH 08/10] Avoid using `anyObjectValueProvider` that is removed in #2583 --- .../custom/MockingJavaFuzzingContext.kt | 33 ++++++++++--------- .../org/utbot/fuzzing/providers/Objects.kt | 15 ++++++--- .../decorators/SeedFilteringValueProvider.kt | 19 +++++++++++ ...vider.kt => TypeFilteringValueProvider.kt} | 4 +-- 4 files changed, 50 insertions(+), 21 deletions(-) create mode 100644 utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/SeedFilteringValueProvider.kt rename utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/{FilteredValueProvider.kt => TypeFilteringValueProvider.kt} (82%) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/custom/MockingJavaFuzzingContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/custom/MockingJavaFuzzingContext.kt index 9b689d33cf..1be43981ef 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/custom/MockingJavaFuzzingContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/custom/MockingJavaFuzzingContext.kt @@ -1,16 +1,15 @@ package org.utbot.framework.context.custom import org.utbot.framework.context.JavaFuzzingContext +import org.utbot.framework.plugin.api.UtNullModel import org.utbot.framework.plugin.api.ExecutableId import org.utbot.fuzzer.FuzzedType import org.utbot.fuzzing.JavaValueProvider +import org.utbot.fuzzing.Seed import org.utbot.fuzzing.providers.AnyDepthNullValueProvider -import org.utbot.fuzzing.providers.MapValueProvider +import org.utbot.fuzzing.providers.AnyObjectValueProvider import org.utbot.fuzzing.spring.unit.MockValueProvider -import org.utbot.fuzzing.providers.NullValueProvider -import org.utbot.fuzzing.providers.ObjectValueProvider -import org.utbot.fuzzing.providers.StringValueProvider -import org.utbot.fuzzing.providers.anyObjectValueProvider +import org.utbot.fuzzing.spring.decorators.filterSeeds import org.utbot.fuzzing.spring.decorators.filterTypes import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult @@ -18,9 +17,10 @@ import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionRe * Makes fuzzer to use mocks in accordance with [mockPredicate]. * * NOTE: - * - fuzzer won't mock types, that have *specific* value providers (e.g. [MapValueProvider] and [StringValueProvider]) - * - [ObjectValueProvider] and [NullValueProvider] do not count as *specific* value providers - * - fuzzer may still resort to mocks despite [mockPredicate] if it can't create other non-null values or at runtime + * - fuzzer won't mock types, that have *specific* value providers + * (i.e. ones that do not implement [AnyObjectValueProvider]) + * - fuzzer may still resort to mocks despite [mockPredicate] and *specific* + * value providers if it can't create other non-null values or at runtime */ fun JavaFuzzingContext.useMocks(mockPredicate: (FuzzedType) -> Boolean) = MockingJavaFuzzingContext(delegateContext = this, mockPredicate) @@ -32,17 +32,20 @@ class MockingJavaFuzzingContext( private val mockValueProvider = MockValueProvider(delegateContext.idGenerator) override val valueProvider: JavaValueProvider = - // NOTE: we first remove `NullValueProvider` and `ObjectValueProvider` from `delegateContext.valueProvider` - // and then add them back as a part of our `withFallback` so they have the same priority as - // `mockValueProvider`, otherwise mocks will never be used where `null` or new object can be used. + delegateContext.valueProvider - .except { it is NullValueProvider } - .except { it is ObjectValueProvider } + // NOTE: we first remove `AnyObjectValueProvider` and `NullValueProvider` from `delegateContext.valueProvider` + // and then add them back as a part of our `withFallback` so they have the same priority as + // `mockValueProvider`, otherwise mocks will never be used where `null` or new object can be used. + .except { it is AnyObjectValueProvider } .withFallback( mockValueProvider.filterTypes(mockPredicate) - .with(anyObjectValueProvider(idGenerator).filterTypes { !mockPredicate(it) }) + .with( + delegateContext.valueProvider + .filterTypes { !mockPredicate(it) } + .filterSeeds { (it as? Seed.Simple)?.value?.model !is UtNullModel } + ) .withFallback(mockValueProvider.with(AnyDepthNullValueProvider)) - .with(NullValueProvider) ) override fun handleFuzzedConcreteExecutionResult( diff --git a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Objects.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Objects.kt index bb14e0ecfd..02f485594c 100644 --- a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Objects.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Objects.kt @@ -70,9 +70,16 @@ fun anyObjectValueProvider(idGenerator: IdentityPreservingIdGenerator) = ovp.withFallback(AbstractsObjectValueProvider(idGenerator)) } +/** + * Marker interface that shows that this [JavaValueProvider] can potentially provide values of + * arbitrary types, unlike type-specific value providers that were designed to provide values of + * few specific popular types (e.g. `List`, `String`, etc.). + */ +interface AnyObjectValueProvider : JavaValueProvider + class ObjectValueProvider( val idGenerator: IdGenerator, -) : JavaValueProvider { +) : AnyObjectValueProvider { override fun accept(type: FuzzedType) = !isIgnored(type.classId) @@ -140,7 +147,7 @@ class ObjectValueProvider( } @Suppress("unused") -object NullValueProvider : JavaValueProvider { +object NullValueProvider : AnyObjectValueProvider { override fun enrich(description: FuzzedDescription, type: FuzzedType, scope: Scope) { // any value in static function is ok to fuzz @@ -170,7 +177,7 @@ object NullValueProvider : JavaValueProvider { * * Intended to be used as a last fallback. */ -object AnyDepthNullValueProvider : JavaValueProvider { +object AnyDepthNullValueProvider : AnyObjectValueProvider { override fun accept(type: FuzzedType) = type.classId.isRefType @@ -185,7 +192,7 @@ object AnyDepthNullValueProvider : JavaValueProvider { */ class AbstractsObjectValueProvider( val idGenerator: IdGenerator, -) : JavaValueProvider { +) : AnyObjectValueProvider { override fun accept(type: FuzzedType) = type.classId.isRefType && !isKnownTypes(type.classId) diff --git a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/SeedFilteringValueProvider.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/SeedFilteringValueProvider.kt new file mode 100644 index 0000000000..62b9dbf8f0 --- /dev/null +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/SeedFilteringValueProvider.kt @@ -0,0 +1,19 @@ +package org.utbot.fuzzing.spring.decorators + +import org.utbot.fuzzing.Description +import org.utbot.fuzzing.Seed +import org.utbot.fuzzing.ValueProvider + +fun > ValueProvider.filterSeeds(predicate: (Seed) -> Boolean) = + SeedFilteringValueProvider(delegate = this, predicate) + +class SeedFilteringValueProvider>( + delegate: ValueProvider, + private val predicate: (Seed) -> Boolean +) : ValueProviderDecorator(delegate) { + override fun wrap(provider: ValueProvider): ValueProvider = + provider.filterSeeds(predicate) + + override fun generate(description: D, type: T): Sequence> = + delegate.generate(description, type).filter(predicate) +} \ No newline at end of file diff --git a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/FilteredValueProvider.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/TypeFilteringValueProvider.kt similarity index 82% rename from utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/FilteredValueProvider.kt rename to utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/TypeFilteringValueProvider.kt index faf2178f03..7c46dfa46b 100644 --- a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/FilteredValueProvider.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/TypeFilteringValueProvider.kt @@ -4,9 +4,9 @@ import org.utbot.fuzzing.Description import org.utbot.fuzzing.ValueProvider fun > ValueProvider.filterTypes(predicate: (T) -> Boolean) = - FilteredValueProvider(delegate = this, predicate) + TypeFilteringValueProvider(delegate = this, predicate) -class FilteredValueProvider>( +class TypeFilteringValueProvider>( delegate: ValueProvider, private val predicate: (T) -> Boolean ) : ValueProviderDecorator(delegate) { From 33c1c21d74e53d74c74b20bfb4ecb1752fd0882b Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Fri, 15 Sep 2023 11:10:08 +0300 Subject: [PATCH 09/10] Make `AnyObjectValueProvider` not extend any interfaces, remove unrelated comment --- .../main/kotlin/org/utbot/fuzzing/providers/Objects.kt | 10 +++++----- .../org/utbot/fuzzing/spring/unit/InjectMocks.kt | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Objects.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Objects.kt index 02f485594c..14d4abfb8a 100644 --- a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Objects.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Objects.kt @@ -75,11 +75,11 @@ fun anyObjectValueProvider(idGenerator: IdentityPreservingIdGenerator) = * arbitrary types, unlike type-specific value providers that were designed to provide values of * few specific popular types (e.g. `List`, `String`, etc.). */ -interface AnyObjectValueProvider : JavaValueProvider +interface AnyObjectValueProvider class ObjectValueProvider( val idGenerator: IdGenerator, -) : AnyObjectValueProvider { +) : JavaValueProvider, AnyObjectValueProvider { override fun accept(type: FuzzedType) = !isIgnored(type.classId) @@ -147,7 +147,7 @@ class ObjectValueProvider( } @Suppress("unused") -object NullValueProvider : AnyObjectValueProvider { +object NullValueProvider : JavaValueProvider, AnyObjectValueProvider { override fun enrich(description: FuzzedDescription, type: FuzzedType, scope: Scope) { // any value in static function is ok to fuzz @@ -177,7 +177,7 @@ object NullValueProvider : AnyObjectValueProvider { * * Intended to be used as a last fallback. */ -object AnyDepthNullValueProvider : AnyObjectValueProvider { +object AnyDepthNullValueProvider : JavaValueProvider, AnyObjectValueProvider { override fun accept(type: FuzzedType) = type.classId.isRefType @@ -192,7 +192,7 @@ object AnyDepthNullValueProvider : AnyObjectValueProvider { */ class AbstractsObjectValueProvider( val idGenerator: IdGenerator, -) : AnyObjectValueProvider { +) : JavaValueProvider, AnyObjectValueProvider { override fun accept(type: FuzzedType) = type.classId.isRefType && !isKnownTypes(type.classId) diff --git a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/unit/InjectMocks.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/unit/InjectMocks.kt index 3843930e92..0ab41c973b 100644 --- a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/unit/InjectMocks.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/unit/InjectMocks.kt @@ -33,7 +33,6 @@ class InjectMockValueProvider( private val classUnderTest: ClassId ) : JavaValueProvider { override fun enrich(description: FuzzedDescription, type: FuzzedType, scope: Scope) { - // any value except this if (description.description.isStatic == false && scope.parameterIndex == 0 && scope.recursionDepth == 1) { scope.putProperty(INJECT_MOCK_FLAG, Unit) } From 98da383ab3858edac89f88ccdced6836cab0f005 Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Tue, 19 Sep 2023 11:07:09 +0300 Subject: [PATCH 10/10] Fix compilation after rebase --- .../kotlin/org/utbot/framework/context/JavaFuzzingContext.kt | 2 -- .../utbot/framework/context/simple/SimpleJavaFuzzingContext.kt | 2 -- .../framework/context/spring/SpringApplicationContextImpl.kt | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/JavaFuzzingContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/JavaFuzzingContext.kt index 51bbd22553..ee4f57acbf 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/JavaFuzzingContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/JavaFuzzingContext.kt @@ -1,6 +1,5 @@ package org.utbot.framework.context -import org.utbot.engine.MockStrategy import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.EnvironmentModels import org.utbot.framework.plugin.api.ExecutableId @@ -12,7 +11,6 @@ import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionRe interface JavaFuzzingContext { val classUnderTest: ClassId - val mockStrategy: MockStrategy val idGenerator: IdentityPreservingIdGenerator val valueProvider: JavaValueProvider diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleJavaFuzzingContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleJavaFuzzingContext.kt index 2c885d5ea0..8951c65d5e 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleJavaFuzzingContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleJavaFuzzingContext.kt @@ -1,6 +1,5 @@ package org.utbot.framework.context.simple -import org.utbot.engine.MockStrategy import org.utbot.framework.context.JavaFuzzingContext import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.EnvironmentModels @@ -15,7 +14,6 @@ import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionRe class SimpleJavaFuzzingContext( override val classUnderTest: ClassId, - override val mockStrategy: MockStrategy, override val idGenerator: IdentityPreservingIdGenerator, ) : JavaFuzzingContext { override val valueProvider: JavaValueProvider = diff --git a/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt b/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt index 6bf72f78a8..aca0011b85 100644 --- a/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt +++ b/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt @@ -76,7 +76,7 @@ class SpringApplicationContextImpl( fuzzingContext .useMocks { type -> ReplacedFuzzedTypeFlag !in type.properties && - fuzzingContext.mockStrategy.eligibleToMock( + mockStrategy.eligibleToMock( classToMock = type.classId, classUnderTest = fuzzingContext.classUnderTest )