Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ class UtBotSymbolicEngine(
packageName = executableId.classId.packageName
}
fuzz(thisMethodDescription, ObjectModelProvider(defaultIdGenerator).apply {
limitValuesCreatedByFieldAccessors = 500
totalLimit = 500
})
}.withMutations(
TrieBasedFuzzerStatistics(coveredInstructionValues), methodUnderTestDescription, *defaultModelMutators().toTypedArray()
Expand Down
36 changes: 18 additions & 18 deletions utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/Fuzzer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import org.utbot.fuzzer.providers.EnumModelProvider
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.*
Expand Down Expand Up @@ -146,40 +145,41 @@ fun <T> Sequence<List<FuzzedValue>>.withMutations(statistics: FuzzerStatistics<T
}

/**
* Creates a model provider from a list of default providers.
* Creates a model provider consisting of providers that do not make recursive calls inside them
*/
fun defaultModelProviders(idGenerator: IdentityPreservingIdGenerator<Int>): ModelProvider {
private fun nonRecursiveProviders(idGenerator: IdentityPreservingIdGenerator<Int>): ModelProvider {
return ModelProvider.of(
ObjectModelProvider(idGenerator),
CollectionModelProvider(idGenerator),
ArrayModelProvider(idGenerator),
EnumModelProvider(idGenerator),
ConstantsModelProvider,
StringConstantModelProvider,
RegexModelProvider,
CharToStringModelProvider,
PrimitivesModelProvider,
ConstantsModelProvider,
PrimitiveDefaultsModelProvider,
PrimitiveWrapperModelProvider,
)
}

/**
* Creates a model provider for [ObjectModelProvider] that generates values for object constructor.
* TODO: write doc here
*/
fun objectModelProviders(idGenerator: IdentityPreservingIdGenerator<Int>): ModelProvider {
private fun recursiveModelProviders(idGenerator: IdentityPreservingIdGenerator<Int>, recursionDepth: Int): ModelProvider {
return ModelProvider.of(
CollectionModelProvider(idGenerator),
ArrayModelProvider(idGenerator),
EnumModelProvider(idGenerator),
StringConstantModelProvider,
RegexModelProvider,
CharToStringModelProvider,
ConstantsModelProvider,
PrimitiveDefaultsModelProvider,
PrimitiveWrapperModelProvider,
ObjectModelProvider(idGenerator, recursionDepth),
ArrayModelProvider(idGenerator, recursionDepth)
)
}

/**
* Creates a model provider from a list of default providers.
*/
fun defaultModelProviders(idGenerator: IdentityPreservingIdGenerator<Int>, recursionDepth: Int = 1): ModelProvider =
if (recursionDepth >= 0)
nonRecursiveProviders(idGenerator).with(recursiveModelProviders(idGenerator, recursionDepth))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, that the other method called 'defaultModelProviders' without parameter with recursion has another set of model providers. Therefore. I'd recommend to change name for this method to avoid ambiguous calls.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should have replaced the method without recursionDepth parameter with no changes in behavior when this parameter is not specified. Seems like I accidently got duplication after rebase. Deleted method without parameter now. Could you please check that it didn't change the behavior?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It changes because PrimitivesModelProvider isn't used anymore. By default I want to keep an ability to set different providers by default, because I usually want to use shallower value set for it. Right now this change is only about PrimitivesModelProvider, but in the future I'd want to add some providers that are used for generating flat parameters and aren't used for recursive.

else
nonRecursiveProviders(idGenerator)


fun defaultModelMutators(): List<ModelMutator> = listOf(
StringRandomMutator,
RegexStringModelMutator,
Expand Down
14 changes: 13 additions & 1 deletion utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/ModelProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,18 @@ fun interface ModelProvider {
return if (this is Combined) {
Combined(providers.filterNot(filter))
} else {
Combined(if (filter(this)) emptyList() else listOf(this))
Combined(if (filter(this)) emptyList() else listOf(this)) // TODO: remove Combined from here (?)
}
}

/**
* Applies [transform] for current provider
*/
fun map(transform: (ModelProvider) -> ModelProvider): ModelProvider {
return if (this is Combined) {
Combined(providers.map(transform))
} else {
transform(this)
}
}

Expand Down Expand Up @@ -123,6 +134,7 @@ fun interface ModelProvider {
/**
* Wrapper class that delegates implementation to the [providers].
*/
// TODO: flatten Combined instances in providers (?)
private class Combined(val providers: List<ModelProvider>): ModelProvider {
override fun generate(description: FuzzedMethodDescription): Sequence<FuzzedParameter> = sequence {
providers.forEach { provider ->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,65 @@
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.UtPrimitiveModel
import org.utbot.framework.plugin.api.util.defaultValueModel
import org.utbot.framework.plugin.api.util.intClassId
import org.utbot.framework.plugin.api.util.isArray
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 java.util.function.IntSupplier
import org.utbot.fuzzer.IdentityPreservingIdGenerator

class ArrayModelProvider(
private val idGenerator: IdGenerator<Int>
) : ModelProvider {
override fun generate(description: FuzzedMethodDescription): Sequence<FuzzedParameter> = sequence {
description.parametersMap
.asSequence()
.filter { (classId, _) -> classId.isArray }
.forEach { (arrayClassId, indices) ->
yieldAllValues(indices, listOf(0, 10).map { arraySize ->
UtArrayModel(
id = idGenerator.createId(),
arrayClassId,
length = arraySize,
arrayClassId.elementClassId!!.defaultValueModel(),
mutableMapOf()
).fuzzed {
this.summary = "%var% = ${arrayClassId.elementClassId!!.simpleName}[$arraySize]"
}
})
idGenerator: IdentityPreservingIdGenerator<Int>,
recursionDepthLeft: Int = 1
) : RecursiveModelProvider(idGenerator, recursionDepthLeft) {
override fun createNewInstance(parentProvider: RecursiveModelProvider, newTotalLimit: Int): RecursiveModelProvider =
ArrayModelProvider(parentProvider.idGenerator, parentProvider.recursionDepthLeft - 1)
.copySettingsFrom(parentProvider)
.apply {
totalLimit = newTotalLimit
if (parentProvider is ArrayModelProvider)
branchingLimit = 1 // This improves performance but also forbids generating "jagged" arrays
}

override fun generateModelConstructors(
description: FuzzedMethodDescription,
classId: ClassId
): List<ModelConstructor> {
if (!classId.isArray)
return listOf()
val lengths = generateArrayLengths(description)
return lengths.map { length ->
ModelConstructor(List(length) { classId.elementClassId!! }) { values ->
createFuzzedArrayModel(classId, length, values.map { it.model } )
}
}
}

private fun generateArrayLengths(description: FuzzedMethodDescription): List<Int> {
val fuzzedLengths = fuzzValuesRecursively(
types = listOf(intClassId),
baseMethodDescription = description,
modelProvider = ConstantsModelProvider
)

// Firstly we will use most "interesting" default sizes, then we will use small sizes obtained from src
return listOf(3, 0) + fuzzedLengths
.map { (it.single().model as UtPrimitiveModel).value as Int }
.filter { it in 1..10 && it != 3 }
.toSortedSet()
.toList()
}

private fun createFuzzedArrayModel(arrayClassId: ClassId, length: Int, values: List<UtModel>?) =
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]"
}
}
Loading