Path:
tests/unit/strictdoc/backend/sdoc_source_code/test_reports/test_junit_xml_reader_ctest.py
Lines:
258
Non-empty lines:
231
Non-empty lines covered with requirements:
231 / 231 (100.0%)
Functions:
6
Functions covered by requirements:
6 / 6 (100.0%)
1
"""2
@relation(SDOC-SRS-143, scope=file)3
"""4
5
import os
6
import tempfile
7
8
import pytest
9
10
from strictdoc.backend.sdoc.models.document import SDocDocument
11
from strictdoc.backend.sdoc.models.node import SDocNode
12
from strictdoc.backend.sdoc_source_code.test_reports.junit_xml_reader import (
13
JUnitXMLReader,
14
)15
from strictdoc.core.file_system.file_tree import File
16
from strictdoc.core.project_config import ProjectConfig
17
from strictdoc.helpers.cast import assert_cast
18
from strictdoc.helpers.paths import SDocRelativePath
19
20
21
def test_01_ctest():
22
source_input = """
23
<?xml version="1.0" encoding="UTF-8"?>24
<testsuite name="(empty)"25
tests="8"26
failures="0"27
disabled="0"28
skipped="0"29
hostname=""30
time="0"31
timestamp="2025-03-10T10:30:39"32
>33
<testcase name="TestPrtMath.TransitionDistance" classname="TestPrtMath.TransitionDistance" time="0.023645" status="run">34
<properties/>35
<system-out>xxxxx36
</system-out>37
</testcase>38
</testsuite>39
""".lstrip()
40
41
project_config: ProjectConfig = ProjectConfig.default_config()
42
43
with tempfile.NamedTemporaryFile(
44
mode="w+", delete=True, suffix=".ctest.junit.xml"
45
) as temp_file:
46
doc_file: File = File(
47
0,
48
temp_file.name,
49
SDocRelativePath(os.path.basename(temp_file.name)),
50
)51
document: SDocDocument = JUnitXMLReader.read_from_string(
52
source_input, doc_file, project_config
53
)54
assert len(document.section_contents) == 1
55
assert len(document.section_contents[0].section_contents) == 2
56
57
test_result_node: SDocNode = assert_cast(
58
document.section_contents[0].section_contents[1], SDocNode
59
)60
assert (
61
test_result_node.get_meta_field_value_by_title("TEST_FUNCTION")
62
== "#GTEST#TestPrtMath.TransitionDistance"
63
)64
65
66
def test_02_testcase_properties_are_mapped_to_fields():
67
source_input = """\
68
<?xml version="1.0" encoding="UTF-8"?>69
<testsuite name="Test suite" tests="1" failures="0" skipped="0">70
<testcase name="TestSuite.Test1"71
classname="TestSuite.Test1"72
time="0.1">73
<properties>74
<property name="requirement" value="REQ1"/>75
<property name="strictdoc:image" value="test1.png"/>76
</properties>77
</testcase>78
</testsuite>79
"""80
81
project_config: ProjectConfig = ProjectConfig.default_config()
82
83
with tempfile.NamedTemporaryFile(
84
mode="w+", delete=True, suffix=".ctest.junit.xml"
85
) as temp_file:
86
doc_file: File = File(
87
0,
88
temp_file.name,
89
SDocRelativePath(os.path.basename(temp_file.name)),
90
)91
document: SDocDocument = JUnitXMLReader.read_from_string(
92
source_input, doc_file, project_config
93
)94
95
test_result_grammar = document.grammar.elements_by_type["TEST_RESULT"]
96
assert (
97
test_result_grammar.fields_map["REQUIREMENT"].human_title
98
== "requirement"
99
)100
assert (
101
test_result_grammar.fields_map["STRICTDOC_IMAGE"].human_title
102
== "strictdoc:image"
103
)104
assert not test_result_grammar.is_field_multiline("REQUIREMENT")
105
assert not test_result_grammar.is_field_multiline("STRICTDOC_IMAGE")
106
107
test_result_node: SDocNode = assert_cast(
108
document.section_contents[0].section_contents[1], SDocNode
109
)110
assert (
111
test_result_node.get_meta_field_value_by_title("REQUIREMENT")
112
== "REQ1"
113
)114
assert (
115
test_result_node.get_meta_field_value_by_title("STRICTDOC_IMAGE")
116
== "test1.png"
117
)118
119
120
def test_03_property_names_may_repeat_across_testcases():
121
source_input = """\
122
<?xml version="1.0" encoding="UTF-8"?>123
<testsuite name="Test suite" tests="2" failures="0" skipped="0">124
<testcase name="TestSuite.Test1"125
classname="TestSuite.Test1"126
time="0.1">127
<properties>128
<property name="requirement" value="REQ1"/>129
</properties>130
</testcase>131
<testcase name="TestSuite.Test2"132
classname="TestSuite.Test2"133
time="0.1">134
<properties>135
<property name="requirement" value="REQ2"/>136
</properties>137
</testcase>138
</testsuite>139
"""140
141
document: SDocDocument = _read_ctest_source(source_input)
142
first_test_result: SDocNode = assert_cast(
143
document.section_contents[0].section_contents[1], SDocNode
144
)145
second_test_result: SDocNode = assert_cast(
146
document.section_contents[0].section_contents[2], SDocNode
147
)148
assert (
149
first_test_result.get_meta_field_value_by_title("REQUIREMENT") == "REQ1"
150
)151
assert (
152
second_test_result.get_meta_field_value_by_title("REQUIREMENT")
153
== "REQ2"
154
)155
156
157
@pytest.mark.parametrize(
158
("property_xml", "expected_error"),
159
[160
(161
'<property name="requirement--id" value="REQ1"/>',
162
(163
"JUnit property name cannot be mapped to a StrictDoc field "164
"name: 'requirement--id'."165
),166
),167
(168
'<property name="status" value="ignored"/>',
169
(170
"JUnit property name maps to a reserved TEST_RESULT field: "171
"'status' -> 'STATUS'."172
),173
),174
(175
"""\
176
<property name="strictdoc:image" value="test1.png"/>177
<property name="strictdoc-image" value="test2.png"/>\178
""",
179
(180
"JUnit property names map to the same StrictDoc field: "181
"'strictdoc:image', 'strictdoc-image' -> "182
"'STRICTDOC_IMAGE'."183
),184
),185
(186
"""\
187
<property name="requirement" value="REQ1"/>188
<property name="requirement" value="REQ2"/>\189
""",
190
("JUnit testcase contains duplicate property name: 'requirement'."),
191
),192
(193
'<property value="REQ1"/>',
194
"JUnit property is missing required 'name' attribute.",
195
),196
(197
'<property name="requirement"/>',
198
"JUnit property is missing required 'value' attribute.",
199
),200
],201
)202
def test_04_invalid_testcase_properties_are_rejected(
203
property_xml: str, expected_error: str
204
):205
source_input = f"""\
206
<?xml version="1.0" encoding="UTF-8"?>207
<testsuite name="Test suite" tests="1" failures="0" skipped="0">208
<testcase name="TestSuite.Test1"209
classname="TestSuite.Test1"210
time="0.1">211
<properties>212
{property_xml}
213
</properties>214
</testcase>215
</testsuite>216
"""217
218
with pytest.raises(RuntimeError) as exc_info:
219
_ = _read_ctest_source(source_input)
220
assert expected_error == str(exc_info.value)
221
222
223
def test__90__error_handling__empty_xml():
224
source_input = ""
225
226
project_config: ProjectConfig = ProjectConfig.default_config()
227
228
with tempfile.NamedTemporaryFile(
229
mode="w+", delete=True, suffix=".ctest.junit.xml"
230
) as temp_file:
231
doc_file: File = File(
232
0,
233
temp_file.name,
234
SDocRelativePath(os.path.basename(temp_file.name)),
235
)236
with pytest.raises(RuntimeError) as exc_info:
237
_ = JUnitXMLReader.read_from_string(
238
source_input, doc_file, project_config
239
)240
assert """\
241
Document is empty, line 1, column 1 (<string>, line 1)\
242
""" == str(exc_info.value)
243
244
245
def _read_ctest_source(source_input: str) -> SDocDocument:
246
project_config: ProjectConfig = ProjectConfig.default_config()
247
248
with tempfile.NamedTemporaryFile(
249
mode="w+", delete=True, suffix=".ctest.junit.xml"
250
) as temp_file:
251
doc_file: File = File(
252
0,
253
temp_file.name,
254
SDocRelativePath(os.path.basename(temp_file.name)),
255
)256
return JUnitXMLReader.read_from_string(
257
source_input, doc_file, project_config
258
)