diff --git a/src/junitparser/junitparser.py b/src/junitparser/junitparser.py index e4cd9cf..0784786 100644 --- a/src/junitparser/junitparser.py +++ b/src/junitparser/junitparser.py @@ -747,6 +747,7 @@ def __iadd__(self, other): return self def add_testsuite(self, suite: TestSuite): + suite = deepcopy(suite) """Add a testsuite.""" for existing_suite in self: if existing_suite == suite: diff --git a/tests/test_general.py b/tests/test_general.py index d41f865..8d8c1d9 100644 --- a/tests/test_general.py +++ b/tests/test_general.py @@ -249,6 +249,31 @@ def test_construct_xml(self): assert len(case) == 1 assert case[0].attrib["name"] == "case1" + def test_add_does_not_mutate_operands(self): + text = """ + + + + test_x.py:11: unconditional skip + + @pytest.fixture(scope="module") def compb(): yield > raise PermissionError E + PermissionError test_x.py:6: PermissionError + + + + """ + a = JUnitXml.fromstring(text) + b = JUnitXml.fromstring(text) + + result = a + b + assert a.tests == 2, f"Operand 'a' was mutated! tests={a.tests}" + assert b.tests == 2, f"Operand 'b' was mutated! tests={b.tests}" + assert result.tests == 4, f"Result wrong: tests={result.tests}" + _ = a + b + assert a.tests == 2, "Operand 'a' emptied after uncaptured +" + assert b.tests == 2, "Operand 'b' emptied after uncaptured +" + def test_add(self): result1 = JUnitXml() suite1 = TestSuite("suite1")