diff --git a/.github/workflows/build-and-run-tests-from-branch.yml b/.github/workflows/build-and-run-tests-from-branch.yml index 3f52f106f4..cf27f2a885 100644 --- a/.github/workflows/build-and-run-tests-from-branch.yml +++ b/.github/workflows/build-and-run-tests-from-branch.yml @@ -242,7 +242,7 @@ jobs: # The option forces to execute all jobs even though some of them have failed. fail-fast: false matrix: - project: [utbot-core, utbot-fuzzers, utbot-gradle, utbot-junit-contest, utbot-sample] + project: [utbot-core, utbot-java-fuzzing, utbot-gradle, utbot-junit-contest, utbot-sample] runs-on: ubuntu-20.04 container: image: unittestbot/java-env:java17-zulu-jdk-gradle7.6.1-kotlinc1.8.0 diff --git a/.github/workflows/run-chosen-tests-from-branch.yml b/.github/workflows/run-chosen-tests-from-branch.yml index 7aecccc73c..788f6187f4 100644 --- a/.github/workflows/run-chosen-tests-from-branch.yml +++ b/.github/workflows/run-chosen-tests-from-branch.yml @@ -14,7 +14,7 @@ on: - utbot-core - utbot-framework-api - utbot-framework - - utbot-fuzzers + - utbot-java-fuzzing - utbot-gradle - utbot-instrumentation-tests - utbot-instrumentation diff --git a/build.gradle.kts b/build.gradle.kts index 259ec1b8e2..32acd8fe3d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -189,7 +189,7 @@ configure( project(":utbot-core"), project(":utbot-framework"), project(":utbot-framework-api"), - project(":utbot-fuzzers"), + project(":utbot-java-fuzzing"), project(":utbot-instrumentation"), project(":utbot-rd"), project(":utbot-summary") diff --git a/settings.gradle.kts b/settings.gradle.kts index c80a375ffc..f5a36b11a5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -24,7 +24,7 @@ include("utbot-framework") include("utbot-framework-api") include("utbot-intellij") include("utbot-sample") -include("utbot-fuzzers") +include("utbot-java-fuzzing") include("utbot-fuzzing") include("utbot-junit-contest") include("utbot-analytics") diff --git a/utbot-framework-test/build.gradle b/utbot-framework-test/build.gradle index 012d6e7c3f..b09414db71 100644 --- a/utbot-framework-test/build.gradle +++ b/utbot-framework-test/build.gradle @@ -14,7 +14,7 @@ dependencies { api project(':utbot-framework-api') testImplementation project(':utbot-testing') - api project(':utbot-fuzzers') + api project(':utbot-java-fuzzing') api project(':utbot-instrumentation') api project(':utbot-summary') diff --git a/utbot-framework/build.gradle b/utbot-framework/build.gradle index 3e0cd02564..8f7bda2b25 100644 --- a/utbot-framework/build.gradle +++ b/utbot-framework/build.gradle @@ -1,6 +1,6 @@ dependencies { - api project(':utbot-fuzzers') + api project(':utbot-java-fuzzing') api project(':utbot-instrumentation') api project(':utbot-summary') api project(':utbot-framework-api') diff --git a/utbot-framework/src/main/kotlin/org/utbot/fuzzer/FallbackModelProvider.kt b/utbot-framework/src/main/kotlin/org/utbot/fuzzer/FallbackModelProvider.kt deleted file mode 100644 index ce5447c1c6..0000000000 --- a/utbot-framework/src/main/kotlin/org/utbot/fuzzer/FallbackModelProvider.kt +++ /dev/null @@ -1,111 +0,0 @@ -package org.utbot.fuzzer - -import org.utbot.common.isPublic -import org.utbot.instrumentation.instrumentation.execution.constructors.UtModelConstructor -import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.UtArrayModel -import org.utbot.framework.plugin.api.UtAssembleModel -import org.utbot.framework.plugin.api.UtCompositeModel -import org.utbot.framework.plugin.api.UtExecutableCallModel -import org.utbot.framework.plugin.api.UtModel -import org.utbot.framework.plugin.api.UtNullModel -import org.utbot.framework.plugin.api.util.defaultValueModel -import org.utbot.framework.plugin.api.util.executableId -import org.utbot.framework.plugin.api.util.id -import org.utbot.framework.plugin.api.util.isArray -import org.utbot.framework.plugin.api.util.isClassType -import org.utbot.framework.plugin.api.util.isEnum -import org.utbot.framework.plugin.api.util.isIterable -import org.utbot.framework.plugin.api.util.isPrimitive -import org.utbot.framework.plugin.api.util.jClass -import org.utbot.framework.plugin.api.util.kClass -import org.utbot.fuzzer.providers.AbstractModelProvider -import java.util.* -import kotlin.collections.ArrayList -import kotlin.collections.HashMap -import kotlin.reflect.KClass - -/** - * Provides some simple default models of any class. - * - * Used as a fallback implementation until other providers cover every type. - */ -open class FallbackModelProvider( - private val idGenerator: IdGenerator -): AbstractModelProvider() { - - override fun toModel(classId: ClassId): UtModel { - return createModelByClassId(classId) - } - - fun toModel(klazz: KClass<*>): UtModel = createSimpleModelByKClass(klazz) - - private fun createModelByClassId(classId: ClassId): UtModel { - val modelConstructor = UtModelConstructor(IdentityHashMap()) - val defaultConstructor = classId.jClass.constructors.firstOrNull { - it.parameters.isEmpty() && it.isPublic - } - return when { - classId.isPrimitive || classId.isEnum || classId.isClassType -> - classId.defaultValueModel() - classId.isArray -> - UtArrayModel( - id = idGenerator.createId(), - classId, - length = 0, - classId.elementClassId!!.defaultValueModel(), - mutableMapOf() - ) - classId.isIterable -> { - @Suppress("RemoveRedundantQualifierName") // ArrayDeque must be taken from java, not from kotlin - val defaultInstance = when { - defaultConstructor != null -> defaultConstructor.newInstance() - classId.jClass.isAssignableFrom(java.util.ArrayList::class.java) -> ArrayList() - classId.jClass.isAssignableFrom(java.util.TreeSet::class.java) -> TreeSet() - classId.jClass.isAssignableFrom(java.util.HashMap::class.java) -> HashMap() - classId.jClass.isAssignableFrom(java.util.ArrayDeque::class.java) -> java.util.ArrayDeque() - classId.jClass.isAssignableFrom(java.util.BitSet::class.java) -> BitSet() - else -> null - } - if (defaultInstance != null) - modelConstructor.construct(defaultInstance, classId) - else - createSimpleModelByKClass(classId.kClass) - } - else -> - createSimpleModelByKClass(classId.kClass) - } - } - - private fun createSimpleModelByKClass(kclass: KClass<*>): UtModel { - val defaultConstructor = kclass.java.constructors.firstOrNull { - it.parameters.isEmpty() && it.isPublic // check constructor is public - } - return when { - kclass.isAbstract -> { - // sealed class is abstract by itself - UtNullModel(kclass.java.id) - - } - kclass.java.isEnum || kclass == java.lang.Class::class -> { - // No sensible fallback solution for these classes except returning default `null` value - UtNullModel(kclass.java.id) - } - defaultConstructor != null -> { - UtAssembleModel( - id = idGenerator.createId(), - kclass.id, - kclass.id.toString(), - UtExecutableCallModel(instance = null, defaultConstructor.executableId, listOf()) - ) - } - else -> { - UtCompositeModel( - id = idGenerator.createId(), - kclass.id, - isMock = false - ) - } - } - } -} diff --git a/utbot-fuzzers/readme.md b/utbot-fuzzers/readme.md deleted file mode 100644 index f15cb0b06f..0000000000 --- a/utbot-fuzzers/readme.md +++ /dev/null @@ -1,206 +0,0 @@ -# UTBot Fuzzer - -Fuzzer generates method input values to improve method coverage or find unexpected errors. In UTBot next strategies can be used to find values like: - -* **Default values** for objects, e.g. 0, 0.0, empty string or null values. -* **Corner case values** of primitives types, e.g. Integer.MAX_VALUE, Double.POSITIVE_INFINITY, etc. -* **Method constants and their simple mutations** of primitive types. -* **Objects** created via its constructors or field mutators. - -After values are found fuzzer creates all its possible combinations and runs methods with these combinations. - -For example, if a method has two parameters of types `boolean` and `int` the follow values can be found: -``` -boolean = [false, true] -int = [0, MAX_VALUE, MIN_VALUE] -``` - -Now, fuzzer creates `2 * 3 = 6` combinations of them: - -``` -[false, 0], [false, MAX_VALUE], [false, MIN_VALUE], [true, 0], [true, MAX_VALUE], [true, MIN_VALUE] -``` - -To find more branches of execution as fast as possible fuzzer also shuffles -combinations and supplies them for the running. - -## Design - -Fuzzer requires model providers that create a set of `UtModel` for a given `ClassId`. -Fuzzer iterates through these providers and creates models, which are used for generating combinations later. -Each combination contains concrete values that can be accepted by the method. -For example, if a method has signature with `String, double, int` as parameters then fuzzer can create combination `"sometext", Double.POSITIVE_INFINITY, 0`. - -Fuzzer's entry point is: -```kotlin -// org.utbot.fuzzer.FuzzerKt -fun fuzz(method: FuzzedMethodDescription, vararg models: ModelProvider): Sequence> -``` - -`FuzzedMethodDescription` stores comprehensive information about a method: -* signature (parameters and return types) -* name/package/class (optional) -* constants found in the method body (should be replaced with CGF when possible) - -`ModelProvider` provides models for a give parameters set as described below. - -Fuzz method returns a sequence of acceptable values for the method in random order. The sequence is lazy. - -Model provider should implement - -```kotlin -fun generate(description: FuzzedMethodDescription): Sequence -``` -For every parameter should exist at least one `UtModel`. `ModelProvider.withFallback` can be used to process those classes which cannot be processed by provider. -Several providers can be combined into one by using `ModelProvider.with(anotherModel: ModelProvider)`. - -Common way to generate all combinations is: - -```kotlin -ObjectModelProvider() - .with(PrimitiveModelProvider) - // ... - .with(ObjectModelProvider) - .withFallback { classId -> - createDefaultModelByClass(classID) - } -``` -or - -```kotlin -// org.utbot.fuzzer.FuzzerKt -fun defaultModelProviders(idGenerator: IntSupplier) -``` - -## List of builtin providers - -### PrimitiveDefaultsModelProvider - -Creates default values for every primitive types: - -``` -boolean: false -byte: 0 -short: 0 -int: 0 -long: 0 -float: 0.0 -double: 0.0 -char: \u0000 -string: "" -``` - -### PrimitiveModelProvider - -Creates default values and some corner case values such as Integer.MAX_VALUE, 0.0, Double.NaN, empty string, etc. - -``` -boolean: false, true -byte: 0, 1, -1, Byte.MIN_VALUE, Byte.MAX_VALUE -short: 0, 1, -1, Short.MIN_VALUE, Short.MAX_VALUE -int: 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE -long: 0, 1, -1, Long.MIN_VALUE, Long.MAX_VALUE -float: 0.0, 1.1, -1.1, Float.MIN_VALUE, Float.MAX_VALUE, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, Float.NaN -double: 0.0, 1.1, -1.1, Double.MIN_VALUE, Double.MAX_VALUE, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Double.NaN -char: Char.MIN_VALUE, Char.MAX_VALUE -string: "", " ", "string", "\n\t\r" -``` - -### PrimitiveWrapperModelProvider - -Creates primitive models for boxed types: `Boolean`, `Byte`, `Short`, `Integer`, `Long`, `Double`, `Float`, `Character`, `String` - -### ConstantsModelProvider - -Uses information about concrete values from `FuzzedMethodDescription#concreteValues` to generate simple values. -Only primitive values are supported. - -### NullModelProvider - -Creates `UtNullModel` for every reference class. - -### EnumModelProvider - -Creates models for any enum type. - -### CollectionModelProvider - -Creates concrete collections for collection interfaces: `List`, `Set`, `Map`, `Collection`, `Iterable`, `Iterator` - -### ArrayModelProvider - -Creates an empty and non-empty for any type. - -### ObjectModelProvider - -ObjectModelProvider is the most sophisticated provider. It creates model of class that has public constructors -and public mutators (fields or setters/getters). If class has constructor that accepts another object within an argument that value -is created recursively. Depth of recursion is limited to 1. Thus, for inner object fuzzing doesn't try to use every -constructor but find the one with the least number of parameters and, if it is possible, only -constructor with primitives values. If there is available only constructor with another object as a parameter then -`null` is passed to it. - -Let's look at this example: - -```java -class A { - private int a; - private Object object; - - public A(int a, A o) { - this.a = a; - this.o = o; - } -} -``` - -For it fuzzing create these models: -``` -new Object(0, new A(0, null)); -new Object(Integer.MIN_VALUE, new A(0, null)); -new Object(Integer.MAX_VALUE, new A(0, null)); -new Object(0, new A(Integer.MIN_VALUE, null)); -new Object(Integer.MIN_VALUE, new A(Integer.MIN_VALUE, null)); -new Object(Integer.MAX_VALUE, new A(Integer.MIN_VALUE, null)); -new Object(0, new A(Integer.MAX_VALUE, null)); -new Object(Integer.MIN_VALUE, new A(Integer.MAX_VALUE, null)); -new Object(Integer.MAX_VALUE, new A(Integer.MAX_VALUE, null)); -``` - -For classes that have empty public constructor and field mutators all those mutators will be fuzzed as well. -Field mutators are listed below: -* public or package-private (and accessible) non-final non-static fields -* pairs of setter/getter that satisfy the common agreement: - * setter/getter is public or package-private (and accessible) - * have field name as a postfix, e.g.: `int myField -> * setMyField(int v)/int getMyField()`, where * means any returned type - -For example, fields _a_, _b_ and _d_ will be fuzzed, but _c_ and _e_ will not: - -```java -class A { - int a; - public char b; - public final int c = 0; - private String d; - private boolean e; - - public A setD(String s) { - this.d = s; - return this; - } - - public String getD() { - return d; - } - - public boolean getE() { - return e; - } -} -``` - -### Other providers - -There are several other providers that can find some values, using addition information, -like `CharToStringModelProvider` that takes all chars found in `charAt(i) == c` statement -and merge them into several strings. \ No newline at end of file diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzedParameter.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzedParameter.kt deleted file mode 100644 index 2009a5b9e2..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzedParameter.kt +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index fd61469f8a..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/Fuzzer.kt +++ /dev/null @@ -1,271 +0,0 @@ -package org.utbot.fuzzer - -import mu.KotlinLogging -import org.utbot.framework.plugin.api.UtPrimitiveModel -import org.utbot.framework.plugin.api.util.intClassId -import org.utbot.framework.plugin.api.util.voidClassId -import org.utbot.fuzzer.mutators.NumberRandomMutator -import org.utbot.fuzzer.mutators.RegexStringModelMutator -import org.utbot.fuzzer.mutators.StringRandomMutator -import org.utbot.fuzzer.objects.replaceWithMock -import org.utbot.fuzzer.providers.ArrayModelProvider -import org.utbot.fuzzer.providers.CharToStringModelProvider -import org.utbot.fuzzer.providers.CollectionWithEmptyStatesModelProvider -import org.utbot.fuzzer.providers.ConstantsModelProvider -import org.utbot.fuzzer.providers.EnumModelProvider -import org.utbot.fuzzer.providers.CollectionWithModificationModelProvider -import org.utbot.fuzzer.providers.NumberClassModelProvider -import org.utbot.fuzzer.providers.ObjectModelProvider -import org.utbot.fuzzer.providers.PrimitiveDefaultsModelProvider -import org.utbot.fuzzer.providers.PrimitiveWrapperModelProvider -import org.utbot.fuzzer.providers.PrimitivesModelProvider -import org.utbot.fuzzer.providers.RegexModelProvider -import org.utbot.fuzzer.providers.StringConstantModelProvider -import java.util.* -import java.util.concurrent.atomic.AtomicInteger -import kotlin.random.Random -import org.utbot.fuzzer.providers.DateConstantModelProvider -import org.utbot.fuzzer.providers.PrimitiveRandomModelProvider -import org.utbot.fuzzer.providers.RecursiveModelProvider -import org.utbot.fuzzing.utils.CartesianProduct - -private val logger by lazy { KotlinLogging.logger {} } - -/** - * Identifier generator interface for fuzzer model providers. - * - * Provides fresh identifiers for generated models. - * - * Warning: specific generators are not guaranteed to be thread-safe. - * - * @param Id the identifier type (e.g., [Int] for [UtReferenceModel] providers) - */ -interface IdGenerator { - /** - * Create a fresh identifier. Each subsequent call should return a different value. - * - * The method is not guaranteed to be thread-safe, unless an implementation makes such a guarantee. - */ - fun createId(): Id -} - -/** - * Identity preserving identifier generator interface. - * - * It allows to optionally save identifiers assigned to specific objects and later get the same identifiers - * for these objects instead of fresh identifiers. This feature is necessary, for example, to implement reference - * equality for enum models. - * - * Warning: specific generators are not guaranteed to be thread-safe. - * - * @param Id the identifier type (e.g., [Int] for [UtReferenceModel] providers) - */ -interface IdentityPreservingIdGenerator : IdGenerator { - /** - * Return an identifier for a specified non-null object. If an identifier has already been assigned - * to an object, subsequent calls should return the same identifier for this object. - * - * Note: the interface does not specify whether reference equality or regular `equals`/`compareTo` equality - * will be used to compare objects. Each implementation may provide these guarantees by itself. - * - * The method is not guaranteed to be thread-safe, unless an implementation makes such a guarantee. - */ - fun getOrCreateIdForValue(value: Any): Id -} - -/** - * An identity preserving id generator for fuzzer value providers that returns identifiers of type [Int]. - * - * When identity-preserving identifier is requested, objects are compared by reference. - * The generator is not thread-safe. - * - * @param lowerBound an integer value so that any generated identifier is strictly greater than it. - * - * Warning: when generating [UtReferenceModel] identifiers, no identifier should be equal to zero, - * as this value is reserved for [UtNullModel]. To guarantee it, [lowerBound] should never be negative. - * Avoid using custom lower bounds (maybe except fuzzer unit tests), use the predefined default value instead. - */ -class ReferencePreservingIntIdGenerator(lowerBound: Int = DEFAULT_LOWER_BOUND) : IdentityPreservingIdGenerator { - private val lastId: AtomicInteger = AtomicInteger(lowerBound) - private val cache: IdentityHashMap = IdentityHashMap() - - override fun getOrCreateIdForValue(value: Any): Int { - return cache.getOrPut(value) { createId() } - } - - override fun createId(): Int { - return lastId.incrementAndGet() - } - - companion object { - /** - * The default lower bound (all generated integer identifiers will be greater than it). - * - * It is defined as a large value because all synthetic [UtModel] instances - * must have greater identifiers than the real models. - */ - const val DEFAULT_LOWER_BOUND: Int = 1500_000_000 - } -} - -/** - * Generated by fuzzer sequence of values which can be passed into the method. - */ -fun fuzz(description: FuzzedMethodDescription, vararg modelProviders: ModelProvider): Sequence> { - if (modelProviders.isEmpty()) { - throw IllegalArgumentException("At least one model provider is required") - } - - val values = List>(description.parameters.size) { mutableListOf() } - modelProviders.forEach { fuzzingProvider -> - fuzzingProvider.generate(description).forEach { (index, model) -> - val mock = replaceWithMock(model.model, description.shouldMock) - values[index].add(FuzzedValue(mock).apply { - summary = model.summary - }) - } - } - description.parameters.forEachIndexed { index, classId -> - val models = values[index] - if (models.isEmpty()) { - logger.warn { "There's no models provided classId=$classId. No suitable values are generated for ${description.name}" } - return emptySequence() - } - } - return CartesianProduct(values, Random(0L)).asSequence() -} - -/** - * Wraps sequence of values, iterates through them and mutates. - * - * Mutation when possible is generated after every value of source sequence and then supplies values until it needed. - * [statistics] should not be updated by this method, but can be changed by caller. - */ -fun Sequence>.withMutations(statistics: FuzzerStatistics, description: FuzzedMethodDescription, vararg mutators: ModelMutator) = sequence { - val fvi = iterator() - val mutatorList = mutators.toList() - val random = Random(0L) - while (fvi.hasNext()) { - // Takes a value that was generated by model providers and submits it - yield(fvi.next()) - // Fuzzing can generate values that don't recover new paths. - // So, fuzzing tries to mutate values on each loop - // if there are too many attempts to find new paths without mutations. - yieldMutated(statistics, description, mutatorList, random) - } - // try mutations if fuzzer tried all combinations if any seeds are available - @Suppress("ControlFlowWithEmptyBody") - while (yieldMutated(statistics, description, mutatorList, random)) {} -} - -/** - * Create a sequence that contains all [defaultValues] plus any value which is found as fuzzing with concrete values. - * - * Method is useful for generating some bound values, - * for example, when for code `array.length > 4` there are 2 values in concrete value: 4 and 5. - * - * All values after filtering are cast to [Int]. - */ -fun fuzzNumbers(concreteValues: Collection, vararg defaultValues: Int, filter: (Number) -> Boolean = { true }): Sequence { - val description = FuzzedMethodDescription("helper: number fuzzing", voidClassId, listOf(intClassId), concreteValues) - val fuzzedValues = fuzz(description, ConstantsModelProvider) - .mapNotNull { ((it.single().model as? UtPrimitiveModel)?.value as? Number) } - .filter(filter) - .map { it.toInt() } - return (defaultValues.asSequence() + fuzzedValues).distinct() -} - -/** - * Creates a model provider from a list of default providers. - */ -fun defaultModelProviders(idGenerator: IdentityPreservingIdGenerator): ModelProvider { - return modelProviderForRecursiveCalls(idGenerator, recursionDepth = -1) - .with(ObjectModelProvider(idGenerator)) - .with(ArrayModelProvider(idGenerator)) - .with(CollectionWithModificationModelProvider(idGenerator)) - .exceptIsInstance() - .except(PrimitiveDefaultsModelProvider) - .with(PrimitivesModelProvider) -} - -/** - * Creates a model provider from a list of providers that we want to use by default in [RecursiveModelProvider] - */ -internal fun modelProviderForRecursiveCalls(idGenerator: IdentityPreservingIdGenerator, recursionDepth: Int): ModelProvider { - val nonRecursiveProviders = ModelProvider.of( - CollectionWithEmptyStatesModelProvider(idGenerator), - EnumModelProvider(idGenerator), - DateConstantModelProvider(idGenerator), - RegexModelProvider, - StringConstantModelProvider, - CharToStringModelProvider, - ConstantsModelProvider, - PrimitiveRandomModelProvider(Random(0)), - PrimitiveDefaultsModelProvider, - PrimitiveWrapperModelProvider, - NumberClassModelProvider(idGenerator, Random(0)), - ) - - return if (recursionDepth >= 0) { - nonRecursiveProviders - .with(ObjectModelProvider(idGenerator, recursionDepth)) - .with(ArrayModelProvider(idGenerator, recursionDepth)) - .with(CollectionWithModificationModelProvider(idGenerator, recursionDepth)) - } else { - nonRecursiveProviders - } -} - - -fun defaultModelMutators(): List = listOf( - StringRandomMutator, - RegexStringModelMutator, - NumberRandomMutator, -) - -/** - * Tries to mutate a random value from the seed. - * - * Returns `null` if didn't try to do any mutation. - */ -fun mutateRandomValueOrNull( - statistics: FuzzerStatistics, - description: FuzzedMethodDescription, - mutators: List = defaultModelMutators(), - random: Random = Random, -): List? { - if (mutators.isEmpty()) return null - val values = statistics.takeIf { it.isNotEmpty() }?.randomValues(random) ?: return null - var newValues :MutableList? = null - mutators.asSequence() - .forEach { mut -> - mut.mutate(description, values, random).forEach { (index, value) -> - newValues = (newValues ?: values.toMutableList()) - newValues?.set(index, value) - } - } - return newValues -} - -/** - * Run mutations and yields values into the sequence. - * - * Mutations are supplied infinitely until [repeat] returns true. [repeat] is run before mutation. - * - * @param statistics coverage-based seed - * @param description method description - * @param mutators mutators which are applied to the random value - * @param random instance that is used to choose random index from the [statistics] - */ -suspend fun SequenceScope>.yieldMutated( - statistics: FuzzerStatistics, - description: FuzzedMethodDescription, - mutators: List, - random: Random -) : Boolean { - mutateRandomValueOrNull(statistics, description, mutators, random)?.let { - yield(it) - return true - } - return false -} \ No newline at end of file diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzerStatistics.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzerStatistics.kt deleted file mode 100644 index 2328362ce3..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzerStatistics.kt +++ /dev/null @@ -1,73 +0,0 @@ -package org.utbot.fuzzer - -import org.utbot.fuzzing.utils.Trie -import org.utbot.fuzzing.utils.chooseOne -import kotlin.math.pow -import kotlin.random.Random - -/** - * Stores information that can be useful for fuzzing such as coverage, run count, etc. - */ -interface FuzzerStatistics { - - val seeds: Collection - - /** - * Returns a random seed to process. - */ - fun randomSeed(random: Random): K? - - fun randomValues(random: Random): List? - - fun executions(seed: K): Int - - operator fun get(seed: K): List? - - fun isEmpty(): Boolean - - fun isNotEmpty(): Boolean { - return !isEmpty() - } -} - -class TrieBasedFuzzerStatistics( - private val values: LinkedHashMap, List> = linkedMapOf() -) : FuzzerStatistics> { - - override val seeds: Collection> - get() = values.keys - - override fun randomSeed(random: Random): Trie.Node? { - return values.keys.elementAtOrNull(randomIndex(random)) - } - - override fun isEmpty(): Boolean { - return values.isEmpty() - } - - override fun isNotEmpty(): Boolean { - return values.isNotEmpty() - } - - override fun randomValues(random: Random): List? { - return values.values.elementAtOrNull(randomIndex(random)) - } - - private fun randomIndex(random: Random): Int { - val frequencies = DoubleArray(values.size).also { f -> - values.keys.forEachIndexed { index, key -> - f[index] = 1 / key.count.toDouble().pow(2) - } - } - return random.chooseOne(frequencies) - } - - override fun get(seed: Trie.Node): List? { - return values[seed] - } - - override fun executions(seed: Trie.Node): Int { - return seed.count - } - -} \ No newline at end of file diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/ModelMutator.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/ModelMutator.kt deleted file mode 100644 index dc80cf4997..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/ModelMutator.kt +++ /dev/null @@ -1,44 +0,0 @@ -package org.utbot.fuzzer - -import org.utbot.framework.plugin.api.UtModel -import kotlin.random.Random - -/** - * Mutates values and returns it. - */ -interface ModelMutator { - - /** - * Mutates values set. - * - * Default implementation iterates through values and delegates to `mutate(FuzzedMethodDescription, Int, Random)`. - */ - fun mutate( - description: FuzzedMethodDescription, - parameters: List, - random: Random, - ) : List { - return parameters - .asSequence() - .mapIndexedNotNull { index, fuzzedValue -> - mutate(description, index, fuzzedValue, random)?.let { mutated -> - FuzzedParameter(index, mutated) - } - } - .toList() - } - - /** - * Mutate a single value if it is possible. - */ - fun mutate( - description: FuzzedMethodDescription, - index: Int, - value: FuzzedValue, - random: Random - ) : FuzzedValue? - - fun UtModel.mutatedFrom(template: FuzzedValue, block: FuzzedValue.() -> Unit = {}): FuzzedValue { - return FuzzedValue(this).apply(block) - } -} \ No newline at end of file diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/ModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/ModelProvider.kt deleted file mode 100644 index 540f73e57a..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/ModelProvider.kt +++ /dev/null @@ -1,164 +0,0 @@ -package org.utbot.fuzzer - -import org.utbot.framework.plugin.api.UtModel -import org.utbot.framework.plugin.api.ClassId - -fun interface ModelProvider { - - /** - * Generates values for the method. - * - * @param description a fuzzed method description - * @return sequence that produces [FuzzedParameter]. - */ - fun generate(description: FuzzedMethodDescription): Sequence - - /** - * Combines this model provider with `anotherModelProvider` into one instance. - * - * This model provider is called before `anotherModelProvider`. - */ - fun with(anotherModelProvider: ModelProvider): ModelProvider { - fun toList(m: ModelProvider) = if (m is Combined) m.providers else listOf(m) - return Combined(toList(this) + toList(anotherModelProvider)) - } - - /** - * Removes `anotherModelProvider` from current one. - */ - fun except(anotherModelProvider: ModelProvider): ModelProvider { - return except { it == anotherModelProvider } - } - - /** - * Removes `anotherModelProvider` from current one. - */ - fun except(filter: (ModelProvider) -> Boolean): ModelProvider { - return if (this is Combined) { - Combined(providers.filterNot(filter)) - } else { - Combined(if (filter(this)) emptyList() else listOf(this)) - } - } - - /** - * Applies [transform] for current provider - */ - fun map(transform: (ModelProvider) -> ModelProvider): ModelProvider { - return if (this is Combined) { - Combined(providers.map(transform)) - } else { - transform(this) - } - } - - /** - * Creates [ModelProvider] that passes unprocessed classes to `modelProvider`. - * - * Returned model provider is called before `modelProvider` is called, therefore consumer will get values - * from returned model provider and only after it calls `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 { - 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.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) - } - } - } - } - } - } - } - - /** - * Creates [ModelProvider] that passes unprocessed classes to `fallbackModelSupplier` function. - * - * This model provider is called before function is called, therefore consumer will get values - * from this model provider and only after it created by `fallbackModelSupplier`. - * - * @param fallbackModelSupplier is called for every [ClassId] which wasn't created by this model provider. - */ - fun withFallback(fallbackModelSupplier: (ClassId) -> UtModel?) : ModelProvider { - return withFallback( ModelProvider { description -> - sequence { - description.parametersMap.forEach { (classId, indices) -> - fallbackModelSupplier(classId)?.let { model -> - indices.forEach { index -> - yieldValue(index, model.fuzzed()) - } - } - } - } - }) - } - - companion object { - @JvmStatic - fun of(vararg providers: ModelProvider): ModelProvider { - return Combined(providers.toList()) - } - - 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) - } - } - } - - suspend fun SequenceScope.yieldAllValues(indices: List, models: List) { - yieldAllValues(indices, models.asSequence()) - } - } - - /** - * Wrapper class that delegates implementation to the [providers]. - */ - private class Combined(providers: List): ModelProvider { - val providers: List - - init { - // Flattening to avoid Combined inside Combined (for correct work of except, map, etc.) - this.providers = providers.flatMap { - if (it is Combined) - it.providers - else - listOf(it) - } - } - - override fun generate(description: FuzzedMethodDescription): Sequence = sequence { - providers.forEach { provider -> - provider.generate(description).forEach { - yieldValue(it.index, it.value) - } - } - } - } - - fun UtModel.fuzzed(block: FuzzedValue.() -> Unit = {}): FuzzedValue = FuzzedValue(this).apply(block) -} - -inline fun ModelProvider.exceptIsInstance(): ModelProvider { - return except { it is T } -} \ No newline at end of file diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/mutators/NumberRandomMutator.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/mutators/NumberRandomMutator.kt deleted file mode 100644 index f00401bd4c..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/mutators/NumberRandomMutator.kt +++ /dev/null @@ -1,60 +0,0 @@ -package org.utbot.fuzzer.mutators - -import org.utbot.framework.plugin.api.UtPrimitiveModel -import org.utbot.fuzzer.FuzzedMethodDescription -import org.utbot.fuzzer.FuzzedValue -import org.utbot.fuzzer.ModelMutator -import org.utbot.fuzzing.utils.invertBit -import kotlin.random.Random - -/** - * Mutates any [Number] changing random bit. - */ -object NumberRandomMutator : ModelMutator { - - override fun mutate( - description: FuzzedMethodDescription, - index: Int, - value: FuzzedValue, - random: Random - ): FuzzedValue? { - val model = value.model - return if (model is UtPrimitiveModel && model.value is Number) { - val newValue = changeRandomBit(random, model.value as Number) - UtPrimitiveModel(newValue).mutatedFrom(value) { - summary = "%var% = $newValue (mutated from ${model.value})" - } - } else null - } - - private fun changeRandomBit(random: Random, number: Number): Number { - val size = when (number) { - is Byte -> Byte.SIZE_BITS - is Short -> Short.SIZE_BITS - is Int -> Int.SIZE_BITS - is Float -> Float.SIZE_BITS - is Long -> Long.SIZE_BITS - is Double -> Double.SIZE_BITS - else -> error("Unknown type: ${number.javaClass}") - } - val asLong = when (number) { - is Byte, is Short, is Int -> number.toLong() - is Long -> number - is Float -> number.toRawBits().toLong() - is Double -> number.toRawBits() - else -> error("Unknown type: ${number.javaClass}") - } - val bitIndex = random.nextInt(size) - val mutated = asLong.invertBit(bitIndex) - return when (number) { - is Byte -> mutated.toByte() - is Short -> mutated.toShort() - is Int -> mutated.toInt() - is Float -> Float.fromBits(mutated.toInt()) - is Long -> mutated - is Double -> Double.fromBits(mutated) - else -> error("Unknown type: ${number.javaClass}") - } - } -} - diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/mutators/RegexStringModelMutator.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/mutators/RegexStringModelMutator.kt deleted file mode 100644 index c9285eb7b8..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/mutators/RegexStringModelMutator.kt +++ /dev/null @@ -1,35 +0,0 @@ -package org.utbot.fuzzer.mutators - -import com.github.curiousoddman.rgxgen.RgxGen -import org.utbot.framework.plugin.api.UtPrimitiveModel -import org.utbot.fuzzer.FuzzedMethodDescription -import org.utbot.fuzzer.FuzzedValue -import org.utbot.fuzzer.ModelMutator -import org.utbot.fuzzer.providers.RegexFuzzedValue -import org.utbot.fuzzer.providers.RegexModelProvider -import kotlin.random.Random -import kotlin.random.asJavaRandom - -/** - * Provides different regex value for a concrete regex pattern - */ -object RegexStringModelMutator : ModelMutator { - - override fun mutate( - description: FuzzedMethodDescription, - index: Int, - value: FuzzedValue, - random: Random - ): FuzzedValue? { - if (value is RegexFuzzedValue) { - val string = RgxGen(value.regex).apply { - setProperties(RegexModelProvider.rgxGenProperties) - }.generate(random.asJavaRandom()) - return RegexFuzzedValue(UtPrimitiveModel(string).mutatedFrom(value) { - summary = "%var% = mutated regex ${value.regex}" - }, value.regex) - } - return null - } - -} \ No newline at end of file diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/mutators/StringRandomMutator.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/mutators/StringRandomMutator.kt deleted file mode 100644 index 8bf71f8afa..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/mutators/StringRandomMutator.kt +++ /dev/null @@ -1,74 +0,0 @@ -package org.utbot.fuzzer.mutators - -import org.utbot.framework.plugin.api.UtPrimitiveModel -import org.utbot.framework.plugin.api.util.stringClassId -import org.utbot.fuzzer.FuzzedMethodDescription -import org.utbot.fuzzer.FuzzedValue -import org.utbot.fuzzer.ModelMutator -import org.utbot.fuzzing.utils.flipCoin -import kotlin.random.Random - -/** - * Mutates string by adding and/or removal symbol at random position. - */ -object StringRandomMutator : ModelMutator { - - override fun mutate( - description: FuzzedMethodDescription, - index: Int, - value: FuzzedValue, - random: Random - ): FuzzedValue? { - return (value.model as? UtPrimitiveModel) - ?.takeIf { it.classId == stringClassId } - ?.let { model -> - mutate(random, model.value as String).let { - UtPrimitiveModel(it).mutatedFrom(value) { - summary = "%var% = mutated string" - } - } - } - } - - private fun mutate(random: Random, string: String): String { - // we can miss some mutation for a purpose - val position = random.nextInt(string.length + 1) - var result: String = string - if (random.flipCoin(probability = 50)) { - result = tryRemoveChar(random, result, position) ?: string - } - if (random.flipCoin(probability = 50) && result.length < 1000) { - result = tryAddChar(random, result, position) - } - return result - } - - private fun tryAddChar(random: Random, value: String, position: Int): String { - val charToMutate = if (value.isNotEmpty()) { - value.random(random) - } else { - // use any meaningful character from the ascii table - random.nextInt(33, 127).toChar() - } - return buildString { - append(value.substring(0, position)) - // try to change char to some that is close enough to origin char - val charTableSpread = 64 - if (random.nextBoolean()) { - append(charToMutate - random.nextInt(1, charTableSpread)) - } else { - append(charToMutate + random.nextInt(1, charTableSpread)) - } - append(value.substring(position, value.length)) - } - } - - private fun tryRemoveChar(random: Random, value: String, position: Int): String? { - if (position >= value.length) return null - val toRemove = random.nextInt(value.length) - return buildString { - append(value.substring(0, toRemove)) - append(value.substring(toRemove + 1, value.length)) - } - } -} \ No newline at end of file diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/objects/FuzzerMockUtils.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/objects/FuzzerMockUtils.kt deleted file mode 100644 index e2c97d0e43..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/objects/FuzzerMockUtils.kt +++ /dev/null @@ -1,82 +0,0 @@ -package org.utbot.fuzzer.objects - -import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.ExecutableId -import org.utbot.framework.plugin.api.MethodId -import org.utbot.framework.plugin.api.UtAssembleModel -import org.utbot.framework.plugin.api.UtCompositeModel -import org.utbot.framework.plugin.api.UtDirectSetFieldModel -import org.utbot.framework.plugin.api.UtExecutableCallModel -import org.utbot.framework.plugin.api.UtModel -import org.utbot.framework.plugin.api.UtStatementModel - -/** - * Implements [MethodId] but also can supply a mock for this execution. - * - * Simplest example: setter and getter, - * when this methodId is a setter, getter can be used for a mock to supply correct value. - */ -internal class FuzzerMockableMethodId( - classId: ClassId, - name: String, - returnType: ClassId, - parameters: List, - val mock: () -> Map> = { emptyMap() }, -) : MethodId(classId, name, returnType, parameters) { - - constructor(copyOf: MethodId, mock: () -> Map> = { emptyMap() }) : this( - copyOf.classId, copyOf.name, copyOf.returnType, copyOf.parameters, mock - ) - -} - -internal fun MethodId.toFuzzerMockable(block: suspend SequenceScope>>.() -> Unit): FuzzerMockableMethodId { - return FuzzerMockableMethodId(this) { - sequence { block() }.toMap() - } -} - -internal fun replaceWithMock(assembleModel: UtModel, shouldMock: (ClassId) -> Boolean): UtModel = when { - assembleModel !is UtAssembleModel -> assembleModel - shouldMock(assembleModel.classId) -> createMockModelFromFuzzerMockable(assembleModel, shouldMock) - else -> updateInnerModels(assembleModel, shouldMock) -} - -private fun createMockModelFromFuzzerMockable(model: UtAssembleModel, shouldMock: (ClassId) -> Boolean): UtCompositeModel { - val mock = UtCompositeModel(model.id, model.classId, true) - for (mutator in model.modificationsChain) { - if (mutator is UtDirectSetFieldModel) { - mock.fields[mutator.fieldId] = replaceWithMock(mutator.fieldModel, shouldMock) - } - if (mutator is UtExecutableCallModel && mutator.executable is FuzzerMockableMethodId) { - (mutator.executable as FuzzerMockableMethodId).mock().forEach { (executionId, models) -> - mock.mocks[executionId] = models.map { p -> replaceWithMock(p, shouldMock) } - } - } - } - return mock -} - -private fun updateInnerModels(model: UtAssembleModel, shouldMock: (ClassId) -> Boolean): UtAssembleModel { - val models = model.modificationsChain.map { call -> - var mockedStatementModel: UtStatementModel? = null - when (call) { - is UtDirectSetFieldModel -> { - val mock = replaceWithMock(call.fieldModel, shouldMock) - if (mock != call.fieldModel) { - mockedStatementModel = UtDirectSetFieldModel(call.instance, call.fieldId, mock) - } - } - is UtExecutableCallModel -> { - val params = call.params.map { m -> replaceWithMock(m, shouldMock) } - if (params != call.params) { - mockedStatementModel = UtExecutableCallModel(call.instance, call.executable, params) - } - } - } - mockedStatementModel ?: call - } - return with(model) { - UtAssembleModel(id, classId, modelName, instantiationCall, origin) { models } - } -} \ No newline at end of file diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/package-info.java b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/package-info.java deleted file mode 100644 index e41294c025..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * @deprecated Code is migrating to the new fuzzing platform. - * @see org.utbot.fuzzing.Fuzzing - * @see org.utbot.fuzzing.JavaLanguageKt#runJavaFuzzing - */ -@Deprecated -package org.utbot.fuzzer; \ No newline at end of file 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 deleted file mode 100644 index 1475850b38..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/AbstractModelProvider.kt +++ /dev/null @@ -1,25 +0,0 @@ -package org.utbot.fuzzer.providers - -import org.utbot.framework.plugin.api.* -import org.utbot.fuzzer.FuzzedMethodDescription -import org.utbot.fuzzer.FuzzedParameter -import org.utbot.fuzzer.ModelProvider -import org.utbot.fuzzer.ModelProvider.Companion.yieldValue - -/** - * Simple model implementation. - */ -@Suppress("unused") -abstract class AbstractModelProvider: ModelProvider { - override fun generate(description: FuzzedMethodDescription): Sequence = sequence{ - description.parametersMap.forEach { (classId, indices) -> - toModel(classId)?.let { defaultModel -> - indices.forEach { index -> - yieldValue(index, defaultModel.fuzzed()) - } - } - } - } - - abstract fun toModel(classId: ClassId): UtModel? -} \ No newline at end of file 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 deleted file mode 100644 index 5dbf6f33c0..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ArrayModelProvider.kt +++ /dev/null @@ -1,51 +0,0 @@ -package org.utbot.fuzzer.providers - -import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.UtArrayModel -import org.utbot.framework.plugin.api.UtModel -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.FuzzedType -import org.utbot.fuzzer.IdentityPreservingIdGenerator -import org.utbot.fuzzer.fuzzNumbers - -class ArrayModelProvider( - idGenerator: IdentityPreservingIdGenerator, - recursionDepthLeft: Int = 2 -) : RecursiveModelProvider(idGenerator, recursionDepthLeft) { - - override fun newInstance(parentProvider: RecursiveModelProvider, constructor: ModelConstructor): RecursiveModelProvider { - val provider = ArrayModelProvider(parentProvider.idGenerator, parentProvider.recursionDepthLeft - 1) - provider.copySettings(parentProvider) - provider.totalLimit = minOf(parentProvider.totalLimit, constructor.limit) - return provider - } - - override fun generateModelConstructors( - description: FuzzedMethodDescription, - parameterIndex: Int, - classId: ClassId, - ): Sequence = sequence { - if (!classId.isArray) return@sequence - val lengths = fuzzNumbers(description.concreteValues, 0, 3) { it in 1..10 }.toList() - lengths.forEach { length -> - yield(ModelConstructor(listOf(FuzzedType(classId.elementClassId!!)), repeat = length) { values -> - createFuzzedArrayModel(classId, length, values.map { it.model } ) - }.apply { - limit = (totalLimit / lengths.size).coerceAtLeast(1) - }) - } - } - - private fun createFuzzedArrayModel(arrayClassId: ClassId, length: Int, values: List?) = - UtArrayModel( - idGenerator.createId(), - arrayClassId, - length, - arrayClassId.elementClassId!!.defaultValueModel(), - values?.withIndex()?.associate { it.index to it.value }?.toMutableMap() ?: mutableMapOf() - ).fuzzed { - this.summary = "%var% = ${arrayClassId.elementClassId!!.simpleName}[$length]" - } -} \ No newline at end of file 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 deleted file mode 100644 index 450cea7115..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CharToStringModelProvider.kt +++ /dev/null @@ -1,33 +0,0 @@ -package org.utbot.fuzzer.providers - -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.FuzzedParameter -import org.utbot.fuzzer.ModelProvider -import org.utbot.fuzzer.ModelProvider.Companion.yieldValue - -/** - * Collects all char constants and creates string with them. - */ -object CharToStringModelProvider : ModelProvider { - 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 } - .map { it.value } - .filterIsInstance() - .joinToString(separator = "") - if (string.isNotEmpty()) { - sequenceOf(string.reversed(), string).forEach { str -> - val model = UtPrimitiveModel(str).fuzzed() - indices.forEach { - yieldValue(it, model) - } - } - } - } - } -} \ No newline at end of file diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CollectionWithEmptyStatesModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CollectionWithEmptyStatesModelProvider.kt deleted file mode 100644 index c3f18831f7..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CollectionWithEmptyStatesModelProvider.kt +++ /dev/null @@ -1,47 +0,0 @@ -package org.utbot.fuzzer.providers - -import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.util.id -import org.utbot.framework.plugin.api.util.isSubtypeOf -import org.utbot.fuzzer.FuzzedMethodDescription -import org.utbot.fuzzer.FuzzedParameter -import org.utbot.fuzzer.IdGenerator -import org.utbot.fuzzer.ModelProvider -import org.utbot.fuzzer.ModelProvider.Companion.yieldAllValues -import org.utbot.fuzzer.objects.create - -/** - * Provides different collection for concrete classes. - * - * For example, ArrayList, LinkedList, Collections.singletonList can be passed to check - * if that parameter breaks anything. For example, in case method doesn't expect - * a non-modifiable collection and tries to add values. - */ -class CollectionWithEmptyStatesModelProvider( - private val idGenerator: IdGenerator -) : ModelProvider { - - private val generators = listOf( - Info(List::class.id, "emptyList"), - Info(Set::class.id, "emptySet"), - Info(Map::class.id, "emptyMap"), - Info(Collection::class.id, "emptyList", returnType = List::class.id), - Info(Iterable::class.id, "emptyList", returnType = List::class.id), - Info(Iterator::class.id, "emptyIterator"), - ) - - override fun generate(description: FuzzedMethodDescription): Sequence = sequence { - description.parametersMap - .asSequence() - .forEach { (classId, indices) -> - generators.find { classId == it.classId }?.let { generator -> - yieldAllValues(indices, listOf(generator.classId.create { - id = { idGenerator.createId() } - using static method(java.util.Collections::class.id, generator.methodName, returns = generator.returnType) with values() - }.fuzzed { summary = "%var% = empty collection" })) - } - } - } - - private class Info(val classId: ClassId, val methodName: String, val returnType: ClassId = classId) -} \ No newline at end of file diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CollectionWithModificationModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CollectionWithModificationModelProvider.kt deleted file mode 100644 index 48a60d8a42..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CollectionWithModificationModelProvider.kt +++ /dev/null @@ -1,142 +0,0 @@ -package org.utbot.fuzzer.providers - -import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.util.isAbstract -import org.utbot.framework.plugin.api.util.booleanClassId -import org.utbot.framework.plugin.api.util.id -import org.utbot.framework.plugin.api.util.jClass -import org.utbot.framework.plugin.api.util.objectClassId -import org.utbot.framework.plugin.api.util.voidClassId -import org.utbot.fuzzer.FuzzedMethodDescription -import org.utbot.fuzzer.FuzzedType -import org.utbot.fuzzer.FuzzedValue -import org.utbot.fuzzer.IdentityPreservingIdGenerator -import org.utbot.fuzzer.fuzzNumbers -import org.utbot.fuzzer.objects.create - -class CollectionWithModificationModelProvider( - idGenerator: IdentityPreservingIdGenerator, - recursionDepthLeft: Int = 2, - private var defaultModificationCount: IntArray = intArrayOf(0, 1, 3) -) : RecursiveModelProvider(idGenerator, recursionDepthLeft) { - - init { - totalLimit = 100_000 - } - - // List of available implementations with modification method to insert values - // Should be listed from more specific interface to more general, - // because suitable info is searched by the list. - private val modifications = listOf( - // SETS - Info(java.util.NavigableSet::class.id, java.util.TreeSet::class.id, "add", listOf(objectClassId), booleanClassId) { - it.size == 1 && it[0].classId.isSubtypeOfWithReflection(java.lang.Comparable::class.id) - }, - Info(java.util.SortedSet::class.id, java.util.TreeSet::class.id, "add", listOf(objectClassId), booleanClassId) { - it.size == 1 && it[0].classId.isSubtypeOfWithReflection(java.lang.Comparable::class.id) - }, - Info(java.util.Set::class.id, java.util.HashSet::class.id, "add", listOf(objectClassId), booleanClassId), - // QUEUES - Info(java.util.Queue::class.id, java.util.ArrayDeque::class.id, "add", listOf(objectClassId), booleanClassId), - Info(java.util.Deque::class.id, java.util.ArrayDeque::class.id, "add", listOf(objectClassId), booleanClassId), - Info(java.util.Stack::class.id, java.util.Stack::class.id, "push", listOf(objectClassId), booleanClassId), - // LISTS - Info(java.util.List::class.id, java.util.ArrayList::class.id, "add", listOf(objectClassId), booleanClassId), - // MAPS - Info(java.util.NavigableMap::class.id, java.util.TreeMap::class.id, "put", listOf(objectClassId, objectClassId), objectClassId) { - it.size == 2 && it[0].classId.isSubtypeOfWithReflection(java.lang.Comparable::class.id) - }, - Info(java.util.SortedMap::class.id, java.util.TreeMap::class.id, "put", listOf(objectClassId, objectClassId), objectClassId) { - it.size == 2 && it[0].classId.isSubtypeOfWithReflection(java.lang.Comparable::class.id) - }, - Info(java.util.Map::class.id, java.util.HashMap::class.id, "put", listOf(objectClassId, objectClassId), objectClassId), - // ITERABLE - Info(java.util.Collection::class.id, java.util.ArrayList::class.id, "add", listOf(objectClassId), booleanClassId), - Info(java.lang.Iterable::class.id, java.util.ArrayList::class.id, "add", listOf(objectClassId), booleanClassId), - ) - private var modificationCount = 7 - - override fun newInstance(parentProvider: RecursiveModelProvider, constructor: ModelConstructor): RecursiveModelProvider { - val newInstance = CollectionWithModificationModelProvider( - parentProvider.idGenerator, parentProvider.recursionDepthLeft - 1 - ) - newInstance.copySettings(parentProvider) - if (parentProvider is CollectionWithModificationModelProvider) { - newInstance.defaultModificationCount = parentProvider.defaultModificationCount - } - return newInstance - } - - override fun generateModelConstructors( - description: FuzzedMethodDescription, - parameterIndex: Int, - classId: ClassId, - ): Sequence { - - val info: Info? = if (!classId.isAbstract) { - when { - classId.isSubtypeOfWithReflection(Collection::class.id) -> Info(classId, classId, "add", listOf(objectClassId), booleanClassId) - classId.isSubtypeOfWithReflection(Map::class.id) -> Info(classId, classId, "put", listOf(objectClassId, objectClassId), objectClassId) - else -> null - } - } else { - modifications.find { - classId == it.superClass - } - } - - val sequence = info?.let { - val genericTypes = description.fuzzerType(parameterIndex)?.generics ?: emptyList() - if (genericTypes.isNotEmpty()) { - // this check removes cases when TreeSet or TreeMap is created without comparable key - val lengths = if (info.canModify(genericTypes)) { - fuzzNumbers(description.concreteValues, *defaultModificationCount) { it in 1..modificationCount } - } else { - sequenceOf(0) - } - lengths.map { length -> - ModelConstructor(genericTypes, repeat = length) { values -> - info.assembleModel(info.concreteClass, values) - } - } - } else { - emptySequence() - } - } - return sequence ?: emptySequence() - } - - private fun Info.assembleModel(concreteClassId: ClassId, values: List): FuzzedValue { - return concreteClassId.create { - id = { idGenerator.createId() } - using empty constructor - val paramCount = params.size - values.asSequence() - .windowed(paramCount, paramCount) - .forEach { each -> - call instance method( - methodName, - params, - returnType - ) with values(*Array(paramCount) { each[it].model }) - } - }.fuzzed { - summary = "%var% = test collection" - } - } - - private class Info( - val superClass: ClassId, - val concreteClass: ClassId, - val methodName: String, - val params: List, - val returnType: ClassId = voidClassId, - val canModify: (List) -> Boolean = { true } - ) - - private fun ClassId.isSubtypeOfWithReflection(another: ClassId): Boolean { - // commented code above doesn't work this case: SomeList extends LinkedList {} and Collection -// return isSubtypeOf(another) - return another.jClass.isAssignableFrom(this.jClass) - } -} \ No newline at end of file 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 deleted file mode 100644 index 95ee2af8d0..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ConstantsModelProvider.kt +++ /dev/null @@ -1,54 +0,0 @@ -package org.utbot.fuzzer.providers - -import org.utbot.framework.plugin.api.UtPrimitiveModel -import org.utbot.framework.plugin.api.util.isPrimitive -import org.utbot.fuzzer.FuzzedContext -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 - -/** - * Traverses through method constants and creates appropriate models for them. - */ -object ConstantsModelProvider : ModelProvider { - - override fun generate(description: FuzzedMethodDescription): Sequence = sequence { - description.concreteValues - .asSequence() - .filter { (classId, _) -> classId.isPrimitive } - .forEach { (_, value, op) -> - sequenceOf( - UtPrimitiveModel(value).fuzzed { summary = "%var% = $value" }, - modifyValue(value, op) - ) - .filterNotNull() - .forEach { m -> - description.parametersMap.getOrElse(m.model.classId) { emptyList() }.forEach { index -> - yieldValue(index, m) - } - } - } - } - - fun modifyValue(value: Any, op: FuzzedContext): FuzzedValue? { - if (op !is FuzzedContext.Comparison) return null - val multiplier = if (op == FuzzedContext.Comparison.LT || op == FuzzedContext.Comparison.GE) -1 else 1 - return when(value) { - is Boolean -> value.not() - is Byte -> value + multiplier.toByte() - is Char -> (value.toInt() + multiplier).toChar() - is Short -> value + multiplier.toShort() - is Int -> value + multiplier - is Long -> value + multiplier.toLong() - is Float -> value + multiplier.toDouble() - is Double -> value + multiplier.toDouble() - else -> null - }?.let { UtPrimitiveModel(it).fuzzed { summary = "%var% ${ - (if (op == FuzzedContext.Comparison.EQ || op == FuzzedContext.Comparison.LE || op == FuzzedContext.Comparison.GE) { - op.reverse() - } else op).sign - } $value" } } - } -} \ No newline at end of file diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/DateConstantModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/DateConstantModelProvider.kt deleted file mode 100644 index 9a7326cd9f..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/DateConstantModelProvider.kt +++ /dev/null @@ -1,170 +0,0 @@ -package org.utbot.fuzzer.providers - -import java.text.SimpleDateFormat -import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.UtAssembleModel -import org.utbot.framework.plugin.api.UtExecutableCallModel -import org.utbot.framework.plugin.api.UtPrimitiveModel -import org.utbot.framework.plugin.api.util.dateClassId -import org.utbot.framework.plugin.api.util.executableId -import org.utbot.framework.plugin.api.util.id -import org.utbot.framework.plugin.api.util.intClassId -import org.utbot.framework.plugin.api.util.jClass -import org.utbot.framework.plugin.api.util.longClassId -import org.utbot.framework.plugin.api.util.stringClassId -import org.utbot.framework.plugin.api.util.voidClassId -import org.utbot.fuzzer.FuzzedMethodDescription -import org.utbot.fuzzer.FuzzedParameter -import org.utbot.fuzzer.FuzzedType -import org.utbot.fuzzer.FuzzedValue -import org.utbot.fuzzer.IdentityPreservingIdGenerator -import org.utbot.fuzzer.ModelProvider -import org.utbot.fuzzer.ModelProvider.Companion.yieldAllValues -import org.utbot.fuzzer.defaultModelProviders -import org.utbot.fuzzer.fuzz -import org.utbot.fuzzing.utils.hex -import org.utbot.fuzzer.objects.assembleModel - -class DateConstantModelProvider( - private val idGenerator: IdentityPreservingIdGenerator, -) : ModelProvider { - - var totalLimit: Int = 20 - - companion object { - private const val defaultDateFormat = "dd-MM-yyyy HH:mm:ss:ms" - } - - private fun String.isDate(format: String): Boolean { - val formatter = SimpleDateFormat(format).apply { - isLenient = false - } - return runCatching { formatter.parse(trim()) }.isSuccess - } - - private fun String.isDateFormat(): Boolean { - return none { it.isDigit() } && // fixes concrete date values - runCatching { SimpleDateFormat(this) }.isSuccess - } - - private fun generateFromNumbers( - baseMethodDescription: FuzzedMethodDescription, - ): Sequence { - val constructorsFromNumbers = dateClassId.allConstructors - .filter { constructor -> - constructor.parameters.isNotEmpty() && - constructor.parameters.all { it == intClassId || it == longClassId } - }.map { constructorId -> - with(constructorId) { - ModelConstructor(parameters.map(::FuzzedType)) { assembleModel(idGenerator.createId(), constructorId, it) } - } - }.sortedBy { it.neededTypes.size } - - return sequence { - constructorsFromNumbers.forEach { constructor -> - yieldAll( - fuzzValues( - constructor.neededTypes.map(FuzzedType::classId), - baseMethodDescription, - defaultModelProviders(idGenerator) - ).map(constructor.createModel) - ) - } - } - } - - private fun generateFromDates( - baseMethodDescription: FuzzedMethodDescription, - ): Sequence { - val strings = baseMethodDescription.concreteValues - .asSequence() - .filter { it.classId == stringClassId } - .map { it.value as String } - .distinct() - val formats = strings.filter { it.isDateFormat() } + defaultDateFormat - val formatToDates = formats.associateWith { format -> strings.filter { it.isDate(format) } } - - return sequence { - formatToDates.forEach { (format, dates) -> - dates.forEach { date -> - yield(assembleDateFromString(idGenerator.createId(), format, date)) - } - } - } - } - - private fun generateNowDate(): Sequence { - val constructor = dateClassId.allConstructors.first { it.parameters.isEmpty() } - return sequenceOf(assembleModel(idGenerator.createId(), constructor, emptyList())) - } - - override fun generate(description: FuzzedMethodDescription): Sequence { - val parameters = description.parametersMap[dateClassId] - if (parameters.isNullOrEmpty()) { - return emptySequence() - } - - return sequence { - yieldAllValues( - parameters, - generateNowDate() + generateFromDates(description) + - generateFromNumbers(description).take(totalLimit) - ) - }.take(totalLimit) - } - - private fun fuzzValues( - types: List, - baseMethodDescription: FuzzedMethodDescription, - modelProvider: ModelProvider, - ): Sequence> { - if (types.isEmpty()) - return sequenceOf(listOf()) - val syntheticMethodDescription = FuzzedMethodDescription( - "", // TODO: maybe add more info here - voidClassId, - types, - baseMethodDescription.concreteValues - ).apply { - packageName = baseMethodDescription.packageName - } - return fuzz(syntheticMethodDescription, modelProvider) - } - - private fun assembleDateFromString(id: Int, formatString: String, dateString: String): FuzzedValue { - val simpleDateFormatModel = assembleSimpleDateFormat(idGenerator.createId(), formatString) - val dateFormatParse = simpleDateFormatModel.classId.jClass - .getMethod("parse", String::class.java).executableId - val instantiationCall = UtExecutableCallModel( - simpleDateFormatModel, dateFormatParse, listOf(UtPrimitiveModel(dateString)) - ) - return UtAssembleModel( - id, - dateClassId, - "$dateFormatParse#" + id.hex(), - instantiationCall - ).fuzzed { - summary = "%var% = $dateFormatParse($stringClassId)" - } - } - - private fun assembleSimpleDateFormat(id: Int, formatString: String): UtAssembleModel { - val simpleDateFormatId = SimpleDateFormat::class.java.id - val formatStringConstructor = simpleDateFormatId.allConstructors.first { - it.parameters.singleOrNull() == stringClassId - } - val formatSetLenient = SimpleDateFormat::setLenient.executableId - val formatModel = UtPrimitiveModel(formatString) - - val instantiationCall = UtExecutableCallModel(instance = null, formatStringConstructor, listOf(formatModel)) - return UtAssembleModel( - id, - simpleDateFormatId, - "$simpleDateFormatId[$stringClassId]#" + id.hex(), - instantiationCall - ) { - listOf(UtExecutableCallModel(instance = this, formatSetLenient, listOf(UtPrimitiveModel(false)))) - } - } - -} 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 deleted file mode 100644 index 57aa0dcf13..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/EnumModelProvider.kt +++ /dev/null @@ -1,23 +0,0 @@ -package org.utbot.fuzzer.providers - -import org.utbot.framework.plugin.api.UtEnumConstantModel -import org.utbot.framework.plugin.api.util.jClass -import org.utbot.fuzzer.IdentityPreservingIdGenerator -import org.utbot.fuzzer.FuzzedMethodDescription -import org.utbot.fuzzer.FuzzedParameter -import org.utbot.fuzzer.ModelProvider -import org.utbot.fuzzer.ModelProvider.Companion.yieldAllValues - -class EnumModelProvider(private val idGenerator: IdentityPreservingIdGenerator) : ModelProvider { - override fun generate(description: FuzzedMethodDescription): Sequence = sequence { - description.parametersMap - .asSequence() - .filter { (classId, _) -> classId.jClass.isEnum } - .forEach { (classId, indices) -> - yieldAllValues(indices, classId.jClass.enumConstants.filterIsInstance>().map { - val id = idGenerator.getOrCreateIdForValue(it) - UtEnumConstantModel(id, 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 deleted file mode 100644 index 5e23a0f2c8..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/NullModelProvider.kt +++ /dev/null @@ -1,25 +0,0 @@ -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.FuzzedParameter -import org.utbot.fuzzer.ModelProvider -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): Sequence = sequence { - description.parametersMap - .asSequence() - .filter { (classId, _) -> classId.isRefType } - .forEach { (classId, indices) -> - val model = UtNullModel(classId) - 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/NumberClassModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/NumberClassModelProvider.kt deleted file mode 100644 index d0a9938abb..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/NumberClassModelProvider.kt +++ /dev/null @@ -1,74 +0,0 @@ -package org.utbot.fuzzer.providers - -import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.UtPrimitiveModel -import org.utbot.framework.plugin.api.util.byteClassId -import org.utbot.framework.plugin.api.util.doubleClassId -import org.utbot.framework.plugin.api.util.floatClassId -import org.utbot.framework.plugin.api.util.id -import org.utbot.framework.plugin.api.util.intClassId -import org.utbot.framework.plugin.api.util.isPrimitive -import org.utbot.framework.plugin.api.util.longClassId -import org.utbot.framework.plugin.api.util.primitiveByWrapper -import org.utbot.framework.plugin.api.util.shortClassId -import org.utbot.framework.plugin.api.util.wrapperByPrimitive -import org.utbot.fuzzer.FuzzedConcreteValue -import org.utbot.fuzzer.FuzzedMethodDescription -import org.utbot.fuzzer.FuzzedParameter -import org.utbot.fuzzer.IdentityPreservingIdGenerator -import org.utbot.fuzzer.ModelProvider -import org.utbot.fuzzer.ModelProvider.Companion.yieldValue -import org.utbot.fuzzer.objects.create -import kotlin.random.Random - -/** - * Provides random implementation if current requested type is [Number]. - */ -class NumberClassModelProvider( - val idGenerator: IdentityPreservingIdGenerator, - val random: Random, -) : ModelProvider { - // byteClassId generates bad code because of type cast on method Byte.valueOf - private val types = setOf(/*byteClassId,*/ shortClassId, intClassId, longClassId, floatClassId, doubleClassId) - - override fun generate(description: FuzzedMethodDescription): Sequence = sequence { - description.parametersMap[Number::class.id]?.forEach { index -> - val fuzzedValues = description.concreteValues.filter { types.contains(it.classId) } + - (-5 until 5).map { FuzzedConcreteValue(types.random(random), it) } - fuzzedValues.forEach { fuzzedValue -> - val targetType = fuzzedValue.classId - check(targetType.isPrimitive) { "$targetType is not primitive value" } - val castedValue = castNumberIfPossible(fuzzedValue.value as Number, targetType) - val targetValues = listOfNotNull( - castedValue.let(::UtPrimitiveModel), - ConstantsModelProvider.modifyValue(castedValue, fuzzedValue.fuzzedContext)?.model - ) - // we use wrapper type to generate simple values, - // because at the moment code generator uses reflection - // if primitive types are provided - val wrapperType = wrapperByPrimitive[targetType] ?: return@sequence - targetValues.forEach { targetValue -> - yieldValue(index, wrapperType.create { - id = { idGenerator.createId() } - using static method( - classId = wrapperType, - name = "valueOf", - params = listOf(primitiveByWrapper[wrapperType]!!), - returns = wrapperType - ) with values(targetValue) - }.fuzzed { summary = "%var% = ${Number::class.simpleName}(${targetValue})" }) - } - } - } - } - - private fun castNumberIfPossible(number: Number, classId: ClassId): Number = when (classId) { - byteClassId -> number.toInt().toByte() - shortClassId -> number.toInt().toShort() - intClassId -> number.toInt() - longClassId -> number.toLong() - floatClassId -> number.toFloat() - doubleClassId -> number.toDouble() - else -> number - } -} \ 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 deleted file mode 100644 index 6dc9c0a213..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ObjectModelProvider.kt +++ /dev/null @@ -1,150 +0,0 @@ -package org.utbot.fuzzer.providers - -import java.lang.reflect.Constructor -import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.ConstructorId -import org.utbot.framework.plugin.api.FieldId -import org.utbot.framework.plugin.api.MethodId -import org.utbot.framework.plugin.api.UtAssembleModel -import org.utbot.framework.plugin.api.UtDirectSetFieldModel -import org.utbot.framework.plugin.api.UtExecutableCallModel -import org.utbot.framework.plugin.api.util.isAbstract -import org.utbot.framework.plugin.api.util.isStatic -import org.utbot.framework.plugin.api.util.dateClassId -import org.utbot.framework.plugin.api.util.id -import org.utbot.framework.plugin.api.util.isEnum -import org.utbot.framework.plugin.api.util.isPrimitive -import org.utbot.framework.plugin.api.util.isPrimitiveWrapper -import org.utbot.framework.plugin.api.util.jClass -import org.utbot.framework.plugin.api.util.stringClassId -import org.utbot.fuzzer.FuzzedMethodDescription -import org.utbot.fuzzer.FuzzedType -import org.utbot.fuzzer.FuzzedValue -import org.utbot.fuzzer.IdentityPreservingIdGenerator -import org.utbot.fuzzer.objects.FuzzerMockableMethodId -import org.utbot.fuzzer.objects.assembleModel -import org.utbot.fuzzing.providers.FieldDescription -import org.utbot.fuzzing.providers.findAccessibleModifiableFields -import org.utbot.fuzzing.providers.isAccessible - -/** - * Creates [UtAssembleModel] for objects which have public constructors - */ -class ObjectModelProvider( - idGenerator: IdentityPreservingIdGenerator, - recursionDepthLeft: Int = 2, -) : RecursiveModelProvider(idGenerator, recursionDepthLeft) { - override fun newInstance(parentProvider: RecursiveModelProvider, constructor: ModelConstructor): RecursiveModelProvider { - val newInstance = ObjectModelProvider(parentProvider.idGenerator, parentProvider.recursionDepthLeft - 1) - newInstance.copySettings(parentProvider) - newInstance.branchingLimit = 1 - return newInstance - } - - override fun generateModelConstructors( - description: FuzzedMethodDescription, - parameterIndex: Int, - classId: ClassId, - ): Sequence = sequence { - if (unwantedConstructorsClasses.contains(classId) - || classId.isPrimitiveWrapper - || classId.isEnum - || classId.isAbstract - || (classId.isInner && !classId.isStatic) - ) return@sequence - - val constructors = collectConstructors(classId) { javaConstructor -> - isAccessible(javaConstructor, description.packageName) - }.sortedWith( - primitiveParameterizedConstructorsFirstAndThenByParameterCount - ) - - constructors.forEach { constructorId -> - // When branching limit = 1 this block tries to create new values - // and mutate some fields. Only if there's no option next block - // with empty constructor should be used. - if (constructorId.parameters.isEmpty()) { - val fields = findAccessibleModifiableFields(null, constructorId.classId, description.packageName) - if (fields.isNotEmpty()) { - yield( - ModelConstructor(fields.map { it.type }) { - generateModelsWithFieldsInitialization(constructorId, fields, it) - } - ) - } - } - yield(ModelConstructor(constructorId.parameters.map { classId -> FuzzedType(classId) }) { - assembleModel(idGenerator.createId(), constructorId, it) - }) - } - } - - private fun generateModelsWithFieldsInitialization( - constructorId: ConstructorId, - fields: List, - fieldValues: List - ): FuzzedValue { - val fuzzedModel = assembleModel(idGenerator.createId(), constructorId, emptyList()) - val assembleModel = fuzzedModel.model as? UtAssembleModel - ?: error("Expected UtAssembleModel but ${fuzzedModel.model::class.java} found") - val modificationChain = - assembleModel.modificationsChain as? MutableList ?: error("Modification chain must be mutable") - fieldValues.asSequence().mapIndexedNotNull { index, value -> - val field = fields[index] - when { - field.canBeSetDirectly -> UtDirectSetFieldModel( - fuzzedModel.model, - FieldId(constructorId.classId, field.name), - value.model - ) - field.setter != null -> UtExecutableCallModel( - fuzzedModel.model, - FuzzerMockableMethodId( - constructorId.classId, - field.setter.name, - field.setter.returnType.id, - listOf(field.type.classId), - mock = { - field.getter?.let { g -> - val getterMethodID = MethodId( - classId = constructorId.classId, - name = g.name, - returnType = g.returnType.id, - parameters = emptyList() - ) - mapOf(getterMethodID to listOf(value.model)) - } ?: emptyMap() - } - ), - listOf(value.model) - ) - else -> null - } - }.forEach(modificationChain::add) - return fuzzedModel - } - - companion object { - - private val unwantedConstructorsClasses = listOf( - stringClassId, dateClassId - ) - - private fun collectConstructors(classId: ClassId, predicate: (Constructor<*>) -> Boolean): Sequence { - return classId.jClass.declaredConstructors.asSequence() - .filter(predicate) - .map { javaConstructor -> - ConstructorId(classId, javaConstructor.parameters.map { it.type.id }) - } - } - - private val primitiveParameterizedConstructorsFirstAndThenByParameterCount = - compareByDescending { constructorId -> - constructorId.parameters.all { classId -> - classId.isPrimitive || classId == stringClassId - } - }.thenComparingInt { constructorId -> - constructorId.parameters.size - } - } -} \ No newline at end of file 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 deleted file mode 100644 index 621e3795c6..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/PrimitiveDefaultsModelProvider.kt +++ /dev/null @@ -1,46 +0,0 @@ -package org.utbot.fuzzer.providers - -import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.UtPrimitiveModel -import org.utbot.framework.plugin.api.util.booleanClassId -import org.utbot.framework.plugin.api.util.byteClassId -import org.utbot.framework.plugin.api.util.charClassId -import org.utbot.framework.plugin.api.util.doubleClassId -import org.utbot.framework.plugin.api.util.floatClassId -import org.utbot.framework.plugin.api.util.intClassId -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 org.utbot.fuzzer.ModelProvider.Companion.yieldValue - -/** - * Provides default values for primitive types. - */ -object PrimitiveDefaultsModelProvider : ModelProvider { - override fun generate(description: FuzzedMethodDescription): Sequence = sequence { - description.parametersMap.forEach { (classId, parameterIndices) -> - valueOf(classId)?.let { model -> - parameterIndices.forEach { index -> - yieldValue(index, model) - } - } - } - } - - fun valueOf(classId: ClassId): FuzzedValue? = when (classId) { - booleanClassId -> UtPrimitiveModel(false).fuzzed { summary = "%var% = false" } - byteClassId -> UtPrimitiveModel(0.toByte()).fuzzed { summary = "%var% = 0" } - charClassId -> UtPrimitiveModel('\u0000').fuzzed { summary = "%var% = \u0000" } - shortClassId -> UtPrimitiveModel(0.toShort()).fuzzed { summary = "%var% = 0" } - intClassId -> UtPrimitiveModel(0).fuzzed { summary = "%var% = 0" } - longClassId -> UtPrimitiveModel(0L).fuzzed { summary = "%var% = 0L" } - floatClassId -> UtPrimitiveModel(0.0f).fuzzed { summary = "%var% = 0f" } - doubleClassId -> UtPrimitiveModel(0.0).fuzzed { summary = "%var% = 0.0" } - stringClassId -> UtPrimitiveModel("").fuzzed { summary = "%var% = \"\"" } - else -> null - } -} \ No newline at end of file diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/PrimitiveRandomModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/PrimitiveRandomModelProvider.kt deleted file mode 100644 index f866742cab..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/PrimitiveRandomModelProvider.kt +++ /dev/null @@ -1,66 +0,0 @@ -package org.utbot.fuzzer.providers - -import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.UtPrimitiveModel -import org.utbot.framework.plugin.api.util.booleanClassId -import org.utbot.framework.plugin.api.util.byteClassId -import org.utbot.framework.plugin.api.util.charClassId -import org.utbot.framework.plugin.api.util.doubleClassId -import org.utbot.framework.plugin.api.util.floatClassId -import org.utbot.framework.plugin.api.util.intClassId -import org.utbot.framework.plugin.api.util.longClassId -import org.utbot.framework.plugin.api.util.primitiveByWrapper -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 org.utbot.fuzzer.ModelProvider.Companion.yieldValue -import kotlin.random.Random - -/** - * Provides default values for primitive types. - */ -class PrimitiveRandomModelProvider(val random: Random, val size: Int = 5) : ModelProvider { - override fun generate(description: FuzzedMethodDescription): Sequence = sequence { - description.parametersMap.forEach { (classId, parameterIndices) -> - for (i in 1..size) { - valueOf(primitiveByWrapper[classId] ?: classId)?.let { model -> - parameterIndices.forEach { index -> - yieldValue(index, model) - } - } - } - } - } - - fun valueOf(classId: ClassId): FuzzedValue? = when (classId) { - booleanClassId -> random.nextBoolean().let { v -> UtPrimitiveModel(v).fuzzed { summary = "%var% = $v" } } - byteClassId -> random.nextInt(Byte.MIN_VALUE.toInt(), Byte.MAX_VALUE.toInt()).let { v -> - UtPrimitiveModel(v.toByte()).fuzzed { summary = "%var% = random byte" } - } - charClassId -> random.nextInt(1, 256).let { v -> - UtPrimitiveModel(v.toChar()).fuzzed { summary = "%var% = random char" } - } - shortClassId -> random.nextInt(Short.MIN_VALUE.toInt(), Short.MAX_VALUE.toInt()).let { v -> - UtPrimitiveModel(v.toShort()).fuzzed { summary = "%var% = random short" } - } - intClassId -> random.nextInt().let { v -> - UtPrimitiveModel(v).fuzzed { summary = "%var% = random integer" } - } - longClassId -> random.nextLong().let { v -> - UtPrimitiveModel(v).fuzzed { summary = "%var% = random long" } - } - floatClassId -> random.nextFloat().let { v -> - UtPrimitiveModel(v).fuzzed { summary = "%var% = random float" } - } - doubleClassId -> random.nextDouble().let { v -> - UtPrimitiveModel(0.0).fuzzed { summary = "%var% = random double" } - } - stringClassId -> (1..5).map { random.nextInt('a'.code, 'z'.code).toChar() }.joinToString("").let { s -> - UtPrimitiveModel(s).fuzzed { summary = "%var% = random string" } - } - else -> null - } -} \ No newline at end of file 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 deleted file mode 100644 index a032ad609f..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/PrimitiveWrapperModelProvider.kt +++ /dev/null @@ -1,64 +0,0 @@ -package org.utbot.fuzzer.providers - -import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.util.isPrimitiveWrapper -import org.utbot.framework.plugin.api.util.primitiveByWrapper -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.yieldAllValues - -object PrimitiveWrapperModelProvider: ModelProvider { - - private val constantModels = ModelProvider.of( - PrimitiveDefaultsModelProvider, - ConstantsModelProvider, - StringConstantModelProvider - ) - - override fun generate(description: FuzzedMethodDescription): Sequence = sequence { - val primitiveWrapperTypesAsPrimitiveTypes = description.parametersMap - .keys - .asSequence() - .filter { - it == stringClassId || it.isPrimitiveWrapper - } - .mapNotNull { classId -> - when { - classId == stringClassId -> stringClassId - classId.isPrimitiveWrapper -> primitiveByWrapper[classId] - else -> null - } - }.toList() - - if (primitiveWrapperTypesAsPrimitiveTypes.isEmpty()) { - return@sequence - } - - val constants = mutableMapOf>() - constantModels.generate(FuzzedMethodDescription( - name = "Primitive wrapper constant generation ", - returnType = voidClassId, - parameters = primitiveWrapperTypesAsPrimitiveTypes, - concreteValues = description.concreteValues - )).forEach { (index, value) -> - val primitiveWrapper = wrapperByPrimitive[primitiveWrapperTypesAsPrimitiveTypes[index]] - if (primitiveWrapper != null) { - constants.computeIfAbsent(primitiveWrapper) { mutableListOf() }.add(value) - } - } - - description.parametersMap - .asSequence() - .filter { (classId, _) -> classId == stringClassId || classId.isPrimitiveWrapper } - .forEach { (classId, indices) -> - constants[classId]?.let { models -> - yieldAllValues(indices, models) - } - } - } -} \ No newline at end of file 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 deleted file mode 100644 index 5c9ffe4090..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/PrimitivesModelProvider.kt +++ /dev/null @@ -1,90 +0,0 @@ -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 org.utbot.fuzzer.ModelProvider.Companion.yieldValue - -/** - * Produces bound values for primitive types. - */ -object PrimitivesModelProvider : ModelProvider { - override fun generate(description: FuzzedMethodDescription): Sequence = sequence { - description.parametersMap.forEach { (classId, parameterIndices) -> - val primitives: List = when (classId) { - booleanClassId -> listOf( - UtPrimitiveModel(false).fuzzed { summary = "%var% = false" }, - UtPrimitiveModel(true).fuzzed { summary = "%var% = true" } - ) - charClassId -> listOf( - UtPrimitiveModel(Char.MIN_VALUE).fuzzed { summary = "%var% = Char.MIN_VALUE" }, - UtPrimitiveModel(Char.MAX_VALUE).fuzzed { summary = "%var% = Char.MAX_VALUE" }, - ) - byteClassId -> listOf( - UtPrimitiveModel(0.toByte()).fuzzed { summary = "%var% = 0" }, - UtPrimitiveModel(1.toByte()).fuzzed { summary = "%var% > 0" }, - UtPrimitiveModel((-1).toByte()).fuzzed { summary = "%var% < 0" }, - UtPrimitiveModel(Byte.MIN_VALUE).fuzzed { summary = "%var% = Byte.MIN_VALUE" }, - UtPrimitiveModel(Byte.MAX_VALUE).fuzzed { summary = "%var% = Byte.MAX_VALUE" }, - ) - shortClassId -> listOf( - UtPrimitiveModel(0.toShort()).fuzzed { summary = "%var% = 0" }, - UtPrimitiveModel(1.toShort()).fuzzed { summary = "%var% > 0" }, - UtPrimitiveModel((-1).toShort()).fuzzed { summary = "%var% < 0" }, - UtPrimitiveModel(Short.MIN_VALUE).fuzzed { summary = "%var% = Short.MIN_VALUE" }, - UtPrimitiveModel(Short.MAX_VALUE).fuzzed { summary = "%var% = Short.MAX_VALUE" }, - ) - intClassId -> listOf( - UtPrimitiveModel(0).fuzzed { summary = "%var% = 0" }, - UtPrimitiveModel(1).fuzzed { summary = "%var% > 0" }, - UtPrimitiveModel((-1)).fuzzed { summary = "%var% < 0" }, - UtPrimitiveModel(Int.MIN_VALUE).fuzzed { summary = "%var% = Int.MIN_VALUE" }, - UtPrimitiveModel(Int.MAX_VALUE).fuzzed { summary = "%var% = Int.MAX_VALUE" }, - ) - longClassId -> listOf( - UtPrimitiveModel(0L).fuzzed { summary = "%var% = 0L" }, - UtPrimitiveModel(1L).fuzzed { summary = "%var% > 0L" }, - UtPrimitiveModel(-1L).fuzzed { summary = "%var% < 0L" }, - UtPrimitiveModel(Long.MIN_VALUE).fuzzed { summary = "%var% = Long.MIN_VALUE" }, - UtPrimitiveModel(Long.MAX_VALUE).fuzzed { summary = "%var% = Long.MAX_VALUE" }, - ) - floatClassId -> listOf( - UtPrimitiveModel(0.0f).fuzzed { summary = "%var% = 0f" }, - UtPrimitiveModel(1.1f).fuzzed { summary = "%var% > 0f" }, - UtPrimitiveModel(-1.1f).fuzzed { summary = "%var% < 0f" }, - UtPrimitiveModel(Float.MIN_VALUE).fuzzed { summary = "%var% = Float.MIN_VALUE" }, - UtPrimitiveModel(Float.MAX_VALUE).fuzzed { summary = "%var% = Float.MAX_VALUE" }, - UtPrimitiveModel(Float.NEGATIVE_INFINITY).fuzzed { summary = "%var% = Float.NEGATIVE_INFINITY" }, - UtPrimitiveModel(Float.POSITIVE_INFINITY).fuzzed { summary = "%var% = Float.POSITIVE_INFINITY" }, - UtPrimitiveModel(Float.NaN).fuzzed { summary = "%var% = Float.NaN" }, - ) - doubleClassId -> listOf( - UtPrimitiveModel(0.0).fuzzed { summary = "%var% = 0.0" }, - UtPrimitiveModel(1.1).fuzzed { summary = "%var% > 0.0" }, - UtPrimitiveModel(-1.1).fuzzed { summary = "%var% < 0.0" }, - UtPrimitiveModel(Double.MIN_VALUE).fuzzed { summary = "%var% = Double.MIN_VALUE" }, - UtPrimitiveModel(Double.MAX_VALUE).fuzzed { summary = "%var% = Double.MAX_VALUE" }, - UtPrimitiveModel(Double.NEGATIVE_INFINITY).fuzzed { summary = "%var% = Double.NEGATIVE_INFINITY" }, - UtPrimitiveModel(Double.POSITIVE_INFINITY).fuzzed { summary = "%var% = Double.POSITIVE_INFINITY" }, - UtPrimitiveModel(Double.NaN).fuzzed { summary = "%var% = Double.NaN" }, - ) - stringClassId -> listOf( - UtPrimitiveModel("").fuzzed { summary = "%var% = empty string" }, - UtPrimitiveModel(" ").fuzzed { summary = "%var% = blank string" }, - UtPrimitiveModel("string").fuzzed { summary = "%var% != empty string" }, - UtPrimitiveModel("\n\t\r").fuzzed { summary = "%var% has special characters" }, - ) - else -> listOf() - } - - primitives.forEach { model -> - parameterIndices.forEach { index -> - yieldValue(index, model) - } - } - } - } -} \ No newline at end of file diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/RecursiveModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/RecursiveModelProvider.kt deleted file mode 100644 index 855886fadb..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/RecursiveModelProvider.kt +++ /dev/null @@ -1,121 +0,0 @@ -package org.utbot.fuzzer.providers - -import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.util.voidClassId -import org.utbot.fuzzer.FuzzedMethodDescription -import org.utbot.fuzzer.FuzzedParameter -import org.utbot.fuzzer.FuzzedType -import org.utbot.fuzzer.FuzzedValue -import org.utbot.fuzzer.IdentityPreservingIdGenerator -import org.utbot.fuzzer.ModelProvider -import org.utbot.fuzzer.ModelProvider.Companion.yieldAllValues -import org.utbot.fuzzer.exceptIsInstance -import org.utbot.fuzzer.fuzz -import org.utbot.fuzzer.modelProviderForRecursiveCalls - -/** - * Auxiliary data class that stores information describing how to construct model from parts (submodels) - * - * @param neededTypes list containing type ([ClassId]) of each submodel - * @param repeat if value greater than 1, [neededTypes] is duplicated, therefore [createModel] should accept `neededTypes.size * repeat` values - * @param createModel lambda that takes subModels (they should have types listed in [neededTypes]) and generates a model using them - */ -data class ModelConstructor( - val neededTypes: List, - val repeat: Int = 1, - val createModel: (subModels: List) -> FuzzedValue, -) { - var limit: Int = Int.MAX_VALUE -} - -/** - * Abstraction for providers that may call other providers recursively inside them. [generate] will firstly get possible - * model constructors (provided by [generateModelConstructors]) and then fuzz parameters for each of them using synthetic method - * - * @param recursionDepthLeft maximum recursion level, i.e. maximum number of nested calls produced by this provider - * - * @property modelProviderForRecursiveCalls providers that can be called by this provider. - * Note that if [modelProviderForRecursiveCalls] has instances of [RecursiveModelProvider] then this provider will use - * their copies created by [newInstance] rather than themselves (this is important because we have to change some - * properties like [recursionDepthLeft], [totalLimit], etc.) - * @property fallbackProvider provider that will be used instead [modelProviderForRecursiveCalls] after reaching maximum recursion level - * @property totalLimit maximum number of values produced by this provider - * @property branchingLimit maximum number of [ModelConstructor]s used by [generate] (see [generateModelConstructors]) - */ -abstract class RecursiveModelProvider( - val idGenerator: IdentityPreservingIdGenerator, - val recursionDepthLeft: Int -) : ModelProvider { - var modelProviderForRecursiveCalls: ModelProvider = modelProviderForRecursiveCalls(idGenerator, recursionDepthLeft - 1) - var fallbackProvider: ModelProvider = NullModelProvider - var totalLimit: Int = 1000 - var branchingLimit: Int = Int.MAX_VALUE - - /** - * Creates instance of the class on which it is called, assuming that it will be called recursively from [parentProvider] - */ - protected abstract fun newInstance(parentProvider: RecursiveModelProvider, constructor: ModelConstructor): RecursiveModelProvider - - /** - * Creates [ModelProvider]s that will be used to generate values recursively. The order of elements in returned list is important: - * only first [branchingLimit] constructors will be used, so you should place most effective providers first - */ - protected abstract fun generateModelConstructors( - description: FuzzedMethodDescription, - parameterIndex: Int, - classId: ClassId, - ): Sequence - - protected open fun copySettings(other: RecursiveModelProvider): RecursiveModelProvider { - modelProviderForRecursiveCalls = other.modelProviderForRecursiveCalls - fallbackProvider = other.fallbackProvider - totalLimit = other.totalLimit - branchingLimit = other.branchingLimit - return this - } - - final override fun generate(description: FuzzedMethodDescription): Sequence = sequence { - description.parameters.forEachIndexed { index, classId -> - generateModelConstructors(description, index, classId) - .take(branchingLimit) - .forEach { creator -> - yieldAllValues(listOf(index), creator.recursiveCall(description)) - } - } - }.take(totalLimit) - - private fun ModelConstructor.recursiveCall(baseMethodDescription: FuzzedMethodDescription): Sequence { - // when no parameters are needed just call model creator once, - // for example, if collection is empty or object has empty constructor - if (neededTypes.isEmpty() || repeat == 0) { - return sequenceOf(createModel(listOf())) - } - val syntheticMethodDescription = FuzzedMethodDescription( - "", - voidClassId, - (1..repeat).flatMap { neededTypes.map { it.classId } }, - baseMethodDescription.concreteValues - ).apply { - packageName = baseMethodDescription.packageName - fuzzerType = { index -> - neededTypes[index % neededTypes.size] // because we can repeat neededTypes several times - } - } - return fuzz(syntheticMethodDescription, nextModelProvider(this)) - .map { createModel(it) } - .take(limit) - } - - private fun nextModelProvider(constructor: ModelConstructor): ModelProvider = - if (recursionDepthLeft > 0) { - modelProviderForRecursiveCalls.map { - if (it is RecursiveModelProvider) { - it.newInstance(this, constructor) - } else { it } - } - } else { - modelProviderForRecursiveCalls - .exceptIsInstance() - .withFallback(fallbackProvider) - } -} \ No newline at end of file diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/RegexModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/RegexModelProvider.kt deleted file mode 100644 index acabdff57c..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/RegexModelProvider.kt +++ /dev/null @@ -1,68 +0,0 @@ -package org.utbot.fuzzer.providers - -import com.github.curiousoddman.rgxgen.RgxGen -import com.github.curiousoddman.rgxgen.config.RgxGenOption -import com.github.curiousoddman.rgxgen.config.RgxGenProperties -import org.utbot.framework.plugin.api.UtPrimitiveModel -import org.utbot.framework.plugin.api.util.id -import org.utbot.framework.plugin.api.util.stringClassId -import org.utbot.fuzzer.FuzzedContext -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.yieldAllValues -import java.util.regex.Pattern -import java.util.regex.PatternSyntaxException -import kotlin.random.Random -import kotlin.random.asJavaRandom - -object RegexModelProvider : ModelProvider { - - val rgxGenProperties = RgxGenProperties().apply { - setProperty(RgxGenOption.INFINITE_PATTERN_REPETITION.key, "5") - } - - override fun generate(description: FuzzedMethodDescription): Sequence { - val parameters = description.parametersMap[stringClassId] - if (parameters.isNullOrEmpty()) { - return emptySequence() - } - val regexes = description.concreteValues - .asSequence() - .filter { it.classId == stringClassId } - .filter { it.fuzzedContext.isPatterMatchingContext() } - .map { it.value as String } - .distinct() - .filter { it.isNotBlank() } - .filter { - try { - Pattern.compile(it); true - } catch (_: PatternSyntaxException) { - false - } - }.map { - it to RgxGen(it).apply { - setProperties(rgxGenProperties) - }.generate(Random(0).asJavaRandom()) - } - - return sequence { - yieldAllValues(parameters, regexes.map { - RegexFuzzedValue(UtPrimitiveModel(it.second).fuzzed { summary = "%var% = regex ${it.first}" }, it.first) - }) - } - } - - private fun FuzzedContext.isPatterMatchingContext(): Boolean { - if (this !is FuzzedContext.Call) return false - val stringMethodWithRegexArguments = setOf("matches", "split") - return when { - method.classId == Pattern::class.java.id -> true - method.classId == String::class.java.id && stringMethodWithRegexArguments.contains(method.name) -> true - else -> false - } - } -} - -class RegexFuzzedValue(value: FuzzedValue, val regex: String) : FuzzedValue(value.model) \ No newline at end of file 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 deleted file mode 100644 index 1f9a47238d..0000000000 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/StringConstantModelProvider.kt +++ /dev/null @@ -1,33 +0,0 @@ -package org.utbot.fuzzer.providers - -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.FuzzedParameter -import org.utbot.fuzzer.ModelProvider -import org.utbot.fuzzer.ModelProvider.Companion.yieldAllValues -import org.utbot.fuzzer.ModelProvider.Companion.yieldValue - -object StringConstantModelProvider : ModelProvider { - - override fun generate(description: FuzzedMethodDescription): Sequence = sequence { - description.concreteValues - .asSequence() - .filter { (classId, _) -> classId == stringClassId } - .forEach { (_, value, _) -> - description.parametersMap.getOrElse(stringClassId) { emptyList() }.forEach { index -> - yieldValue(index, UtPrimitiveModel(value).fuzzed { summary = "%var% = string" }) - } - } - val charsAsStrings = description.concreteValues - .asSequence() - .filter { (classId, _) -> classId == charClassId } - .map { (_, value, _) -> - UtPrimitiveModel((value as Char).toString()).fuzzed { - summary = "%var% = $value" - } - } - yieldAllValues(description.parametersMap.getOrElse(stringClassId) { emptyList() }, charsAsStrings) - } -} \ No newline at end of file diff --git a/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/CollectionModelProviderTest.kt b/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/CollectionModelProviderTest.kt deleted file mode 100644 index 9f29d50ef0..0000000000 --- a/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/CollectionModelProviderTest.kt +++ /dev/null @@ -1,271 +0,0 @@ -package org.utbot.framework.plugin.api - -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.Test -import org.utbot.framework.plugin.api.util.UtContext -import org.utbot.framework.plugin.api.util.booleanClassId -import org.utbot.framework.plugin.api.util.id -import org.utbot.framework.plugin.api.util.intClassId -import org.utbot.framework.plugin.api.util.intWrapperClassId -import org.utbot.framework.plugin.api.util.jClass -import org.utbot.framework.plugin.api.util.objectClassId -import org.utbot.framework.plugin.api.util.primitiveByWrapper -import org.utbot.framework.plugin.api.util.primitiveWrappers -import org.utbot.framework.plugin.api.util.stringClassId -import org.utbot.framework.plugin.api.util.withUtContext -import org.utbot.fuzzer.FuzzedType -import org.utbot.fuzzer.exceptIsInstance -import org.utbot.fuzzer.providers.CollectionWithEmptyStatesModelProvider -import org.utbot.fuzzer.providers.CollectionWithModificationModelProvider -import java.util.* - -class CollectionModelProviderTest { - - interface MyInterface - - @Test - fun `empty collection is created for unknown interface without modifications`() { - withUtContext(UtContext(this::class.java.classLoader)) { - val result = collect( - CollectionWithModificationModelProvider(TestIdentityPreservingIdGenerator), - parameters = listOf(Collection::class.id), - ) { - fuzzerType = { FuzzedType(Collection::class.id, listOf(FuzzedType(MyInterface::class.id))) } - } - assertEquals(1, result.size) - val models = result[0]!! - assertEquals(1, models.size) { "test should generate only 1 empty model" } - val model = models[0] - assertTrue(model is UtAssembleModel) { "unexpected model type" } - assertEquals(0, (model as UtAssembleModel).modificationsChain.size) { "Model should not have any modifications" } - } - } - - @Test - fun `collection is created with modification of concrete class`() { - val modifications = intArrayOf(0, 1, 3, 5) - withUtContext(UtContext(this::class.java.classLoader)) { - val result = collect( - CollectionWithModificationModelProvider( - TestIdentityPreservingIdGenerator, - defaultModificationCount = modifications - ), - parameters = listOf(Collection::class.id), - ) { - fuzzerType = { FuzzedType(Collection::class.id, listOf(FuzzedType(objectClassId))) } - } - assertEquals(1, result.size) - val models = result[0]!! - assertEquals(modifications.size, models.size) { "test should generate only 3 model: empty, with 1 modification and 3 modification" } - modifications.forEachIndexed { index, expectedModifications -> - val model = models[index] - assertTrue(model is UtAssembleModel) { "unexpected model type" } - assertEquals(expectedModifications, (model as UtAssembleModel).modificationsChain.size) { "Model has unexpected number of modifications" } - } - } - } - - @Test - fun `collection can create simple values with concrete type`() { - val modifications = intArrayOf(1) - withUtContext(UtContext(this::class.java.classLoader)) { - val result = collect( - CollectionWithModificationModelProvider( - TestIdentityPreservingIdGenerator, - defaultModificationCount = modifications - ).apply { - totalLimit = 1 - }, - parameters = listOf(Collection::class.id), - ) { - fuzzerType = { FuzzedType(Collection::class.id, listOf(FuzzedType(intWrapperClassId))) } - } - assertEquals(1, result.size) - val models = result[0]!! - assertEquals(modifications.size, models.size) - modifications.forEachIndexed { index, expectedModifications -> - val model = models[index] - assertTrue(model is UtAssembleModel) - val modificationsChain = (model as UtAssembleModel).modificationsChain - assertEquals(expectedModifications, modificationsChain.size) - val statementModel = modificationsChain[0] - testStatementIsAsSimpleAddIntToCollection(ArrayList::class.id, statementModel) - } - } - } - - @Test - fun `collection can create recursively values with concrete type`() { - val modifications = intArrayOf(1) - withUtContext(UtContext(this::class.java.classLoader)) { - val result = collect( - CollectionWithModificationModelProvider( - TestIdentityPreservingIdGenerator, - defaultModificationCount = modifications - ).apply { - // removes empty collections from the result - modelProviderForRecursiveCalls = modelProviderForRecursiveCalls - .exceptIsInstance() - totalLimit = 1 - }, - parameters = listOf(Collection::class.id), - ) { - fuzzerType = { - FuzzedType(Collection::class.id, listOf( - FuzzedType(Set::class.id, listOf( - FuzzedType(intWrapperClassId) - )) - )) - } - } - assertEquals(1, result.size) - val models = result[0]!! - assertEquals(modifications.size, models.size) - modifications.forEachIndexed { index, expectedModifications -> - val model = models[index] - assertTrue(model is UtAssembleModel) - val modificationsChain = (model as UtAssembleModel).modificationsChain - assertEquals(expectedModifications, modificationsChain.size) - var statementModel = modificationsChain[0] - assertTrue(statementModel is UtExecutableCallModel) - statementModel as UtExecutableCallModel - assertEquals( - MethodId(ArrayList::class.id, "add", booleanClassId, listOf(objectClassId)), - statementModel.executable - ) - assertEquals(1, statementModel.params.size) - val innerType = statementModel.params[0] - assertTrue(innerType is UtAssembleModel) - innerType as UtAssembleModel - assertEquals(HashSet::class.id, innerType.classId) - assertEquals(1, innerType.modificationsChain.size) - statementModel = innerType.modificationsChain[0] - testStatementIsAsSimpleAddIntToCollection(HashSet::class.id, statementModel) - } - } - } - - private fun testStatementIsAsSimpleAddIntToCollection(collectionId: ClassId, statementModel: UtStatementModel) { - testStatementIsAsSimpleAddGenericSimpleTypeToCollection(collectionId, intWrapperClassId, statementModel) - } - - private fun testStatementIsAsSimpleAddGenericSimpleTypeToCollection(collectionId: ClassId, genericId: ClassId, statementModel: UtStatementModel) { - assertTrue(primitiveWrappers.contains(genericId)) { "This test works only with primitive wrapper types" } - assertTrue(statementModel is UtExecutableCallModel) - statementModel as UtExecutableCallModel - assertEquals( - MethodId(collectionId, "add", booleanClassId, listOf(objectClassId)), - statementModel.executable - ) - assertEquals(1, statementModel.params.size) - val classModel = statementModel.params[0] - assertTrue(classModel is UtPrimitiveModel) - classModel as UtPrimitiveModel - assertEquals(primitiveByWrapper[genericId], classModel.classId) - assertTrue(genericId.jClass.isAssignableFrom(classModel.value::class.java)) - } - - @Test - fun `map can create simple values with concrete type`() { - val modifications = intArrayOf(1) - withUtContext(UtContext(this::class.java.classLoader)) { - val result = collect( - CollectionWithModificationModelProvider( - TestIdentityPreservingIdGenerator, - defaultModificationCount = modifications - ).apply { - totalLimit = 1 - }, - parameters = listOf(Map::class.id), - ) { - fuzzerType = { FuzzedType(Map::class.id, listOf(FuzzedType(intWrapperClassId), FuzzedType(stringClassId))) } - } - assertEquals(1, result.size) - val models = result[0]!! - assertEquals(modifications.size, models.size) - modifications.forEachIndexed { index, expectedModifications -> - val model = models[index] - assertTrue(model is UtAssembleModel) - val modificationsChain = (model as UtAssembleModel).modificationsChain - assertEquals(expectedModifications, modificationsChain.size) - val statementModel = modificationsChain[0] - testStatementIsAsSimpleAddIntStringToMap(HashMap::class.id, statementModel) - } - } - } - - private fun testStatementIsAsSimpleAddIntStringToMap(collectionId: ClassId, statementModel: UtStatementModel) { - assertTrue(statementModel is UtExecutableCallModel) - statementModel as UtExecutableCallModel - assertEquals( - MethodId(collectionId, "put", objectClassId, listOf(objectClassId, objectClassId)), - statementModel.executable - ) - assertEquals(2, statementModel.params.size) - val intClassModel = statementModel.params[0] - assertTrue(intClassModel is UtPrimitiveModel) - intClassModel as UtPrimitiveModel - assertEquals(intClassId, intClassModel.classId) - assertTrue(intClassModel.value is Int) - val stringClassModel = statementModel.params[1] - assertTrue(stringClassModel is UtPrimitiveModel) - stringClassModel as UtPrimitiveModel - assertEquals(stringClassId, stringClassModel.classId) - assertTrue(stringClassModel.value is String) - } - - ///region REGRESSION TESTS - @Test - fun lists() { - testExpectedCollectionIsCreatedWithCorrectGenericType(Collection::class.id, ArrayList::class.id, intWrapperClassId) - testExpectedCollectionIsCreatedWithCorrectGenericType(List::class.id, ArrayList::class.id, intWrapperClassId) - testExpectedCollectionIsCreatedWithCorrectGenericType(Stack::class.id, Stack::class.id, intWrapperClassId) - testExpectedCollectionIsCreatedWithCorrectGenericType(java.util.Deque::class.id, java.util.ArrayDeque::class.id, intWrapperClassId) - testExpectedCollectionIsCreatedWithCorrectGenericType(Queue::class.id, java.util.ArrayDeque::class.id, intWrapperClassId) - } - - @Test - fun sets() { - testExpectedCollectionIsCreatedWithCorrectGenericType(Set::class.id, HashSet::class.id, intWrapperClassId) - testExpectedCollectionIsCreatedWithCorrectGenericType(SortedSet::class.id, TreeSet::class.id, intWrapperClassId) - testExpectedCollectionIsCreatedWithCorrectGenericType(NavigableSet::class.id, TreeSet::class.id, intWrapperClassId) - } - - class ConcreteClass : LinkedList() - - @Test - fun `concrete class is created`() { - testExpectedCollectionIsCreatedWithCorrectGenericType(ConcreteClass::class.id, ConcreteClass::class.id, intWrapperClassId) - } - - private fun testExpectedCollectionIsCreatedWithCorrectGenericType(collectionId: ClassId, expectedId: ClassId, genericId: ClassId) { - withUtContext(UtContext(this::class.java.classLoader)) { - val modifications = intArrayOf(1) - val result = collect( - CollectionWithModificationModelProvider( - TestIdentityPreservingIdGenerator, - defaultModificationCount = modifications - ).apply { - totalLimit = 1 - }, - parameters = listOf(collectionId), - ) { - fuzzerType = { FuzzedType(collectionId, listOf(FuzzedType(genericId))) } - } - assertEquals(1, result.size) - val models = result[0]!! - assertEquals(modifications.size, models.size) - modifications.forEachIndexed { index, expectedModifications -> - val model = models[index] - assertTrue(model is UtAssembleModel) - val modificationsChain = (model as UtAssembleModel).modificationsChain - assertEquals(expectedModifications, modificationsChain.size) - val statementModel = modificationsChain[0] - testStatementIsAsSimpleAddGenericSimpleTypeToCollection(expectedId, genericId, statementModel) - } - } - } - - ///end region -} \ No newline at end of file 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 deleted file mode 100644 index f357b2260c..0000000000 --- a/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/FuzzedValueDescriptionTest.kt +++ /dev/null @@ -1,60 +0,0 @@ -package org.utbot.framework.plugin.api - -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test -import org.utbot.framework.plugin.api.util.intClassId -import org.utbot.framework.plugin.api.util.voidClassId -import org.utbot.fuzzer.FuzzedConcreteValue -import org.utbot.fuzzer.FuzzedMethodDescription -import org.utbot.fuzzer.FuzzedContext -import org.utbot.fuzzer.FuzzedValue -import org.utbot.fuzzer.providers.ConstantsModelProvider - -class FuzzedValueDescriptionTest { - - @Test - fun testConstantModelProviderTest() { - val values = mutableListOf() - val concreteValues = listOf( - FuzzedConcreteValue(intClassId, 10, FuzzedContext.Comparison.EQ), - FuzzedConcreteValue(intClassId, 20, FuzzedContext.Comparison.NE), - FuzzedConcreteValue(intClassId, 30, FuzzedContext.Comparison.LT), - FuzzedConcreteValue(intClassId, 40, FuzzedContext.Comparison.LE), - FuzzedConcreteValue(intClassId, 50, FuzzedContext.Comparison.GT), - FuzzedConcreteValue(intClassId, 60, FuzzedContext.Comparison.GE), - ) - val summaries = listOf( - "%var% = 10" to 10, - "%var% != 10" to 11, // 1, FuzzedOp.EQ -> %var% == 10: False - "%var% = 20" to 20, - "%var% != 20" to 21, // 2, FuzzedOp.NE -> %var% != 20: True - "%var% = 30" to 30, - "%var% < 30" to 29, // 3, FuzzedOp.LT -> %var% < 30: True - "%var% = 40" to 40, - "%var% > 40" to 41, // 4, FuzzedOp.LE -> %var% <= 40: False - "%var% = 50" to 50, - "%var% > 50" to 51, // 5, FuzzedOp.GT -> %var% > 50: True - "%var% = 60" to 60, - "%var% < 60" to 59, // 6, FuzzedOp.GE -> %var% >= 60: False - ) - val expected = concreteValues.size * 2 - ConstantsModelProvider.generate( - FuzzedMethodDescription( - name = "name", - returnType = voidClassId, - parameters = listOf(intClassId), - concreteValues = concreteValues - ) - ).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" - } - for (i in summaries.indices) { - assertEquals(summaries[i].second, (values[i].model as UtPrimitiveModel).value) { - "Constant model provider should change constant values to reverse if-statement" - } - assertEquals(summaries[i].first, values[i].summary) - } - } - -} \ No newline at end of file diff --git a/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/FuzzerTest.kt b/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/FuzzerTest.kt deleted file mode 100644 index da4e5135c0..0000000000 --- a/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/FuzzerTest.kt +++ /dev/null @@ -1,160 +0,0 @@ -package org.utbot.framework.plugin.api - -import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.Timeout -import org.junit.jupiter.api.assertThrows -import org.utbot.framework.plugin.api.util.booleanClassId -import org.utbot.framework.plugin.api.util.byteClassId -import org.utbot.framework.plugin.api.util.charClassId -import org.utbot.framework.plugin.api.util.doubleClassId -import org.utbot.framework.plugin.api.util.floatClassId -import org.utbot.framework.plugin.api.util.id -import org.utbot.framework.plugin.api.util.intClassId -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.framework.plugin.api.util.voidClassId -import org.utbot.fuzzer.FuzzedConcreteValue -import org.utbot.fuzzer.FuzzedMethodDescription -import org.utbot.fuzzer.FuzzedParameter -import org.utbot.fuzzer.ModelProvider -import org.utbot.fuzzer.fuzz -import org.utbot.fuzzer.providers.ConstantsModelProvider -import org.utbot.fuzzer.providers.NullModelProvider -import org.utbot.fuzzer.providers.PrimitiveDefaultsModelProvider -import org.utbot.fuzzer.providers.PrimitiveWrapperModelProvider.fuzzed -import java.lang.IllegalArgumentException -import java.util.concurrent.TimeUnit - -class FuzzerTest { - - private val testProvider = ModelProvider.of(PrimitiveDefaultsModelProvider, NullModelProvider) - - @Test - fun `error when no provider is passed`() { - assertThrows { - fuzz(newDescription(emptyList())) - } - } - - @Test - fun `zero values for empty input`() { - val fuzz = fuzz(newDescription(emptyList()), testProvider) - assertNull(fuzz.firstOrNull()) - } - - @Test - fun `single value for every type`() { - val fuzz = fuzz( - newDescription( - defaultTypes() - ), - testProvider - ) - assertEquals(1, fuzz.count()) { "Default provider should create 1 value for every type, but have ${fuzz.count()}" } - assertEquals(listOf( - UtPrimitiveModel(false), - UtPrimitiveModel(0.toByte()), - UtPrimitiveModel('\u0000'), - UtPrimitiveModel(0.toShort()), - UtPrimitiveModel(0), - UtPrimitiveModel(0L), - UtPrimitiveModel(0.0f), - UtPrimitiveModel(0.0), - UtNullModel(Any::class.java.id) - ), fuzz.first().map { it.model }) - } - - @Test - fun `concrete values are created`() { - val concreteValues = listOf( - FuzzedConcreteValue(intClassId, 1), - FuzzedConcreteValue(intClassId, 2), - FuzzedConcreteValue(intClassId, 3), - ) - val fuzz = fuzz(newDescription(listOf(intClassId), concreteValues), ConstantsModelProvider) - assertEquals(concreteValues.size, fuzz.count()) - assertEquals(setOf( - UtPrimitiveModel(1), - UtPrimitiveModel(2), - UtPrimitiveModel(3), - ), fuzz.map { it.first().model }.toSet()) - } - - @Test - fun `concrete values are created but filtered`() { - val concreteValues = listOf( - FuzzedConcreteValue(intClassId, 1), - FuzzedConcreteValue(intClassId, 2), - FuzzedConcreteValue(intClassId, 3), - ) - val fuzz = fuzz(newDescription(listOf(charClassId), concreteValues), ConstantsModelProvider) - assertEquals(0, fuzz.count()) - } - - @Test - fun `all combinations is found`() { - val fuzz = fuzz(newDescription(listOf(booleanClassId, intClassId)), ModelProvider { - sequenceOf( - FuzzedParameter(0, UtPrimitiveModel(true).fuzzed()), - FuzzedParameter(0, UtPrimitiveModel(false).fuzzed()), - FuzzedParameter(1, UtPrimitiveModel(-1).fuzzed()), - FuzzedParameter(1, UtPrimitiveModel(0).fuzzed()), - FuzzedParameter(1, UtPrimitiveModel(1).fuzzed()), - ) - }) - assertEquals(6, fuzz.count()) - assertEquals(setOf( - listOf(UtPrimitiveModel(true), UtPrimitiveModel(-1)), - listOf(UtPrimitiveModel(false), UtPrimitiveModel(-1)), - listOf(UtPrimitiveModel(true), UtPrimitiveModel(0)), - listOf(UtPrimitiveModel(false), UtPrimitiveModel(0)), - listOf(UtPrimitiveModel(true), UtPrimitiveModel(1)), - listOf(UtPrimitiveModel(false), UtPrimitiveModel(1)), - ), fuzz.map { arguments -> arguments.map { fuzzedValue -> fuzzedValue.model } }.toSet()) - } - - // Because of Long limitation fuzzer can process no more than 511 values for method with 7 parameters - @Test - @Timeout(1, unit = TimeUnit.SECONDS) - fun `the worst case works well`() { - assertDoesNotThrow { - val values = (0 until 511).map { UtPrimitiveModel(it).fuzzed() }.asSequence() - val provider = ModelProvider { descr -> - (0 until descr.parameters.size).asSequence() - .flatMap { index -> values.map { FuzzedParameter(index, it) } } - } - val parameters = (0 until 7).mapTo(mutableListOf()) { intClassId } - val fuzz = fuzz(newDescription(parameters), provider) - val first10 = fuzz.take(10).toList() - assertEquals(10, first10.size) - } - } - - private fun defaultTypes(includeStringId: Boolean = false): List { - val result = mutableListOf( - booleanClassId, - byteClassId, - charClassId, - shortClassId, - intClassId, - longClassId, - floatClassId, - doubleClassId, - ) - if (includeStringId) { - result += stringClassId - } - result += Any::class.java.id - return result - } - - private fun newDescription( - parameters: List, - concreteValues: Collection = emptyList() - ): FuzzedMethodDescription { - return FuzzedMethodDescription("testMethod", voidClassId, parameters, concreteValues) - } - -} \ No newline at end of file diff --git a/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/MockOfObjectModelProviderTest.kt b/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/MockOfObjectModelProviderTest.kt deleted file mode 100644 index d24e85e98e..0000000000 --- a/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/MockOfObjectModelProviderTest.kt +++ /dev/null @@ -1,123 +0,0 @@ -package org.utbot.framework.plugin.api - -import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.Test -import org.utbot.framework.plugin.api.util.UtContext -import org.utbot.framework.plugin.api.util.doubleWrapperClassId -import org.utbot.framework.plugin.api.util.id -import org.utbot.framework.plugin.api.util.voidClassId -import org.utbot.framework.plugin.api.util.withUtContext -import org.utbot.fuzzer.FuzzedMethodDescription -import org.utbot.fuzzer.objects.create -import org.utbot.fuzzer.objects.replaceWithMock -import org.utbot.fuzzer.objects.toFuzzerMockable -import org.utbot.fuzzer.providers.ObjectModelProvider - -class MockOfObjectModelProviderTest { - - class Some { - @Suppress("unused") - var another: Some? = null - } - - @Test - fun `no mock is generated by default`() = withContext { - val description = FuzzedMethodDescription("test", voidClassId, listOf(Some::class.id)) - val provider = ObjectModelProvider(TestIdentityPreservingIdGenerator) - val results = provider.generate(description).map { it.value.model }.map { - replaceWithMock(it) { m -> description.shouldMock(m) } - }.toList() - assertEquals(2, results.size) - results.forEach { model -> - assertInstanceOf(UtAssembleModel::class.java, model) - } - assertEquals(0, (results[1] as UtAssembleModel).modificationsChain.size) - assertEquals(1, (results[0] as UtAssembleModel).modificationsChain.size) - } - - @Test - fun `mock is generated`() = withContext { - val description = FuzzedMethodDescription("test", voidClassId, listOf(Some::class.id)).apply { - shouldMock = { true } - } - val provider = ObjectModelProvider(TestIdentityPreservingIdGenerator) - val results = provider.generate(description).map { it.value.model }.map { - replaceWithMock(it) { m -> description.shouldMock(m) } - }.toList() - assertEquals(2, results.size) - results.forEach { model -> - assertInstanceOf(UtCompositeModel::class.java, model) - assertTrue((model as UtCompositeModel).isMock) - } - } - - @Test - fun `mock is generated for several recursion level`() = withContext { - val description = FuzzedMethodDescription("test", voidClassId, listOf(Some::class.id)).apply { - shouldMock = { true } - } - val provider = ObjectModelProvider(TestIdentityPreservingIdGenerator, recursionDepthLeft = 2) - val results = provider.generate(description).map { it.value.model }.map { - replaceWithMock(it) { m -> description.shouldMock(m) } - }.toList() - assertEquals(2, results.size) - results.forEach { model -> - assertInstanceOf(UtCompositeModel::class.java, model) - assertTrue((model as UtCompositeModel).isMock) - } - val modelWithFieldChanger = results[0] as UtCompositeModel - assertEquals(1, modelWithFieldChanger.mocks.size) - val entry = modelWithFieldChanger.mocks.entries.single() - assertEquals("getAnother", entry.key.name) - assertEquals(Some::class.id, entry.key.returnType) - assertEquals(1, entry.value.size) - assertInstanceOf(UtCompositeModel::class.java, entry.value.single()) - } - - @Test - fun `check field replaced with concrete values`() { - val customModel = Any::class.id.create { - using empty constructor - call instance field("some") with UtNullModel(Nothing::class.id) - } - val replacedModel = replaceWithMock(customModel) { true } - assertInstanceOf(UtCompositeModel::class.java, replacedModel) - replacedModel as UtCompositeModel - assertEquals(0, replacedModel.mocks.size) - val fields = replacedModel.fields - assertEquals(1, fields.size) - val entry = fields.entries.single() - assertEquals("some", entry.key.name) - assertEquals(UtNullModel(Nothing::class.id), entry.value) - } - - @Test - fun `check method replaced with mock values`() { - val customModel = Any::class.id.create { - using empty constructor - call instance method("some").toFuzzerMockable { - yield(MethodId(classId, "another", doubleWrapperClassId, emptyList()) to listOf(UtPrimitiveModel(2.0))) - } with values(UtNullModel(Nothing::class.id)) - } - val replacedModel = replaceWithMock(customModel) { true } - assertInstanceOf(UtCompositeModel::class.java, replacedModel) - replacedModel as UtCompositeModel - assertEquals(0, replacedModel.fields.size) - val mocks = replacedModel.mocks - assertEquals(1, replacedModel.mocks.size) - val (executableId, models) = mocks.entries.single() - assertEquals("another", executableId.name) - assertEquals(doubleWrapperClassId, executableId.returnType) - assertEquals(0, executableId.parameters.size) - assertEquals(1, models.size) - assertInstanceOf(UtPrimitiveModel::class.java, models.single()) - assertEquals(2.0, (models.single() as UtPrimitiveModel).value) - } - - private fun withContext(block: () -> T) { - withUtContext(UtContext(this::class.java.classLoader)) { - block() - } - } - -} \ No newline at end of file diff --git a/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/ModelMutatorTest.kt b/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/ModelMutatorTest.kt deleted file mode 100644 index 45750f1a2b..0000000000 --- a/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/ModelMutatorTest.kt +++ /dev/null @@ -1,37 +0,0 @@ -package org.utbot.framework.plugin.api - -import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.Test -import org.utbot.fuzzing.utils.invertBit -import kotlin.random.Random - -class ModelMutatorTest { - - @Test - fun `invert bit works for long`() { - var attempts = 100_000 - val random = Random(2210) - sequence { - while (true) { - yield(random.nextLong()) - } - }.forEach { value -> - if (attempts-- <= 0) { return } - for (bit in 0 until Long.SIZE_BITS) { - val newValue = value.invertBit(bit) - val oldBinary = value.toBinaryString() - val newBinary = newValue.toBinaryString() - assertEquals(oldBinary.length, newBinary.length) - for (test in Long.SIZE_BITS - 1 downTo 0) { - if (test != Long.SIZE_BITS - 1 - bit) { - assertEquals(oldBinary[test], newBinary[test]) { "$oldBinary : $newBinary for value $value" } - } else { - assertNotEquals(oldBinary[test], newBinary[test]) { "$oldBinary : $newBinary for value $value" } - } - } - } - } - } - - private fun Long.toBinaryString() = java.lang.Long.toBinaryString(this).padStart(Long.SIZE_BITS, '0') -} \ No newline at end of file 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 deleted file mode 100644 index 041ea33339..0000000000 --- a/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/ModelProviderTest.kt +++ /dev/null @@ -1,613 +0,0 @@ -package org.utbot.framework.plugin.api - -import org.utbot.framework.plugin.api.util.UtContext -import org.utbot.framework.plugin.api.util.booleanClassId -import org.utbot.framework.plugin.api.util.byteClassId -import org.utbot.framework.plugin.api.util.charClassId -import org.utbot.framework.plugin.api.util.doubleClassId -import org.utbot.framework.plugin.api.util.floatClassId -import org.utbot.framework.plugin.api.util.id -import org.utbot.framework.plugin.api.util.intClassId -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.framework.plugin.api.util.voidClassId -import org.utbot.framework.plugin.api.util.withUtContext -import org.utbot.fuzzer.FuzzedConcreteValue -import org.utbot.fuzzer.FuzzedMethodDescription -import org.utbot.fuzzer.ModelProvider -import org.utbot.fuzzer.providers.ConstantsModelProvider -import org.utbot.fuzzer.providers.ObjectModelProvider -import org.utbot.fuzzer.providers.PrimitivesModelProvider -import org.utbot.fuzzer.providers.StringConstantModelProvider -import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.Test -import org.utbot.framework.plugin.api.samples.FieldSetterClass -import org.utbot.framework.plugin.api.samples.OuterClassWithEnums -import org.utbot.framework.plugin.api.samples.PackagePrivateFieldAndClass -import org.utbot.framework.plugin.api.samples.SampleEnum -import org.utbot.framework.plugin.api.samples.WithInnerClass -import org.utbot.framework.plugin.api.util.executableId -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.FuzzedContext -import org.utbot.fuzzer.FuzzedValue -import org.utbot.fuzzer.IdentityPreservingIdGenerator -import org.utbot.fuzzer.ReferencePreservingIntIdGenerator -import org.utbot.fuzzer.ModelProvider.Companion.yieldValue -import org.utbot.fuzzer.defaultModelProviders -import org.utbot.fuzzer.mutators.StringRandomMutator -import org.utbot.fuzzer.providers.CharToStringModelProvider.fuzzed -import org.utbot.fuzzer.providers.EnumModelProvider -import org.utbot.fuzzer.providers.PrimitiveDefaultsModelProvider -import java.util.Date -import java.util.concurrent.atomic.AtomicInteger -import kotlin.random.Random - -class ModelProviderTest { - - @Test - fun `test generate primitive models for boolean`() { - val models = collect(PrimitivesModelProvider, - parameters = listOf(booleanClassId) - ) - - assertEquals(1, models.size) - assertEquals(2, models[0]!!.size) - assertTrue(models[0]!!.contains(UtPrimitiveModel(true))) - assertTrue(models[0]!!.contains(UtPrimitiveModel(false))) - } - - @Test - fun `test all known primitive types are generate at least one value`() { - val primitiveTypes = listOf( - byteClassId, - booleanClassId, - charClassId, - shortClassId, - intClassId, - longClassId, - floatClassId, - doubleClassId, - stringClassId, - ) - val models = collect(PrimitivesModelProvider, - parameters = primitiveTypes - ) - - assertEquals(primitiveTypes.size, models.size) - primitiveTypes.indices.forEach { - assertTrue(models[it]!!.isNotEmpty()) - } - } - - @Test - fun `test that empty constants don't generate any models`() { - val models = collect(ConstantsModelProvider, - parameters = listOf(intClassId), - constants = emptyList() - ) - - assertEquals(0, models.size) - } - - @Test - fun `test that one constant generate corresponding value`() { - val models = collect(ConstantsModelProvider, - parameters = listOf(intClassId), - constants = listOf( - FuzzedConcreteValue(intClassId, 123) - ) - ) - - assertEquals(1, models.size) - assertEquals(1, models[0]!!.size) - assertEquals(UtPrimitiveModel(123), models[0]!![0]) - assertEquals(intClassId, models[0]!![0].classId) - } - - @Test - fun `test that constants are mutated if comparison operation is set`() { - val models = collect(ConstantsModelProvider, - parameters = listOf(intClassId), - constants = listOf( - FuzzedConcreteValue(intClassId, 10, FuzzedContext.Comparison.EQ), - FuzzedConcreteValue(intClassId, 20, FuzzedContext.Comparison.NE), - FuzzedConcreteValue(intClassId, 30, FuzzedContext.Comparison.LT), - FuzzedConcreteValue(intClassId, 40, FuzzedContext.Comparison.LE), - FuzzedConcreteValue(intClassId, 50, FuzzedContext.Comparison.GT), - FuzzedConcreteValue(intClassId, 60, FuzzedContext.Comparison.GE), - ) - ) - - assertEquals(1, models.size) - val expectedValues = listOf(10, 11, 20, 21, 29, 30, 40, 41, 50, 51, 59, 60) - assertEquals(expectedValues.size, models[0]!!.size) - expectedValues.forEach { - assertTrue(models[0]!!.contains(UtPrimitiveModel(it))) - } - } - - @Test - fun `test constant empty string generates only corresponding model`() { - val models = collect(StringConstantModelProvider, - parameters = listOf(stringClassId), - constants = listOf( - FuzzedConcreteValue(stringClassId, ""), - ) - ) - - assertEquals(1, models.size) - assertEquals(1, models[0]!!.size) - assertEquals(UtPrimitiveModel(""), models[0]!![0]) - } - - @Test - fun `test non-empty string is not mutated if operation is not set`() { - val models = collect(StringConstantModelProvider, - parameters = listOf(stringClassId), - constants = listOf( - FuzzedConcreteValue(stringClassId, "nonemptystring"), - ) - ) - - assertEquals(1, models.size) - assertEquals(1, models[0]!!.size) - assertEquals(UtPrimitiveModel("nonemptystring"), models[0]!![0]) - } - - @Test - fun `test non-empty string is mutated if modification operation is set`() { - val method = String::class.java.getDeclaredMethod("subSequence", Int::class.java, Int::class.java) - - val description = FuzzedMethodDescription( - "method", - voidClassId, - listOf(stringClassId), - listOf( - FuzzedConcreteValue(stringClassId, "nonemptystring", FuzzedContext.Call(method.executableId)) - ) - ) - - val models = mutableMapOf>().apply { - StringConstantModelProvider.generate(description).forEach { (i, m) -> - computeIfAbsent(i) { mutableListOf() }.add(m) - } - } - - assertEquals(1, models.size) - assertEquals(1, models[0]!!.size) - - val mutate = StringRandomMutator.mutate(description, listOf(models[0]!![0]), Random(0)) - - assertEquals(1, mutate.size) - assertEquals(UtPrimitiveModel("nonemptystring"), models[0]!![0].model) - assertEquals(UtPrimitiveModel("nonemptstring"), mutate[0].value.model) - } - - @Test - @Suppress("unused", "UNUSED_PARAMETER", "RemoveEmptySecondaryConstructorBody") - fun `test default object model creation for simple constructors`() { - withUtContext(UtContext(this::class.java.classLoader)) { - class A { - constructor(a: Int) {} - constructor(a: Int, b: String) {} - constructor(a: Int, b: String, c: Boolean) - } - - val classId = A::class.java.id - val models = collect( - ObjectModelProvider(ReferencePreservingIntIdGenerator(0)).apply { - modelProviderForRecursiveCalls = ModelProvider.of(PrimitiveDefaultsModelProvider) - }, - parameters = listOf(classId) - ) - - assertEquals(1, models.size) - assertEquals(3, models[0]!!.size) - assertTrue(models[0]!!.all { it is UtAssembleModel && it.classId == classId }) - - models[0]!!.filterIsInstance().forEachIndexed { index, model -> - val stm = model.instantiationCall - val paramCountInConstructorAsTheyListed = index + 1 - assertEquals(paramCountInConstructorAsTheyListed, stm.params.size) - } - } - } - - @Test - fun `test no object model is created for empty constructor`() { - withUtContext(UtContext(this::class.java.classLoader)) { - class A - - val classId = A::class.java.id - val models = collect( - ObjectModelProvider(ReferencePreservingIntIdGenerator(0)), - parameters = listOf(classId) - ) - - assertEquals(1, models.size) - assertEquals(1, models[0]!!.size) - } - } - - @Test - @Suppress("unused", "UNUSED_PARAMETER") - fun `test that constructors with not primitive parameters are ignored`() { - withUtContext(UtContext(this::class.java.classLoader)) { - class A { - constructor(a: Int, b: Int) - constructor(a: Int, b: Date) - } - - val classId = A::class.java.id - val models = collect( - ObjectModelProvider(ReferencePreservingIntIdGenerator(0)), - parameters = listOf(classId) - ) - - assertEquals(1, models.size) - assertTrue(models[0]!!.isNotEmpty()) - val chain = (models[0]!![0] as UtAssembleModel).instantiationCall - chain.params.forEach { - assertEquals(intClassId, it.classId) - } - } - } - - @Test - fun `test fallback model can create custom values for any parameter`() { - val firstParameterIsUserGenerated = ModelProvider { - sequence { - yieldValue(0, UtPrimitiveModel(-123).fuzzed()) - } - }.withFallback(PrimitivesModelProvider) - - val result = collect( - firstParameterIsUserGenerated, - parameters = listOf(intClassId, intClassId) - ) - - assertEquals(2, result.size) - assertEquals(1, result[0]!!.size) - assertTrue(result[1]!!.size > 1) - assertEquals(UtPrimitiveModel(-123), result[0]!![0]) - } - - @Test - fun `test collection model can produce basic values with assembled model`() { - withUtContext(UtContext(this::class.java.classLoader)) { - val result = collect( - defaultModelProviders(ReferencePreservingIntIdGenerator(0)), - parameters = listOf(java.util.List::class.java.id) - ) - - assertEquals(1, result.size) - } - } - - @Test - fun `test enum model provider`() { - withUtContext(UtContext(this::class.java.classLoader)) { - val result = collect(EnumModelProvider(ReferencePreservingIntIdGenerator(0)), parameters = listOf(OneTwoThree::class.java.id)) - assertEquals(1, result.size) - assertEquals(3, result[0]!!.size) - OneTwoThree.values().forEachIndexed { index: Int, value -> - assertEquals(UtEnumConstantModel(index + 1, OneTwoThree::class.java.id, value), result[0]!![index]) - } - } - } - - @Test - fun `test string value generates only primitive models`() { - withUtContext(UtContext(this::class.java.classLoader)) { - val result = collect( - defaultModelProviders(ReferencePreservingIntIdGenerator(0)), - parameters = listOf(stringClassId) - ) - assertEquals(1, result.size) - result[0]!!.forEach { - assertInstanceOf(UtPrimitiveModel::class.java, it) - assertEquals(stringClassId, it.classId) - } - } - } - - @Test - fun `test wrapper primitives generate only primitive models`() { - withUtContext(UtContext(this::class.java.classLoader)) { - primitiveWrappers.asSequence().filterNot { it == voidWrapperClassId }.forEach { classId -> - val result = collect( - defaultModelProviders(ReferencePreservingIntIdGenerator(0)), - parameters = listOf(classId) - ) - assertEquals(1, result.size) - result[0]!!.forEach { - assertInstanceOf(UtPrimitiveModel::class.java, it) - val expectPrimitiveBecauseItShouldBeGeneratedByDefaultProviders = primitiveByWrapper[classId] - assertEquals(expectPrimitiveBecauseItShouldBeGeneratedByDefaultProviders, it.classId) - } - } - } - } - - @Test - fun `test at least one string is created if characters exist as constants`() { - withUtContext(UtContext(this::class.java.classLoader)) { - val result = collect( - defaultModelProviders(ReferencePreservingIntIdGenerator(0)), - parameters = listOf(stringClassId), - constants = listOf( - FuzzedConcreteValue(charClassId, 'a'), - FuzzedConcreteValue(charClassId, 'b'), - FuzzedConcreteValue(charClassId, 'c'), - ) - ) - assertEquals(1, result.size) - assertTrue(result[0]!!.any { - it is UtPrimitiveModel && it.value == "abc" - }) - } - } - - @Test - @Suppress("unused", "UNUSED_PARAMETER", "ConvertSecondaryConstructorToPrimary") - fun `test complex object is constructed and it is not null`() { - class A { - constructor(some: Any) - } - - withUtContext(UtContext(this::class.java.classLoader)) { - val result = collect( - ObjectModelProvider(ReferencePreservingIntIdGenerator(0)), - parameters = listOf(A::class.java.id) - ) - assertEquals(1, result.size) - assertEquals(1, result[0]!!.size) - assertInstanceOf(UtAssembleModel::class.java, result[0]!![0]) - assertEquals(A::class.java.id, result[0]!![0].classId) - (result[0]!![0] as UtAssembleModel).instantiationCall.let { - assertEquals(1, it.params.size) - val objectParamInConstructor = it.params[0] - assertInstanceOf(UtAssembleModel::class.java, objectParamInConstructor) - val innerAssembledModel = objectParamInConstructor as UtAssembleModel - assertEquals(Any::class.java.id, innerAssembledModel.classId) - val objectCreation = innerAssembledModel.instantiationCall - assertEquals(0, objectCreation.params.size) - assertInstanceOf(ConstructorId::class.java, objectCreation.executable) - } - } - } - - @Test - @Suppress("unused", "UNUSED_PARAMETER", "ConvertSecondaryConstructorToPrimary") - fun `test recursive constructor calls and can pass null into inner if no other values exist`() { - class MyA { - constructor(some: MyA?) - } - - withUtContext(UtContext(this::class.java.classLoader)) { - val result = collect( - ObjectModelProvider(ReferencePreservingIntIdGenerator(0), recursionDepthLeft = 1), - parameters = listOf(MyA::class.java.id) - ) - assertEquals(1, result.size) - assertEquals(1, result[0]!!.size) - val outerModel = result[0]!![0] as UtAssembleModel - outerModel.instantiationCall.let { - val constructorParameters = it.params - assertEquals(1, constructorParameters.size) - val innerModel = (constructorParameters[0] as UtAssembleModel) - assertEquals(MyA::class.java.id, innerModel.classId) - val innerConstructorParameters = innerModel.instantiationCall - assertEquals(1, innerConstructorParameters.params.size) - assertInstanceOf(UtNullModel::class.java, innerConstructorParameters.params[0]) - } - } - } - - @Test - @Suppress("unused", "UNUSED_PARAMETER", "ConvertSecondaryConstructorToPrimary") - fun `test complex object is constructed with the simplest inner object constructor`() { - - class Inner { - constructor(some: Inner?) - - constructor(some: Inner?, other: Any) - - // this constructor should be chosen - constructor(int: Int, double: Double) - - constructor(other: Any, int: Int) - - constructor(some: Inner?, other: Double) - } - - class Outer { - constructor(inner: Inner) - } - - withUtContext(UtContext(this::class.java.classLoader)) { - val result = collect( - ObjectModelProvider(ReferencePreservingIntIdGenerator(0)), - parameters = listOf(Outer::class.java.id) - ) - assertEquals(1, result.size) - var callCount = 0 - result[0]!!.filterIsInstance().forEach { outerModel -> - callCount++ - outerModel.instantiationCall.let { - val constructorParameters = it.params - assertEquals(1, constructorParameters.size) - val innerModel = (constructorParameters[0] as UtAssembleModel) - assertEquals(Inner::class.java.id, innerModel.classId) - val innerConstructorParameters = innerModel.instantiationCall - assertEquals(2, innerConstructorParameters.params.size) - assertTrue(innerConstructorParameters.params.all { param -> param is UtPrimitiveModel }) - assertEquals(intClassId, innerConstructorParameters.params[0].classId) - assertEquals(doubleClassId, innerConstructorParameters.params[1].classId) - } - } - assertEquals(callCount, result[0]!!.size) - } - } - - @Test - fun `test complex object is created with setters`() { - val j = FieldSetterClass::class.java - assertEquals(6, j.declaredFields.size) - assertTrue( - setOf( - "pubStaticField", - "pubFinalField", - "pubField", - "pubFieldWithSetter", - "prvField", - "prvFieldWithSetter", - ).containsAll(j.declaredFields.map { it.name }) - ) - assertEquals(4, j.declaredMethods.size) - assertTrue( - setOf( - "getPubFieldWithSetter", - "setPubFieldWithSetter", - "getPrvFieldWithSetter", - "setPrvFieldWithSetter", - ).containsAll(j.declaredMethods.map { it.name }) - ) - - withUtContext(UtContext(this::class.java.classLoader)) { - val result = collect(ObjectModelProvider(ReferencePreservingIntIdGenerator(0), recursionDepthLeft = 1).apply { - modelProviderForRecursiveCalls = PrimitiveDefaultsModelProvider - }, parameters = listOf(FieldSetterClass::class.java.id)) - assertEquals(1, result.size) - assertEquals(2, result[0]!!.size) - assertEquals(0, (result[0]!![1] as UtAssembleModel).modificationsChain.size) { "One of models must be without any modifications" } - val expectedModificationSize = 3 - val modificationsChain = (result[0]!![0] as UtAssembleModel).modificationsChain - val actualModificationSize = modificationsChain.size - assertEquals(expectedModificationSize, actualModificationSize) { "In target class there's only $expectedModificationSize fields that can be changed, but generated $actualModificationSize modifications" } - - assertEquals("pubField", (modificationsChain[0] as UtDirectSetFieldModel).fieldId.name) - assertEquals("pubFieldWithSetter", (modificationsChain[1] as UtDirectSetFieldModel).fieldId.name) - assertEquals("setPrvFieldWithSetter", (modificationsChain[2] as UtExecutableCallModel).executable.name) - } - } - - @Test - fun `test complex object is created with setters and package private field and constructor`() { - val j = PackagePrivateFieldAndClass::class.java - assertEquals(1, j.declaredFields.size) - assertTrue( - setOf( - "pkgField", - ).containsAll(j.declaredFields.map { it.name }) - ) - - withUtContext(UtContext(this::class.java.classLoader)) { - val result = collect(ObjectModelProvider(ReferencePreservingIntIdGenerator(0)).apply { - modelProviderForRecursiveCalls = PrimitiveDefaultsModelProvider - }, parameters = listOf(PackagePrivateFieldAndClass::class.java.id)) { - packageName = PackagePrivateFieldAndClass::class.java.`package`.name - } - assertEquals(1, result.size) - assertEquals(3, result[0]!!.size) - assertEquals(0, (result[0]!![2] as UtAssembleModel).modificationsChain.size) { "One of models must be without any modifications" } - assertEquals(0, (result[0]!![1] as UtAssembleModel).modificationsChain.size) { "Modification by constructor doesn't change fields" } - val expectedModificationSize = 1 - val modificationsChain = (result[0]!![0] as UtAssembleModel).modificationsChain - val actualModificationSize = modificationsChain.size - assertEquals(expectedModificationSize, actualModificationSize) { "In target class there's only $expectedModificationSize fields that can be changed, but generated $actualModificationSize modifications" } - - assertEquals("pkgField", (modificationsChain[0] as UtDirectSetFieldModel).fieldId.name) - } - } - - @Test - fun `test that enum models in a recursive object model are consistent`() { - withUtContext(UtContext(this::class.java.classLoader)) { - val idGenerator = ReferencePreservingIntIdGenerator() - val expectedIds = SampleEnum.values().associateWith { idGenerator.getOrCreateIdForValue(it) } - - val result = collect( - ObjectModelProvider(idGenerator), - parameters = listOf(OuterClassWithEnums::class.java.id) - ) - - assertEquals(1, result.size) - val models = result[0] ?: fail("Inconsistent result") - - for (model in models) { - val outerModel = (model as? UtAssembleModel) - ?.instantiationCall - ?: fail("No final instantiation model found for the outer class") - for (param in outerModel.params) { - when (param) { - is UtEnumConstantModel -> { - assertEquals(expectedIds[param.value], param.id) - } - is UtAssembleModel -> { - for (enumParam in param.instantiationCall.params) { - enumParam as UtEnumConstantModel - assertEquals(expectedIds[enumParam.value], enumParam.id) - } - } - else -> { - fail("Unexpected parameter model: $param") - } - } - } - } - } - } - - @Test - fun `no models are created for inner non-static class`() { - withUtContext(UtContext(this::class.java.classLoader)) { - val result = collect( - ObjectModelProvider(TestIdentityPreservingIdGenerator), - parameters = listOf(WithInnerClass.NonStatic::class.id) - ) - assertEquals(0, result.size) - } - } - - @Test - fun `some models are created for inner static class`() { - withUtContext(UtContext(this::class.java.classLoader)) { - val result = collect( - ObjectModelProvider(TestIdentityPreservingIdGenerator), - parameters = listOf(WithInnerClass.Static::class.id) - ) - assertEquals(1, result.size) - assertTrue(result[0]!!.isNotEmpty()) - } - } - - private enum class OneTwoThree { - ONE, TWO, THREE - } -} - -internal fun collect( - modelProvider: ModelProvider, - name: String = "testMethod", - returnType: ClassId = voidClassId, - parameters: List, - constants: List = emptyList(), - block: FuzzedMethodDescription.() -> Unit = {} -): Map> { - return mutableMapOf>().apply { - modelProvider.generate(FuzzedMethodDescription(name, returnType, parameters, constants).apply(block)).forEach { (i, m) -> - computeIfAbsent(i) { mutableListOf() }.add(m.model) - } - } -} - -internal object TestIdentityPreservingIdGenerator : IdentityPreservingIdGenerator { - private val cache = mutableMapOf() - private val gen = AtomicInteger() - override fun getOrCreateIdForValue(value: Any): Int = cache.computeIfAbsent(value) { createId() } - override fun createId(): Int = gen.incrementAndGet() -} \ No newline at end of file diff --git a/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/Api.kt b/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/Api.kt index 8c0c47bfcf..aa810f2378 100644 --- a/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/Api.kt +++ b/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/Api.kt @@ -1,7 +1,7 @@ @file:JvmName("FuzzingApi") package org.utbot.fuzzing -import kotlinx.coroutines.yield +import kotlinx.coroutines.* import mu.KotlinLogging import org.utbot.fuzzing.seeds.KnownValue import org.utbot.fuzzing.utils.MissedSeed @@ -47,24 +47,31 @@ interface Fuzzing, FEEDBACK : Feed suspend fun handle(description: DESCRIPTION, values: List): FEEDBACK /** - * This method is called before every fuzzing attempt. - * - * Usually, is used to update configuration or manipulate some data in the statistics - * (for example, clear some [Statistic.missedTypes] types). - * - * @param description contains user-defined information about current run. Can be used as a state of the run. - * @param statistic statistic about fuzzing generation like elapsed time or number of the runs. - * @param configuration current used configuration; it can be changes for tuning fuzzing. + * Starts fuzzing with new description but with copy of [Statistic]. + */ + suspend fun fork(description: DESCRIPTION, statistics: Statistic) { + fuzz(description, StatisticImpl(statistics)) + } + + /** + * Checks whether the fuzzer should stop. */ - suspend fun update(description: DESCRIPTION, statistic: Statistic, configuration: Configuration) {} + suspend fun isCancelled(description: DESCRIPTION, stats: Statistic): Boolean { + return description.parameters.isEmpty() + } + + suspend fun beforeIteration(description: DESCRIPTION, statistics: Statistic) { } + suspend fun afterIteration(description: DESCRIPTION, statistics: Statistic) { } } /** * Some description of current fuzzing run. Usually, it contains the name of the target method and its parameter list. */ open class Description( - val parameters: List -) + parameters: List +) { + val parameters: List = parameters.toList() +} /** * Input value that fuzzing knows how to build and use them. @@ -115,7 +122,7 @@ sealed interface Seed { * Routine is a task that is used to build a value. * * There are several types of a routine, which all are generally only functions. - * These function accepts some data and generates target value. + * These functions accept some data and generate target value. */ sealed class Routine(val types: List) : Iterable by types { @@ -211,13 +218,6 @@ enum class Control { */ CONTINUE, - /** - * Reset type cache and continue. - * - * Current seed and result will be analysed and cached. - */ - RESET_TYPE_CACHE_AND_CONTINUE, - /** * Do not process this feedback and just start next value generation. */ @@ -253,81 +253,71 @@ class NoSeedValueException internal constructor( val type: Any? ) : Exception("No seed candidates generated for type: $type") +suspend fun , F : Feedback> Fuzzing.fuzz( + description: D, + random: Random = Random(0), + configuration: Configuration = Configuration() +) { + fuzz(description, StatisticImpl(random = random, configuration = configuration)) +} + /** * Starts fuzzing for this [Fuzzing] object. * * This is an entry point for every fuzzing. */ -suspend fun , F : Feedback> Fuzzing.fuzz( +private suspend fun , F : Feedback> Fuzzing.fuzz( description: D, - random: Random = Random(0), - configuration: Configuration = Configuration() + statistic: StatisticImpl, ) { - class StatImpl( - override var totalRuns: Long = 0, - val startTime: Long = System.nanoTime(), - override var missedTypes: MissedSeed = MissedSeed(), - ) : Statistic { - override val elapsedTime: Long - get() = System.nanoTime() - startTime - } - val userStatistic = StatImpl() + val random = statistic.random + val configuration = statistic.configuration val fuzzing = this val typeCache = hashMapOf>>() - fun fuzzOne(): Node = fuzz( - parameters = description.parameters, + fun fuzzOne(parameters: List): Node = fuzz( + parameters = parameters, fuzzing = fuzzing, description = description, random = random, configuration = configuration, builder = PassRoutine("Main Routine"), - state = State(1, typeCache, userStatistic.missedTypes), + state = State(1, typeCache, statistic.missedTypes), ) - val dynamicallyGenerated = mutableListOf>() - val seeds = Statistics() - run breaking@ { - sequence { - while (description.parameters.isNotEmpty()) { - if (dynamicallyGenerated.isNotEmpty()) { - yield(dynamicallyGenerated.removeFirst()) - } else { - val fuzzOne = fuzzOne() - // fuzz one value, seems to be bad, when have only a few and simple values - yield(fuzzOne) - - val randomSeed = seeds.getRandomSeed(random, configuration) - if (randomSeed != null) { - dynamicallyGenerated += mutate( - randomSeed, - fuzzing, - random, - configuration, - State(1, typeCache, userStatistic.missedTypes) - ) - } - } + + while (!fuzzing.isCancelled(description, statistic)) { + beforeIteration(description, statistic) + val seed = if (statistic.isNotEmpty() && random.flipCoin(configuration.probSeedRetrievingInsteadGenerating)) { + statistic.getRandomSeed(random, configuration) + } else { + val actualParameters = description.parameters + // fuzz one value, seems to be bad, when have only a few and simple values + fuzzOne(actualParameters) + } + val values = mutate( + seed, + fuzzing, + random, + configuration, + State(1, typeCache, statistic.missedTypes) + ) + afterIteration(description, statistic) + + yield() + statistic.apply { + totalRuns++ + } + check(values.parameters.size == values.result.size) { "Cannot create value for ${values.parameters}" } + val valuesCache = mutableMapOf, R>() + val result = values.result.map { valuesCache.computeIfAbsent(it) { r -> create(r) } } + val feedback = fuzzing.handle(description, result) + when (feedback.control) { + Control.CONTINUE -> { + statistic.put(random, configuration, feedback, values) } - }.forEach execution@ { values -> - yield() - fuzzing.update(description, userStatistic.apply { - totalRuns++ - }, configuration) - check(values.parameters.size == values.result.size) { "Cannot create value for ${values.parameters}" } - val valuesCache = mutableMapOf, R>() - val result = values.result.map { valuesCache.computeIfAbsent(it) { r -> create(r) } } - val feedback = fuzzing.handle(description, result) - when (feedback.control) { - Control.CONTINUE -> { - seeds.put(random, configuration, feedback, values) - } - Control.RESET_TYPE_CACHE_AND_CONTINUE -> { - dynamicallyGenerated.clear() - typeCache.clear() - seeds.put(random, configuration, feedback, values) - } - Control.STOP -> { return@breaking } - Control.PASS -> {} + Control.STOP -> { + break } + Control.PASS -> {} } } } @@ -678,8 +668,24 @@ private class Node( val builder: Routine, ) +private class StatisticImpl>( + override var totalRuns: Long = 0, + override val startTime: Long = System.nanoTime(), + override var missedTypes: MissedSeed = MissedSeed(), + override val random: Random, + override val configuration: Configuration, +) : Statistic { + + constructor(source: Statistic) : this( + totalRuns = source.totalRuns, + startTime = source.startTime, + missedTypes = source.missedTypes, + random = source.random, + configuration = source.configuration.copy(), + ) -private class Statistics> { + override val elapsedTime: Long + get() = System.nanoTime() - startTime private val seeds = linkedMapOf>() private val count = linkedMapOf() @@ -692,8 +698,8 @@ private class Statistics> { count[feedback] = count.getOrDefault(feedback, 0L) + 1L } - fun getRandomSeed(random: Random, configuration: Configuration): Node? { - if (seeds.isEmpty()) return null + fun getRandomSeed(random: Random, configuration: Configuration): Node { + if (seeds.isEmpty()) error("Call `isNotEmpty` before getting the seed") val entries = seeds.entries.toList() val frequencies = DoubleArray(seeds.size).also { f -> entries.forEachIndexed { index, (key, _) -> @@ -703,6 +709,7 @@ private class Statistics> { val index = random.chooseOne(frequencies) return entries[index].value } -} -///endregion \ No newline at end of file + fun isNotEmpty() = seeds.isNotEmpty() +} +///endregion diff --git a/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/Configuration.kt b/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/Configuration.kt index 29cf61b5a3..6f43fadbc2 100644 --- a/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/Configuration.kt +++ b/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/Configuration.kt @@ -5,7 +5,13 @@ import kotlin.math.pow /** * Configures fuzzing behaviour. Usually, it is not required to tune anything. */ -class Configuration( +data class Configuration( + + /** + * Choose between already generated values and new generation of values. + */ + var probSeedRetrievingInsteadGenerating: Int = 70, + /** * Fuzzer creates a tree of object for generating values. At some point this recursion should be stopped. * 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 319dfecb64..f2b1e9ca1c 100644 --- a/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/Providers.kt +++ b/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/Providers.kt @@ -29,8 +29,6 @@ class BaseFuzzing, F : Feedback>( val exec: suspend (description: D, values: List) -> F ) : Fuzzing { - var update: suspend (D, Statistic, Configuration) -> Unit = { d, s, c -> super.update(d, s, c) } - constructor(vararg providers: ValueProvider, exec: suspend (description: D, values: List) -> F) : this(providers.toList(), exec) override fun generate(description: D, type: T): Sequence> { @@ -51,10 +49,6 @@ class BaseFuzzing, F : Feedback>( override suspend fun handle(description: D, values: List): F { return exec(description, values) } - - override suspend fun update(description: D, statistic: Statistic, configuration: Configuration) { - update.invoke(description, statistic, configuration) - } } /** diff --git a/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/Statistic.kt b/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/Statistic.kt index 3641d3b064..877937cedb 100644 --- a/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/Statistic.kt +++ b/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/Statistic.kt @@ -1,14 +1,16 @@ package org.utbot.fuzzing import org.utbot.fuzzing.utils.MissedSeed +import kotlin.random.Random /** * User class that holds data about current fuzzing running. - * - * Concrete implementation is passed to the [Fuzzing.update]. */ interface Statistic { + val startTime: Long val totalRuns: Long val elapsedTime: Long val missedTypes: MissedSeed + val random: Random + val configuration: Configuration } \ No newline at end of file diff --git a/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/demo/ForkFuzzing.kt b/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/demo/ForkFuzzing.kt new file mode 100644 index 0000000000..99be17e156 --- /dev/null +++ b/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/demo/ForkFuzzing.kt @@ -0,0 +1,57 @@ +package org.utbot.fuzzing.demo + +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import org.utbot.fuzzing.* +import java.util.concurrent.atomic.AtomicLong + +private enum class Type { + ANY, CONCRETE, MORE_CONCRETE +} + +fun main(): Unit = runBlocking { + launch { + object : Fuzzing, Feedback> { + + private val runs = mutableMapOf() + + override fun generate(description: Description, type: Type): Sequence> { + return sequenceOf(Seed.Simple(type.name)) + } + + override suspend fun handle(description: Description, values: List): Feedback { + description.parameters.forEach { + runs[it]!!.incrementAndGet() + } + println(values) + return emptyFeedback() + } + + override suspend fun afterIteration( + description: Description, + stats: Statistic, + ) { + if (stats.totalRuns % 10 == 0L && description.parameters.size == 1) { + val newTypes = when (description.parameters[0]) { + Type.ANY -> listOf(Type.CONCRETE) + Type.CONCRETE -> listOf(Type.MORE_CONCRETE) + Type.MORE_CONCRETE -> listOf() + } + if (newTypes.isNotEmpty()) { + val d = Description(newTypes) + fork(d, stats) + // Description can be used as a transfer object, + // that collects information about the current running. + println("Fork ended: ${d.parameters}") + } + } + } + + override suspend fun isCancelled(description: Description, stats: Statistic): Boolean { + println("info: ${description.parameters} runs ${stats.totalRuns}") + return description.parameters.all { runs.computeIfAbsent(it) { AtomicLong(0) }.get() >= 10 } + } + }.fuzz(Description(listOf(Type.ANY))) + } +// .cancel() +} \ No newline at end of file diff --git a/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/demo/JsonFuzzing.kt b/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/demo/JsonFuzzing.kt index 2c7eb0b3e5..ce51986901 100644 --- a/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/demo/JsonFuzzing.kt +++ b/utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/demo/JsonFuzzing.kt @@ -4,6 +4,7 @@ import org.utbot.fuzzing.* import org.utbot.fuzzing.seeds.BitVectorValue import org.utbot.fuzzing.seeds.Signed import org.utbot.fuzzing.seeds.StringValue +import java.util.concurrent.atomic.AtomicLong import kotlin.random.Random private enum class CustomType { @@ -32,6 +33,7 @@ private class JsonBuilder( @Suppress("RemoveExplicitTypeArguments") suspend fun main() { var count = 0 + val set = mutableMapOf() BaseFuzzing, Feedback>( TypeProvider(CustomType.INT) { _, _ -> for (b in Signed.values()) { @@ -79,8 +81,13 @@ suspend fun main() { } }, ) { _, values -> - println(values) - if (++count < 1000) emptyFeedback() else error("") + val result = values.toString() + println(result) + set.computeIfAbsent(result) { AtomicLong() }.incrementAndGet() + if (++count < 10000) emptyFeedback() else { + println("Duplication ratio:" + set.size / count.toDouble()) + error("Forced from the example") + } }.fuzz( Description(listOf(CustomType.LST, CustomType.OBJ)), Random(0), diff --git a/utbot-fuzzing/src/test/kotlin/org/utbot/fuzzing/FuzzerSmokeTest.kt b/utbot-fuzzing/src/test/kotlin/org/utbot/fuzzing/FuzzerSmokeTest.kt index 14cc68290b..9699cb5641 100644 --- a/utbot-fuzzing/src/test/kotlin/org/utbot/fuzzing/FuzzerSmokeTest.kt +++ b/utbot-fuzzing/src/test/kotlin/org/utbot/fuzzing/FuzzerSmokeTest.kt @@ -1,6 +1,7 @@ package org.utbot.fuzzing import kotlinx.coroutines.* +import kotlinx.coroutines.flow.flow import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows @@ -96,28 +97,6 @@ class FuzzerSmokeTest { } } - @Test - fun `fuzzing runs value generation every type when cache is being reset`() { - runBlocking { - var count = 10 - var generations = 0 - runFuzzing( - { _, _ -> - generations++ - sequenceOf(Seed.Simple(Unit)) - }, - Description(listOf(Unit)) - ) { _, _ -> - BaseFeedback(Unit, if (--count == 0) Control.STOP else Control.RESET_TYPE_CACHE_AND_CONTINUE) - } - Assertions.assertEquals(0, count) - // fuzzing swaps generated and modified values, - // therefore it can call generation only once, - // but at the moment it should be called 5 times - Assertions.assertEquals(5, generations) - } - } - @Test fun `fuzzer rethrow exception from execution block`() { class SpecialException : Exception() @@ -253,4 +232,30 @@ class FuzzerSmokeTest { Assertions.assertEquals(firstRun, thirdRun) Assertions.assertEquals(secondRun, thirdRun) } + + @Test + fun `check flow invariant is not violated`() { + val timeConsumer: (Long) -> Unit = {} + runBlocking { + val deferred = async { + val start = System.currentTimeMillis() + flow { + runFuzzing( + { _, _ -> sequenceOf(Seed.Simple(Unit)) }, + Description(listOf(Unit)) + ) { _, _ -> + if (System.currentTimeMillis() - start > 10_000) { + error("Fuzzer didn't stopped in 10_000 ms") + } + emit(System.currentTimeMillis()) + BaseFeedback(Unit, Control.CONTINUE) + } + }.collect { + timeConsumer(it) + } + } + delay(1000) + deferred.cancel() + } + } } \ No newline at end of file diff --git a/utbot-fuzzing/src/test/kotlin/org/utbot/fuzzing/utils/RandomExtensionsTest.kt b/utbot-fuzzing/src/test/kotlin/org/utbot/fuzzing/utils/RandomExtensionsTest.kt index cfc4ada3dc..ab83236b09 100644 --- a/utbot-fuzzing/src/test/kotlin/org/utbot/fuzzing/utils/RandomExtensionsTest.kt +++ b/utbot-fuzzing/src/test/kotlin/org/utbot/fuzzing/utils/RandomExtensionsTest.kt @@ -69,4 +69,32 @@ class RandomExtensionsTest { val error = experiments / 1000 // 0.1 % assertTrue(abs(result - experiments * probability / 100) < error) } + + @Test + fun `invert bit works for long`() { + var attempts = 100_000 + val random = Random(2210) + sequence { + while (true) { + yield(random.nextLong()) + } + }.forEach { value -> + if (attempts-- <= 0) { return } + for (bit in 0 until Long.SIZE_BITS) { + val newValue = value.invertBit(bit) + val oldBinary = value.toBinaryString() + val newBinary = newValue.toBinaryString() + assertEquals(oldBinary.length, newBinary.length) + for (test in Long.SIZE_BITS - 1 downTo 0) { + if (test != Long.SIZE_BITS - 1 - bit) { + assertEquals(oldBinary[test], newBinary[test]) { "$oldBinary : $newBinary for value $value" } + } else { + assertNotEquals(oldBinary[test], newBinary[test]) { "$oldBinary : $newBinary for value $value" } + } + } + } + } + } + + private fun Long.toBinaryString() = java.lang.Long.toBinaryString(this).padStart(Long.SIZE_BITS, '0') } \ No newline at end of file diff --git a/utbot-go/build.gradle.kts b/utbot-go/build.gradle.kts index 09fc810f3c..a1c25e11d0 100644 --- a/utbot-go/build.gradle.kts +++ b/utbot-go/build.gradle.kts @@ -21,7 +21,7 @@ tasks { } dependencies { - api(project(":utbot-fuzzers")) + api(project(":utbot-java-fuzzing")) api(project(":utbot-framework")) testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.1") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") diff --git a/utbot-intellij/build.gradle.kts b/utbot-intellij/build.gradle.kts index 5314824aed..0f5ba2215b 100644 --- a/utbot-intellij/build.gradle.kts +++ b/utbot-intellij/build.gradle.kts @@ -143,7 +143,7 @@ dependencies { implementation(group = "com.fasterxml.jackson.module", name = "jackson-module-kotlin", version = jacksonVersion) implementation(project(":utbot-framework")) { exclude(group = "org.slf4j", module = "slf4j-api") } - implementation(project(":utbot-fuzzers")) + implementation(project(":utbot-java-fuzzing")) //api(project(":utbot-analytics")) testImplementation("org.mock-server:mockserver-netty:5.4.1") testApi(project(":utbot-framework")) diff --git a/utbot-fuzzers/build.gradle.kts b/utbot-java-fuzzing/build.gradle.kts similarity index 100% rename from utbot-fuzzers/build.gradle.kts rename to utbot-java-fuzzing/build.gradle.kts diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzedConcreteValue.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/FuzzedConcreteValue.kt similarity index 100% rename from utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzedConcreteValue.kt rename to utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/FuzzedConcreteValue.kt diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzedContext.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/FuzzedContext.kt similarity index 100% rename from utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzedContext.kt rename to utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/FuzzedContext.kt diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzedMethodDescription.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/FuzzedMethodDescription.kt similarity index 100% rename from utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzedMethodDescription.kt rename to utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/FuzzedMethodDescription.kt diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzedType.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/FuzzedType.kt similarity index 100% rename from utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzedType.kt rename to utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/FuzzedType.kt diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzedValue.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/FuzzedValue.kt similarity index 100% rename from utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/FuzzedValue.kt rename to utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/FuzzedValue.kt diff --git a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/IdGenerator.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/IdGenerator.kt new file mode 100644 index 0000000000..1d66dcfef5 --- /dev/null +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/IdGenerator.kt @@ -0,0 +1,84 @@ +package org.utbot.fuzzer + +import org.utbot.framework.plugin.api.UtModel +import java.util.* +import java.util.concurrent.atomic.AtomicInteger + +/** + * Identifier generator interface for fuzzer model providers. + * + * Provides fresh identifiers for generated models. + * + * Warning: specific generators are not guaranteed to be thread-safe. + * + * @param Id the identifier type (e.g., [Int] for [UtReferenceModel] providers) + */ +interface IdGenerator { + /** + * Create a fresh identifier. Each subsequent call should return a different value. + * + * The method is not guaranteed to be thread-safe, unless an implementation makes such a guarantee. + */ + fun createId(): Id +} + +/** + * Identity preserving identifier generator interface. + * + * It allows to optionally save identifiers assigned to specific objects and later get the same identifiers + * for these objects instead of fresh identifiers. This feature is necessary, for example, to implement reference + * equality for enum models. + * + * Warning: specific generators are not guaranteed to be thread-safe. + * + * @param Id the identifier type (e.g., [Int] for [UtReferenceModel] providers) + */ +interface IdentityPreservingIdGenerator : IdGenerator { + /** + * Return an identifier for a specified non-null object. If an identifier has already been assigned + * to an object, subsequent calls should return the same identifier for this object. + * + * Note: the interface does not specify whether reference equality or regular `equals`/`compareTo` equality + * will be used to compare objects. Each implementation may provide these guarantees by itself. + * + * The method is not guaranteed to be thread-safe, unless an implementation makes such a guarantee. + */ + fun getOrCreateIdForValue(value: Any): Id +} + +/** + * An identity preserving id generator for fuzzer value providers that returns identifiers of type [Int]. + * + * When identity-preserving identifier is requested, objects are compared by reference. + * The generator is not thread-safe. + * + * @param lowerBound an integer value so that any generated identifier is strictly greater than it. + * + * Warning: when generating [UtReferenceModel] identifiers, no identifier should be equal to zero, + * as this value is reserved for [UtNullModel]. To guarantee it, [lowerBound] should never be negative. + * Avoid using custom lower bounds (maybe except fuzzer unit tests), use the predefined default value instead. + */ +class ReferencePreservingIntIdGenerator(lowerBound: Int = DEFAULT_LOWER_BOUND) : IdentityPreservingIdGenerator { + private val lastId: AtomicInteger = AtomicInteger(lowerBound) + private val cache: IdentityHashMap = IdentityHashMap() + + override fun getOrCreateIdForValue(value: Any): Int { + return cache.getOrPut(value) { createId() } + } + + override fun createId(): Int { + return lastId.incrementAndGet() + } + + companion object { + /** + * The default lower bound (all generated integer identifiers will be greater than it). + * + * It is defined as a large value because all synthetic [UtModel] instances + * must have greater identifiers than the real models. + */ + const val DEFAULT_LOWER_BOUND: Int = 1500_000_000 + } +} + +fun UtModel.fuzzed(block: FuzzedValue.() -> Unit = {}): FuzzedValue = FuzzedValue(this).apply(block) \ No newline at end of file diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/UtFuzzedExecution.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/UtFuzzedExecution.kt similarity index 100% rename from utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/UtFuzzedExecution.kt rename to utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/UtFuzzedExecution.kt diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/objects/AssembleModelUtils.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/objects/AssembleModelUtils.kt similarity index 87% rename from utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/objects/AssembleModelUtils.kt rename to utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/objects/AssembleModelUtils.kt index d90f6bc1be..bc50efcfa0 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/objects/AssembleModelUtils.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzer/objects/AssembleModelUtils.kt @@ -11,21 +11,6 @@ import org.utbot.framework.plugin.api.UtExecutableCallModel import org.utbot.framework.plugin.api.UtModel import org.utbot.framework.plugin.api.UtStatementModel import org.utbot.framework.plugin.api.util.voidClassId -import org.utbot.fuzzer.FuzzedValue -import org.utbot.fuzzer.ModelProvider -import org.utbot.fuzzing.utils.hex - - -fun ModelProvider.assembleModel(id: Int, constructorId: ConstructorId, params: List): FuzzedValue { - return UtAssembleModel( - id, - constructorId.classId, - "${constructorId.classId.name}${constructorId.parameters}#" + id.hex(), - UtExecutableCallModel(instance = null, constructorId, params.map { it.model }) - ).fuzzed { - summary = "%var% = ${constructorId.classId.simpleName}(${constructorId.parameters.joinToString { it.simpleName }})" - } -} fun ClassId.create( block: AssembleModelDsl.() -> Unit diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzing/JavaLanguage.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/JavaLanguage.kt similarity index 100% rename from utbot-fuzzers/src/main/kotlin/org/utbot/fuzzing/JavaLanguage.kt rename to utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/JavaLanguage.kt diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzing/providers/Arrays.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Arrays.kt similarity index 97% rename from utbot-fuzzers/src/main/kotlin/org/utbot/fuzzing/providers/Arrays.kt rename to utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Arrays.kt index 1d64e2443e..1cf2c84331 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzing/providers/Arrays.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Arrays.kt @@ -6,7 +6,7 @@ import org.utbot.framework.plugin.api.util.isArray import org.utbot.fuzzer.FuzzedType import org.utbot.fuzzer.FuzzedValue import org.utbot.fuzzer.IdGenerator -import org.utbot.fuzzer.providers.ConstantsModelProvider.fuzzed +import org.utbot.fuzzer.fuzzed import org.utbot.fuzzing.* class ArrayValueProvider( diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzing/providers/Collections.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Collections.kt similarity index 99% rename from utbot-fuzzers/src/main/kotlin/org/utbot/fuzzing/providers/Collections.kt rename to utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Collections.kt index c5309c3694..86091e3e33 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzing/providers/Collections.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Collections.kt @@ -5,7 +5,7 @@ import org.utbot.framework.plugin.api.util.* import org.utbot.fuzzer.FuzzedType import org.utbot.fuzzer.FuzzedValue import org.utbot.fuzzer.IdGenerator -import org.utbot.fuzzer.providers.PrimitivesModelProvider.fuzzed +import org.utbot.fuzzer.fuzzed import org.utbot.fuzzing.* import org.utbot.fuzzing.utils.hex import kotlin.reflect.KClass diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzing/providers/Enums.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Enums.kt similarity index 95% rename from utbot-fuzzers/src/main/kotlin/org/utbot/fuzzing/providers/Enums.kt rename to utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Enums.kt index 80bbc46b73..fb1e92e3c5 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzing/providers/Enums.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Enums.kt @@ -6,7 +6,7 @@ import org.utbot.framework.plugin.api.util.jClass import org.utbot.fuzzer.FuzzedType import org.utbot.fuzzer.FuzzedValue import org.utbot.fuzzer.IdentityPreservingIdGenerator -import org.utbot.fuzzer.providers.ConstantsModelProvider.fuzzed +import org.utbot.fuzzer.fuzzed import org.utbot.fuzzing.FuzzedDescription import org.utbot.fuzzing.Seed import org.utbot.fuzzing.ValueProvider diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzing/providers/Objects.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Objects.kt similarity index 99% rename from utbot-fuzzers/src/main/kotlin/org/utbot/fuzzing/providers/Objects.kt rename to utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Objects.kt index 21666be0ff..b314314311 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzing/providers/Objects.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Objects.kt @@ -5,7 +5,7 @@ import org.utbot.framework.plugin.api.util.* import org.utbot.fuzzer.FuzzedType import org.utbot.fuzzer.FuzzedValue import org.utbot.fuzzer.IdGenerator -import org.utbot.fuzzer.providers.ConstantsModelProvider.fuzzed +import org.utbot.fuzzer.fuzzed import org.utbot.fuzzing.* import org.utbot.fuzzing.utils.hex import java.lang.reflect.Field diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzing/providers/Others.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Others.kt similarity index 98% rename from utbot-fuzzers/src/main/kotlin/org/utbot/fuzzing/providers/Others.kt rename to utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Others.kt index 19a37137ec..e019d95904 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzing/providers/Others.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Others.kt @@ -5,7 +5,7 @@ import org.utbot.framework.plugin.api.util.* import org.utbot.fuzzer.FuzzedType import org.utbot.fuzzer.FuzzedValue import org.utbot.fuzzer.IdGenerator -import org.utbot.fuzzer.providers.PrimitivesModelProvider.fuzzed +import org.utbot.fuzzer.fuzzed import org.utbot.fuzzing.* import org.utbot.fuzzing.utils.hex import java.text.SimpleDateFormat diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzing/providers/Primitives.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Primitives.kt similarity index 99% rename from utbot-fuzzers/src/main/kotlin/org/utbot/fuzzing/providers/Primitives.kt rename to utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Primitives.kt index f08736b073..e81d644d47 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzing/providers/Primitives.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Primitives.kt @@ -7,7 +7,7 @@ import org.utbot.fuzzer.FuzzedContext import org.utbot.fuzzer.FuzzedContext.Comparison.* import org.utbot.fuzzer.FuzzedType import org.utbot.fuzzer.FuzzedValue -import org.utbot.fuzzer.providers.ConstantsModelProvider.fuzzed +import org.utbot.fuzzer.fuzzed import org.utbot.fuzzing.* import org.utbot.fuzzing.seeds.* import java.util.regex.Pattern diff --git a/utbot-fuzzers/src/test/java/org/utbot/fuzzing/samples/AccessibleObjects.java b/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/AccessibleObjects.java similarity index 100% rename from utbot-fuzzers/src/test/java/org/utbot/fuzzing/samples/AccessibleObjects.java rename to utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/AccessibleObjects.java diff --git a/utbot-fuzzers/src/test/java/org/utbot/fuzzing/samples/DeepNested.java b/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/DeepNested.java similarity index 100% rename from utbot-fuzzers/src/test/java/org/utbot/fuzzing/samples/DeepNested.java rename to utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/DeepNested.java diff --git a/utbot-fuzzers/src/test/java/org/utbot/fuzzing/samples/FailToGenerateListGeneric.java b/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/FailToGenerateListGeneric.java similarity index 100% rename from utbot-fuzzers/src/test/java/org/utbot/fuzzing/samples/FailToGenerateListGeneric.java rename to utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/FailToGenerateListGeneric.java diff --git a/utbot-fuzzers/src/test/java/org/utbot/framework/plugin/api/samples/FieldSetterClass.java b/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/FieldSetterClass.java similarity index 93% rename from utbot-fuzzers/src/test/java/org/utbot/framework/plugin/api/samples/FieldSetterClass.java rename to utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/FieldSetterClass.java index 1e4d344c3f..d8d184c6b3 100644 --- a/utbot-fuzzers/src/test/java/org/utbot/framework/plugin/api/samples/FieldSetterClass.java +++ b/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/FieldSetterClass.java @@ -1,4 +1,4 @@ -package org.utbot.framework.plugin.api.samples; +package org.utbot.fuzzing.samples; @SuppressWarnings("All") public class FieldSetterClass { diff --git a/utbot-fuzzers/src/test/java/org/utbot/framework/plugin/api/samples/InnerClassWithEnums.java b/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/InnerClassWithEnums.java similarity index 82% rename from utbot-fuzzers/src/test/java/org/utbot/framework/plugin/api/samples/InnerClassWithEnums.java rename to utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/InnerClassWithEnums.java index 3f3dcd8be0..5e86197403 100644 --- a/utbot-fuzzers/src/test/java/org/utbot/framework/plugin/api/samples/InnerClassWithEnums.java +++ b/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/InnerClassWithEnums.java @@ -1,6 +1,4 @@ -package org.utbot.framework.plugin.api.samples; - -import org.jetbrains.annotations.NotNull; +package org.utbot.fuzzing.samples; public class InnerClassWithEnums { private SampleEnum a; diff --git a/utbot-fuzzers/src/test/java/org/utbot/framework/plugin/api/samples/OuterClassWithEnums.java b/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/OuterClassWithEnums.java similarity index 95% rename from utbot-fuzzers/src/test/java/org/utbot/framework/plugin/api/samples/OuterClassWithEnums.java rename to utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/OuterClassWithEnums.java index 61354b2c52..4118036977 100644 --- a/utbot-fuzzers/src/test/java/org/utbot/framework/plugin/api/samples/OuterClassWithEnums.java +++ b/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/OuterClassWithEnums.java @@ -1,4 +1,4 @@ -package org.utbot.framework.plugin.api.samples; +package org.utbot.fuzzing.samples; public class OuterClassWithEnums { private SampleEnum value; diff --git a/utbot-fuzzers/src/test/java/org/utbot/framework/plugin/api/samples/PackagePrivateFieldAndClass.java b/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/PackagePrivateFieldAndClass.java similarity index 82% rename from utbot-fuzzers/src/test/java/org/utbot/framework/plugin/api/samples/PackagePrivateFieldAndClass.java rename to utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/PackagePrivateFieldAndClass.java index f8975924b0..11986d8a16 100644 --- a/utbot-fuzzers/src/test/java/org/utbot/framework/plugin/api/samples/PackagePrivateFieldAndClass.java +++ b/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/PackagePrivateFieldAndClass.java @@ -1,4 +1,4 @@ -package org.utbot.framework.plugin.api.samples; +package org.utbot.fuzzing.samples; @SuppressWarnings("All") public class PackagePrivateFieldAndClass { diff --git a/utbot-fuzzers/src/test/java/org/utbot/framework/plugin/api/samples/SampleEnum.java b/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/SampleEnum.java similarity index 50% rename from utbot-fuzzers/src/test/java/org/utbot/framework/plugin/api/samples/SampleEnum.java rename to utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/SampleEnum.java index 1571254a70..401bd83217 100644 --- a/utbot-fuzzers/src/test/java/org/utbot/framework/plugin/api/samples/SampleEnum.java +++ b/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/SampleEnum.java @@ -1,4 +1,4 @@ -package org.utbot.framework.plugin.api.samples; +package org.utbot.fuzzing.samples; public enum SampleEnum { LEFT, diff --git a/utbot-fuzzers/src/test/java/org/utbot/fuzzing/samples/Stubs.java b/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/Stubs.java similarity index 100% rename from utbot-fuzzers/src/test/java/org/utbot/fuzzing/samples/Stubs.java rename to utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/Stubs.java diff --git a/utbot-fuzzers/src/test/java/org/utbot/framework/plugin/api/samples/WithInnerClass.java b/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/WithInnerClass.java similarity index 88% rename from utbot-fuzzers/src/test/java/org/utbot/framework/plugin/api/samples/WithInnerClass.java rename to utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/WithInnerClass.java index 49da2e8fda..3b012a73ad 100644 --- a/utbot-fuzzers/src/test/java/org/utbot/framework/plugin/api/samples/WithInnerClass.java +++ b/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/WithInnerClass.java @@ -1,4 +1,4 @@ -package org.utbot.framework.plugin.api.samples; +package org.utbot.fuzzing.samples; public class WithInnerClass { public class NonStatic { diff --git a/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/IdGeneratorTest.kt b/utbot-java-fuzzing/src/test/kotlin/org/utbot/fuzzing/IdGeneratorTest.kt similarity index 98% rename from utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/IdGeneratorTest.kt rename to utbot-java-fuzzing/src/test/kotlin/org/utbot/fuzzing/IdGeneratorTest.kt index fbad13f551..98efebd2f4 100644 --- a/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/IdGeneratorTest.kt +++ b/utbot-java-fuzzing/src/test/kotlin/org/utbot/fuzzing/IdGeneratorTest.kt @@ -1,4 +1,4 @@ -package org.utbot.framework.plugin.api +package org.utbot.fuzzing import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertNotEquals diff --git a/utbot-fuzzers/src/test/kotlin/org/utbot/fuzzing/JavaFuzzingTest.kt b/utbot-java-fuzzing/src/test/kotlin/org/utbot/fuzzing/JavaFuzzingTest.kt similarity index 96% rename from utbot-fuzzers/src/test/kotlin/org/utbot/fuzzing/JavaFuzzingTest.kt rename to utbot-java-fuzzing/src/test/kotlin/org/utbot/fuzzing/JavaFuzzingTest.kt index 5976abe0a9..9b651a0901 100644 --- a/utbot-fuzzers/src/test/kotlin/org/utbot/fuzzing/JavaFuzzingTest.kt +++ b/utbot-java-fuzzing/src/test/kotlin/org/utbot/fuzzing/JavaFuzzingTest.kt @@ -5,13 +5,13 @@ import kotlinx.coroutines.withTimeout import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.Test import org.utbot.framework.plugin.api.MethodId -import org.utbot.framework.plugin.api.TestIdentityPreservingIdGenerator import org.utbot.framework.plugin.api.UtAssembleModel import org.utbot.framework.plugin.api.UtPrimitiveModel import org.utbot.framework.plugin.api.util.* import org.utbot.fuzzer.FuzzedConcreteValue import org.utbot.fuzzing.samples.DeepNested import org.utbot.fuzzer.FuzzedType +import org.utbot.fuzzer.IdentityPreservingIdGenerator import org.utbot.fuzzing.samples.AccessibleObjects import org.utbot.fuzzing.samples.FailToGenerateListGeneric import org.utbot.fuzzing.samples.Stubs @@ -20,6 +20,14 @@ import java.lang.reflect.GenericArrayType import java.lang.reflect.ParameterizedType import java.lang.reflect.Type import java.util.IdentityHashMap +import java.util.concurrent.atomic.AtomicInteger + +internal object TestIdentityPreservingIdGenerator : IdentityPreservingIdGenerator { + private val cache = mutableMapOf() + private val gen = AtomicInteger() + override fun getOrCreateIdForValue(value: Any): Int = cache.computeIfAbsent(value) { createId() } + override fun createId(): Int = gen.incrementAndGet() +} class JavaFuzzingTest { diff --git a/utbot-js/src/main/kotlin/fuzzer/JsFuzzerApi.kt b/utbot-js/src/main/kotlin/fuzzer/JsFuzzerApi.kt index cbef94b64c..761552ee5a 100644 --- a/utbot-js/src/main/kotlin/fuzzer/JsFuzzerApi.kt +++ b/utbot-js/src/main/kotlin/fuzzer/JsFuzzerApi.kt @@ -6,8 +6,8 @@ import framework.api.js.util.isClass import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.UtModel import org.utbot.framework.plugin.api.UtTimeoutException -import org.utbot.fuzzing.Control import org.utbot.fuzzing.Description +import org.utbot.fuzzing.Control import org.utbot.fuzzing.Feedback import org.utbot.fuzzing.utils.Trie import java.util.concurrent.atomic.AtomicInteger diff --git a/utbot-maven/build.gradle b/utbot-maven/build.gradle index 8ca1b87986..9a8a701f4b 100644 --- a/utbot-maven/build.gradle +++ b/utbot-maven/build.gradle @@ -147,7 +147,7 @@ generatePluginDescriptor.dependsOn([ project(':utbot-instrumentation'), project(':utbot-framework'), project(':utbot-framework-api'), - project(':utbot-fuzzers'), + project(':utbot-java-fuzzing'), project(':utbot-fuzzing'), project(':utbot-rd'), project(':utbot-summary') diff --git a/utbot-python/src/main/kotlin/org/utbot/python/PythonEngine.kt b/utbot-python/src/main/kotlin/org/utbot/python/PythonEngine.kt index 20d5ac040c..7621178348 100644 --- a/utbot-python/src/main/kotlin/org/utbot/python/PythonEngine.kt +++ b/utbot-python/src/main/kotlin/org/utbot/python/PythonEngine.kt @@ -5,6 +5,7 @@ import kotlinx.coroutines.flow.flow import mu.KotlinLogging import org.utbot.framework.plugin.api.* import org.utbot.fuzzing.Control +import org.utbot.fuzzing.NoSeedValueException import org.utbot.fuzzing.fuzz import org.utbot.fuzzing.utils.Trie import org.utbot.python.evaluation.* @@ -283,7 +284,7 @@ class PythonEngine( emit(result.fuzzingExecutionFeedback) return@PythonFuzzing result.fuzzingPlatformFeedback }.fuzz(pmd) - } catch (_: Exception) { // e.g. NoSeedValueException + } catch (_: NoSeedValueException) { // e.g. NoSeedValueException logger.info { "Cannot fuzz values for types: ${parameters.map { it.pythonTypeRepresentation() }}" } } } diff --git a/utbot-python/src/main/kotlin/org/utbot/python/fuzzing/PythonApi.kt b/utbot-python/src/main/kotlin/org/utbot/python/fuzzing/PythonApi.kt index a55e125d5c..8e43fd68d3 100644 --- a/utbot-python/src/main/kotlin/org/utbot/python/fuzzing/PythonApi.kt +++ b/utbot-python/src/main/kotlin/org/utbot/python/fuzzing/PythonApi.kt @@ -4,13 +4,7 @@ import mu.KotlinLogging import org.utbot.framework.plugin.api.Instruction import org.utbot.framework.plugin.api.UtError import org.utbot.fuzzer.FuzzedContext -import org.utbot.fuzzing.Configuration -import org.utbot.fuzzing.Control -import org.utbot.fuzzing.Description -import org.utbot.fuzzing.Feedback -import org.utbot.fuzzing.Fuzzing -import org.utbot.fuzzing.Seed -import org.utbot.fuzzing.Statistic +import org.utbot.fuzzing.* import org.utbot.fuzzing.utils.Trie import org.utbot.python.framework.api.python.PythonTree import org.utbot.python.framework.api.python.PythonUtExecution @@ -84,7 +78,7 @@ class PythonFuzzing( val execute: suspend (description: PythonMethodDescription, values: List) -> PythonFeedback, ) : Fuzzing { - private fun generateDefault(description: PythonMethodDescription, type: Type)= sequence> { + private fun generateDefault(description: PythonMethodDescription, type: Type)= sequence { pythonDefaultValueProviders(pythonTypeStorage).asSequence().forEach { provider -> if (provider.accept(type)) { logger.debug { "Provider ${provider.javaClass.simpleName} accepts type ${type.pythonTypeRepresentation()}" } @@ -108,12 +102,4 @@ class PythonFuzzing( override suspend fun handle(description: PythonMethodDescription, values: List): PythonFeedback { return execute(description, values) } - - override suspend fun update( - description: PythonMethodDescription, - statistic: Statistic, - configuration: Configuration - ) { - super.update(description, statistic, configuration) - } } diff --git a/utbot-summary/build.gradle.kts b/utbot-summary/build.gradle.kts index e087927bbb..ae72e4b778 100644 --- a/utbot-summary/build.gradle.kts +++ b/utbot-summary/build.gradle.kts @@ -9,7 +9,7 @@ dependencies { implementation("org.unittestbot.soot:soot-utbot-fork:${sootVersion}") { exclude(group="com.google.guava", module="guava") } - implementation(project(":utbot-fuzzers")) + implementation(project(":utbot-java-fuzzing")) implementation(project(":utbot-instrumentation")) implementation(group = "com.github.haifengl", name = "smile-kotlin", version = "2.6.0") implementation(group = "com.github.haifengl", name = "smile-core", version = "2.6.0") diff --git a/utbot-testing/build.gradle b/utbot-testing/build.gradle index 7b72db1e63..1b48b5ea6f 100644 --- a/utbot-testing/build.gradle +++ b/utbot-testing/build.gradle @@ -18,7 +18,7 @@ java { dependencies { api project(':utbot-framework-api') - api project(':utbot-fuzzers') + api project(':utbot-java-fuzzing') api project(':utbot-instrumentation') api project(':utbot-summary') diff --git a/utbot-ui-commons/src/test/kotlin/org/utbot/intellij/plugin/ui/utils/RootUtilsTest.kt b/utbot-ui-commons/src/test/kotlin/org/utbot/intellij/plugin/ui/utils/RootUtilsTest.kt index 7b3371c2eb..cbc295104f 100644 --- a/utbot-ui-commons/src/test/kotlin/org/utbot/intellij/plugin/ui/utils/RootUtilsTest.kt +++ b/utbot-ui-commons/src/test/kotlin/org/utbot/intellij/plugin/ui/utils/RootUtilsTest.kt @@ -35,8 +35,8 @@ internal class RootUtilsTest { MockTestSourceRoot("/UTBotJavaTest/utbot-framework-api/src/test/kotlin"), MockTestSourceRoot("/UTBotJavaTest/utbot-framework-test/src/test/java"), MockTestSourceRoot("/UTBotJavaTest/utbot-framework-test/src/test/kotlin"), - MockTestSourceRoot("/UTBotJavaTest/utbot-fuzzers/src/test/java"), - MockTestSourceRoot("/UTBotJavaTest/utbot-fuzzers/src/test/kotlin"), + MockTestSourceRoot("/UTBotJavaTest/utbot-java-fuzzing/src/test/java"), + MockTestSourceRoot("/UTBotJavaTest/utbot-java-fuzzing/src/test/kotlin"), MockTestSourceRoot("/UTBotJavaTest/utbot-gradle/src/test/kotlin"), MockTestSourceRoot("/UTBotJavaTest/utbot-instrumentation/src/test/java"), MockTestSourceRoot("/UTBotJavaTest/utbot-instrumentation/src/test/kotlin"),