Skip to content

Commit 6181459

Browse files
committed
Add more correct type resolves for collections and maps
1 parent 36c23ff commit 6181459

File tree

4 files changed

+122
-3
lines changed

4 files changed

+122
-3
lines changed

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

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
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
910
import org.utbot.fuzzing.*
11+
import org.utbot.fuzzing.spring.utils.jType
1012
import org.utbot.fuzzing.utils.hex
13+
import java.lang.reflect.Method
1114
import kotlin.reflect.KClass
1215

1316
class EmptyCollectionValueProvider(
@@ -80,9 +83,25 @@ class EmptyCollectionValueProvider(
8083
class MapValueProvider(
8184
idGenerator: IdGenerator<Int>
8285
) : CollectionValueProvider(idGenerator, java.util.Map::class.id) {
86+
87+
private enum class MethodCall { KEYS, VALUES }
88+
89+
private fun findTypeByMethod(description: FuzzedDescription, type: FuzzedType, method: MethodCall): FuzzedType {
90+
val methodName = when (method) {
91+
MethodCall.KEYS -> "keySet"
92+
MethodCall.VALUES -> "values"
93+
}
94+
val m = Map::class.java.getMethod(methodName)
95+
return resolveTypeByMethod(description, type, m)?.let {
96+
assert(it.classId.isSubtypeOf(collectionClassId))
97+
assert(it.generics.size == 1)
98+
it.generics[0]
99+
} ?: FuzzedType(objectClassId)
100+
}
101+
83102
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)
103+
val keyGeneric = findTypeByMethod(description, type, MethodCall.KEYS)
104+
val valueGeneric = findTypeByMethod(description, type, MethodCall.VALUES)
86105
when (type.classId) {
87106
java.util.Map::class.id -> {
88107
if (keyGeneric.classId isSubtypeOf Comparable::class) {
@@ -108,8 +127,20 @@ class MapValueProvider(
108127
class ListSetValueProvider(
109128
idGenerator: IdGenerator<Int>
110129
) : CollectionValueProvider(idGenerator, java.util.Collection::class.id) {
130+
131+
private val iteratorClassId = java.util.Iterator::class.java.id
132+
133+
private fun findTypeByMethod(description: FuzzedDescription, type: FuzzedType): FuzzedType {
134+
val method = java.util.Collection::class.java.getMethod("iterator")
135+
return resolveTypeByMethod(description, type, method)?.let {
136+
assert(it.classId.isSubtypeOf(iteratorClassId))
137+
assert(it.generics.size == 1)
138+
it.generics[0]
139+
} ?: FuzzedType(objectClassId)
140+
}
141+
111142
override fun resolveType(description: FuzzedDescription, type: FuzzedType) = sequence {
112-
val generic = type.generics.firstOrNull() ?: FuzzedType(objectClassId)
143+
val generic = findTypeByMethod(description, type)
113144
when (type.classId) {
114145
java.util.Queue::class.id,
115146
java.util.Deque::class.id-> {
@@ -171,6 +202,20 @@ abstract class CollectionValueProvider(
171202
}
172203
}
173204

205+
/**
206+
* Can be used to resolve some types using [type] and some method of this type
207+
*/
208+
protected fun resolveTypeByMethod(description: FuzzedDescription, type: FuzzedType, method: Method): FuzzedType? {
209+
return try {
210+
toFuzzerType(
211+
TypeToken.of(type.jType).resolveType(method.genericReturnType).type,
212+
description.typeCache
213+
)
214+
} catch (t: Throwable) {
215+
null
216+
}
217+
}
218+
174219
/**
175220
* Types should be resolved with type parameters
176221
*/
Lines changed: 6 additions & 0 deletions
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+
}
Lines changed: 7 additions & 0 deletions
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+
}
Lines changed: 61 additions & 0 deletions
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)