Skip to content

Commit 9c122a9

Browse files
authored
UTBot Python fix bugs (#2581)
1 parent 5ee3695 commit 9c122a9

File tree

12 files changed

+77
-34
lines changed

12 files changed

+77
-34
lines changed

utbot-cli-python/src/main/kotlin/org/utbot/cli/language/python/PythonGenerateTestsCommand.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,14 @@ class PythonGenerateTestsCommand : CliktCommand(
129129
val topLevelClasses = PythonCode.getTopLevelClasses(parsedModule)
130130

131131
val selectedMethods = methods
132+
val filterMethods = listOf("__init__", "__new__")
132133
if (pythonClass == null && methods == null) {
133134
return if (topLevelFunctions.isNotEmpty())
134135
Success(
135136
topLevelFunctions
136137
.mapNotNull { parseFunctionDefinition(it) }
137138
.map { PythonMethodHeader(it.name.toString(), absSourceFile(), null) }
139+
.filter { !filterMethods.contains(it.name) }
138140
)
139141
else {
140142
val topLevelClassMethods = topLevelClasses
@@ -146,6 +148,7 @@ class PythonGenerateTestsCommand : CliktCommand(
146148
val parsedClassName = PythonClassId(cls.name.toString())
147149
PythonMethodHeader(function.name.toString(), absSourceFile(), parsedClassName)
148150
}
151+
.filter { !filterMethods.contains(it.name) }
149152
}
150153
if (topLevelClassMethods.isNotEmpty()) {
151154
Success(topLevelClassMethods)
@@ -178,6 +181,7 @@ class PythonGenerateTestsCommand : CliktCommand(
178181
.map {
179182
PythonMethodHeader(it.name.toString(), absSourceFile(), parsedClassId)
180183
}
184+
.filter { !filterMethods.contains(it.name) }
181185
if (fineMethods.isNotEmpty())
182186
Success(fineMethods)
183187
else

utbot-python-executor/src/main/python/utbot_executor/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "utbot-executor"
3-
version = "1.4.41"
3+
version = "1.4.44"
44
description = ""
55
authors = ["Vyacheslav Tamarin <vyacheslav.tamarin@yandex.ru>"]
66
readme = "README.md"

utbot-python-executor/src/main/python/utbot_executor/tests/test_deep_serialization.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,28 @@ def test_comparable():
192192
assert memory_dump.objects[serialized_obj_ids[0]].comparable
193193

194194

195+
def test_complex():
196+
obj = complex(real=float('-inf'), imag=float('nan'))
197+
serialized_obj_ids, _, serialized_memory_dump = serialize_objects_dump([obj], True)
198+
memory_dump = json_converter.deserialize_memory_objects(serialized_memory_dump)
199+
assert not memory_dump.objects[serialized_obj_ids[0]].comparable
200+
201+
202+
def test_complex_state():
203+
class A:
204+
def __init__(self, c):
205+
self.c = c
206+
207+
obj = A(complex(real=float('-inf'), imag=float('nan')))
208+
serialized_obj_ids, _, serialized_memory_dump = serialize_objects_dump([obj], True)
209+
memory_dump = json_converter.deserialize_memory_objects(serialized_memory_dump)
210+
deserialized_obj = memory_dump.objects[serialized_obj_ids[0]]
211+
assert not deserialized_obj.comparable
212+
state = memory_dump.objects[deserialized_obj.state].items
213+
field_value = memory_dump.objects[list(state.values())[0]]
214+
assert not field_value.comparable
215+
216+
195217
class IncomparableClass:
196218
pass
197219

utbot-python-executor/src/main/python/utbot_executor/utbot_executor/deep_serialization/memory_objects.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,14 +307,20 @@ def initialize(self) -> None:
307307
state = serializer[self.state]
308308
if isinstance(state, dict):
309309
for key, value in state.items():
310-
setattr(deserialized_obj, key, value)
310+
try:
311+
setattr(deserialized_obj, key, value)
312+
except AttributeError:
313+
pass
311314
elif hasattr(deserialized_obj, "__setstate__"):
312315
deserialized_obj.__setstate__(state)
313316
elif isinstance(state, tuple) and len(state) == 2:
314317
_, slotstate = state
315318
if slotstate:
316319
for key, value in slotstate.items():
317-
setattr(deserialized_obj, key, value)
320+
try:
321+
setattr(deserialized_obj, key, value)
322+
except AttributeError:
323+
pass
318324

319325
items = serializer[self.listitems]
320326
if isinstance(items, Iterable):

utbot-python-executor/src/main/python/utbot_executor/utbot_executor/executor.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323
__all__ = ['PythonExecutor']
2424

2525

26-
def _update_states(init_memory_dump: MemoryDump, state_before: MemoryDump) -> MemoryDump:
27-
for id_, obj in state_before.objects.items():
28-
if id_ not in init_memory_dump.objects:
26+
def _update_states(init_memory_dump: MemoryDump, before_memory_dump: MemoryDump) -> MemoryDump:
27+
for id_, obj in before_memory_dump.objects.items():
28+
if id_ in init_memory_dump.objects:
29+
init_memory_dump.objects[id_].comparable = obj.comparable
30+
else:
2931
init_memory_dump.objects[id_] = obj
3032
return init_memory_dump
3133

@@ -98,15 +100,16 @@ def run_function(self, request: ExecutionRequest) -> ExecutionResponse:
98100
args = [loader.load_object(PythonId(arg_id)) for arg_id in request.arguments_ids]
99101
logging.debug("Arguments: %s", args)
100102
kwargs = {name: loader.load_object(PythonId(kwarg_id)) for name, kwarg_id in request.kwarguments_ids.items()}
103+
logging.debug("Kwarguments: %s", kwargs)
101104
except Exception as _:
102105
logging.debug("Error \n%s", traceback.format_exc())
103106
return ExecutionFailResponse("fail", traceback.format_exc())
104107
logging.debug("Arguments have been created")
105108

106109
try:
107-
state_before_memory = _load_objects(args + list(kwargs.values()))
108-
init_state_before = _update_states(loader.reload_id(), state_before_memory)
109-
serialized_state_init = serialize_memory_dump(init_state_before)
110+
state_init_memory = _load_objects(args + list(kwargs.values()))
111+
state_init = _update_states(loader.reload_id(), state_init_memory)
112+
serialized_state_init = serialize_memory_dump(state_init)
110113

111114
def _coverage_sender(info: typing.Tuple[str, int]):
112115
if pathlib.Path(info[0]) == pathlib.Path(request.filepath):
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.4.41
1+
1.4.44

utbot-python/samples/run_tests.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ def check_coverage(
117117

118118
def main_test_generation(args):
119119
config = parse_config(args.config_file)
120-
shutil.rmtree(args.coverage_output_dir)
120+
if pathlib.Path(args.coverage_output_dir).exists():
121+
shutil.rmtree(args.coverage_output_dir)
121122
for part in config['parts']:
122123
for file in part['files']:
123124
for group in file['groups']:

utbot-python/samples/test_configuration.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@
207207
"classes": null,
208208
"methods": null,
209209
"timeout": 30,
210-
"coverage": 92
210+
"coverage": 88
211211
}
212212
]
213213
}

utbot-python/src/main/kotlin/org/utbot/python/framework/api/python/PythonApi.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package org.utbot.python.framework.api.python
22

33
import org.utbot.framework.plugin.api.*
44
import org.utbot.python.PythonArgument
5-
import org.utbot.python.framework.api.python.util.comparePythonTree
65
import org.utbot.python.framework.api.python.util.moduleOfType
76

87
/**
@@ -80,7 +79,7 @@ class PythonTreeModel(
8079
if (other !is PythonTreeModel) {
8180
return false
8281
}
83-
return comparePythonTree(tree, other.tree)
82+
return tree == other.tree
8483
}
8584

8685
override fun hashCode(): Int {

utbot-python/src/main/kotlin/org/utbot/python/framework/api/python/PythonTree.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ object PythonTree {
5454
) {
5555
constructor(type: PythonClassId, comparable: Boolean = true) : this(PythonIdGenerator.createId(), type, comparable)
5656

57+
fun PythonTreeNode.wrap(): PythonTreeWrapper = PythonTreeWrapper(this)
58+
5759
open val children: List<PythonTreeNode> = emptyList()
5860

5961
fun isRecursive(): Boolean {
@@ -75,7 +77,7 @@ object PythonTree {
7577
if (other !is PythonTreeNode) {
7678
return false
7779
}
78-
return id == other.id
80+
return this.wrap() == other.wrap()
7981
}
8082

8183
override fun hashCode(): Int {
@@ -367,7 +369,7 @@ class PythonTreeWrapper(val tree: PythonTree.PythonTreeNode) {
367369
if (other !is PythonTreeWrapper)
368370
return false
369371
if (PythonTree.isRecursiveObject(tree) || PythonTree.isRecursiveObject(other.tree))
370-
return tree == other.tree
372+
return tree.id == other.tree.id
371373
return tree.softEquals(other.tree)
372374
}
373375

utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/constructor/tree/PythonCgMethodConstructor.kt

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ class PythonCgMethodConstructor(context: CgContext) : CgMethodConstructor(contex
189189
assertEquality(
190190
expected = it.second,
191191
actual = it.first,
192-
expectedVariableName = paramNames[executableId]?.get(index) + "_modified"
192+
expectedVariableName = paramNames[executableId]?.get(index) + "_expected"
193193
)
194194
}
195195
if (assertThisObject.isNotEmpty()) {
@@ -199,7 +199,7 @@ class PythonCgMethodConstructor(context: CgContext) : CgMethodConstructor(contex
199199
assertEquality(
200200
expected = it.second,
201201
actual = it.first,
202-
expectedVariableName = it.first.name + "_modified"
202+
expectedVariableName = it.first.name + "_expected"
203203
)
204204
}
205205
}
@@ -408,23 +408,29 @@ class PythonCgMethodConstructor(context: CgContext) : CgMethodConstructor(contex
408408
is PythonTree.ReduceNode -> {
409409
if (expectedNode.state.isNotEmpty()) {
410410
expectedNode.state.forEach { (field, value) ->
411-
val fieldActual = newVar(value.type, "actual_$field") {
412-
CgFieldAccess(
413-
actual, FieldId(
414-
value.type,
415-
field
411+
if (value.comparable) {
412+
val fieldActual = newVar(value.type, "actual_$field") {
413+
CgFieldAccess(
414+
actual, FieldId(
415+
value.type,
416+
field
417+
)
416418
)
417-
)
418-
}
419-
val fieldExpected = newVar(value.type, "expected_$field") {
420-
CgFieldAccess(
421-
expected, FieldId(
422-
value.type,
423-
field
424-
)
425-
)
419+
}
420+
val fieldExpected = if (useExpectedAsValue) {
421+
newVar(value.type, "expected_$field") {
422+
CgFieldAccess(
423+
expected, FieldId(
424+
value.type,
425+
field
426+
)
427+
)
428+
}
429+
} else {
430+
variableConstructor.getOrCreateVariable(PythonTreeModel(expectedNode))
431+
}
432+
pythonDeepTreeEquals(value, fieldExpected, fieldActual, depth - 1, useExpectedAsValue = useExpectedAsValue)
426433
}
427-
pythonDeepTreeEquals(value, fieldExpected, fieldActual, depth - 1)
428434
}
429435
} else {
430436
emptyLineIfNeeded()

utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/constructor/tree/PythonCgVariableConstructor.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class PythonCgVariableConstructor(cgContext: CgContext) : CgVariableConstructor(
3535
}
3636
}
3737

38-
private fun pythonBuildObject(objectNode: PythonTree.PythonTreeNode, baseName: String? = null, depth: Int = 6): Pair<CgValue, List<CgStatement>> {
38+
private fun pythonBuildObject(objectNode: PythonTree.PythonTreeNode, baseName: String? = null): Pair<CgValue, List<CgStatement>> {
3939
val id = objectNode.id
4040
val assistant = (context.cgLanguageAssistant as PythonCgLanguageAssistant)
4141
return when (objectNode) {

0 commit comments

Comments
 (0)