From ac35ab3ca04fafb51d1c5b4ea6da19a1bdf8409a Mon Sep 17 00:00:00 2001 From: Maksim Pelevin Date: Fri, 30 Sep 2022 10:59:47 +0300 Subject: [PATCH 1/3] Improve fuzzer recursive model providers --- .../org/utbot/fuzzer/providers/ArrayModelProvider.kt | 6 ++++-- .../CollectionWithModificationModelProvider.kt | 2 +- .../org/utbot/fuzzer/providers/ObjectModelProvider.kt | 11 +++++++---- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ArrayModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ArrayModelProvider.kt index ecca10b591..b4ddd7c9d3 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ArrayModelProvider.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ArrayModelProvider.kt @@ -12,7 +12,7 @@ import org.utbot.fuzzer.fuzzNumbers class ArrayModelProvider( idGenerator: IdentityPreservingIdGenerator, - recursionDepthLeft: Int = 1 + recursionDepthLeft: Int = 2 ) : RecursiveModelProvider(idGenerator, recursionDepthLeft) { override fun newInstance(parentProvider: RecursiveModelProvider): RecursiveModelProvider = @@ -25,10 +25,12 @@ class ArrayModelProvider( classId: ClassId, ): Sequence = sequence { if (!classId.isArray) return@sequence - val lengths = fuzzNumbers(description.concreteValues, 0, 3) { it in 1..10 } + val lengths = fuzzNumbers(description.concreteValues, 0, 3) { it in 1..10 }.toList() lengths.forEach { length -> yield(ModelConstructor(listOf(FuzzedType(classId.elementClassId!!)), repeat = length) { values -> createFuzzedArrayModel(classId, length, values.map { it.model } ) + }.apply { + limit = (totalLimit / lengths.size).coerceAtLeast(1) }) } } diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CollectionWithModificationModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CollectionWithModificationModelProvider.kt index 94ac32465d..c9f6507de8 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CollectionWithModificationModelProvider.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CollectionWithModificationModelProvider.kt @@ -15,7 +15,7 @@ import org.utbot.fuzzer.objects.create class CollectionWithModificationModelProvider( idGenerator: IdentityPreservingIdGenerator, - recursionDepthLeft: Int = 1, + recursionDepthLeft: Int = 2, private var defaultModificationCount: IntArray = intArrayOf(0, 1, 3) ) : RecursiveModelProvider(idGenerator, recursionDepthLeft) { diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ObjectModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ObjectModelProvider.kt index 3a3fef826c..95f9541508 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ObjectModelProvider.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ObjectModelProvider.kt @@ -34,7 +34,7 @@ import org.utbot.fuzzer.objects.assembleModel */ class ObjectModelProvider( idGenerator: IdentityPreservingIdGenerator, - recursionDepthLeft: Int = 1, + recursionDepthLeft: Int = 2, ) : RecursiveModelProvider(idGenerator, recursionDepthLeft) { override fun newInstance(parentProvider: RecursiveModelProvider): RecursiveModelProvider { val newInstance = ObjectModelProvider(parentProvider.idGenerator, parentProvider.recursionDepthLeft - 1) @@ -62,9 +62,9 @@ class ObjectModelProvider( ) constructors.forEach { constructorId -> - yield(ModelConstructor(constructorId.parameters.map { classId -> FuzzedType(classId) }) { - assembleModel(idGenerator.createId(), constructorId, it) - }) + // When branching limit = 1 this block tries to create new values + // and mutate some fields. Only if there's no option next block + // with empty constructor should be used. if (constructorId.parameters.isEmpty()) { val fields = findSuitableFields(constructorId.classId, description) if (fields.isNotEmpty()) { @@ -75,6 +75,9 @@ class ObjectModelProvider( ) } } + yield(ModelConstructor(constructorId.parameters.map { classId -> FuzzedType(classId) }) { + assembleModel(idGenerator.createId(), constructorId, it) + }) } } From ffa5d0e490bc5d39fcd215aa8f0770d636622ddf Mon Sep 17 00:00:00 2001 From: Maksim Pelevin Date: Fri, 30 Sep 2022 11:10:53 +0300 Subject: [PATCH 2/3] Fix tests --- .../framework/plugin/api/ModelProviderTest.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/ModelProviderTest.kt b/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/ModelProviderTest.kt index f44db5063d..041ea33339 100644 --- a/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/ModelProviderTest.kt +++ b/utbot-fuzzers/src/test/kotlin/org/utbot/framework/plugin/api/ModelProviderTest.kt @@ -389,7 +389,7 @@ class ModelProviderTest { withUtContext(UtContext(this::class.java.classLoader)) { val result = collect( - ObjectModelProvider(ReferencePreservingIntIdGenerator(0)), + ObjectModelProvider(ReferencePreservingIntIdGenerator(0), recursionDepthLeft = 1), parameters = listOf(MyA::class.java.id) ) assertEquals(1, result.size) @@ -478,14 +478,14 @@ class ModelProviderTest { ) withUtContext(UtContext(this::class.java.classLoader)) { - val result = collect(ObjectModelProvider(ReferencePreservingIntIdGenerator(0)).apply { + val result = collect(ObjectModelProvider(ReferencePreservingIntIdGenerator(0), recursionDepthLeft = 1).apply { modelProviderForRecursiveCalls = PrimitiveDefaultsModelProvider }, parameters = listOf(FieldSetterClass::class.java.id)) assertEquals(1, result.size) assertEquals(2, result[0]!!.size) - assertEquals(0, (result[0]!![0] as UtAssembleModel).modificationsChain.size) { "One of models must be without any modifications" } + assertEquals(0, (result[0]!![1] as UtAssembleModel).modificationsChain.size) { "One of models must be without any modifications" } val expectedModificationSize = 3 - val modificationsChain = (result[0]!![1] as UtAssembleModel).modificationsChain + val modificationsChain = (result[0]!![0] as UtAssembleModel).modificationsChain val actualModificationSize = modificationsChain.size assertEquals(expectedModificationSize, actualModificationSize) { "In target class there's only $expectedModificationSize fields that can be changed, but generated $actualModificationSize modifications" } @@ -513,10 +513,10 @@ class ModelProviderTest { } assertEquals(1, result.size) assertEquals(3, result[0]!!.size) - assertEquals(0, (result[0]!![0] as UtAssembleModel).modificationsChain.size) { "One of models must be without any modifications" } - assertEquals(0, (result[0]!![2] as UtAssembleModel).modificationsChain.size) { "Modification by constructor doesn't change fields" } + assertEquals(0, (result[0]!![2] as UtAssembleModel).modificationsChain.size) { "One of models must be without any modifications" } + assertEquals(0, (result[0]!![1] as UtAssembleModel).modificationsChain.size) { "Modification by constructor doesn't change fields" } val expectedModificationSize = 1 - val modificationsChain = (result[0]!![1] as UtAssembleModel).modificationsChain + val modificationsChain = (result[0]!![0] as UtAssembleModel).modificationsChain val actualModificationSize = modificationsChain.size assertEquals(expectedModificationSize, actualModificationSize) { "In target class there's only $expectedModificationSize fields that can be changed, but generated $actualModificationSize modifications" } From ad867370ea37cf9065e1b8b58db4ca9b5aa4eb85 Mon Sep 17 00:00:00 2001 From: Maksim Pelevin Date: Mon, 3 Oct 2022 10:45:54 +0300 Subject: [PATCH 3/3] Pass limit of constructor to limit total values --- .../org/utbot/fuzzer/providers/ArrayModelProvider.kt | 9 ++++++--- .../providers/CollectionWithModificationModelProvider.kt | 2 +- .../org/utbot/fuzzer/providers/ObjectModelProvider.kt | 2 +- .../org/utbot/fuzzer/providers/RecursiveModelProvider.kt | 8 ++++---- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ArrayModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ArrayModelProvider.kt index b4ddd7c9d3..5dbf6f33c0 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ArrayModelProvider.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ArrayModelProvider.kt @@ -15,9 +15,12 @@ class ArrayModelProvider( recursionDepthLeft: Int = 2 ) : RecursiveModelProvider(idGenerator, recursionDepthLeft) { - override fun newInstance(parentProvider: RecursiveModelProvider): RecursiveModelProvider = - ArrayModelProvider(parentProvider.idGenerator, parentProvider.recursionDepthLeft - 1) - .copySettings(parentProvider) + override fun newInstance(parentProvider: RecursiveModelProvider, constructor: ModelConstructor): RecursiveModelProvider { + val provider = ArrayModelProvider(parentProvider.idGenerator, parentProvider.recursionDepthLeft - 1) + provider.copySettings(parentProvider) + provider.totalLimit = minOf(parentProvider.totalLimit, constructor.limit) + return provider + } override fun generateModelConstructors( description: FuzzedMethodDescription, diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CollectionWithModificationModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CollectionWithModificationModelProvider.kt index c9f6507de8..434c3056dd 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CollectionWithModificationModelProvider.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/CollectionWithModificationModelProvider.kt @@ -55,7 +55,7 @@ class CollectionWithModificationModelProvider( ) private var modificationCount = 7 - override fun newInstance(parentProvider: RecursiveModelProvider): RecursiveModelProvider { + override fun newInstance(parentProvider: RecursiveModelProvider, constructor: ModelConstructor): RecursiveModelProvider { val newInstance = CollectionWithModificationModelProvider( parentProvider.idGenerator, parentProvider.recursionDepthLeft - 1 ) diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ObjectModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ObjectModelProvider.kt index 95f9541508..8c612e3866 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ObjectModelProvider.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/ObjectModelProvider.kt @@ -36,7 +36,7 @@ class ObjectModelProvider( idGenerator: IdentityPreservingIdGenerator, recursionDepthLeft: Int = 2, ) : RecursiveModelProvider(idGenerator, recursionDepthLeft) { - override fun newInstance(parentProvider: RecursiveModelProvider): RecursiveModelProvider { + override fun newInstance(parentProvider: RecursiveModelProvider, constructor: ModelConstructor): RecursiveModelProvider { val newInstance = ObjectModelProvider(parentProvider.idGenerator, parentProvider.recursionDepthLeft - 1) newInstance.copySettings(parentProvider) newInstance.branchingLimit = 1 diff --git a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/RecursiveModelProvider.kt b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/RecursiveModelProvider.kt index fa4eb01e13..855886fadb 100644 --- a/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/RecursiveModelProvider.kt +++ b/utbot-fuzzers/src/main/kotlin/org/utbot/fuzzer/providers/RecursiveModelProvider.kt @@ -54,7 +54,7 @@ abstract class RecursiveModelProvider( /** * Creates instance of the class on which it is called, assuming that it will be called recursively from [parentProvider] */ - protected abstract fun newInstance(parentProvider: RecursiveModelProvider): RecursiveModelProvider + protected abstract fun newInstance(parentProvider: RecursiveModelProvider, constructor: ModelConstructor): RecursiveModelProvider /** * Creates [ModelProvider]s that will be used to generate values recursively. The order of elements in returned list is important: @@ -101,16 +101,16 @@ abstract class RecursiveModelProvider( neededTypes[index % neededTypes.size] // because we can repeat neededTypes several times } } - return fuzz(syntheticMethodDescription, nextModelProvider()) + return fuzz(syntheticMethodDescription, nextModelProvider(this)) .map { createModel(it) } .take(limit) } - private fun nextModelProvider(): ModelProvider = + private fun nextModelProvider(constructor: ModelConstructor): ModelProvider = if (recursionDepthLeft > 0) { modelProviderForRecursiveCalls.map { if (it is RecursiveModelProvider) { - it.newInstance(this) + it.newInstance(this, constructor) } else { it } } } else {