Skip to content

Commit a2c4a98

Browse files
committed
activated isCancelled button; restructured PythonEngine
1 parent 81c4af4 commit a2c4a98

File tree

5 files changed

+214
-186
lines changed

5 files changed

+214
-186
lines changed

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/python/PythonDialogProcessor.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ object PythonDialogProcessor {
9494
val pythonPath = model.srcModule.sdk?.homePath ?: error("Couldn't find Python interpreter")
9595
val testSourceRoot = model.testSourceRoot!!.path
9696
val filePath = model.file.virtualFile.path
97-
97+
9898
// PythonCodeCollector.refreshProjectClassesList(model.project.basePath!!)
9999
PythonTypesStorage.refreshProjectClassesList(
100100
filePath,
@@ -114,7 +114,7 @@ object PythonDialogProcessor {
114114
pythonPath,
115115
model.project.basePath!!,
116116
filePath
117-
)
117+
) { indicator.isCanceled }
118118
}
119119

120120
val tests = pythonMethods.map { method ->
@@ -125,7 +125,7 @@ object PythonDialogProcessor {
125125
if (it.executions.isEmpty() && it.errors.isEmpty()) it.method.name else null
126126
}
127127

128-
if (functionsWithoutTests.isNotEmpty()) {
128+
if (functionsWithoutTests.isNotEmpty() && !indicator.isCanceled) {
129129
showErrorDialogLater(
130130
project,
131131
message = "Cannot create tests for the following functions: " + functionsWithoutTests.joinToString { it },
Lines changed: 52 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.utbot.python
22

33
import org.utbot.framework.plugin.api.*
4+
import org.utbot.fuzzer.FuzzedConcreteValue
45
import org.utbot.fuzzer.FuzzedMethodDescription
56
import org.utbot.fuzzer.fuzz
67
import org.utbot.fuzzer.names.MethodBasedNameSuggester
@@ -20,190 +21,79 @@ class PythonEngine(
2021
private val directoriesForSysPath: List<String>,
2122
private val moduleToImport: String,
2223
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>
2526
) {
2627
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
4130
}
4231

43-
val argInfoCollector = ArgInfoCollector(methodUnderTest, argumentTypes)
4432
val methodUnderTestDescription = FuzzedMethodDescription(
4533
methodUnderTest.name,
4634
pythonAnyClassId,
47-
argumentTypes,
48-
argInfoCollector.getConstants()
35+
types,
36+
fuzzedConcreteValues
4937
).apply {
5038
compilableName = methodUnderTest.name // what's the difference with ordinary name?
5139
parameterNameMap = { index -> methodUnderTest.arguments.getOrNull(index)?.name }
5240
}
5341

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-
7442
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
7555

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
11057

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 {
11761

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)
13765
return@sequence
138-
}
139-
}
140-
}
14166

142-
private val inf = 1000
67+
val resultAsModel = PythonDefaultModel(resultJSON.output, "")
68+
val result = UtExecutionSuccess(resultAsModel)
14369

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
17675
}
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+
)
17792
}
178-
}
179-
return candidates.toList().sortedByDescending { it.second }.map { it.first }
180-
}
18193

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
19597
}
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-
)
20898
}
20999
}

0 commit comments

Comments
 (0)