Skip to content

Commit 4a62a03

Browse files
committed
2 parents 5950f59 + 35ec8d6 commit 4a62a03

File tree

6 files changed

+114
-11
lines changed

6 files changed

+114
-11
lines changed

.github/workflows/test-os.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ on:
1010
required: true
1111
type: string
1212
include:
13-
required: true
13+
required: false
1414
type: string
15+
default: '[]'
1516

1617
jobs:
1718
test:

.github/workflows/test-whl.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ on:
1010
required: true
1111
type: string
1212
include:
13-
required: true
13+
required: false
1414
type: string
15+
default: '[]'
1516

1617
jobs:
1718
test:

README.rst

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,18 +142,24 @@ Junitparser also support extra schemas:
142142

143143
.. code-block:: python
144144
145+
# Extended with extra properties/attributes from the xunit2 schema.
145146
from junitparser.xunit2 import TestCase, TestSuite, RerunFailure
146-
# These classes are redefined to support extra properties and attributes
147-
# of the xunit2 schema.
147+
148+
# TestSuite supports system_err.
148149
suite = TestSuite("mySuite")
149-
suite.system_err = "System err" # xunit2 specific property
150+
suite.system_err = "System err"
151+
152+
# TestCase supports interim results.
150153
case = TestCase("myCase")
151-
rerun_failure = RerunFailure("Not found", "404") # case property
154+
rerun_failure = RerunFailure("Not found", "404")
152155
rerun_failure.stack_trace = "Stack"
153156
rerun_failure.system_err = "E404"
154157
rerun_failure.system_out = "NOT FOUND"
155158
case.add_interim_result(rerun_failure)
156159
160+
# TestCase supports properties.
161+
case.add_property("cmake_labels", "cuda;tier2")
162+
157163
Currently supported schemas including:
158164

159165
- xunit2_, supported by pytest, Erlang/OTP, Maven Surefire, CppTest, etc.

junitparser/junitparser.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ def system_err(self, value: str):
428428

429429

430430
class Property(Element):
431-
"""A key/value pare that's stored in the testsuite.
431+
"""A key/value pair that's stored in the testsuite or testcase properties.
432432
433433
Use it to store anything you find interesting or useful.
434434
@@ -458,7 +458,7 @@ def __lt__(self, other):
458458

459459

460460
class Properties(Element):
461-
"""A list of properties inside a testsuite.
461+
"""A list of properties inside a testsuite or testcase.
462462
463463
See :class:`Property`
464464
"""
@@ -688,7 +688,7 @@ class JUnitXml(Element):
688688

689689
testsuite = TestSuite
690690

691-
def __init__(self, name: str | None =None):
691+
def __init__(self, name: str | None = None):
692692
super().__init__(self._tag)
693693
self.filepath = None
694694
self.name = name

junitparser/xunit2.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,36 @@ def add_interim_result(self, result: InterimResult):
154154
"""Append an interim (rerun or flaky) result to the testcase. A testcase can have multiple interim results."""
155155
self.append(result)
156156

157+
def add_property(self, name: str, value: str):
158+
"""Add a property *name* = *value* to the testcase.
159+
160+
See :class:`junitparser.Property` and :class:`junitparser.Properties`.
161+
"""
162+
163+
props = self.child(junitparser.Properties)
164+
if props is None:
165+
props = junitparser.Properties()
166+
self.append(props)
167+
prop = junitparser.Property(name, value)
168+
props.add_property(prop)
169+
170+
def properties(self):
171+
"""Iterate through all :class:`junitparser.Property` elements in the testcase."""
172+
props = self.child(junitparser.Properties)
173+
if props is None:
174+
return
175+
for prop in props:
176+
yield prop
177+
178+
def remove_property(self, property_: junitparser.Property):
179+
"""Remove property *property_* from the testcase."""
180+
props = self.child(junitparser.Properties)
181+
if props is None:
182+
return
183+
for prop in props:
184+
if prop == property_:
185+
props.remove(property_)
186+
157187

158188
class TestSuite(junitparser.TestSuite):
159189
"""TestSuite for Pytest, with some different attributes."""

tests/test_xunit2.py

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
1-
from junitparser.xunit2 import JUnitXml, TestSuite, TestCase, RerunFailure, RerunError, FlakyFailure, FlakyError
2-
from junitparser import Failure
1+
import textwrap
2+
from junitparser.xunit2 import (
3+
JUnitXml,
4+
TestSuite,
5+
TestCase,
6+
RerunFailure,
7+
RerunError,
8+
FlakyFailure,
9+
FlakyError,
10+
)
11+
from junitparser import Failure, Property
312
from copy import deepcopy
413

514

@@ -137,6 +146,62 @@ def test_case_rerun(self):
137146
case.add_interim_result(failure2)
138147
assert len(case.rerun_failures()) == 2
139148

149+
def test_properties_and_output(self):
150+
text = textwrap.dedent("""\
151+
<testcase name="test_pushstringvector" classname="test_pushstringvector" status="run">
152+
<properties>
153+
<property name="cmake_labels" value="util;script"/>
154+
<property name="TestType" value="LATENCY_EDMA" />
155+
</properties>
156+
<system-out>
157+
a line of output
158+
another line
159+
</system-out>
160+
</testcase>
161+
""")
162+
case = TestCase.fromstring(text)
163+
assert case.name == "test_pushstringvector"
164+
assert case.system_out == "\na line of output\nanother line\n"
165+
# Check that there are two properties in the TestCase, then check the values.
166+
case_properties = list(case.properties())
167+
assert len(case_properties) == 2
168+
prop1, prop2 = case_properties
169+
assert prop1.name == "cmake_labels" and prop1.value == "util;script"
170+
assert prop2.name == "TestType" and prop2.value == "LATENCY_EDMA"
171+
172+
def test_suite_parses_testcase_properties(self):
173+
text = textwrap.dedent("""\
174+
<testsuite name="suitename1" tests="1" failures="0">
175+
<testcase name="testname1">
176+
<properties>
177+
<property name="labels" value="foo;bar"/>
178+
<property name="test_type" value="latency" />
179+
</properties>
180+
</testcase>
181+
</testsuite>""")
182+
test_suite1 = TestSuite.fromstring(text)
183+
assert test_suite1.name == "suitename1"
184+
cases = list(iter(test_suite1))
185+
assert len(cases) == 1
186+
case = cases[0]
187+
case_properties = list(case.properties())
188+
assert len(case_properties) == 2
189+
prop1, prop2 = case_properties
190+
assert prop1.name == "labels" and prop1.value == "foo;bar"
191+
assert prop2.name == "test_type" and prop2.value == "latency"
192+
193+
def test_add_remove_property(self):
194+
case = TestCase()
195+
case.add_property("prop1", "foo")
196+
case.add_property("prop2", "bar")
197+
prop_to_remove = Property("prop1", "foo")
198+
case.remove_property(prop_to_remove)
199+
assert len(list(case.properties())) == 1
200+
assert case.tostring() in [
201+
b'<testcase><properties><property name="prop2" value="bar" /></properties></testcase>',
202+
b'<testcase><properties><property name="prop2" value="bar"/></properties></testcase>',
203+
]
204+
140205

141206
class Test_TestSuite:
142207
def test_properties(self):

0 commit comments

Comments
 (0)