From a7550afe976d16d30a78b74c2b036700e9560610 Mon Sep 17 00:00:00 2001 From: Maksim Pelevin Date: Wed, 13 Jul 2022 11:12:42 +0300 Subject: [PATCH] Generate test by fuzzing for methods with no parameters #511 --- .../org/utbot/engine/UtBotSymbolicEngine.kt | 34 +++++++-- .../org/utbot/external/api/UtBotJavaApi.kt | 13 ++-- .../org/utbot/fuzzer/FuzzedParameter.kt | 15 ++++ .../main/kotlin/org/utbot/fuzzer/Fuzzer.kt | 2 +- .../kotlin/org/utbot/fuzzer/ModelProvider.kt | 76 ++++++++++--------- .../fuzzer/providers/AbstractModelProvider.kt | 8 +- .../fuzzer/providers/ArrayModelProvider.kt | 9 +-- .../providers/CharToStringModelProvider.kt | 16 ++-- .../providers/CollectionModelProvider.kt | 9 +-- .../providers/ConstantsModelProvider.kt | 7 +- .../fuzzer/providers/EnumModelProvider.kt | 9 +-- .../fuzzer/providers/NullModelProvider.kt | 9 ++- .../fuzzer/providers/ObjectModelProvider.kt | 15 ++-- .../PrimitiveDefaultsModelProvider.kt | 7 +- .../PrimitiveWrapperModelProvider.kt | 14 ++-- .../providers/PrimitivesModelProvider.kt | 7 +- .../providers/StringConstantModelProvider.kt | 8 +- .../plugin/api/FuzzedValueDescriptionTest.kt | 2 +- .../framework/plugin/api/ModelProviderTest.kt | 9 ++- 19 files changed, 164 insertions(+), 105 deletions(-) create mode 100644 utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzedParameter.kt 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 4397c2b005..9ff7cc09a7 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt @@ -64,6 +64,7 @@ import org.utbot.framework.plugin.api.EnvironmentModels import org.utbot.framework.plugin.api.Instruction import org.utbot.framework.plugin.api.MissingState import org.utbot.framework.plugin.api.Step +import org.utbot.framework.plugin.api.UtAssembleModel import org.utbot.framework.plugin.api.UtConcreteExecutionFailure import org.utbot.framework.plugin.api.UtError import org.utbot.framework.plugin.api.UtExecution @@ -79,6 +80,7 @@ import org.utbot.framework.plugin.api.util.id import org.utbot.framework.plugin.api.util.utContext import org.utbot.framework.plugin.api.util.description import org.utbot.framework.util.jimpleBody +import org.utbot.framework.plugin.api.util.voidClassId import org.utbot.fuzzer.FallbackModelProvider import org.utbot.fuzzer.FuzzedMethodDescription import org.utbot.fuzzer.FuzzedValue @@ -89,10 +91,12 @@ import org.utbot.fuzzer.defaultModelProviders import org.utbot.fuzzer.fuzz import org.utbot.fuzzer.names.MethodBasedNameSuggester import org.utbot.fuzzer.names.ModelBasedNameSuggester +import org.utbot.fuzzer.providers.ObjectModelProvider import org.utbot.instrumentation.ConcreteExecutor import soot.jimple.Stmt import soot.tagkit.ParamNamesTag import java.lang.reflect.Method +import kotlin.random.Random import kotlin.system.measureTimeMillis val logger = KotlinLogging.logger {} @@ -384,6 +388,7 @@ class UtBotSymbolicEngine( } val fallbackModelProvider = FallbackModelProvider { nextDefaultModelId++ } + val constantValues = collectConstantsForFuzzer(graph) val thisInstance = when { methodUnderTest.isStatic -> null @@ -396,7 +401,9 @@ class UtBotSymbolicEngine( null } else -> { - fallbackModelProvider.toModel(methodUnderTest.clazz).apply { + ObjectModelProvider { nextDefaultModelId++ }.withFallback(fallbackModelProvider).generate( + FuzzedMethodDescription("thisInstance", voidClassId, listOf(methodUnderTest.clazz.id), constantValues) + ).take(10).shuffled(Random(0)).map { it.value.model }.first().apply { if (this is UtNullModel) { // it will definitely fail because of NPE, return@flow } @@ -411,17 +418,34 @@ class UtBotSymbolicEngine( val names = graph.body.method.tags.filterIsInstance().firstOrNull()?.names parameterNameMap = { index -> names?.getOrNull(index) } } - val modelProviderWithFallback = modelProvider(defaultModelProviders { nextDefaultModelId++ }).withFallback(fallbackModelProvider::toModel) val coveredInstructionTracker = Trie(Instruction::id) val coveredInstructionValues = mutableMapOf, List>() var attempts = UtSettings.fuzzingMaxAttempts - fuzz(methodUnderTestDescription, modelProviderWithFallback).forEach { values -> + val hasMethodUnderTestParametersToFuzz = executableId.parameters.isNotEmpty() + val fuzzedValues = if (hasMethodUnderTestParametersToFuzz) { + fuzz(methodUnderTestDescription, modelProvider(defaultModelProviders { nextDefaultModelId++ })) + } else { + // in case a method with no parameters is passed fuzzing tries to fuzz this instance with different constructors, setters and field mutators + val thisMethodDescription = FuzzedMethodDescription("thisInstance", voidClassId, listOf(methodUnderTest.clazz.id), constantValues).apply { + className = executableId.classId.simpleName + packageName = executableId.classId.packageName + } + fuzz(thisMethodDescription, ObjectModelProvider { nextDefaultModelId++ }.apply { + limitValuesCreatedByFieldAccessors = 500 + }) + } + fuzzedValues.forEach { values -> if (System.currentTimeMillis() >= until) { logger.info { "Fuzzing overtime: $methodUnderTest" } return@flow } - val initialEnvironmentModels = EnvironmentModels(thisInstance, values.map { it.model }, mapOf()) + val initialEnvironmentModels = if (hasMethodUnderTestParametersToFuzz) { + EnvironmentModels(thisInstance, values.map { it.model }, mapOf()) + } else { + check(values.size == 1 && values.first().model is UtAssembleModel) + EnvironmentModels(values.first().model, emptyList(), mapOf()) + } try { val concreteExecutionResult = @@ -462,7 +486,7 @@ class UtBotSymbolicEngine( fullPath = emptyList(), coverage = concreteExecutionResult.coverage, testMethodName = testMethodName?.testName, - displayName = testMethodName?.displayName + displayName = testMethodName?.takeIf { hasMethodUnderTestParametersToFuzz }?.displayName ) ) } catch (e: CancellationException) { diff --git a/utbot-framework/src/main/kotlin/org/utbot/external/api/UtBotJavaApi.kt b/utbot-framework/src/main/kotlin/org/utbot/external/api/UtBotJavaApi.kt index 8c94862f84..e81f452cad 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/external/api/UtBotJavaApi.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/external/api/UtBotJavaApi.kt @@ -32,6 +32,7 @@ import org.utbot.framework.plugin.api.util.withUtContext import org.utbot.framework.plugin.api.util.wrapperByPrimitive import org.utbot.fuzzer.FuzzedValue import org.utbot.fuzzer.ModelProvider +import org.utbot.fuzzer.ModelProvider.Companion.yieldValue import org.utbot.instrumentation.ConcreteExecutor import org.utbot.instrumentation.execute import java.lang.reflect.Method @@ -175,11 +176,13 @@ object UtBotJavaApi { } ?.map { UtPrimitiveModel(it) } ?: emptySequence() - val customModelProvider = ModelProvider { description, consumer -> - description.parametersMap.forEach { (classId, indices) -> - createPrimitiveModels(primitiveValuesSupplier, classId).forEach { model -> - indices.forEach { index -> - consumer.accept(index, FuzzedValue(model)) + val customModelProvider = ModelProvider { description -> + sequence { + description.parametersMap.forEach { (classId, indices) -> + createPrimitiveModels(primitiveValuesSupplier, classId).forEach { model -> + indices.forEach { index -> + yieldValue(index, FuzzedValue(model)) + } } } } diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzedParameter.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzedParameter.kt new file mode 100644 index 0000000000..2009a5b9e2 --- /dev/null +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzedParameter.kt @@ -0,0 +1,15 @@ +package org.utbot.fuzzer + +/** + * Fuzzed parameter of a method. + * + * @param index of the parameter in method signature + * @param value fuzzed values + */ +class FuzzedParameter( + val index: Int, + val value: FuzzedValue +) { + operator fun component1() = index + operator fun component2() = value +} \ No newline at end of file diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/Fuzzer.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/Fuzzer.kt index b15bbf19d9..52775f12ec 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/Fuzzer.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/Fuzzer.kt @@ -20,7 +20,7 @@ private val logger = KotlinLogging.logger {} fun fuzz(description: FuzzedMethodDescription, vararg modelProviders: ModelProvider): Sequence> { val values = List>(description.parameters.size) { mutableListOf() } modelProviders.forEach { fuzzingProvider -> - fuzzingProvider.generate(description) { index, model -> + fuzzingProvider.generate(description).forEach { (index, model) -> values[index].add(model) } } diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/ModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/ModelProvider.kt index 45d51fd83c..42e6eadc5b 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/ModelProvider.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/ModelProvider.kt @@ -2,7 +2,6 @@ package org.utbot.fuzzer import org.utbot.framework.plugin.api.UtModel import org.utbot.framework.plugin.api.ClassId -import java.util.function.BiConsumer fun interface ModelProvider { @@ -10,9 +9,9 @@ fun interface ModelProvider { * Generates values for the method. * * @param description a fuzzed method description - * @param consumer accepts index in the parameter list and [UtModel] for this parameter. + * @return sequence that produces [FuzzedParameter]. */ - fun generate(description: FuzzedMethodDescription, consumer: BiConsumer) + fun generate(description: FuzzedMethodDescription): Sequence /** * Combines this model provider with `anotherModelProvider` into one instance. @@ -51,25 +50,24 @@ fun interface ModelProvider { * @param modelProvider is called and every value of [ClassId] is collected which wasn't created by this model provider. */ fun withFallback(modelProvider: ModelProvider) : ModelProvider { - return ModelProvider { description, consumer -> - val providedByDelegateMethodParameters = mutableMapOf>() - this@ModelProvider.generate(description) { index, model -> - providedByDelegateMethodParameters.computeIfAbsent(index) { mutableListOf() }.add(model) - } - providedByDelegateMethodParameters.forEach { (index, models) -> - models.forEach { model -> - consumer.accept(index, model) + val thisModelProvider = this + return ModelProvider { description -> + sequence { + val providedByDelegateMethodParameters = mutableSetOf() + thisModelProvider.generate(description).forEach { (index, model) -> + providedByDelegateMethodParameters += index + yieldValue(index, model) } - } - val missingParameters = - (0 until description.parameters.size).filter { !providedByDelegateMethodParameters.containsKey(it) } - if (missingParameters.isNotEmpty()) { - val values = mutableMapOf>() - modelProvider.generate(description) { i, m -> values.computeIfAbsent(i) { mutableListOf() }.add(m) } - missingParameters.forEach { index -> - values[index]?.let { models -> - models.forEach { model -> - consumer.accept(index, model) + val missingParameters = + (0 until description.parameters.size).filter { !providedByDelegateMethodParameters.contains(it) } + if (missingParameters.isNotEmpty()) { + val values = mutableMapOf>() + modelProvider.generate(description).forEach { (i, m) -> values.computeIfAbsent(i) { mutableListOf() }.add(m) } + missingParameters.forEach { index -> + values[index]?.let { models -> + models.forEach { model -> + yieldValue(index, model) + } } } } @@ -86,15 +84,17 @@ fun interface ModelProvider { * @param fallbackModelSupplier is called for every [ClassId] which wasn't created by this model provider. */ fun withFallback(fallbackModelSupplier: (ClassId) -> UtModel?) : ModelProvider { - return withFallback { description, consumer -> - description.parametersMap.forEach { (classId, indices) -> - fallbackModelSupplier(classId)?.let { model -> - indices.forEach { index -> - consumer.accept(index, model.fuzzed()) + return withFallback( ModelProvider { description -> + sequence { + description.parametersMap.forEach { (classId, indices) -> + fallbackModelSupplier(classId)?.let { model -> + indices.forEach { index -> + yieldValue(index, model.fuzzed()) + } } } } - } + }) } companion object { @@ -103,16 +103,20 @@ fun interface ModelProvider { return Combined(providers.toList()) } - fun BiConsumer.consumeAll(indices: List, models: Sequence) { - models.forEach { model -> - indices.forEach { index -> - accept(index, model) + suspend fun SequenceScope.yieldValue(index: Int, value: FuzzedValue) { + yield(FuzzedParameter(index, value)) + } + + suspend fun SequenceScope.yieldAllValues(indices: List, models: Sequence) { + indices.forEach { index -> + models.forEach { model -> + yieldValue(index, model) } } } - fun BiConsumer.consumeAll(indices: List, models: List) { - consumeAll(indices, models.asSequence()) + suspend fun SequenceScope.yieldAllValues(indices: List, models: List) { + yieldAllValues(indices, models.asSequence()) } } @@ -120,9 +124,11 @@ fun interface ModelProvider { * Wrapper class that delegates implementation to the [providers]. */ private class Combined(val providers: List): ModelProvider { - override fun generate(description: FuzzedMethodDescription, consumer: BiConsumer) { + override fun generate(description: FuzzedMethodDescription): Sequence = sequence { providers.forEach { provider -> - provider.generate(description, consumer) + provider.generate(description).forEach { + yieldValue(it.index, it.value) + } } } } diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/AbstractModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/AbstractModelProvider.kt index d7dccf977c..1475850b38 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/AbstractModelProvider.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/AbstractModelProvider.kt @@ -2,20 +2,20 @@ package org.utbot.fuzzer.providers import org.utbot.framework.plugin.api.* import org.utbot.fuzzer.FuzzedMethodDescription -import org.utbot.fuzzer.FuzzedValue +import org.utbot.fuzzer.FuzzedParameter import org.utbot.fuzzer.ModelProvider -import java.util.function.BiConsumer +import org.utbot.fuzzer.ModelProvider.Companion.yieldValue /** * Simple model implementation. */ @Suppress("unused") abstract class AbstractModelProvider: ModelProvider { - override fun generate(description: FuzzedMethodDescription, consumer: BiConsumer) { + override fun generate(description: FuzzedMethodDescription): Sequence = sequence{ description.parametersMap.forEach { (classId, indices) -> toModel(classId)?.let { defaultModel -> indices.forEach { index -> - consumer.accept(index, defaultModel.fuzzed()) + yieldValue(index, defaultModel.fuzzed()) } } } diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ArrayModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ArrayModelProvider.kt index 92095009b2..622853d505 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ArrayModelProvider.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ArrayModelProvider.kt @@ -4,21 +4,20 @@ import org.utbot.framework.plugin.api.UtArrayModel import org.utbot.framework.plugin.api.util.defaultValueModel import org.utbot.framework.plugin.api.util.isArray import org.utbot.fuzzer.FuzzedMethodDescription -import org.utbot.fuzzer.FuzzedValue +import org.utbot.fuzzer.FuzzedParameter import org.utbot.fuzzer.ModelProvider -import org.utbot.fuzzer.ModelProvider.Companion.consumeAll -import java.util.function.BiConsumer +import org.utbot.fuzzer.ModelProvider.Companion.yieldAllValues import java.util.function.IntSupplier class ArrayModelProvider( private val idGenerator: IntSupplier ) : ModelProvider { - override fun generate(description: FuzzedMethodDescription, consumer: BiConsumer) { + override fun generate(description: FuzzedMethodDescription): Sequence = sequence { description.parametersMap .asSequence() .filter { (classId, _) -> classId.isArray } .forEach { (arrayClassId, indices) -> - consumer.consumeAll(indices, listOf(0, 10).map { arraySize -> + yieldAllValues(indices, listOf(0, 10).map { arraySize -> UtArrayModel( id = idGenerator.asInt, arrayClassId, diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CharToStringModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CharToStringModelProvider.kt index 16e20b6adc..450cea7115 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CharToStringModelProvider.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CharToStringModelProvider.kt @@ -4,16 +4,16 @@ import org.utbot.framework.plugin.api.UtPrimitiveModel import org.utbot.framework.plugin.api.util.charClassId import org.utbot.framework.plugin.api.util.stringClassId import org.utbot.fuzzer.FuzzedMethodDescription -import org.utbot.fuzzer.FuzzedValue +import org.utbot.fuzzer.FuzzedParameter import org.utbot.fuzzer.ModelProvider -import java.util.function.BiConsumer +import org.utbot.fuzzer.ModelProvider.Companion.yieldValue /** * Collects all char constants and creates string with them. */ object CharToStringModelProvider : ModelProvider { - override fun generate(description: FuzzedMethodDescription, consumer: BiConsumer) { - val indices = description.parametersMap[stringClassId] ?: return + override fun generate(description: FuzzedMethodDescription): Sequence = sequence { + val indices = description.parametersMap[stringClassId] ?: return@sequence if (indices.isNotEmpty()) { val string = description.concreteValues.asSequence() .filter { it.classId == charClassId } @@ -21,9 +21,11 @@ object CharToStringModelProvider : ModelProvider { .filterIsInstance() .joinToString(separator = "") if (string.isNotEmpty()) { - val model = UtPrimitiveModel(string).fuzzed() - indices.forEach { - consumer.accept(it, model) + sequenceOf(string.reversed(), string).forEach { str -> + val model = UtPrimitiveModel(str).fuzzed() + indices.forEach { + yieldValue(it, model) + } } } } diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CollectionModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CollectionModelProvider.kt index 349ab90aef..828822687a 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CollectionModelProvider.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CollectionModelProvider.kt @@ -10,10 +10,9 @@ import org.utbot.framework.plugin.api.UtStatementModel import org.utbot.framework.plugin.api.util.id import org.utbot.framework.plugin.api.util.jClass import org.utbot.fuzzer.FuzzedMethodDescription -import org.utbot.fuzzer.FuzzedValue +import org.utbot.fuzzer.FuzzedParameter import org.utbot.fuzzer.ModelProvider -import org.utbot.fuzzer.ModelProvider.Companion.consumeAll -import java.util.function.BiConsumer +import org.utbot.fuzzer.ModelProvider.Companion.yieldAllValues import java.util.function.IntSupplier /** @@ -36,12 +35,12 @@ class CollectionModelProvider( java.util.Iterator::class.java to ::createIteratorModels, ) - override fun generate(description: FuzzedMethodDescription, consumer: BiConsumer) { + override fun generate(description: FuzzedMethodDescription): Sequence = sequence { description.parametersMap .asSequence() .forEach { (classId, indices) -> generators[classId.jClass]?.let { createModels -> - consumer.consumeAll(indices, createModels().map { it.fuzzed() }) + yieldAllValues(indices, createModels().map { it.fuzzed() }) } } } diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ConstantsModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ConstantsModelProvider.kt index 659a2281c2..cf3f7d30f7 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ConstantsModelProvider.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ConstantsModelProvider.kt @@ -4,16 +4,17 @@ import org.utbot.framework.plugin.api.UtPrimitiveModel import org.utbot.framework.plugin.api.util.isPrimitive import org.utbot.fuzzer.FuzzedMethodDescription import org.utbot.fuzzer.FuzzedOp +import org.utbot.fuzzer.FuzzedParameter import org.utbot.fuzzer.FuzzedValue import org.utbot.fuzzer.ModelProvider -import java.util.function.BiConsumer +import org.utbot.fuzzer.ModelProvider.Companion.yieldValue /** * Traverses through method constants and creates appropriate models for them. */ object ConstantsModelProvider : ModelProvider { - override fun generate(description: FuzzedMethodDescription, consumer: BiConsumer) { + override fun generate(description: FuzzedMethodDescription): Sequence = sequence { description.concreteValues .asSequence() .filter { (classId, _) -> classId.isPrimitive } @@ -25,7 +26,7 @@ object ConstantsModelProvider : ModelProvider { .filterNotNull() .forEach { m -> description.parametersMap.getOrElse(m.model.classId) { emptyList() }.forEach { index -> - consumer.accept(index, m) + yieldValue(index, m) } } } diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/EnumModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/EnumModelProvider.kt index 68af765931..ed472ff9ca 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/EnumModelProvider.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/EnumModelProvider.kt @@ -5,18 +5,17 @@ import org.utbot.framework.plugin.api.util.id import org.utbot.framework.plugin.api.util.isSubtypeOf import org.utbot.framework.plugin.api.util.jClass import org.utbot.fuzzer.FuzzedMethodDescription -import org.utbot.fuzzer.FuzzedValue +import org.utbot.fuzzer.FuzzedParameter import org.utbot.fuzzer.ModelProvider -import org.utbot.fuzzer.ModelProvider.Companion.consumeAll -import java.util.function.BiConsumer +import org.utbot.fuzzer.ModelProvider.Companion.yieldAllValues object EnumModelProvider : ModelProvider { - override fun generate(description: FuzzedMethodDescription, consumer: BiConsumer) { + override fun generate(description: FuzzedMethodDescription): Sequence = sequence { description.parametersMap .asSequence() .filter { (classId, _) -> classId.isSubtypeOf(Enum::class.java.id) } .forEach { (classId, indices) -> - consumer.consumeAll(indices, classId.jClass.enumConstants.filterIsInstance>().map { + yieldAllValues(indices, classId.jClass.enumConstants.filterIsInstance>().map { UtEnumConstantModel(classId, it).fuzzed { summary = "%var% = ${it.name}" } }) } diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/NullModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/NullModelProvider.kt index 3aa9085d95..5e23a0f2c8 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/NullModelProvider.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/NullModelProvider.kt @@ -3,22 +3,23 @@ package org.utbot.fuzzer.providers import org.utbot.framework.plugin.api.UtNullModel import org.utbot.framework.plugin.api.util.isRefType import org.utbot.fuzzer.FuzzedMethodDescription -import org.utbot.fuzzer.FuzzedValue +import org.utbot.fuzzer.FuzzedParameter import org.utbot.fuzzer.ModelProvider -import java.util.function.BiConsumer +import org.utbot.fuzzer.ModelProvider.Companion.yieldValue /** * Provides [UtNullModel] for every reference class. */ @Suppress("unused") // disabled until fuzzer breaks test with null/nonnull annotations object NullModelProvider : ModelProvider { - override fun generate(description: FuzzedMethodDescription, consumer: BiConsumer) { + override fun generate(description: FuzzedMethodDescription): Sequence = sequence { description.parametersMap .asSequence() .filter { (classId, _) -> classId.isRefType } .forEach { (classId, indices) -> val model = UtNullModel(classId) - indices.forEach { consumer.accept(it, model.fuzzed { this.summary = "%var% = null" }) } + indices.forEach { + yieldValue(it, model.fuzzed { this.summary = "%var% = null" }) } } } } \ No newline at end of file diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ObjectModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ObjectModelProvider.kt index a383f642e3..7806569f57 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ObjectModelProvider.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ObjectModelProvider.kt @@ -16,8 +16,10 @@ import org.utbot.framework.plugin.api.util.stringClassId import org.utbot.framework.plugin.api.util.voidClassId import org.utbot.fuzzer.FuzzedConcreteValue import org.utbot.fuzzer.FuzzedMethodDescription +import org.utbot.fuzzer.FuzzedParameter import org.utbot.fuzzer.FuzzedValue import org.utbot.fuzzer.ModelProvider +import org.utbot.fuzzer.ModelProvider.Companion.yieldValue import org.utbot.fuzzer.exceptIsInstance import org.utbot.fuzzer.fuzz import org.utbot.fuzzer.objectModelProviders @@ -27,7 +29,6 @@ import java.lang.reflect.Field import java.lang.reflect.Member import java.lang.reflect.Method import java.lang.reflect.Modifier.* -import java.util.function.BiConsumer import java.util.function.IntSupplier /** @@ -66,7 +67,7 @@ class ObjectModelProvider : ModelProvider { this.modelProvider = objectModelProviders(idGenerator) } - override fun generate(description: FuzzedMethodDescription, consumer: BiConsumer) { + override fun generate(description: FuzzedMethodDescription): Sequence = sequence { val fuzzedValues = with(description) { parameters.asSequence() .filterNot { it == stringClassId || it.isPrimitiveWrapper } @@ -98,7 +99,7 @@ class ObjectModelProvider : ModelProvider { fuzzedValues.forEach { fuzzedValue -> description.parametersMap[fuzzedValue.model.classId]?.forEach { index -> - consumer.accept(index, fuzzedValue) + yieldValue(index, fuzzedValue) } } } @@ -111,7 +112,9 @@ class ObjectModelProvider : ModelProvider { voidClassId, fields.map { it.classId }, concreteValues - ) + ).apply { + packageName = description.packageName + } return fuzz(syntheticClassFieldsSetterMethodDescription, nonRecursiveModelProvider) .take(limitValuesCreatedByFieldAccessors) // limit the number of fuzzed values in this particular case @@ -164,7 +167,9 @@ class ObjectModelProvider : ModelProvider { val fuzzedMethod = FuzzedMethodDescription( executableId = constructorId, concreteValues = this.concreteValues - ) + ).apply { + this.packageName = this@fuzzParameters.packageName + } return fuzz(fuzzedMethod, *modelProviders) } diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/PrimitiveDefaultsModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/PrimitiveDefaultsModelProvider.kt index b28d0c69ee..621e3795c6 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/PrimitiveDefaultsModelProvider.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/PrimitiveDefaultsModelProvider.kt @@ -12,19 +12,20 @@ import org.utbot.framework.plugin.api.util.longClassId import org.utbot.framework.plugin.api.util.shortClassId import org.utbot.framework.plugin.api.util.stringClassId import org.utbot.fuzzer.FuzzedMethodDescription +import org.utbot.fuzzer.FuzzedParameter import org.utbot.fuzzer.FuzzedValue import org.utbot.fuzzer.ModelProvider -import java.util.function.BiConsumer +import org.utbot.fuzzer.ModelProvider.Companion.yieldValue /** * Provides default values for primitive types. */ object PrimitiveDefaultsModelProvider : ModelProvider { - override fun generate(description: FuzzedMethodDescription, consumer: BiConsumer) { + override fun generate(description: FuzzedMethodDescription): Sequence = sequence { description.parametersMap.forEach { (classId, parameterIndices) -> valueOf(classId)?.let { model -> parameterIndices.forEach { index -> - consumer.accept(index, model) + yieldValue(index, model) } } } diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/PrimitiveWrapperModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/PrimitiveWrapperModelProvider.kt index 2a568f9e04..a032ad609f 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/PrimitiveWrapperModelProvider.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/PrimitiveWrapperModelProvider.kt @@ -7,10 +7,10 @@ import org.utbot.framework.plugin.api.util.stringClassId import org.utbot.framework.plugin.api.util.voidClassId import org.utbot.framework.plugin.api.util.wrapperByPrimitive import org.utbot.fuzzer.FuzzedMethodDescription +import org.utbot.fuzzer.FuzzedParameter import org.utbot.fuzzer.FuzzedValue import org.utbot.fuzzer.ModelProvider -import org.utbot.fuzzer.ModelProvider.Companion.consumeAll -import java.util.function.BiConsumer +import org.utbot.fuzzer.ModelProvider.Companion.yieldAllValues object PrimitiveWrapperModelProvider: ModelProvider { @@ -20,7 +20,7 @@ object PrimitiveWrapperModelProvider: ModelProvider { StringConstantModelProvider ) - override fun generate(description: FuzzedMethodDescription, consumer: BiConsumer) { + override fun generate(description: FuzzedMethodDescription): Sequence = sequence { val primitiveWrapperTypesAsPrimitiveTypes = description.parametersMap .keys .asSequence() @@ -36,16 +36,16 @@ object PrimitiveWrapperModelProvider: ModelProvider { }.toList() if (primitiveWrapperTypesAsPrimitiveTypes.isEmpty()) { - return + return@sequence } val constants = mutableMapOf>() constantModels.generate(FuzzedMethodDescription( - name = this::class.simpleName + " constant generation ", + name = "Primitive wrapper constant generation ", returnType = voidClassId, parameters = primitiveWrapperTypesAsPrimitiveTypes, concreteValues = description.concreteValues - )) { index, value -> + )).forEach { (index, value) -> val primitiveWrapper = wrapperByPrimitive[primitiveWrapperTypesAsPrimitiveTypes[index]] if (primitiveWrapper != null) { constants.computeIfAbsent(primitiveWrapper) { mutableListOf() }.add(value) @@ -57,7 +57,7 @@ object PrimitiveWrapperModelProvider: ModelProvider { .filter { (classId, _) -> classId == stringClassId || classId.isPrimitiveWrapper } .forEach { (classId, indices) -> constants[classId]?.let { models -> - consumer.consumeAll(indices, models) + yieldAllValues(indices, models) } } } diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/PrimitivesModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/PrimitivesModelProvider.kt index ee206cfbf8..5c9ffe4090 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/PrimitivesModelProvider.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/PrimitivesModelProvider.kt @@ -3,15 +3,16 @@ package org.utbot.fuzzer.providers import org.utbot.framework.plugin.api.UtPrimitiveModel import org.utbot.framework.plugin.api.util.* import org.utbot.fuzzer.FuzzedMethodDescription +import org.utbot.fuzzer.FuzzedParameter import org.utbot.fuzzer.FuzzedValue import org.utbot.fuzzer.ModelProvider -import java.util.function.BiConsumer +import org.utbot.fuzzer.ModelProvider.Companion.yieldValue /** * Produces bound values for primitive types. */ object PrimitivesModelProvider : ModelProvider { - override fun generate(description: FuzzedMethodDescription, consumer: BiConsumer) { + override fun generate(description: FuzzedMethodDescription): Sequence = sequence { description.parametersMap.forEach { (classId, parameterIndices) -> val primitives: List = when (classId) { booleanClassId -> listOf( @@ -81,7 +82,7 @@ object PrimitivesModelProvider : ModelProvider { primitives.forEach { model -> parameterIndices.forEach { index -> - consumer.accept(index, model) + yieldValue(index, model) } } } diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/StringConstantModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/StringConstantModelProvider.kt index 9beff9b93b..cc2e22dba4 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/StringConstantModelProvider.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/StringConstantModelProvider.kt @@ -4,14 +4,14 @@ import org.utbot.framework.plugin.api.UtPrimitiveModel import org.utbot.framework.plugin.api.util.stringClassId import org.utbot.fuzzer.FuzzedMethodDescription import org.utbot.fuzzer.FuzzedOp -import org.utbot.fuzzer.FuzzedValue +import org.utbot.fuzzer.FuzzedParameter import org.utbot.fuzzer.ModelProvider -import java.util.function.BiConsumer +import org.utbot.fuzzer.ModelProvider.Companion.yieldValue import kotlin.random.Random object StringConstantModelProvider : ModelProvider { - override fun generate(description: FuzzedMethodDescription, consumer: BiConsumer) { + override fun generate(description: FuzzedMethodDescription): Sequence = sequence { val random = Random(72923L) description.concreteValues .asSequence() @@ -22,7 +22,7 @@ object StringConstantModelProvider : ModelProvider { .filterNotNull() .map { UtPrimitiveModel(it) }.forEach { model -> description.parametersMap.getOrElse(model.classId) { emptyList() }.forEach { index -> - consumer.accept(index, model.fuzzed { summary = "%var% = string" }) + yieldValue(index, model.fuzzed { summary = "%var% = string" }) } } } diff --git a/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/FuzzedValueDescriptionTest.kt b/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/FuzzedValueDescriptionTest.kt index e08ae0f48f..ab95fe25d0 100644 --- a/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/FuzzedValueDescriptionTest.kt +++ b/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/FuzzedValueDescriptionTest.kt @@ -45,7 +45,7 @@ class FuzzedValueDescriptionTest { parameters = listOf(intClassId), concreteValues = concreteValues ) - ) { _, value -> values.add(value) } + ).forEach { (_, value) -> values.add(value) } assertEquals(expected, values.size) { "Expected $expected values: a half is origin values and another is modified, but only ${values.size} are generated" } diff --git a/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/ModelProviderTest.kt b/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/ModelProviderTest.kt index 4be6de845c..0216bf6942 100644 --- a/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/ModelProviderTest.kt +++ b/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/ModelProviderTest.kt @@ -28,6 +28,7 @@ import org.utbot.framework.plugin.api.samples.PackagePrivateFieldAndClass import org.utbot.framework.plugin.api.util.primitiveByWrapper import org.utbot.framework.plugin.api.util.primitiveWrappers import org.utbot.framework.plugin.api.util.voidWrapperClassId +import org.utbot.fuzzer.ModelProvider.Companion.yieldValue import org.utbot.fuzzer.defaultModelProviders import org.utbot.fuzzer.providers.EnumModelProvider import org.utbot.fuzzer.providers.EnumModelProvider.fuzzed @@ -254,8 +255,10 @@ class ModelProviderTest { @Test fun `test fallback model can create custom values for any parameter`() { - val firstParameterIsUserGenerated = ModelProvider { _, consumer -> - consumer.accept(0, UtPrimitiveModel(-123).fuzzed()) + val firstParameterIsUserGenerated = ModelProvider { + sequence { + yieldValue(0, UtPrimitiveModel(-123).fuzzed()) + } }.withFallback(PrimitivesModelProvider) val result = collect( @@ -513,7 +516,7 @@ class ModelProviderTest { block: FuzzedMethodDescription.() -> Unit = {} ): Map> { return mutableMapOf>().apply { - modelProvider.generate(FuzzedMethodDescription(name, returnType, parameters, constants).apply(block)) { i, m -> + modelProvider.generate(FuzzedMethodDescription(name, returnType, parameters, constants).apply(block)).forEach { (i, m) -> computeIfAbsent(i) { mutableListOf() }.add(m.model) } }