Skip to content

Commit 6e3c1c4

Browse files
committed
Add an option to enable 'always generate value' in fuzzing
1 parent 93be3c2 commit 6e3c1c4

File tree

4 files changed

+89
-31
lines changed

4 files changed

+89
-31
lines changed

utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,11 @@ object UtSettings : AbstractSettings(logger, defaultKeyForSettingsPath, defaultS
236236
*/
237237
var fuzzingTimeoutInMillis: Long by getLongProperty(3_000L, 0, Long.MAX_VALUE)
238238

239+
/**
240+
* Fuzzer will create objects when they cannot be created by other providers (e.g. private classes)
241+
*/
242+
var fuzzObjectWhenTheyCannotBeCreatedClean: Boolean by getBooleanProperty(false)
243+
239244
/**
240245
* Generate tests that treat possible overflows in arithmetic operations as errors
241246
* that throw Arithmetic Exception.

utbot-framework/src/main/kotlin/org/utbot/fuzzer/FuzzerFunctions.kt

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
11
package org.utbot.fuzzer
22

33
import mu.KotlinLogging
4+
import org.utbot.framework.UtSettings
45
import org.utbot.framework.plugin.api.classId
5-
import org.utbot.framework.plugin.api.util.booleanClassId
6-
import org.utbot.framework.plugin.api.util.byteClassId
7-
import org.utbot.framework.plugin.api.util.charClassId
8-
import org.utbot.framework.plugin.api.util.doubleClassId
9-
import org.utbot.framework.plugin.api.util.floatClassId
10-
import org.utbot.framework.plugin.api.util.intClassId
11-
import org.utbot.framework.plugin.api.util.longClassId
12-
import org.utbot.framework.plugin.api.util.shortClassId
13-
import org.utbot.framework.plugin.api.util.stringClassId
6+
import org.utbot.framework.plugin.api.util.*
147
import org.utbot.framework.util.executableId
8+
import org.utbot.fuzzing.providers.CreateObjectAnywayValueProvider
159
import soot.BooleanType
1610
import soot.ByteType
1711
import soot.CharType
@@ -28,23 +22,7 @@ import soot.jimple.Constant
2822
import soot.jimple.IntConstant
2923
import soot.jimple.InvokeExpr
3024
import soot.jimple.NullConstant
31-
import soot.jimple.internal.AbstractSwitchStmt
32-
import soot.jimple.internal.ImmediateBox
33-
import soot.jimple.internal.JAssignStmt
34-
import soot.jimple.internal.JCastExpr
35-
import soot.jimple.internal.JEqExpr
36-
import soot.jimple.internal.JGeExpr
37-
import soot.jimple.internal.JGtExpr
38-
import soot.jimple.internal.JIfStmt
39-
import soot.jimple.internal.JInvokeStmt
40-
import soot.jimple.internal.JLeExpr
41-
import soot.jimple.internal.JLookupSwitchStmt
42-
import soot.jimple.internal.JLtExpr
43-
import soot.jimple.internal.JNeExpr
44-
import soot.jimple.internal.JSpecialInvokeExpr
45-
import soot.jimple.internal.JStaticInvokeExpr
46-
import soot.jimple.internal.JTableSwitchStmt
47-
import soot.jimple.internal.JVirtualInvokeExpr
25+
import soot.jimple.internal.*
4826
import soot.toolkits.graph.ExceptionalUnitGraph
4927

5028
private val logger = KotlinLogging.logger {}
@@ -70,6 +48,7 @@ fun collectConstantsForFuzzer(graph: ExceptionalUnitGraph): Set<FuzzedConcreteVa
7048
StringConstant,
7149
RegexByVarStringConstant,
7250
DateFormatByVarStringConstant,
51+
AbstractMethodIsCalled,
7352
).flatMap { finder ->
7453
try {
7554
finder.find(graph, unit, value)
@@ -270,6 +249,16 @@ private object DateFormatByVarStringConstant: ConstantsFinder {
270249
}
271250
}
272251

252+
private object AbstractMethodIsCalled: ConstantsFinder {
253+
override fun find(graph: ExceptionalUnitGraph, unit: Unit, value: Value): List<FuzzedConcreteValue> {
254+
if (UtSettings.fuzzObjectWhenTheyCannotBeCreatedClean && value is JInterfaceInvokeExpr) {
255+
// todo do a better way to add information about virtual method calls to providers
256+
return listOf(FuzzedConcreteValue(value.method.javaClass.id, CreateObjectAnywayValueProvider::class, FuzzedContext.Call(value.method.executableId)))
257+
}
258+
return emptyList()
259+
}
260+
}
261+
273262
private object ConstantsAsIs: ConstantsFinder {
274263
override fun find(graph: ExceptionalUnitGraph, unit: Unit, value: Value): List<FuzzedConcreteValue> {
275264
if (value !is Constant || value is NullConstant) return emptyList()

utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/JavaLanguage.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.utbot.fuzzing
22

33
import mu.KotlinLogging
4+
import org.utbot.framework.UtSettings
45
import org.utbot.framework.plugin.api.ClassId
56
import org.utbot.framework.plugin.api.ExecutableId
67
import org.utbot.framework.plugin.api.Instruction
@@ -42,7 +43,9 @@ fun defaultValueProviders(idGenerator: IdentityPreservingIdGenerator<Int>) = lis
4243
FloatValueProvider,
4344
StringValueProvider,
4445
NumberValueProvider,
45-
ObjectValueProvider(idGenerator),
46+
ObjectValueProvider(idGenerator).letIf(UtSettings.fuzzObjectWhenTheyCannotBeCreatedClean) { ovp ->
47+
ovp.withFallback(CreateObjectAnywayValueProvider(idGenerator, useMock = true))
48+
},
4649
ArrayValueProvider(idGenerator),
4750
EnumValueProvider(idGenerator),
4851
ListSetValueProvider(idGenerator),

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

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
package org.utbot.fuzzing.providers
22

3+
import org.utbot.common.isAbstract
34
import org.utbot.framework.plugin.api.*
45
import org.utbot.framework.plugin.api.util.*
5-
import org.utbot.fuzzer.FuzzedType
6-
import org.utbot.fuzzer.FuzzedValue
7-
import org.utbot.fuzzer.IdGenerator
8-
import org.utbot.fuzzer.fuzzed
6+
import org.utbot.fuzzer.*
97
import org.utbot.fuzzing.*
108
import org.utbot.fuzzing.utils.hex
119
import java.lang.reflect.Field
@@ -134,6 +132,69 @@ object NullValueProvider : ValueProvider<FuzzedType, FuzzedValue, FuzzedDescript
134132
}
135133
}
136134

135+
class CreateObjectAnywayValueProvider(
136+
val idGenerator: IdGenerator<Int>,
137+
val useMock: Boolean = true,
138+
) : ValueProvider<FuzzedType, FuzzedValue, FuzzedDescription> {
139+
140+
override fun accept(type: FuzzedType) = type.classId.isRefType
141+
142+
override fun generate(description: FuzzedDescription, type: FuzzedType) = sequence<Seed<FuzzedType, FuzzedValue>> {
143+
val methodCalls = description.constants.filter {
144+
it.value == CreateObjectAnywayValueProvider::class
145+
}.mapNotNull {
146+
it.fuzzedContext as? FuzzedContext.Call
147+
}.map {
148+
it.method
149+
}.toSet()
150+
151+
yield(Seed.Recursive(
152+
construct = Routine.Create(emptyList()) {
153+
UtCompositeModel(idGenerator.createId(), type.classId, useMock).fuzzed {
154+
summary = "some object"
155+
}
156+
},
157+
modify = sequence {
158+
// generate all fields
159+
generateSequence(type.classId.jClass) {
160+
it.superclass
161+
}.flatMap { javaClass ->
162+
javaClass.declaredFields.toList()
163+
}.forEach { field ->
164+
yield(Routine.Call(listOf(toFuzzerType(field.type, description.typeCache))) { instance, args ->
165+
(instance.model as UtCompositeModel).fields[field.fieldId] = args.first().model
166+
})
167+
}
168+
169+
generateSequence(listOf(type.classId.jClass)) { classList ->
170+
classList.flatMap { listOf(it.superclass) + it.interfaces }.filterNotNull().takeIf { it.isNotEmpty() }
171+
}.flatten().filter {
172+
isAccessible(it, description.description.packageName)
173+
}.flatMap { javaClass ->
174+
javaClass.declaredMethods.filter {
175+
javaClass.isInterface || it.isAbstract
176+
}.filter {
177+
isAccessible(it, description.description.packageName)
178+
}
179+
// todo filter by methods seen in code
180+
}.forEach { method ->
181+
val executableId = method.executableId
182+
if (methodCalls.contains(executableId)) {
183+
yield(Routine.Call(listOf(toFuzzerType(method.returnType, description.typeCache))) { instance, args ->
184+
(instance.model as UtCompositeModel).mocks[executableId] = args.map(FuzzedValue::model)
185+
})
186+
}
187+
}
188+
},
189+
empty = Routine.Empty {
190+
UtCompositeModel(idGenerator.createId(), type.classId, useMock).fuzzed {
191+
summary = "some object"
192+
}
193+
}
194+
))
195+
}
196+
}
197+
137198
internal class PublicSetterGetter(
138199
val setter: Method,
139200
val getter: Method,

0 commit comments

Comments
 (0)