Skip to content

Commit be47d83

Browse files
authored
Add more correct type resolving for collections and maps (#2610)
1 parent b901732 commit be47d83

File tree

4 files changed

+98
-4
lines changed

4 files changed

+98
-4
lines changed

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

+24-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package org.utbot.fuzzing.providers
22

3+
import com.google.common.reflect.TypeToken
34
import org.utbot.framework.plugin.api.*
45
import org.utbot.framework.plugin.api.util.*
56
import org.utbot.fuzzer.FuzzedType
67
import org.utbot.fuzzer.FuzzedValue
78
import org.utbot.fuzzer.IdGenerator
89
import org.utbot.fuzzer.fuzzed
10+
import org.utbot.fuzzer.jType
911
import org.utbot.fuzzing.*
1012
import org.utbot.fuzzing.utils.hex
1113
import kotlin.reflect.KClass
@@ -80,9 +82,9 @@ class EmptyCollectionValueProvider(
8082
class MapValueProvider(
8183
idGenerator: IdGenerator<Int>
8284
) : CollectionValueProvider(idGenerator, java.util.Map::class.id) {
85+
8386
override fun resolveType(description: FuzzedDescription, type: FuzzedType) = sequence {
84-
val keyGeneric = type.generics.getOrNull(0) ?: FuzzedType(objectClassId)
85-
val valueGeneric = type.generics.getOrNull(1) ?: FuzzedType(objectClassId)
87+
val (keyGeneric, valueGeneric) = resolveGenericsOfSuperClass<Map<*, *>>(description, type)
8688
when (type.classId) {
8789
java.util.Map::class.id -> {
8890
if (keyGeneric.classId isSubtypeOf Comparable::class) {
@@ -108,8 +110,9 @@ class MapValueProvider(
108110
class ListSetValueProvider(
109111
idGenerator: IdGenerator<Int>
110112
) : CollectionValueProvider(idGenerator, java.util.Collection::class.id) {
113+
111114
override fun resolveType(description: FuzzedDescription, type: FuzzedType) = sequence {
112-
val generic = type.generics.firstOrNull() ?: FuzzedType(objectClassId)
115+
val (generic) = resolveGenericsOfSuperClass<Collection<*>>(description, type)
113116
when (type.classId) {
114117
java.util.Queue::class.id,
115118
java.util.Deque::class.id-> {
@@ -222,7 +225,7 @@ class IteratorValueProvider(val idGenerator: IdGenerator<Int>) : JavaValueProvid
222225
}
223226

224227
override fun generate(description: FuzzedDescription, type: FuzzedType): Sequence<Seed<FuzzedType, FuzzedValue>> {
225-
val generic = type.generics.firstOrNull() ?: FuzzedType(objectClassId)
228+
val (generic) = resolveGenericsOfSuperClass<Iterator<*>>(description, type)
226229
return sequenceOf(Seed.Recursive(
227230
construct = Routine.Create(listOf(FuzzedType(iterableClassId, listOf(generic)))) { v ->
228231
val id = idGenerator.createId()
@@ -261,4 +264,21 @@ class IteratorValueProvider(val idGenerator: IdGenerator<Int>) : JavaValueProvid
261264
}
262265
))
263266
}
267+
}
268+
269+
private inline fun <reified T> resolveGenericsOfSuperClass(
270+
description: FuzzedDescription,
271+
type: FuzzedType,
272+
): List<FuzzedType> {
273+
val superClass = T::class.java
274+
return try {
275+
check(superClass.isAssignableFrom(type.classId.jClass)) { "$superClass isn't super class of $type" }
276+
@Suppress("UNCHECKED_CAST")
277+
toFuzzerType(
278+
TypeToken.of(type.jType).getSupertype(superClass as Class<in Any>).type,
279+
description.typeCache
280+
).generics
281+
} catch (e: Throwable) {
282+
superClass.typeParameters.map { toFuzzerType(it, description.typeCache) }
283+
}
264284
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package org.utbot.fuzzing.samples;
2+
3+
import java.util.HashMap;
4+
5+
public class ConcreateMap<V extends Number> extends HashMap<String, V> {
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.utbot.fuzzing.samples;
2+
3+
import java.util.ArrayList;
4+
import java.util.Collection;
5+
6+
public class ConcreteList extends ArrayList<Collection<String>> {
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package org.utbot.fuzzing
2+
3+
import org.junit.jupiter.api.Assertions
4+
import org.junit.jupiter.api.Test
5+
import org.utbot.framework.plugin.api.Instruction
6+
import org.utbot.framework.plugin.api.util.collectionClassId
7+
import org.utbot.framework.plugin.api.util.id
8+
import org.utbot.framework.plugin.api.util.stringClassId
9+
import org.utbot.framework.plugin.api.util.voidClassId
10+
import org.utbot.fuzzer.FuzzedMethodDescription
11+
import org.utbot.fuzzer.FuzzedType
12+
import org.utbot.fuzzing.providers.ListSetValueProvider
13+
import org.utbot.fuzzing.providers.MapValueProvider
14+
import org.utbot.fuzzing.samples.ConcreateMap
15+
import org.utbot.fuzzing.samples.ConcreteList
16+
import org.utbot.fuzzing.utils.Trie
17+
import java.lang.reflect.Type
18+
import kotlin.random.Random
19+
20+
fun emptyFuzzerDescription(typeCache: MutableMap<Type, FuzzedType>) = FuzzedDescription(
21+
FuzzedMethodDescription("no name", voidClassId, emptyList()),
22+
Trie(Instruction::id),
23+
typeCache,
24+
Random(42)
25+
)
26+
27+
class JavaValueProviderTest {
28+
29+
@Test
30+
fun `collection value provider correctly resolves types for concrete types of map`() {
31+
val typeCache = mutableMapOf<Type, FuzzedType>()
32+
runBlockingWithContext {
33+
val seed = MapValueProvider(TestIdentityPreservingIdGenerator).generate(
34+
emptyFuzzerDescription(typeCache),
35+
toFuzzerType(ConcreateMap::class.java, typeCache)
36+
).first()
37+
val collection = seed as Seed.Collection
38+
val types = collection.modify.types
39+
Assertions.assertEquals(2, types.size)
40+
Assertions.assertEquals(types[0].classId, stringClassId)
41+
Assertions.assertEquals(types[1].classId, java.lang.Number::class.java.id)
42+
}
43+
}
44+
45+
@Test
46+
fun `collection value provider correctly resolves types for concrete types of list`() {
47+
val typeCache = mutableMapOf<Type, FuzzedType>()
48+
runBlockingWithContext {
49+
val seed = ListSetValueProvider(TestIdentityPreservingIdGenerator).generate(
50+
emptyFuzzerDescription(typeCache),
51+
toFuzzerType(ConcreteList::class.java, typeCache)
52+
).first()
53+
val collection = seed as Seed.Collection
54+
val types = collection.modify.types
55+
Assertions.assertEquals(1, types.size)
56+
Assertions.assertEquals(types[0].classId, collectionClassId)
57+
Assertions.assertEquals(1, types[0].generics.size)
58+
Assertions.assertEquals(types[0].generics[0].classId, stringClassId)
59+
}
60+
}
61+
}

0 commit comments

Comments
 (0)