Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle namespaced XML #7

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions test.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,15 @@ class Test8(X, TestCase):

def test_bad_suite_time(self):
assert self.tr.time is None


class TestNamespaced(TestCase):

def setUp(self):
with open(os.path.join('tests', 'casperjs.xml')) as f:
self.ts, self.tr = parse(f)

def test_nocrash(self):
'We do not crash when the XML is namespaced, such as CasperJS results'
assert self.ts
assert self.tr
1 change: 1 addition & 0 deletions tests/casperjs.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><testsuites xmlns="http://www.w3.org/1999/xhtml" time="10.433"><testsuite name="Signing up, logging out, logging in, logged in" tests="5" failures="1" errors="0" time="8.709" timestamp="2015-05-21T13:04:47.899Z" package="dgsource/ci/behaviour/platform/authentication"><testcase name="Find &quot;Testuser 1432213477481&quot; within the selector &quot;.ci-username&quot;" classname="dgsource/ci/behaviour/platform/authentication" time="2.365"></testcase><testcase name="Find text within the document body" classname="dgsource/ci/behaviour/platform/authentication" time="0.086"></testcase><testcase name="Find text within the document body" classname="dgsource/ci/behaviour/platform/authentication" time="0.035"></testcase><testcase name="Find &quot;Testuser 1432213477481&quot; within the selector &quot;.ci-username&quot;" classname="dgsource/ci/behaviour/platform/authentication" time="1.187"></testcase><testcase name="&quot;.fffff&quot; still did not exist in 5000ms" classname="dgsource/ci/behaviour/platform/authentication" time="5.036"><failure type="uncaughtError">".fffff" still did not exist in 5000ms</failure></testcase><system-out></system-out></testsuite><testsuite name="signup, create inventory session cookie" tests="2" failures="0" errors="0" time="1.724" timestamp="2015-05-21T13:04:47.900Z" package="dgsource/ci/behaviour/platform/regression/authentication"><testcase name="Find &quot;Testuser 1432213486177&quot; within the selector &quot;.ci-username&quot;" classname="dgsource/ci/behaviour/platform/regression/authentication" time="1.181"></testcase><testcase name="Fail to find element matching selector: .login-form" classname="dgsource/ci/behaviour/platform/regression/authentication" time="0.543"></testcase><system-out></system-out></testsuite></testsuites>
34 changes: 22 additions & 12 deletions xunitparser.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import math
import re
import unittest
from datetime import timedelta
from xml.etree import ElementTree

TAG_RE = re.compile(r'(?P<ns>{.*})?(?P<name>\w+)')


def get_tagname(tag):
match = re.search(TAG_RE, tag)
return match.group('name')


def to_timedelta(val):
if val is None:
Expand Down Expand Up @@ -142,7 +150,7 @@ def parse(self, source):

def parse_root(self, root):
ts = self.TS_CLASS()
if root.tag == 'testsuites':
if get_tagname(root.tag) == 'testsuites':
for subroot in root:
self.parse_testsuite(subroot, ts)
else:
Expand All @@ -165,17 +173,18 @@ def parse_root(self, root):
return (ts, tr)

def parse_testsuite(self, root, ts):
assert root.tag == 'testsuite'
assert get_tagname(root.tag) == 'testsuite'
ts.name = root.attrib.get('name')
ts.package = root.attrib.get('package')
for el in root:
if el.tag == 'testcase':
tagname = get_tagname(el.tag)
if tagname == 'testcase':
self.parse_testcase(el, ts)
if el.tag == 'properties':
if tagname == 'properties':
self.parse_properties(el, ts)
if el.tag == 'system-out' and el.text:
if tagname == 'system-out' and el.text:
ts.stdout = el.text.strip()
if el.tag == 'system-err' and el.text:
if tagname == 'system-err' and el.text:
ts.stderr = el.text.strip()

def parse_testcase(self, el, ts):
Expand All @@ -186,10 +195,11 @@ def parse_testcase(self, el, ts):
message = None
text = None
for e in el:
tagname = get_tagname(e.tag)
# error takes over failure in JUnit 4
if e.tag in ('failure', 'error', 'skipped'):
if tagname in ('failure', 'error', 'skipped'):
tc = self.TC_CLASS(tc_classname, el.attrib['name'])
result = e.tag
result = tagname
typename = e.attrib.get('type')

# reuse old if empty
Expand All @@ -198,18 +208,18 @@ def parse_testcase(self, el, ts):

tc.seed(result, typename, message, text)
tc.time = to_timedelta(el.attrib.get('time'))
if e.tag == 'system-out' and e.text:
if tagname == 'system-out' and e.text:
tc.stdout = e.text.strip()
if e.tag == 'system-err' and e.text:
if tagname == 'system-err' and e.text:
tc.stderr = e.text.strip()

# add either the original "success" tc or a tc created by elements
ts.addTest(tc)

def parse_properties(self, el, ts):
for e in el:
if e.tag == 'property':
assert e.attrib['name'] not in ts.properties
if get_tagname(e.tag) == 'property':
# assert e.attrib['name'] not in ts.properties # TODO: Care about this
ts.properties[e.attrib['name']] = e.attrib['value']


Expand Down