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/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..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,41 +1,51 @@ 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.providers.MapValueProvider +import org.utbot.fuzzing.Seed +import org.utbot.fuzzing.providers.AnyDepthNullValueProvider +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.spring.decorators.filterSeeds +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]. + * Makes fuzzer to use mocks in accordance with [mockPredicate]. * - * 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 + * (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.mockAllTypesWithoutSpecificValueProvider() = - MockingJavaFuzzingContext(delegateContext = this) +fun JavaFuzzingContext.useMocks(mockPredicate: (FuzzedType) -> Boolean) = + MockingJavaFuzzingContext(delegateContext = this, mockPredicate) class MockingJavaFuzzingContext( - val delegateContext: JavaFuzzingContext + val delegateContext: JavaFuzzingContext, + val mockPredicate: (FuzzedType) -> Boolean, ) : 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. + 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 - .with(NullValueProvider) + mockValueProvider.filterTypes(mockPredicate) + .with( + delegateContext.valueProvider + .filterTypes { !mockPredicate(it) } + .filterSeeds { (it as? Seed.Simple)?.value?.model !is UtNullModel } + ) + .withFallback(mockValueProvider.with(AnyDepthNullValueProvider)) ) override fun handleFuzzedConcreteExecutionResult( 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-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/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/Objects.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Objects.kt index bb14e0ecfd..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 @@ -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 + class ObjectValueProvider( val idGenerator: IdGenerator, -) : JavaValueProvider { +) : JavaValueProvider, AnyObjectValueProvider { override fun accept(type: FuzzedType) = !isIgnored(type.classId) @@ -140,7 +147,7 @@ class ObjectValueProvider( } @Suppress("unused") -object NullValueProvider : JavaValueProvider { +object NullValueProvider : JavaValueProvider, 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 : JavaValueProvider, AnyObjectValueProvider { override fun accept(type: FuzzedType) = type.classId.isRefType @@ -185,7 +192,7 @@ object AnyDepthNullValueProvider : JavaValueProvider { */ class AbstractsObjectValueProvider( val idGenerator: IdGenerator, -) : JavaValueProvider { +) : 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/providers/ModifyingWithMethodsProviderWrapper.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/ModifyingWithMethodsProviderWrapper.kt similarity index 85% 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 fa3ab0b4cc..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 @@ -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.providers.findMethodsToModifyWith /** * 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/decorators/PropertyPreservingValueProvider.kt similarity index 76% 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 986d6d2ead..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 @@ -6,8 +6,10 @@ 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.FuzzedTypeProperty +import org.utbot.fuzzing.spring.addProperties +import org.utbot.fuzzing.spring.properties /** * @see preserveProperties @@ -25,14 +27,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 +69,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/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/TypeFilteringValueProvider.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/TypeFilteringValueProvider.kt new file mode 100644 index 0000000000..7c46dfa46b --- /dev/null +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/TypeFilteringValueProvider.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) = + TypeFilteringValueProvider(delegate = this, predicate) + +class TypeFilteringValueProvider>( + 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..142c6c82d8 --- /dev/null +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/decorators/ValueProviderDecorator.kt @@ -0,0 +1,24 @@ +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 map(transform: (ValueProvider) -> ValueProvider): ValueProvider = + transform(wrap(delegate.map(transform))) +} \ No newline at end of file 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..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 @@ -13,20 +13,35 @@ 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) { + 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-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/SpringApplicationContextImpl.kt b/utbot-spring-framework/src/main/kotlin/org/utbot/framework/context/spring/SpringApplicationContextImpl.kt index 9bddff2a52..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 @@ -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 @@ -12,9 +14,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.useMocks 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 +27,12 @@ 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.toFuzzerType class SpringApplicationContextImpl( private val delegateContext: ApplicationContext, @@ -37,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) @@ -65,13 +74,32 @@ class SpringApplicationContextImpl( return when (springTestType) { SpringTestType.UNIT_TEST -> delegateConcreteExecutionContext.transformJavaFuzzingContext { fuzzingContext -> fuzzingContext - .withValueProvider( + .useMocks { type -> + ReplacedFuzzedTypeFlag !in type.properties && + mockStrategy.eligibleToMock( + classToMock = type.classId, + classUnderTest = fuzzingContext.classUnderTest + ) + } + .transformValueProvider { origValueProvider -> InjectMockValueProvider( idGenerator = fuzzingContext.idGenerator, - classToUseCompositeModelFor = fuzzingContext.classUnderTest + classUnderTest = fuzzingContext.classUnderTest ) - ) - .mockAllTypesWithoutSpecificValueProvider() + .withFallback(origValueProvider) + .replaceTypes { description, type -> + typeReplacer.replaceTypeIfNeeded(type.classId) + ?.let { replacementClassId -> + // TODO infer generic type of replacement + val replacement = + if (type.classId == replacementClassId) type + else toFuzzerType(replacementClassId.jClass, description.typeCache) + replacement.addProperties( + dynamicPropertiesOf(ReplacedFuzzedTypeFlag.withValue(Unit)) + ) + } ?: type + } + } } SpringTestType.INTEGRATION_TEST -> RerunningConcreteExecutionContext( 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 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