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..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 @@ -12,12 +12,15 @@ import org.utbot.fuzzer.fuzzNumbers class ArrayModelProvider( idGenerator: IdentityPreservingIdGenerator, - recursionDepthLeft: Int = 1 + 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, @@ -25,10 +28,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..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 @@ -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) { @@ -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 3a3fef826c..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 @@ -34,9 +34,9 @@ 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 { + override fun newInstance(parentProvider: RecursiveModelProvider, constructor: ModelConstructor): RecursiveModelProvider { val newInstance = ObjectModelProvider(parentProvider.idGenerator, parentProvider.recursionDepthLeft - 1) newInstance.copySettings(parentProvider) newInstance.branchingLimit = 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) + }) } } 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 { 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" }