1
1
package org.utbot.fuzzer.providers
2
2
3
- import mu.KotlinLogging
4
3
import org.utbot.framework.plugin.api.ClassId
5
4
import org.utbot.framework.plugin.api.ConstructorId
6
5
import org.utbot.framework.plugin.api.FieldId
@@ -16,113 +15,93 @@ import org.utbot.framework.plugin.api.util.jClass
16
15
import org.utbot.framework.plugin.api.util.stringClassId
17
16
import org.utbot.fuzzer.IdentityPreservingIdGenerator
18
17
import org.utbot.fuzzer.FuzzedMethodDescription
19
- import org.utbot.fuzzer.FuzzedParameter
20
18
import org.utbot.fuzzer.FuzzedValue
21
- import org.utbot.fuzzer.ModelProvider
22
- import org.utbot.fuzzer.ModelProvider.Companion.yieldValue
23
- import org.utbot.fuzzer.TooManyCombinationsException
24
- import org.utbot.fuzzer.fuzz
25
19
import org.utbot.fuzzer.providers.ConstantsModelProvider.fuzzed
26
20
import java.lang.reflect.Constructor
27
21
import java.lang.reflect.Field
28
22
import java.lang.reflect.Member
29
23
import java.lang.reflect.Method
30
24
import java.lang.reflect.Modifier.*
31
25
32
- private val logger by lazy { KotlinLogging .logger {} }
33
-
34
26
/* *
35
27
* Creates [UtAssembleModel] for objects which have public constructors with primitives types and String as parameters.
36
28
*/
37
29
class ObjectModelProvider (
38
30
idGenerator : IdentityPreservingIdGenerator <Int >,
39
31
recursion : Int = 1 ,
40
32
) : RecursiveModelProvider(idGenerator, recursion) {
33
+ override fun copy (idGenerator : IdentityPreservingIdGenerator <Int >, recursionDepthLeft : Int ) =
34
+ ObjectModelProvider (idGenerator, recursionDepthLeft)
35
+
36
+ override fun generateModelConstructors (
37
+ description : FuzzedMethodDescription ,
38
+ clazz : ClassId
39
+ ): List <ModelConstructor > {
40
+ if (clazz == stringClassId || clazz.isPrimitiveWrapper)
41
+ return listOf ()
42
+
43
+ val constructors = collectConstructors(clazz) { javaConstructor ->
44
+ isAccessible(javaConstructor, description.packageName)
45
+ }.sortedWith(
46
+ primitiveParameterizedConstructorsFirstAndThenByParameterCount
47
+ )
41
48
42
- // TODO: can we make it private val (maybe depending on recursion)?
43
- var limitValuesCreatedByFieldAccessors: Int = 100
44
- set(value) {
45
- field = maxOf(0 , value)
46
- }
47
-
48
- private val limit: Int =
49
- when (recursion) {
50
- 1 -> Int .MAX_VALUE
51
- else -> 1
52
- }
49
+ return buildList {
53
50
54
- override fun generate (description : FuzzedMethodDescription ): Sequence <FuzzedParameter > = sequence {
55
- val fuzzedValues = with (description) {
56
- parameters.asSequence()
57
- .filterNot { it == stringClassId || it.isPrimitiveWrapper }
58
- .flatMap { classId ->
59
- collectConstructors(classId) { javaConstructor ->
60
- isAccessible(javaConstructor, description.packageName)
61
- }.sortedWith(
62
- primitiveParameterizedConstructorsFirstAndThenByParameterCount
63
- ).take(limit)
64
- }
65
- .associateWith { constructorId ->
66
- fuzzParameters(
67
- constructorId,
68
- generateRecursiveProvider()
51
+ constructors.forEach { constructorId ->
52
+ with (constructorId) {
53
+ add(
54
+ ModelConstructor (parameters) { assembleModel(idGenerator.createId(), constructorId, it) }
69
55
)
70
- }
71
- .asSequence()
72
- .flatMap { (constructorId, fuzzedParameters) ->
73
- if (constructorId.parameters.isEmpty()) {
74
- sequenceOf(assembleModel(idGenerator.createId(), constructorId, emptyList())) +
75
- generateModelsWithFieldsInitialization(constructorId, description)
76
- }
77
- else {
78
- fuzzedParameters.map { params ->
79
- assembleModel(idGenerator.createId(), constructorId, params)
56
+ if (parameters.isEmpty()) {
57
+ val fields = findSuitableFields(classId, description)
58
+ if (fields.isNotEmpty()) {
59
+ add(
60
+ ModelConstructor (fields.map { it.classId }) {
61
+ generateModelsWithFieldsInitialization(this , fields, it)
62
+ }
63
+ )
80
64
}
81
65
}
82
66
}
83
- }
84
-
85
- fuzzedValues.forEach { fuzzedValue ->
86
- description.parametersMap[fuzzedValue.model.classId]?.forEach { index ->
87
- yieldValue(index, fuzzedValue)
88
67
}
68
+
69
+ // add(ModelConstructor(listOf()) { UtNullModel(clazz).fuzzed {}})
89
70
}
90
71
}
91
72
92
- private fun generateModelsWithFieldsInitialization (constructorId : ConstructorId , description : FuzzedMethodDescription ): Sequence <FuzzedValue > {
93
- if (limitValuesCreatedByFieldAccessors == 0 ) return emptySequence()
94
- val fields = findSuitableFields(constructorId.classId, description)
95
-
96
- val fieldValuesSets = fuzzValuesRecursively(
97
- types = fields.map { it.classId },
98
- baseMethodDescription = description,
99
- modelProvider = generateRecursiveProvider(),
100
- generatedValuesName = " ${constructorId.classId.simpleName} fields"
101
- ).take(limitValuesCreatedByFieldAccessors) // limit the number of fuzzed values in this particular case
102
-
103
- return fieldValuesSets
104
- .map { fieldValues ->
105
- val fuzzedModel = assembleModel(idGenerator.createId(), constructorId, emptyList())
106
- val assembleModel = fuzzedModel.model as ? UtAssembleModel ? : error(" Expected UtAssembleModel but ${fuzzedModel.model::class .java} found" )
107
- val modificationChain = assembleModel.modificationsChain as ? MutableList ? : error(" Modification chain must be mutable" )
108
- fieldValues.asSequence().mapIndexedNotNull { index, value ->
109
- val field = fields[index]
110
- when {
111
- field.canBeSetDirectly -> UtDirectSetFieldModel (
112
- fuzzedModel.model,
113
- FieldId (constructorId.classId, field.name),
114
- value.model
115
- )
116
- field.setter != null -> UtExecutableCallModel (
117
- fuzzedModel.model,
118
- MethodId (constructorId.classId, field.setter.name, field.setter.returnType.id, listOf (field.classId)),
119
- listOf (value.model)
120
- )
121
- else -> null
122
- }
123
- }.forEach(modificationChain::add)
124
- fuzzedModel
73
+ private fun generateModelsWithFieldsInitialization (
74
+ constructorId : ConstructorId ,
75
+ fields : List <FieldDescription >,
76
+ fieldValues : List <FuzzedValue >
77
+ ): FuzzedValue {
78
+ val fuzzedModel = assembleModel(idGenerator.createId(), constructorId, emptyList())
79
+ val assembleModel = fuzzedModel.model as ? UtAssembleModel
80
+ ? : error(" Expected UtAssembleModel but ${fuzzedModel.model::class .java} found" )
81
+ val modificationChain =
82
+ assembleModel.modificationsChain as ? MutableList ? : error(" Modification chain must be mutable" )
83
+ fieldValues.asSequence().mapIndexedNotNull { index, value ->
84
+ val field = fields[index]
85
+ when {
86
+ field.canBeSetDirectly -> UtDirectSetFieldModel (
87
+ fuzzedModel.model,
88
+ FieldId (constructorId.classId, field.name),
89
+ value.model
90
+ )
91
+ field.setter != null -> UtExecutableCallModel (
92
+ fuzzedModel.model,
93
+ MethodId (
94
+ constructorId.classId,
95
+ field.setter.name,
96
+ field.setter.returnType.id,
97
+ listOf (field.classId)
98
+ ),
99
+ listOf (value.model)
100
+ )
101
+ else -> null
125
102
}
103
+ }.forEach(modificationChain::add)
104
+ return fuzzedModel
126
105
}
127
106
128
107
companion object {
@@ -146,21 +125,6 @@ class ObjectModelProvider(
146
125
return ! hasAnyAccessModifier
147
126
}
148
127
149
- private fun FuzzedMethodDescription.fuzzParameters (constructorId : ConstructorId , vararg modelProviders : ModelProvider ): Sequence <List <FuzzedValue >> {
150
- val fuzzedMethod = FuzzedMethodDescription (
151
- executableId = constructorId,
152
- concreteValues = this .concreteValues
153
- ).apply {
154
- this .packageName = this @fuzzParameters.packageName
155
- }
156
- return try {
157
- fuzz(fuzzedMethod, * modelProviders)
158
- } catch (t: TooManyCombinationsException ) {
159
- logger.warn(t) { " Number of combination of ${parameters.size} parameters is huge. Fuzzing is skipped for $name " }
160
- emptySequence()
161
- }
162
- }
163
-
164
128
private fun assembleModel (id : Int , constructorId : ConstructorId , params : List <FuzzedValue >): FuzzedValue {
165
129
val instantiationChain = mutableListOf<UtStatementModel >()
166
130
return UtAssembleModel (
@@ -221,4 +185,4 @@ class ObjectModelProvider(
221
185
val setter : Method ? ,
222
186
)
223
187
}
224
- }
188
+ }
0 commit comments