Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -41,6 +41,8 @@ import org.utbot.framework.util.sootMethod
import org.utbot.fuzzer.*
import org.utbot.fuzzing.*
import org.utbot.fuzzing.providers.ObjectValueProvider
import org.utbot.fuzzing.providers.FieldValueProvider
import org.utbot.fuzzing.spring.SavedEntityProvider
import org.utbot.fuzzing.spring.SpringBeanValueProvider
import org.utbot.fuzzing.utils.Trie
import org.utbot.instrumentation.ConcreteExecutor
Expand Down Expand Up @@ -394,6 +396,9 @@ class UtBotSymbolicEngine(
entityClassId = ClassId("com.rest.order.models.Order")
)
)
val generatedValueFieldIds = listOf(
FieldId(ClassId("com.rest.order.models.Order"), "id")
)
logger.info { "Relevant repositories: $relevantRepositories" }
// spring should try to generate bean values, but if it fails, then object value provider is used for it
val springBeanValueProvider = SpringBeanValueProvider(
Expand All @@ -405,7 +410,11 @@ class UtBotSymbolicEngine(
},
relevantRepositories = relevantRepositories
).withFallback(ObjectValueProvider(defaultIdGenerator))
provider.except { p -> p is ObjectValueProvider }.with(springBeanValueProvider)
provider
.except { p -> p is ObjectValueProvider }
.with(springBeanValueProvider)
.with(ValueProvider.of(relevantRepositories.map { SavedEntityProvider(defaultIdGenerator, it) }))
.with(ValueProvider.of(generatedValueFieldIds.map { FieldValueProvider(defaultIdGenerator, it) }))
}.let(transform)
runJavaFuzzing(
defaultIdGenerator,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,18 +240,13 @@ open class CgVariableConstructor(val context: CgContext) :
val executable = statementCall.statement
val params = statementCall.params

val type = when (executable) {
is MethodId -> executable.returnType
is DirectFieldAccessId -> executable.fieldId.type
is ConstructorId -> executable.classId
}
// Don't use redundant constructors for primitives and String
val initExpr = if (isPrimitiveWrapperOrString(type)) {
val initExpr = if (executable is ConstructorId && isPrimitiveWrapperOrString(model.classId)) {
cgLiteralForWrapper(params)
} else {
createCgExecutableCallFromUtExecutableCall(statementCall)
}
newVar(type, model, baseName) {
newVar(model.classId, model, baseName) {
initExpr
}.also {
valueByUtModelWrapper[model.wrap()] = it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,13 @@ class MockValueConstructor(

val instantiationExecutableCall = assembleModel.instantiationCall
val result = updateWithStatementCallModel(instantiationExecutableCall)

// Executions that get `null` in a complicated way (e.g. like this: `new Pair(null, null).getFirst()`)
// are only produced by fuzzer and are considered undesirable because fuzzer can also produce simpler
// executions that just use `null` literal.
//
// So for such executions we throw `IllegalStateException` that indicates that construction of arguments
// has failed and causes execution to terminate with `UtConcreteExecutionProcessedFailure` execution result.
checkNotNull(result) {
"Tracked instance can't be null for call ${instantiationExecutableCall.statement} in model $assembleModel"
}
Expand Down Expand Up @@ -437,7 +444,7 @@ class MockValueConstructor(
newInstance(*args.toTypedArray())
}

private fun DirectFieldAccessId.get(instance: Any?): Any {
private fun DirectFieldAccessId.get(instance: Any?): Any? {
val field = fieldId.jField
return field.runSandbox {
field.get(instance)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class EmptyCollectionValueProvider(
summary = "%var% = ${executableId.classId.simpleName}#${executableId.name}"
}
} else {
UtNullModel(classId).fuzzed { summary = "%var% = null" }
nullFuzzedValue(classId)
}
},
))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package org.utbot.fuzzing.providers

import mu.KotlinLogging
import org.utbot.framework.plugin.api.DirectFieldAccessId
import org.utbot.framework.plugin.api.FieldId
import org.utbot.framework.plugin.api.UtAssembleModel
import org.utbot.framework.plugin.api.UtDirectGetFieldModel
import org.utbot.framework.plugin.api.UtNullModel
import org.utbot.framework.plugin.api.UtReferenceModel
import org.utbot.framework.plugin.api.util.jClass
import org.utbot.fuzzer.FuzzedType
import org.utbot.fuzzer.FuzzedValue
import org.utbot.fuzzer.IdGenerator
import org.utbot.fuzzer.fuzzed
import org.utbot.fuzzing.FuzzedDescription
import org.utbot.fuzzing.JavaValueProvider
import org.utbot.fuzzing.Routine
import org.utbot.fuzzing.Seed
import org.utbot.fuzzing.toFuzzerType

class FieldValueProvider(
private val idGenerator: IdGenerator<Int>,
private val fieldId: FieldId,
) : JavaValueProvider {
companion object {
private val logger = KotlinLogging.logger {}
}

override fun accept(type: FuzzedType): Boolean = type.classId == fieldId.type

override fun generate(description: FuzzedDescription, type: FuzzedType): Sequence<Seed<FuzzedType, FuzzedValue>> = sequenceOf(
Seed.Recursive(
construct = Routine.Create(listOf(
toFuzzerType(fieldId.declaringClass.jClass, description.typeCache)
)) { values ->
val thisInstanceValue = values.single()
val thisInstanceModel = when (val model = thisInstanceValue.model) {
is UtReferenceModel -> model
is UtNullModel -> return@Create nullFuzzedValue(type.classId)
else -> {
logger.warn { "This instance model can be only UtReferenceModel or UtNullModel, but $model is met" }
return@Create nullFuzzedValue(type.classId)
}
}
UtAssembleModel(
id = idGenerator.createId(),
classId = type.classId,
modelName = "${thisInstanceModel.modelName}.${fieldId.name}",
instantiationCall = UtDirectGetFieldModel(
instance = thisInstanceModel,
fieldAccess = DirectFieldAccessId(
classId = fieldId.declaringClass,
name = "<direct_get_${fieldId.name}>",
fieldId = fieldId
)
)
).fuzzed {
summary = "${thisInstanceValue.summary}.${fieldId.name}"
}
},
modify = emptySequence(),
empty = nullRoutine(type.classId)
)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,7 @@ class ObjectValueProvider(
}
}
},
empty = Routine.Empty {
UtNullModel(classId).fuzzed {
summary = "%var% = null"
}
}
empty = nullRoutine(classId)
)
}

Expand Down Expand Up @@ -133,9 +129,7 @@ object NullValueProvider : ValueProvider<FuzzedType, FuzzedValue, FuzzedDescript
type: FuzzedType
) = sequence<Seed<FuzzedType, FuzzedValue>> {
if (description.scope?.getProperty(NULLABLE_PROP) == true) {
yield(Seed.Simple(UtNullModel(type.classId).fuzzed {
summary = "%var% = null"
}))
yield(Seed.Simple(nullFuzzedValue(classClassId)))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.utbot.fuzzing.providers

import org.utbot.framework.plugin.api.ClassId
import org.utbot.framework.plugin.api.UtNullModel
import org.utbot.fuzzer.FuzzedType
import org.utbot.fuzzer.FuzzedValue
import org.utbot.fuzzer.fuzzed
import org.utbot.fuzzing.Routine

fun nullRoutine(classId: ClassId): Routine.Empty<FuzzedType, FuzzedValue> =
Routine.Empty { nullFuzzedValue(classId) }

fun nullFuzzedValue(classId: ClassId): FuzzedValue =
UtNullModel(classId).fuzzed { summary = "%var% = null" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.utbot.fuzzing.spring

import org.utbot.framework.plugin.api.SpringRepositoryId
import org.utbot.framework.plugin.api.UtAssembleModel
import org.utbot.framework.plugin.api.UtReferenceModel
import org.utbot.framework.plugin.api.util.SpringModelUtils
import org.utbot.fuzzer.FuzzedType
import org.utbot.fuzzer.FuzzedValue
import org.utbot.fuzzer.IdGenerator
import org.utbot.fuzzer.fuzzed
import org.utbot.fuzzing.FuzzedDescription
import org.utbot.fuzzing.JavaValueProvider
import org.utbot.fuzzing.Routine
import org.utbot.fuzzing.Seed
import org.utbot.fuzzing.providers.nullRoutine

class SavedEntityProvider(
private val idGenerator: IdGenerator<Int>,
private val repositoryId: SpringRepositoryId
) : JavaValueProvider {
override fun accept(type: FuzzedType): Boolean = type.classId == repositoryId.entityClassId

override fun generate(description: FuzzedDescription, type: FuzzedType): Sequence<Seed<FuzzedType, FuzzedValue>> =
sequenceOf(
Seed.Recursive(
construct = Routine.Create(listOf(type)) { values ->
val entityValue = values.single()
val entityModel = entityValue.model
UtAssembleModel(
id = idGenerator.createId(),
classId = type.classId,
modelName = "${repositoryId.repositoryBeanName}.save(${(entityModel as? UtReferenceModel)?.modelName ?: "..."})",
instantiationCall = SpringModelUtils.createSaveCallModel(
repositoryId = repositoryId,
id = idGenerator.createId(),
entityModel = entityModel
)
).fuzzed {
summary = "%var% = ${repositoryId.repositoryBeanName}.save(${entityValue.summary})"
}
},
modify = emptySequence(),
empty = nullRoutine(type.classId)
)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import org.utbot.fuzzer.IdGenerator
import org.utbot.fuzzer.fuzzed
import org.utbot.fuzzing.*
import org.utbot.fuzzing.providers.SPRING_BEAN_PROP
import org.utbot.fuzzing.providers.nullRoutine

class SpringBeanValueProvider(
private val idGenerator: IdGenerator<Int>,
Expand Down Expand Up @@ -59,11 +60,7 @@ class SpringBeanValueProvider(
})
}
},
empty = Routine.Empty {
UtNullModel(type.classId).fuzzed {
summary = "%var% = null"
}
}
empty = nullRoutine(type.classId)
)
)
}
Expand Down