diff --git a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Collections.kt b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Collections.kt index c860fbbd33..f408d4c563 100644 --- a/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Collections.kt +++ b/utbot-java-fuzzing/src/main/kotlin/org/utbot/fuzzing/providers/Collections.kt @@ -1,11 +1,13 @@ package org.utbot.fuzzing.providers +import com.google.common.reflect.TypeToken import org.utbot.framework.plugin.api.* import org.utbot.framework.plugin.api.util.* import org.utbot.fuzzer.FuzzedType import org.utbot.fuzzer.FuzzedValue import org.utbot.fuzzer.IdGenerator import org.utbot.fuzzer.fuzzed +import org.utbot.fuzzer.jType import org.utbot.fuzzing.* import org.utbot.fuzzing.utils.hex import kotlin.reflect.KClass @@ -80,9 +82,9 @@ class EmptyCollectionValueProvider( class MapValueProvider( idGenerator: IdGenerator ) : CollectionValueProvider(idGenerator, java.util.Map::class.id) { + override fun resolveType(description: FuzzedDescription, type: FuzzedType) = sequence { - val keyGeneric = type.generics.getOrNull(0) ?: FuzzedType(objectClassId) - val valueGeneric = type.generics.getOrNull(1) ?: FuzzedType(objectClassId) + val (keyGeneric, valueGeneric) = resolveGenericsOfSuperClass>(description, type) when (type.classId) { java.util.Map::class.id -> { if (keyGeneric.classId isSubtypeOf Comparable::class) { @@ -108,8 +110,9 @@ class MapValueProvider( class ListSetValueProvider( idGenerator: IdGenerator ) : CollectionValueProvider(idGenerator, java.util.Collection::class.id) { + override fun resolveType(description: FuzzedDescription, type: FuzzedType) = sequence { - val generic = type.generics.firstOrNull() ?: FuzzedType(objectClassId) + val (generic) = resolveGenericsOfSuperClass>(description, type) when (type.classId) { java.util.Queue::class.id, java.util.Deque::class.id-> { @@ -222,7 +225,7 @@ class IteratorValueProvider(val idGenerator: IdGenerator) : JavaValueProvid } override fun generate(description: FuzzedDescription, type: FuzzedType): Sequence> { - val generic = type.generics.firstOrNull() ?: FuzzedType(objectClassId) + val (generic) = resolveGenericsOfSuperClass>(description, type) return sequenceOf(Seed.Recursive( construct = Routine.Create(listOf(FuzzedType(iterableClassId, listOf(generic)))) { v -> val id = idGenerator.createId() @@ -261,4 +264,21 @@ class IteratorValueProvider(val idGenerator: IdGenerator) : JavaValueProvid } )) } +} + +private inline fun resolveGenericsOfSuperClass( + description: FuzzedDescription, + type: FuzzedType, +): List { + val superClass = T::class.java + return try { + check(superClass.isAssignableFrom(type.classId.jClass)) { "$superClass isn't super class of $type" } + @Suppress("UNCHECKED_CAST") + toFuzzerType( + TypeToken.of(type.jType).getSupertype(superClass as Class).type, + description.typeCache + ).generics + } catch (e: Throwable) { + superClass.typeParameters.map { toFuzzerType(it, description.typeCache) } + } } \ No newline at end of file diff --git a/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/ConcreateMap.java b/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/ConcreateMap.java new file mode 100644 index 0000000000..36a7891e10 --- /dev/null +++ b/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/ConcreateMap.java @@ -0,0 +1,6 @@ +package org.utbot.fuzzing.samples; + +import java.util.HashMap; + +public class ConcreateMap extends HashMap { +} diff --git a/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/ConcreteList.java b/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/ConcreteList.java new file mode 100644 index 0000000000..14d1749cd8 --- /dev/null +++ b/utbot-java-fuzzing/src/test/java/org/utbot/fuzzing/samples/ConcreteList.java @@ -0,0 +1,7 @@ +package org.utbot.fuzzing.samples; + +import java.util.ArrayList; +import java.util.Collection; + +public class ConcreteList extends ArrayList> { +} diff --git a/utbot-java-fuzzing/src/test/kotlin/org/utbot/fuzzing/JavaValueProviderTest.kt b/utbot-java-fuzzing/src/test/kotlin/org/utbot/fuzzing/JavaValueProviderTest.kt new file mode 100644 index 0000000000..32fcf7b156 --- /dev/null +++ b/utbot-java-fuzzing/src/test/kotlin/org/utbot/fuzzing/JavaValueProviderTest.kt @@ -0,0 +1,61 @@ +package org.utbot.fuzzing + +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import org.utbot.framework.plugin.api.Instruction +import org.utbot.framework.plugin.api.util.collectionClassId +import org.utbot.framework.plugin.api.util.id +import org.utbot.framework.plugin.api.util.stringClassId +import org.utbot.framework.plugin.api.util.voidClassId +import org.utbot.fuzzer.FuzzedMethodDescription +import org.utbot.fuzzer.FuzzedType +import org.utbot.fuzzing.providers.ListSetValueProvider +import org.utbot.fuzzing.providers.MapValueProvider +import org.utbot.fuzzing.samples.ConcreateMap +import org.utbot.fuzzing.samples.ConcreteList +import org.utbot.fuzzing.utils.Trie +import java.lang.reflect.Type +import kotlin.random.Random + +fun emptyFuzzerDescription(typeCache: MutableMap) = FuzzedDescription( + FuzzedMethodDescription("no name", voidClassId, emptyList()), + Trie(Instruction::id), + typeCache, + Random(42) +) + +class JavaValueProviderTest { + + @Test + fun `collection value provider correctly resolves types for concrete types of map`() { + val typeCache = mutableMapOf() + runBlockingWithContext { + val seed = MapValueProvider(TestIdentityPreservingIdGenerator).generate( + emptyFuzzerDescription(typeCache), + toFuzzerType(ConcreateMap::class.java, typeCache) + ).first() + val collection = seed as Seed.Collection + val types = collection.modify.types + Assertions.assertEquals(2, types.size) + Assertions.assertEquals(types[0].classId, stringClassId) + Assertions.assertEquals(types[1].classId, java.lang.Number::class.java.id) + } + } + + @Test + fun `collection value provider correctly resolves types for concrete types of list`() { + val typeCache = mutableMapOf() + runBlockingWithContext { + val seed = ListSetValueProvider(TestIdentityPreservingIdGenerator).generate( + emptyFuzzerDescription(typeCache), + toFuzzerType(ConcreteList::class.java, typeCache) + ).first() + val collection = seed as Seed.Collection + val types = collection.modify.types + Assertions.assertEquals(1, types.size) + Assertions.assertEquals(types[0].classId, collectionClassId) + Assertions.assertEquals(1, types[0].generics.size) + Assertions.assertEquals(types[0].generics[0].classId, stringClassId) + } + } +} \ No newline at end of file