1
1
package org.utbot.python
2
2
3
3
import org.utbot.framework.plugin.api.*
4
+ import org.utbot.fuzzer.FuzzedConcreteValue
4
5
import org.utbot.fuzzer.FuzzedMethodDescription
5
6
import org.utbot.fuzzer.fuzz
6
7
import org.utbot.fuzzer.names.MethodBasedNameSuggester
@@ -20,190 +21,79 @@ class PythonEngine(
20
21
private val directoriesForSysPath : List <String >,
21
22
private val moduleToImport : String ,
22
23
private val pythonPath : String ,
23
- private val projectRoot : String ,
24
- private val fileOfMethod : String
24
+ private val fuzzedConcreteValues : List < FuzzedConcreteValue > ,
25
+ private val selectedTypeMap : Map < String , ClassId >
25
26
) {
26
27
fun fuzzing (): Sequence <PythonResult > = sequence {
27
- val argumentTypes = methodUnderTest.arguments.map {
28
- annotationToClassId(
29
- it.annotation,
30
- pythonPath,
31
- projectRoot,
32
- fileOfMethod,
33
- directoriesForSysPath,
34
- testSourceRoot
35
- )
36
- }
37
- val existingAnnotations = mutableMapOf<String , String >()
38
- argumentTypes.forEachIndexed { index, classId ->
39
- if (classId != pythonAnyClassId)
40
- existingAnnotations[methodUnderTest.arguments[index].name] = classId.name
28
+ val types = methodUnderTest.arguments.map {
29
+ selectedTypeMap[it.name] ? : pythonAnyClassId
41
30
}
42
31
43
- val argInfoCollector = ArgInfoCollector (methodUnderTest, argumentTypes)
44
32
val methodUnderTestDescription = FuzzedMethodDescription (
45
33
methodUnderTest.name,
46
34
pythonAnyClassId,
47
- argumentTypes ,
48
- argInfoCollector.getConstants()
35
+ types ,
36
+ fuzzedConcreteValues
49
37
).apply {
50
38
compilableName = methodUnderTest.name // what's the difference with ordinary name?
51
39
parameterNameMap = { index -> methodUnderTest.arguments.getOrNull(index)?.name }
52
40
}
53
41
54
- val annotations: Sequence <Map <String , ClassId >> =
55
- if (existingAnnotations.size == methodUnderTest.arguments.size)
56
- sequenceOf(
57
- existingAnnotations.mapValues { entry -> ClassId (entry.value) }
58
- )
59
- else
60
- joinAnnotations(
61
- argInfoCollector,
62
- methodUnderTest,
63
- existingAnnotations,
64
- testSourceRoot,
65
- moduleToImport,
66
- directoriesForSysPath,
67
- pythonPath,
68
- fileOfMethod
69
- )
70
-
71
- // model provider argwith fallback?
72
- // attempts?
73
-
74
42
var testsGenerated = 0
43
+ fuzz(methodUnderTestDescription, concreteTypesModelProvider).forEach { values ->
44
+ val modelList = values.map { it.model }
45
+ val evalResult = PythonEvaluation .evaluate(
46
+ methodUnderTest,
47
+ modelList,
48
+ testSourceRoot,
49
+ directoriesForSysPath,
50
+ moduleToImport,
51
+ pythonPath
52
+ )
53
+ if (evalResult is EvaluationError )
54
+ return @sequence
75
55
76
- annotations.forEach { types ->
77
- val classIds = methodUnderTest.arguments.map {
78
- types[it.name] ? : pythonAnyClassId
79
- }
80
- val substitutedDescription = substituteTypesByIndex(methodUnderTestDescription, classIds)
81
- fuzz(substitutedDescription, concreteTypesModelProvider).forEach { values ->
82
- val modelList = values.map { it.model }
83
-
84
- // execute method to get function return
85
- // what if exception happens?
86
- val evalResult = PythonEvaluation .evaluate(
87
- methodUnderTest,
88
- modelList,
89
- testSourceRoot,
90
- directoriesForSysPath,
91
- moduleToImport,
92
- pythonPath
93
- )
94
- if (evalResult is EvaluationError )
95
- return @sequence
96
-
97
- val (resultJSON, isException) = evalResult as EvaluationSuccess
98
-
99
- if (isException) {
100
- yield (PythonError (UtError (resultJSON.output, Throwable ()), modelList))
101
- } else {
102
-
103
- // some types cannot be used as return types in tests (like socket or memoryview)
104
- val outputType = ClassId (resultJSON.type)
105
- if (PythonTypesStorage .getTypeByName(outputType)?.returnRenderType == ReturnRenderType .NONE )
106
- return @sequence
107
-
108
- val resultAsModel = PythonDefaultModel (resultJSON.output, " " )
109
- val result = UtExecutionSuccess (resultAsModel)
56
+ val (resultJSON, isException) = evalResult as EvaluationSuccess
110
57
111
- val nameSuggester = sequenceOf(ModelBasedNameSuggester (), MethodBasedNameSuggester ())
112
- val testMethodName = try {
113
- nameSuggester.flatMap { it.suggest(methodUnderTestDescription, values, result) }.firstOrNull()
114
- } catch (t: Throwable ) {
115
- null
116
- }
58
+ if (isException) {
59
+ yield (PythonError (UtError (resultJSON.output, Throwable ()), modelList))
60
+ } else {
117
61
118
- yield (
119
- PythonExecution (
120
- UtExecution (
121
- stateBefore = EnvironmentModels (null , modelList, emptyMap()),
122
- stateAfter = EnvironmentModels (null , modelList, emptyMap()),
123
- result = result,
124
- instrumentation = emptyList(),
125
- path = mutableListOf (), // ??
126
- fullPath = emptyList(), // ??
127
- testMethodName = testMethodName?.testName,
128
- displayName = testMethodName?.displayName
129
- ),
130
- modelList
131
- )
132
- )
133
- }
134
-
135
- testsGenerated + = 1
136
- if (testsGenerated == 100 )
62
+ // some types cannot be used as return types in tests (like socket or memoryview)
63
+ val outputType = ClassId (resultJSON.type)
64
+ if (PythonTypesStorage .getTypeByName(outputType)?.returnRenderType == ReturnRenderType .NONE )
137
65
return @sequence
138
- }
139
- }
140
- }
141
66
142
- private val inf = 1000
67
+ val resultAsModel = PythonDefaultModel (resultJSON.output, " " )
68
+ val result = UtExecutionSuccess (resultAsModel)
143
69
144
- private fun increaseValue (map : MutableMap <String , Int >, key : String ) {
145
- if (map[key] == inf)
146
- return
147
- map[key] = (map[key] ? : 0 ) + 1
148
- }
149
-
150
- private fun findTypeCandidates (
151
- storages : List <ArgInfoCollector .BaseStorage >?
152
- ): List <String > {
153
- val candidates = mutableMapOf<String , Int >() // key: type, value: priority
154
- PythonTypesStorage .builtinTypes.associateByTo(destination = candidates, { it }, { 0 })
155
- storages?.forEach { argInfoStorage ->
156
- when (argInfoStorage) {
157
- is ArgInfoCollector .TypeStorage -> candidates[argInfoStorage.name] = inf
158
- is ArgInfoCollector .MethodStorage -> {
159
- val typesWithMethod = PythonTypesStorage .findTypeWithMethod(argInfoStorage.name)
160
- typesWithMethod.forEach { increaseValue(candidates, it) }
161
- }
162
- is ArgInfoCollector .FieldStorage -> {
163
- val typesWithField = PythonTypesStorage .findTypeWithField(argInfoStorage.name)
164
- typesWithField.forEach { increaseValue(candidates, it) }
165
- }
166
- is ArgInfoCollector .FunctionArgStorage -> {
167
- StubFileFinder .findTypeByFunctionWithArgumentPosition(
168
- argInfoStorage.name,
169
- argumentPosition = argInfoStorage.index
170
- ).forEach { increaseValue(candidates, it) }
171
- }
172
- is ArgInfoCollector .FunctionRetStorage -> {
173
- StubFileFinder .findTypeByFunctionReturnValue(
174
- argInfoStorage.name
175
- ).forEach { increaseValue(candidates, it) }
70
+ val nameSuggester = sequenceOf(ModelBasedNameSuggester (), MethodBasedNameSuggester ())
71
+ val testMethodName = try {
72
+ nameSuggester.flatMap { it.suggest(methodUnderTestDescription, values, result) }.firstOrNull()
73
+ } catch (t: Throwable ) {
74
+ null
176
75
}
76
+
77
+ yield (
78
+ PythonExecution (
79
+ UtExecution (
80
+ stateBefore = EnvironmentModels (null , modelList, emptyMap()),
81
+ stateAfter = EnvironmentModels (null , modelList, emptyMap()),
82
+ result = result,
83
+ instrumentation = emptyList(),
84
+ path = mutableListOf (), // ??
85
+ fullPath = emptyList(), // ??
86
+ testMethodName = testMethodName?.testName,
87
+ displayName = testMethodName?.displayName
88
+ ),
89
+ modelList
90
+ )
91
+ )
177
92
}
178
- }
179
- return candidates.toList().sortedByDescending { it.second }.map { it.first }
180
- }
181
93
182
- private fun joinAnnotations (
183
- argInfoCollector : ArgInfoCollector ,
184
- methodUnderTest : PythonMethod ,
185
- existingAnnotations : Map <String , String >,
186
- testSourceRoot : String ,
187
- moduleToImport : String ,
188
- directoriesForSysPath : List <String >,
189
- pythonPath : String ,
190
- fileOfMethod : String
191
- ): Sequence <Map <String , ClassId >> {
192
- val storageMap = argInfoCollector.getAllStorages()
193
- val userAnnotations = existingAnnotations.entries.associate {
194
- it.key to listOf (it.value)
94
+ testsGenerated + = 1
95
+ if (testsGenerated == 100 )
96
+ return @sequence
195
97
}
196
- val annotationCombinations = storageMap.entries.associate { (name, storages) ->
197
- name to findTypeCandidates(storages)
198
- }
199
-
200
- return MypyAnnotations .mypyCheckAnnotations(
201
- methodUnderTest,
202
- userAnnotations + annotationCombinations,
203
- testSourceRoot,
204
- moduleToImport,
205
- directoriesForSysPath + listOf (File (fileOfMethod).parentFile.path),
206
- pythonPath
207
- )
208
98
}
209
99
}
0 commit comments