Skip to content

Commit 19fc16c

Browse files
authored
Fix JaCoCo for Contest Estimator (#2373)
1 parent f44dd6f commit 19fc16c

File tree

11 files changed

+211
-101
lines changed

11 files changed

+211
-101
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+
* Find implementations of interfaces and abstract classes to fuzz.
241+
*/
242+
var fuzzingImplementationOfAbstractClasses: Boolean by getBooleanProperty(true)
243+
239244
/**
240245
* Generate tests that treat possible overflows in arithmetic operations as errors
241246
* that throw Arithmetic Exception.

utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,8 @@ val Type.classId: ClassId
881881
else -> error("Unknown type $this")
882882
}
883883

884+
private val logger = KotlinLogging.logger {}
885+
884886
/**
885887
* Class id. Contains name, not a full qualified name.
886888
*
@@ -905,7 +907,9 @@ open class ClassId @JvmOverloads constructor(
905907
get() = jClass.modifiers
906908

907909
open val canonicalName: String
908-
get() = jClass.canonicalName ?: error("ClassId $name does not have canonical name")
910+
get() = jClass.canonicalName ?: name.also {
911+
logger.error("ClassId $name does not have canonical name")
912+
}
909913

910914
open val simpleName: String get() = jClass.simpleName
911915

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

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

33
import mu.KotlinLogging
44
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
5+
import org.utbot.framework.plugin.api.util.*
146
import org.utbot.framework.util.executableId
157
import soot.BooleanType
168
import soot.ByteType
@@ -28,23 +20,7 @@ import soot.jimple.Constant
2820
import soot.jimple.IntConstant
2921
import soot.jimple.InvokeExpr
3022
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
23+
import soot.jimple.internal.*
4824
import soot.toolkits.graph.ExceptionalUnitGraph
4925

5026
private val logger = KotlinLogging.logger {}

utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/Api.kt

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import org.utbot.fuzzing.seeds.KnownValue
77
import org.utbot.fuzzing.utils.MissedSeed
88
import org.utbot.fuzzing.utils.chooseOne
99
import org.utbot.fuzzing.utils.flipCoin
10+
import org.utbot.fuzzing.utils.transformIfNotEmpty
1011
import kotlin.random.Random
1112

1213
private val logger by lazy { KotlinLogging.logger {} }
@@ -288,7 +289,14 @@ private object EmptyFeedback : Feedback<Nothing, Nothing> {
288289
class NoSeedValueException internal constructor(
289290
// this type cannot be generalized because Java forbids types for [Throwable].
290291
val type: Any?
291-
) : Exception("No seed candidates generated for type: $type")
292+
) : Exception() {
293+
override fun fillInStackTrace(): Throwable {
294+
return this
295+
}
296+
297+
override val message: String
298+
get() = "No seed candidates generated for type: $type"
299+
}
292300

293301
suspend fun <T, R, D : Description<T>, F : Feedback<T, R>> Fuzzing<T, R, D, F>.fuzz(
294302
description: D,
@@ -515,11 +523,11 @@ private fun <TYPE, RESULT, DESCRIPTION : Description<TYPE>, FEEDBACK : Feedback<
515523
}
516524
),
517525
modify = task.modify
518-
// .toMutableList()
519-
// .transformIfNotEmpty {
520-
// shuffle(random)
521-
// take(random.nextInt(size + 1))
522-
// }
526+
.toMutableList()
527+
.transformIfNotEmpty {
528+
shuffle(random)
529+
take(configuration.maxNumberOfRecursiveSeedModifications)
530+
}
523531
.mapTo(arrayListOf()) { routine ->
524532
fuzz(
525533
routine.types,

utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/Configuration.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,9 @@ data class Configuration(
9090
* to generate a recursive object, but will use [Seed.Recursive.empty] instead.
9191
*/
9292
var generateEmptyRecursiveForMissedTypes: Boolean = true,
93+
94+
/**
95+
* Limits maximum number of recursive seed modifications
96+
*/
97+
var maxNumberOfRecursiveSeedModifications: Int = 10,
9398
)

utbot-fuzzing/src/main/kotlin/org/utbot/fuzzing/Providers.kt

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,9 @@ fun interface ValueProvider<T, R, D : Description<T>> {
9696
*/
9797
fun except(filter: (ValueProvider<T, R, D>) -> Boolean): ValueProvider<T, R, D> {
9898
return if (this is Combined) {
99-
Combined(providers.filterNot(filter))
99+
Combined(providers.map { it.unwrapIfFallback() }.filterNot(filter))
100100
} else {
101-
Combined(if (filter(this)) emptyList() else listOf(this))
101+
Combined(if (filter(unwrapIfFallback())) emptyList() else listOf(this))
102102
}
103103
}
104104

@@ -117,26 +117,7 @@ fun interface ValueProvider<T, R, D : Description<T>> {
117117
* Uses fallback value provider in case when 'this' one failed to generate any value.
118118
*/
119119
fun withFallback(fallback: ValueProvider<T, R, D>) : ValueProvider<T, R, D> {
120-
val thisProvider = this
121-
return object : ValueProvider<T, R, D> {
122-
override fun enrich(description: D, type: T, scope: Scope) {
123-
thisProvider.enrich(description, type, scope)
124-
// Enriching scope by fallback value provider in this point is not quite right,
125-
// but it doesn't look as a problem right now.
126-
fallback.enrich(description, type, scope)
127-
}
128-
129-
override fun generate(description: D, type: T): Sequence<Seed<T, R>> {
130-
val default = if (thisProvider.accept(type)) thisProvider.generate(description, type) else emptySequence()
131-
return if (default.iterator().hasNext()) {
132-
default
133-
} else if (fallback.accept(type)) {
134-
fallback.generate(description, type)
135-
} else {
136-
emptySequence()
137-
}
138-
}
139-
}
120+
return Fallback(this, fallback)
140121
}
141122

142123
/**
@@ -152,6 +133,42 @@ fun interface ValueProvider<T, R, D : Description<T>> {
152133
return if (flag) block(this) else this
153134
}
154135

136+
/**
137+
* Checks if current provider has fallback and return the initial provider.
138+
*
139+
* If the initial provider is also fallback, then it is unwrapped too.
140+
*
141+
* @return unwrapped provider or this if it is not fallback
142+
*/
143+
fun unwrapIfFallback(): ValueProvider<T, R, D> {
144+
return if (this is Fallback<T, R, D>) { provider.unwrapIfFallback() } else { this }
145+
}
146+
147+
private class Fallback<T, R, D : Description<T>>(
148+
val provider: ValueProvider<T, R, D>,
149+
val fallback: ValueProvider<T, R, D>,
150+
): ValueProvider<T, R, D> {
151+
152+
override fun enrich(description: D, type: T, scope: Scope) {
153+
provider.enrich(description, type, scope)
154+
// Enriching scope by fallback value provider in this point is not quite right,
155+
// but it doesn't look as a problem right now.
156+
fallback.enrich(description, type, scope)
157+
}
158+
159+
override fun generate(description: D, type: T): Sequence<Seed<T, R>> {
160+
val default = if (provider.accept(type)) provider.generate(description, type) else emptySequence()
161+
return if (default.iterator().hasNext()) {
162+
default
163+
} else if (fallback.accept(type)) {
164+
fallback.generate(description, type)
165+
} else {
166+
emptySequence()
167+
}
168+
}
169+
170+
}
171+
155172
/**
156173
* Wrapper class that delegates implementation to the [providers].
157174
*/

utbot-fuzzing/src/test/kotlin/org/utbot/fuzzing/ProvidersTest.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,27 @@ class ProvidersTest {
111111
Assertions.assertEquals(3, (seq.drop(1).first() as Seed.Simple).value)
112112
}
113113

114+
@Test
115+
fun `test fallback unwrapping from providers`() {
116+
val provider1 = p { 2 }
117+
val provider2 = p { 3 }
118+
val fallback = p { 4 }
119+
val providers1 = ValueProvider.of(listOf(
120+
provider1.withFallback(fallback),
121+
provider2
122+
))
123+
val seq1 = providers1.generate(description, Unit).toSet()
124+
Assertions.assertEquals(2, seq1.count())
125+
Assertions.assertEquals(2, (seq1.first() as Seed.Simple).value)
126+
Assertions.assertEquals(3, (seq1.drop(1).first() as Seed.Simple).value)
127+
128+
val providers2 = providers1.except(provider1)
129+
130+
val seq2 = providers2.generate(description, Unit).toSet()
131+
Assertions.assertEquals(1, seq2.count())
132+
Assertions.assertEquals(3, (seq2.first() as Seed.Simple).value)
133+
}
134+
114135
@Test
115136
fun `provider is not called when accept-method returns false`() {
116137
val seq = ValueProvider.of(listOf(

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.fuzzingImplementationOfAbstractClasses) { ovp ->
47+
ovp.withFallback(AbstractsObjectValueProvider(idGenerator))
48+
},
4649
ArrayValueProvider(idGenerator),
4750
EnumValueProvider(idGenerator),
4851
ListSetValueProvider(idGenerator),

0 commit comments

Comments
 (0)