diff --git a/CHANGELOG b/CHANGELOG index 93e6807d7..a3d6b41c3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -31,6 +31,7 @@ New features Bug fixes / Maintenance ++++++++++++++++++++++++++ +- fix issue104 proper escaping for test names in junitxml plugin - fix issue57 -f|--looponfail to work with xpassing tests - fix pyimport() to work with directories - streamline py.path.local.mkdtemp implementation and usage diff --git a/py/_plugin/pytest_junitxml.py b/py/_plugin/pytest_junitxml.py index 64945cc24..4fca5ffe3 100644 --- a/py/_plugin/pytest_junitxml.py +++ b/py/_plugin/pytest_junitxml.py @@ -37,7 +37,7 @@ class LogXML(object): d = {'time': self._durations.pop(report.item, "0")} names = [x.replace(".py", "") for x in node.listnames() if x != "()"] d['classname'] = ".".join(names[:-1]) - d['name'] = names[-1] + d['name'] = py.xml.escape(names[-1]) attrs = ['%s="%s"' % item for item in sorted(d.items())] self.test_logs.append("\n" % " ".join(attrs)) @@ -71,7 +71,7 @@ class LogXML(object): d = {'time': '???'} names = [x.replace(".py", "") for x in node.listnames() if x != "()"] d['classname'] = ".".join(names[:-1]) - d['name'] = names[-1] + d['name'] = py.xml.escape(names[-1]) attrs = ['%s="%s"' % item for item in sorted(d.items())] self.test_logs.append("\n" % " ".join(attrs)) diff --git a/testing/plugin/test_pytest_junitxml.py b/testing/plugin/test_pytest_junitxml.py index 6f64bd344..ba51e4b01 100644 --- a/testing/plugin/test_pytest_junitxml.py +++ b/testing/plugin/test_pytest_junitxml.py @@ -98,6 +98,27 @@ class TestPython: assert_attr(fnode, message="test failure") assert "ValueError" in fnode.toxml() + def test_failure_escape(self, testdir): + testdir.makepyfile(""" + def pytest_generate_tests(metafunc): + metafunc.addcall(id="<", funcargs=dict(arg1=42)) + metafunc.addcall(id="&", funcargs=dict(arg1=44)) + def test_func(arg1): + assert 0 + """) + result, dom = runandparse(testdir) + assert result.ret + node = dom.getElementsByTagName("testsuite")[0] + assert_attr(node, failures=2, tests=2) + tnode = node.getElementsByTagName("testcase")[0] + assert_attr(tnode, + classname="test_failure_escape.test_failure_escape", + name="test_func[<]") + tnode = node.getElementsByTagName("testcase")[1] + assert_attr(tnode, + classname="test_failure_escape.test_failure_escape", + name="test_func[&]") + def test_xfailure_function(self, testdir): testdir.makepyfile(""" import py