diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d30433f3d..ccbbe2a79 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,7 +5,8 @@ * -* +* Fix (`#469`_): junit parses report.nodeid incorrectly, when params contain + ``::``. * @@ -102,6 +103,7 @@ .. _`traceback style docs`: https://pytest.org/latest/usage.html#modifying-python-traceback-printing +.. _#469: https://github.com/pytest-dev/pytest/issues/469 .. _#1422: https://github.com/pytest-dev/pytest/issues/1422 .. _#1379: https://github.com/pytest-dev/pytest/issues/1379 .. _#1366: https://github.com/pytest-dev/pytest/issues/1366 diff --git a/_pytest/junitxml.py b/_pytest/junitxml.py index 6c090f9c0..660d718a6 100644 --- a/_pytest/junitxml.py +++ b/_pytest/junitxml.py @@ -46,6 +46,8 @@ del _legal_chars del _legal_ranges del _legal_xml_re +_py_ext_re = re.compile(r"\.py$") + def bin_xml_escape(arg): def repl(matchobj): @@ -89,7 +91,7 @@ class _NodeReporter(object): def record_testreport(self, testreport): assert not self.testcase - names = mangle_testnames(testreport.nodeid.split("::")) + names = mangle_test_address(testreport.nodeid) classnames = names[:-1] if self.xml.prefix: classnames.insert(0, self.xml.prefix) @@ -235,9 +237,18 @@ def pytest_unconfigure(config): config.pluginmanager.unregister(xml) -def mangle_testnames(names): - names = [x.replace(".py", "") for x in names if x != '()'] +def mangle_test_address(address): + path, possible_open_bracket, params = address.partition('[') + names = path.split("::") + try: + names.remove('()') + except ValueError: + pass + # convert file path to dotted path names[0] = names[0].replace("/", '.') + names[0] = _py_ext_re.sub("", names[0]) + # put any params back + names[-1] += possible_open_bracket + params return names diff --git a/testing/test_junitxml.py b/testing/test_junitxml.py index 99c59cb7a..7506efeea 100644 --- a/testing/test_junitxml.py +++ b/testing/test_junitxml.py @@ -449,11 +449,12 @@ class TestPython: assert "hello-stderr" in systemout.toxml() -def test_mangle_testnames(): - from _pytest.junitxml import mangle_testnames - names = ["a/pything.py", "Class", "()", "method"] - newnames = mangle_testnames(names) - assert newnames == ["a.pything", "Class", "method"] +def test_mangle_test_address(): + from _pytest.junitxml import mangle_test_address + address = '::'.join( + ["a/my.py.thing.py", "Class", "()", "method", "[a-1-::]"]) + newnames = mangle_test_address(address) + assert newnames == ["a.my.py.thing", "Class", "method", "[a-1-::]"] def test_dont_configure_on_slaves(tmpdir): @@ -619,6 +620,20 @@ def test_escaped_parametrized_names_xml(testdir): node.assert_attr(name="test_func[#x00]") +def test_double_colon_split_issue469(testdir): + testdir.makepyfile(""" + import pytest + @pytest.mark.parametrize('param', ["double::colon"]) + def test_func(param): + pass + """) + result, dom = runandparse(testdir) + assert result.ret == 0 + node = dom.find_first_by_tag("testcase") + node.assert_attr(classname="test_double_colon_split_issue469") + node.assert_attr(name='test_func[double::colon]') + + def test_unicode_issue368(testdir): path = testdir.tmpdir.join("test.xml") log = LogXML(str(path), None)