Skip to content

Commit d7319b0

Browse files
authored
Support using identifiers generated by database as method arguments (#2285)
* Support using identifiers generated by database as method arguments * Properly handle `instantiationCall` of type `UtDirectGetFieldModel` evaluating into `null` * Improve check for redundant constructors for primitives and String in code generation
1 parent ad605b7 commit d7319b0

File tree

9 files changed

+150
-23
lines changed

9 files changed

+150
-23
lines changed

utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ import org.utbot.framework.util.sootMethod
4141
import org.utbot.fuzzer.*
4242
import org.utbot.fuzzing.*
4343
import org.utbot.fuzzing.providers.ObjectValueProvider
44+
import org.utbot.fuzzing.providers.FieldValueProvider
45+
import org.utbot.fuzzing.spring.SavedEntityProvider
4446
import org.utbot.fuzzing.spring.SpringBeanValueProvider
4547
import org.utbot.fuzzing.utils.Trie
4648
import org.utbot.instrumentation.ConcreteExecutor
@@ -394,6 +396,9 @@ class UtBotSymbolicEngine(
394396
entityClassId = ClassId("com.rest.order.models.Order")
395397
)
396398
)
399+
val generatedValueFieldIds = listOf(
400+
FieldId(ClassId("com.rest.order.models.Order"), "id")
401+
)
397402
logger.info { "Relevant repositories: $relevantRepositories" }
398403
// spring should try to generate bean values, but if it fails, then object value provider is used for it
399404
val springBeanValueProvider = SpringBeanValueProvider(
@@ -405,7 +410,11 @@ class UtBotSymbolicEngine(
405410
},
406411
relevantRepositories = relevantRepositories
407412
).withFallback(ObjectValueProvider(defaultIdGenerator))
408-
provider.except { p -> p is ObjectValueProvider }.with(springBeanValueProvider)
413+
provider
414+
.except { p -> p is ObjectValueProvider }
415+
.with(springBeanValueProvider)
416+
.with(ValueProvider.of(relevantRepositories.map { SavedEntityProvider(defaultIdGenerator, it) }))
417+
.with(ValueProvider.of(generatedValueFieldIds.map { FieldValueProvider(defaultIdGenerator, it) }))
409418
}.let(transform)
410419
runJavaFuzzing(
411420
defaultIdGenerator,

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgVariableConstructor.kt

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -240,18 +240,13 @@ open class CgVariableConstructor(val context: CgContext) :
240240
val executable = statementCall.statement
241241
val params = statementCall.params
242242

243-
val type = when (executable) {
244-
is MethodId -> executable.returnType
245-
is DirectFieldAccessId -> executable.fieldId.type
246-
is ConstructorId -> executable.classId
247-
}
248243
// Don't use redundant constructors for primitives and String
249-
val initExpr = if (isPrimitiveWrapperOrString(type)) {
244+
val initExpr = if (executable is ConstructorId && isPrimitiveWrapperOrString(model.classId)) {
250245
cgLiteralForWrapper(params)
251246
} else {
252247
createCgExecutableCallFromUtExecutableCall(statementCall)
253248
}
254-
newVar(type, model, baseName) {
249+
newVar(model.classId, model, baseName) {
255250
initExpr
256251
}.also {
257252
valueByUtModelWrapper[model.wrap()] = it

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/MockValueConstructor.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,13 @@ class MockValueConstructor(
323323

324324
val instantiationExecutableCall = assembleModel.instantiationCall
325325
val result = updateWithStatementCallModel(instantiationExecutableCall)
326+
327+
// Executions that get `null` in a complicated way (e.g. like this: `new Pair(null, null).getFirst()`)
328+
// are only produced by fuzzer and are considered undesirable because fuzzer can also produce simpler
329+
// executions that just use `null` literal.
330+
//
331+
// So for such executions we throw `IllegalStateException` that indicates that construction of arguments
332+
// has failed and causes execution to terminate with `UtConcreteExecutionProcessedFailure` execution result.
326333
checkNotNull(result) {
327334
"Tracked instance can't be null for call ${instantiationExecutableCall.statement} in model $assembleModel"
328335
}
@@ -437,7 +444,7 @@ class MockValueConstructor(
437444
newInstance(*args.toTypedArray())
438445
}
439446

440-
private fun DirectFieldAccessId.get(instance: Any?): Any {
447+
private fun DirectFieldAccessId.get(instance: Any?): Any? {
441448
val field = fieldId.jField
442449
return field.runSandbox {
443450
field.get(instance)

utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Collections.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class EmptyCollectionValueProvider(
7070
summary = "%var% = ${executableId.classId.simpleName}#${executableId.name}"
7171
}
7272
} else {
73-
UtNullModel(classId).fuzzed { summary = "%var% = null" }
73+
nullFuzzedValue(classId)
7474
}
7575
},
7676
))
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package org.utbot.fuzzing.providers
2+
3+
import mu.KotlinLogging
4+
import org.utbot.framework.plugin.api.DirectFieldAccessId
5+
import org.utbot.framework.plugin.api.FieldId
6+
import org.utbot.framework.plugin.api.UtAssembleModel
7+
import org.utbot.framework.plugin.api.UtDirectGetFieldModel
8+
import org.utbot.framework.plugin.api.UtNullModel
9+
import org.utbot.framework.plugin.api.UtReferenceModel
10+
import org.utbot.framework.plugin.api.util.jClass
11+
import org.utbot.fuzzer.FuzzedType
12+
import org.utbot.fuzzer.FuzzedValue
13+
import org.utbot.fuzzer.IdGenerator
14+
import org.utbot.fuzzer.fuzzed
15+
import org.utbot.fuzzing.FuzzedDescription
16+
import org.utbot.fuzzing.JavaValueProvider
17+
import org.utbot.fuzzing.Routine
18+
import org.utbot.fuzzing.Seed
19+
import org.utbot.fuzzing.toFuzzerType
20+
21+
class FieldValueProvider(
22+
private val idGenerator: IdGenerator<Int>,
23+
private val fieldId: FieldId,
24+
) : JavaValueProvider {
25+
companion object {
26+
private val logger = KotlinLogging.logger {}
27+
}
28+
29+
override fun accept(type: FuzzedType): Boolean = type.classId == fieldId.type
30+
31+
override fun generate(description: FuzzedDescription, type: FuzzedType): Sequence<Seed<FuzzedType, FuzzedValue>> = sequenceOf(
32+
Seed.Recursive(
33+
construct = Routine.Create(listOf(
34+
toFuzzerType(fieldId.declaringClass.jClass, description.typeCache)
35+
)) { values ->
36+
val thisInstanceValue = values.single()
37+
val thisInstanceModel = when (val model = thisInstanceValue.model) {
38+
is UtReferenceModel -> model
39+
is UtNullModel -> return@Create nullFuzzedValue(type.classId)
40+
else -> {
41+
logger.warn { "This instance model can be only UtReferenceModel or UtNullModel, but $model is met" }
42+
return@Create nullFuzzedValue(type.classId)
43+
}
44+
}
45+
UtAssembleModel(
46+
id = idGenerator.createId(),
47+
classId = type.classId,
48+
modelName = "${thisInstanceModel.modelName}.${fieldId.name}",
49+
instantiationCall = UtDirectGetFieldModel(
50+
instance = thisInstanceModel,
51+
fieldAccess = DirectFieldAccessId(
52+
classId = fieldId.declaringClass,
53+
name = "<direct_get_${fieldId.name}>",
54+
fieldId = fieldId
55+
)
56+
)
57+
).fuzzed {
58+
summary = "${thisInstanceValue.summary}.${fieldId.name}"
59+
}
60+
},
61+
modify = emptySequence(),
62+
empty = nullRoutine(type.classId)
63+
)
64+
)
65+
}

utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Objects.kt

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,7 @@ class ObjectValueProvider(
8686
}
8787
}
8888
},
89-
empty = Routine.Empty {
90-
UtNullModel(classId).fuzzed {
91-
summary = "%var% = null"
92-
}
93-
}
89+
empty = nullRoutine(classId)
9490
)
9591
}
9692

@@ -133,9 +129,7 @@ object NullValueProvider : ValueProvider<FuzzedType, FuzzedValue, FuzzedDescript
133129
type: FuzzedType
134130
) = sequence<Seed<FuzzedType, FuzzedValue>> {
135131
if (description.scope?.getProperty(NULLABLE_PROP) == true) {
136-
yield(Seed.Simple(UtNullModel(type.classId).fuzzed {
137-
summary = "%var% = null"
138-
}))
132+
yield(Seed.Simple(nullFuzzedValue(classClassId)))
139133
}
140134
}
141135
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.utbot.fuzzing.providers
2+
3+
import org.utbot.framework.plugin.api.ClassId
4+
import org.utbot.framework.plugin.api.UtNullModel
5+
import org.utbot.fuzzer.FuzzedType
6+
import org.utbot.fuzzer.FuzzedValue
7+
import org.utbot.fuzzer.fuzzed
8+
import org.utbot.fuzzing.Routine
9+
10+
fun nullRoutine(classId: ClassId): Routine.Empty<FuzzedType, FuzzedValue> =
11+
Routine.Empty { nullFuzzedValue(classId) }
12+
13+
fun nullFuzzedValue(classId: ClassId): FuzzedValue =
14+
UtNullModel(classId).fuzzed { summary = "%var% = null" }
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package org.utbot.fuzzing.spring
2+
3+
import org.utbot.framework.plugin.api.SpringRepositoryId
4+
import org.utbot.framework.plugin.api.UtAssembleModel
5+
import org.utbot.framework.plugin.api.UtReferenceModel
6+
import org.utbot.framework.plugin.api.util.SpringModelUtils
7+
import org.utbot.fuzzer.FuzzedType
8+
import org.utbot.fuzzer.FuzzedValue
9+
import org.utbot.fuzzer.IdGenerator
10+
import org.utbot.fuzzer.fuzzed
11+
import org.utbot.fuzzing.FuzzedDescription
12+
import org.utbot.fuzzing.JavaValueProvider
13+
import org.utbot.fuzzing.Routine
14+
import org.utbot.fuzzing.Seed
15+
import org.utbot.fuzzing.providers.nullRoutine
16+
17+
class SavedEntityProvider(
18+
private val idGenerator: IdGenerator<Int>,
19+
private val repositoryId: SpringRepositoryId
20+
) : JavaValueProvider {
21+
override fun accept(type: FuzzedType): Boolean = type.classId == repositoryId.entityClassId
22+
23+
override fun generate(description: FuzzedDescription, type: FuzzedType): Sequence<Seed<FuzzedType, FuzzedValue>> =
24+
sequenceOf(
25+
Seed.Recursive(
26+
construct = Routine.Create(listOf(type)) { values ->
27+
val entityValue = values.single()
28+
val entityModel = entityValue.model
29+
UtAssembleModel(
30+
id = idGenerator.createId(),
31+
classId = type.classId,
32+
modelName = "${repositoryId.repositoryBeanName}.save(${(entityModel as? UtReferenceModel)?.modelName ?: "..."})",
33+
instantiationCall = SpringModelUtils.createSaveCallModel(
34+
repositoryId = repositoryId,
35+
id = idGenerator.createId(),
36+
entityModel = entityModel
37+
)
38+
).fuzzed {
39+
summary = "%var% = ${repositoryId.repositoryBeanName}.save(${entityValue.summary})"
40+
}
41+
},
42+
modify = emptySequence(),
43+
empty = nullRoutine(type.classId)
44+
)
45+
)
46+
}

utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/spring/SpringBeanValueProvider.kt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import org.utbot.fuzzer.IdGenerator
99
import org.utbot.fuzzer.fuzzed
1010
import org.utbot.fuzzing.*
1111
import org.utbot.fuzzing.providers.SPRING_BEAN_PROP
12+
import org.utbot.fuzzing.providers.nullRoutine
1213

1314
class SpringBeanValueProvider(
1415
private val idGenerator: IdGenerator<Int>,
@@ -59,11 +60,7 @@ class SpringBeanValueProvider(
5960
})
6061
}
6162
},
62-
empty = Routine.Empty {
63-
UtNullModel(type.classId).fuzzed {
64-
summary = "%var% = null"
65-
}
66-
}
63+
empty = nullRoutine(type.classId)
6764
)
6865
)
6966
}

0 commit comments

Comments
 (0)