Skip to content

Commit af4f7de

Browse files
committed
Fallback provider should not prevent providers filtering when applied
1 parent 5afee97 commit af4f7de

File tree

3 files changed

+62
-24
lines changed

3 files changed

+62
-24
lines changed

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/providers/Objects.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ class CreateObjectAnywayValueProvider(
151151
yield(Seed.Recursive(
152152
construct = Routine.Create(emptyList()) {
153153
UtCompositeModel(idGenerator.createId(), type.classId, useMock).fuzzed {
154-
summary = "some object"
154+
summary = "Unsafe object"
155155
}
156156
},
157157
modify = sequence {
@@ -188,7 +188,7 @@ class CreateObjectAnywayValueProvider(
188188
},
189189
empty = Routine.Empty {
190190
UtCompositeModel(idGenerator.createId(), type.classId, useMock).fuzzed {
191-
summary = "some object"
191+
summary = "Unsafe object"
192192
}
193193
}
194194
))

0 commit comments

Comments
 (0)