[Python-modules-commits] [python-junit-xml] 01/04: Import python-junit-xml_1.6.orig.tar.gz
Sandro Tosi
morph at moszumanska.debian.org
Wed Nov 4 20:24:59 UTC 2015
This is an automated email from the git hooks/post-receive script.
morph pushed a commit to branch master
in repository python-junit-xml.
commit fe2cf19abde96c74ac52749d532eb21d5559de52
Author: Sandro Tosi <morph at debian.org>
Date: Wed Nov 4 19:49:53 2015 +0000
Import python-junit-xml_1.6.orig.tar.gz
---
MANIFEST.in | 7 +-
PKG-INFO | 2 +-
junit_xml.egg-info/PKG-INFO | 2 +-
junit_xml.egg-info/SOURCES.txt | 2 +
junit_xml/__init__.py | 184 +++++++++++-----
setup.py | 30 +--
test_junit_xml.py | 478 +++++++++++++++++++++++++++++++++++++++++
tox.ini | 38 ++++
8 files changed, 667 insertions(+), 76 deletions(-)
diff --git a/MANIFEST.in b/MANIFEST.in
index 123fdc2..2ef3470 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,4 +1,5 @@
-include setup.py
-include README.rst
include LICENSE.txt
-include tests.py
\ No newline at end of file
+include README.rst
+include setup.py
+include test_junit_xml.py
+include tox.ini
diff --git a/PKG-INFO b/PKG-INFO
index 1986703..3d9e280 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: junit-xml
-Version: 1.4
+Version: 1.6
Summary: Creates JUnit XML test result documents that can be read by tools such as Jenkins
Home-page: https://github.com/kyrus/python-junit-xml
Author: Brian Beyer
diff --git a/junit_xml.egg-info/PKG-INFO b/junit_xml.egg-info/PKG-INFO
index 1986703..3d9e280 100644
--- a/junit_xml.egg-info/PKG-INFO
+++ b/junit_xml.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: junit-xml
-Version: 1.4
+Version: 1.6
Summary: Creates JUnit XML test result documents that can be read by tools such as Jenkins
Home-page: https://github.com/kyrus/python-junit-xml
Author: Brian Beyer
diff --git a/junit_xml.egg-info/SOURCES.txt b/junit_xml.egg-info/SOURCES.txt
index 626822b..d421cad 100644
--- a/junit_xml.egg-info/SOURCES.txt
+++ b/junit_xml.egg-info/SOURCES.txt
@@ -2,6 +2,8 @@ LICENSE.txt
MANIFEST.in
README.rst
setup.py
+test_junit_xml.py
+tox.ini
junit_xml/__init__.py
junit_xml.egg-info/PKG-INFO
junit_xml.egg-info/SOURCES.txt
diff --git a/junit_xml/__init__.py b/junit_xml/__init__.py
index e96b458..8e99bd6 100644
--- a/junit_xml/__init__.py
+++ b/junit_xml/__init__.py
@@ -1,9 +1,12 @@
#!/usr/bin/env python
-import sys, re
+# -*- coding: UTF-8 -*-
+from collections import defaultdict
+import sys
+import re
import xml.etree.ElementTree as ET
import xml.dom.minidom
-from six import u
+from six import u, iteritems, PY2
try:
# Python 2
@@ -13,32 +16,32 @@ except NameError: # pragma: nocover
unichr = chr
"""
-Based on the following understanding of what Jenkins can parse for JUnit XML files.
+Based on the understanding of what Jenkins can parse for JUnit XML files.
<?xml version="1.0" encoding="utf-8"?>
<testsuites errors="1" failures="1" tests="4" time="45">
- <testsuite errors="1" failures="1" hostname="localhost" id="0" name="base_test_1"
+ <testsuite errors="1" failures="1" hostname="localhost" id="0" name="test1"
package="testdb" tests="4" timestamp="2012-11-15T01:02:29">
<properties>
<property name="assert-passed" value="1"/>
</properties>
- <testcase classname="testdb.directory" name="001-passed-test" time="10"/>
- <testcase classname="testdb.directory" name="002-failed-test" time="20">
- <failure message="Assertion FAILED: some failed assert" type="failure">
+ <testcase classname="testdb.directory" name="1-passed-test" time="10"/>
+ <testcase classname="testdb.directory" name="2-failed-test" time="20">
+ <failure message="Assertion FAILED: failed assert" type="failure">
the output of the testcase
</failure>
</testcase>
- <testcase classname="package.directory" name="003-errord-test" time="15">
- <error message="Assertion ERROR: some error assert" type="error">
+ <testcase classname="package.directory" name="3-errord-test" time="15">
+ <error message="Assertion ERROR: error assert" type="error">
the output of the testcase
</error>
</testcase>
- <testcase classname="package.directory" name="003-skipped-test" time="0">
- <skipped message="SKIPPED Test" type="skipped">
+ <testcase classname="package.directory" name="3-skipped-test" time="0">
+ <skipped message="SKIPPED Test" type="skipped">
the output of the testcase
- </skipped>
- </testcase>
- <testcase classname="testdb.directory" name="003-passed-test" time="10">
+ </skipped>
+ </testcase>
+ <testcase classname="testdb.directory" name="3-passed-test" time="10">
<system-out>
I am system output
</system-out>
@@ -51,10 +54,31 @@ Based on the following understanding of what Jenkins can parse for JUnit XML fil
"""
+def decode(var, encoding):
+ '''
+ If not already unicode, decode it.
+ '''
+ if PY2:
+ if isinstance(var, unicode):
+ ret = var
+ elif isinstance(var, str):
+ if encoding:
+ ret = var.decode(encoding)
+ else:
+ ret = unicode(var)
+ else:
+ ret = unicode(var)
+ else:
+ ret = str(var)
+ return ret
+
+
class TestSuite(object):
- """Suite of test cases"""
+ '''Suite of test cases.
+ Can handle unicode strings or binary strings if their encoding is provided.
+ '''
- def __init__(self, name, test_cases=None, hostname=None, id=None,\
+ def __init__(self, name, test_cases=None, hostname=None, id=None,
package=None, timestamp=None, properties=None):
self.name = name
if not test_cases:
@@ -70,25 +94,36 @@ class TestSuite(object):
self.timestamp = timestamp
self.properties = properties
- def build_xml_doc(self):
- """Builds the XML document for the JUnit test suite"""
+
+ def build_xml_doc(self, encoding=None):
+ '''
+ Builds the XML document for the JUnit test suite.
+ Produces clean unicode strings and decodes non-unicode with the help of encoding.
+ @param encoding: Used to decode encoded strings.
+ @return: XML document with unicode string elements
+ '''
+
# build the test suite element
test_suite_attributes = dict()
- test_suite_attributes['name'] = str(self.name)
- test_suite_attributes['failures'] = str(len([c for c in self.test_cases if c.is_failure()]))
- test_suite_attributes['errors'] = str(len([c for c in self.test_cases if c.is_error()]))
- test_suite_attributes['skipped'] = str(len([c for c in self.test_cases if c.is_skipped()]))
- test_suite_attributes['time'] = str(sum(c.elapsed_sec for c in self.test_cases if c.elapsed_sec))
+ test_suite_attributes['name'] = decode(self.name, encoding)
+ test_suite_attributes['failures'] = \
+ str(len([c for c in self.test_cases if c.is_failure()]))
+ test_suite_attributes['errors'] = \
+ str(len([c for c in self.test_cases if c.is_error()]))
+ test_suite_attributes['skipped'] = \
+ str(len([c for c in self.test_cases if c.is_skipped()]))
+ test_suite_attributes['time'] = \
+ str(sum(c.elapsed_sec for c in self.test_cases if c.elapsed_sec))
test_suite_attributes['tests'] = str(len(self.test_cases))
if self.hostname:
- test_suite_attributes['hostname'] = str(self.hostname)
+ test_suite_attributes['hostname'] = decode(self.hostname, encoding)
if self.id:
- test_suite_attributes['id'] = str(self.id)
+ test_suite_attributes['id'] = decode(self.id, encoding)
if self.package:
- test_suite_attributes['package'] = str(self.package)
+ test_suite_attributes['package'] = decode(self.package, encoding)
if self.timestamp:
- test_suite_attributes['timestamp'] = str(self.timestamp)
+ test_suite_attributes['timestamp'] = decode(self.timestamp, encoding)
xml_element = ET.Element("testsuite", test_suite_attributes)
@@ -96,100 +131,134 @@ class TestSuite(object):
if self.properties:
props_element = ET.SubElement(xml_element, "properties")
for k, v in self.properties.items():
- attrs = {'name': str(k), 'value': str(v)}
+ attrs = {'name': decode(k, encoding), 'value': decode(v, encoding)}
ET.SubElement(props_element, "property", attrs)
# test cases
for case in self.test_cases:
test_case_attributes = dict()
- test_case_attributes['name'] = str(case.name)
+ test_case_attributes['name'] = decode(case.name, encoding)
if case.elapsed_sec:
test_case_attributes['time'] = "%f" % case.elapsed_sec
if case.classname:
- test_case_attributes['classname'] = str(case.classname)
+ test_case_attributes['classname'] = decode(case.classname, encoding)
- test_case_element = ET.SubElement(xml_element, "testcase", test_case_attributes)
+ test_case_element = ET.SubElement(
+ xml_element, "testcase", test_case_attributes)
# failures
if case.is_failure():
attrs = {'type': 'failure'}
if case.failure_message:
- attrs['message'] = case.failure_message
+ attrs['message'] = decode(case.failure_message, encoding)
failure_element = ET.Element("failure", attrs)
if case.failure_output:
- failure_element.text = case.failure_output
+ failure_element.text = decode(case.failure_output, encoding)
test_case_element.append(failure_element)
# errors
if case.is_error():
attrs = {'type': 'error'}
if case.error_message:
- attrs['message'] = case.error_message
+ attrs['message'] = decode(case.error_message, encoding)
error_element = ET.Element("error", attrs)
if case.error_output:
- error_element.text = case.error_output
+ error_element.text = decode(case.error_output, encoding)
test_case_element.append(error_element)
# skippeds
if case.is_skipped():
attrs = {'type': 'skipped'}
if case.skipped_message:
- attrs['message'] = case.skipped_message
+ attrs['message'] = decode(case.skipped_message, encoding)
skipped_element = ET.Element("skipped", attrs)
- if case.error_output:
- skipped_element.text = case.skipped_output
+ if case.skipped_output:
+ skipped_element.text = decode(case.skipped_output, encoding)
test_case_element.append(skipped_element)
# test stdout
if case.stdout:
stdout_element = ET.Element("system-out")
- stdout_element.text = case.stdout
+ stdout_element.text = decode(case.stdout, encoding)
test_case_element.append(stdout_element)
# test stderr
if case.stderr:
stderr_element = ET.Element("system-err")
- stderr_element.text = case.stderr
+ stderr_element.text = decode(case.stderr, encoding)
test_case_element.append(stderr_element)
return xml_element
@staticmethod
def to_xml_string(test_suites, prettyprint=True, encoding=None):
- """Returns the string representation of the JUnit XML document"""
+ '''Returns the string representation of the JUnit XML document.
+ @param encoding: The encoding of the input.
+ @return: unicode string
+ '''
+
try:
iter(test_suites)
except TypeError:
raise Exception('test_suites must be a list of test suites')
xml_element = ET.Element("testsuites")
+ attributes = defaultdict(int)
for ts in test_suites:
- xml_element.append(ts.build_xml_doc())
+ ts_xml = ts.build_xml_doc(encoding=encoding)
+ for key in ['failures', 'errors', 'skipped', 'tests']:
+ attributes[key] += int(ts_xml.get(key, 0))
+ for key in ['time']:
+ attributes[key] += float(ts_xml.get(key, 0))
+ xml_element.append(ts_xml)
+ for key, value in iteritems(attributes):
+ xml_element.set(key, str(value))
xml_string = ET.tostring(xml_element, encoding=encoding)
- xml_string = TestSuite._clean_illegal_xml_chars(xml_string.decode(encoding or 'utf-8'))
+ # is encoded now
+ xml_string = TestSuite._clean_illegal_xml_chars(
+ xml_string.decode(encoding or 'utf-8'))
+ # is unicode now
if prettyprint:
- xml_string = xml.dom.minidom.parseString(xml_string).toprettyxml()
+ # minidom.parseString() works just on correctly encoded binary strings
+ xml_string = xml_string.encode(encoding or 'utf-8')
+ xml_string = xml.dom.minidom.parseString(xml_string)
+ # toprettyxml() produces unicode if no encoding is being passed or binary string with an encoding
+ xml_string = xml_string.toprettyxml(encoding=encoding)
+ if encoding:
+ xml_string = xml_string.decode(encoding)
+ # is unicode now
return xml_string
@staticmethod
def to_file(file_descriptor, test_suites, prettyprint=True, encoding=None):
- """Writes the JUnit XML document to file"""
- file_descriptor.write(TestSuite.to_xml_string(test_suites, prettyprint, encoding))
+ '''
+ Writes the JUnit XML document to a file.
+ '''
+ xml_string = TestSuite.to_xml_string(
+ test_suites, prettyprint=prettyprint, encoding=encoding)
+ # has problems with encoded str with non-ASCII (non-default-encoding) characters!
+ file_descriptor.write(xml_string)
+
@staticmethod
def _clean_illegal_xml_chars(string_to_clean):
- """Removes any illegal unicode characters from the given XML string"""
- # see http://stackoverflow.com/questions/1707890/fast-way-to-filter-illegal-xml-unicode-chars-in-python
- illegal_unichrs = [(0x00, 0x08), (0x0B, 0x1F), (0x7F, 0x84), (0x86, 0x9F),
- (0xD800, 0xDFFF), (0xFDD0, 0xFDDF), (0xFFFE, 0xFFFF),
- (0x1FFFE, 0x1FFFF), (0x2FFFE, 0x2FFFF), (0x3FFFE, 0x3FFFF),
- (0x4FFFE, 0x4FFFF), (0x5FFFE, 0x5FFFF), (0x6FFFE, 0x6FFFF),
- (0x7FFFE, 0x7FFFF), (0x8FFFE, 0x8FFFF), (0x9FFFE, 0x9FFFF),
- (0xAFFFE, 0xAFFFF), (0xBFFFE, 0xBFFFF), (0xCFFFE, 0xCFFFF),
- (0xDFFFE, 0xDFFFF), (0xEFFFE, 0xEFFFF), (0xFFFFE, 0xFFFFF),
- (0x10FFFE, 0x10FFFF)]
+ '''
+ Removes any illegal unicode characters from the given XML string.
+
+ @see: http://stackoverflow.com/questions/1707890/fast-way-to-filter-illegal-xml-unicode-chars-in-python
+ '''
+
+ illegal_unichrs = [
+ (0x00, 0x08), (0x0B, 0x1F), (0x7F, 0x84), (0x86, 0x9F),
+ (0xD800, 0xDFFF), (0xFDD0, 0xFDDF), (0xFFFE, 0xFFFF),
+ (0x1FFFE, 0x1FFFF), (0x2FFFE, 0x2FFFF), (0x3FFFE, 0x3FFFF),
+ (0x4FFFE, 0x4FFFF), (0x5FFFE, 0x5FFFF), (0x6FFFE, 0x6FFFF),
+ (0x7FFFE, 0x7FFFF), (0x8FFFE, 0x8FFFF), (0x9FFFE, 0x9FFFF),
+ (0xAFFFE, 0xAFFFF), (0xBFFFE, 0xBFFFF), (0xCFFFE, 0xCFFFF),
+ (0xDFFFE, 0xDFFFF), (0xEFFFE, 0xEFFFF), (0xFFFFE, 0xFFFFF),
+ (0x10FFFE, 0x10FFFF)]
illegal_ranges = ["%s-%s" % (unichr(low), unichr(high))
for (low, high) in illegal_unichrs
@@ -202,7 +271,8 @@ class TestSuite(object):
class TestCase(object):
"""A JUnit test case with a result and possibly some stdout or stderr"""
- def __init__(self, name, classname=None, elapsed_sec=None, stdout=None, stderr=None):
+ def __init__(self, name, classname=None, elapsed_sec=None, stdout=None,
+ stderr=None):
self.name = name
self.elapsed_sec = elapsed_sec
self.stdout = stdout
diff --git a/setup.py b/setup.py
index d3c0ba6..6e7134f 100644
--- a/setup.py
+++ b/setup.py
@@ -2,20 +2,23 @@
from setuptools import setup, find_packages
import os
+
def read(fname):
- return open(os.path.join(os.path.dirname(__file__), fname)).read()
+ return open(os.path.join(os.path.dirname(__file__), fname)).read()
-setup(name='junit-xml',
- author='Brian Beyer',
- author_email='brian at kyr.us',
- url='https://github.com/kyrus/python-junit-xml',
- license='MIT',
- packages=find_packages(),
- test_suite="test_junit_xml",
- description='Creates JUnit XML test result documents that can be read by tools such as Jenkins',
- long_description=read('README.rst'),
- version = "1.4",
- classifiers=[
+setup(
+ name='junit-xml',
+ author='Brian Beyer',
+ author_email='brian at kyr.us',
+ url='https://github.com/kyrus/python-junit-xml',
+ license='MIT',
+ packages=find_packages(),
+ test_suite='test_junit_xml',
+ description='Creates JUnit XML test result documents that can be read by '
+ 'tools such as Jenkins',
+ long_description=read('README.rst'),
+ version='1.6',
+ classifiers=[
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'License :: Freely Distributable',
@@ -25,9 +28,8 @@ setup(name='junit-xml',
'Programming Language :: Python :: 3',
'Topic :: Software Development :: Build Tools',
'Topic :: Software Development :: Testing',
- ],
+ ],
install_requires=[
'six'
]
)
-
diff --git a/test_junit_xml.py b/test_junit_xml.py
new file mode 100644
index 0000000..d3c703e
--- /dev/null
+++ b/test_junit_xml.py
@@ -0,0 +1,478 @@
+# -*- coding: UTF-8 -*-
+from __future__ import with_statement
+import unittest
+import os
+import tempfile
+import textwrap
+from xml.dom import minidom
+import codecs
+
+from six import u, PY2
+
+from junit_xml import TestCase, TestSuite, decode
+
+
+def serialize_and_read(test_suites, to_file=False, prettyprint=False, encoding=None):
+ """writes the test suite to an XML string and then re-reads it using minidom,
+ returning => (test suite element, list of test case elements)"""
+ try:
+ iter(test_suites)
+ except TypeError:
+ test_suites = [test_suites]
+
+ if to_file:
+ fd, filename = tempfile.mkstemp(text=True)
+ os.close(fd)
+ with codecs.open(filename, mode='w', encoding=encoding) as f:
+ TestSuite.to_file(f, test_suites, prettyprint=prettyprint, encoding=encoding)
+ print("Serialized XML to temp file [%s]" % filename)
+ xmldoc = minidom.parse(filename)
+ os.remove(filename)
+ else:
+ xml_string = TestSuite.to_xml_string(
+ test_suites, prettyprint=prettyprint, encoding=encoding)
+ if PY2:
+ assert isinstance(xml_string, unicode)
+ print("Serialized XML to string:\n%s" % xml_string)
+ if encoding:
+ xml_string = xml_string.encode(encoding)
+ xmldoc = minidom.parseString(xml_string)
+
+ def remove_blanks(node):
+ for x in node.childNodes:
+ if x.nodeType == minidom.Node.TEXT_NODE:
+ if x.nodeValue:
+ x.nodeValue = x.nodeValue.strip()
+ elif x.nodeType == minidom.Node.ELEMENT_NODE:
+ remove_blanks(x)
+ remove_blanks(xmldoc)
+ xmldoc.normalize()
+
+ ret = []
+ suites = xmldoc.getElementsByTagName("testsuites")[0]
+ for suite in suites.getElementsByTagName("testsuite"):
+ cases = suite.getElementsByTagName("testcase")
+ ret.append((suite, cases))
+ return ret
+
+
+class TestSuiteTests(unittest.TestCase):
+ def test_single_suite_single_test_case(self):
+ try:
+ (ts, tcs) = serialize_and_read(
+ TestSuite('test', TestCase('Test1')), to_file=True)[0]
+ self.fail("This should've raised an exeception") # pragma: nocover
+ except Exception as exc:
+ self.assertEqual(
+ str(exc), 'test_cases must be a list of test cases')
+
+ def test_single_suite_no_test_cases(self):
+ properties = {'foo': 'bar'}
+ package = 'mypackage'
+ timestamp = 1398382805
+
+ (ts, tcs) = serialize_and_read(
+ TestSuite(
+ 'test',
+ [],
+ hostname='localhost',
+ id=1,
+ properties=properties,
+ package=package,
+ timestamp=timestamp
+ ),
+ to_file=True,
+ prettyprint=True
+ )[0]
+ self.assertEqual(ts.tagName, 'testsuite')
+ self.assertEqual(ts.attributes['package'].value, package)
+ self.assertEqual(ts.attributes['timestamp'].value, str(timestamp))
+ self.assertEqual(
+ ts.childNodes[0].childNodes[0].attributes['name'].value,
+ 'foo')
+ self.assertEqual(
+ ts.childNodes[0].childNodes[0].attributes['value'].value,
+ 'bar')
+
+ def test_single_suite_no_test_cases_utf8(self):
+ properties = {'foö': 'bär'}
+ package = 'mypäckage'
+ timestamp = 1398382805
+
+ test_suite = TestSuite(
+ 'äöü',
+ [],
+ hostname='löcalhost',
+ id='äöü',
+ properties=properties,
+ package=package,
+ timestamp=timestamp
+ )
+ (ts, tcs) = serialize_and_read(
+ test_suite,
+ to_file=True,
+ prettyprint=True,
+ encoding='utf-8'
+ )[0]
+ self.assertEqual(ts.tagName, 'testsuite')
+ self.assertEqual(ts.attributes['package'].value, decode(package, 'utf-8'))
+ self.assertEqual(ts.attributes['timestamp'].value, str(timestamp))
+ self.assertEqual(
+ ts.childNodes[0].childNodes[0].attributes['name'].value,
+ decode('foö', 'utf-8'))
+ self.assertEqual(
+ ts.childNodes[0].childNodes[0].attributes['value'].value,
+ decode('bär', 'utf-8'))
+
+ def test_single_suite_no_test_cases_unicode(self):
+ properties = {decode('foö', 'utf-8'): decode('bär', 'utf-8')}
+ package = decode('mypäckage', 'utf-8')
+ timestamp = 1398382805
+
+ (ts, tcs) = serialize_and_read(
+ TestSuite(
+ decode('äöü', 'utf-8'),
+ [],
+ hostname=decode('löcalhost', 'utf-8'),
+ id=decode('äöü', 'utf-8'),
+ properties=properties,
+ package=package,
+ timestamp=timestamp
+ ),
+ to_file=True,
+ prettyprint=True,
+ encoding='utf-8'
+ )[0]
+ self.assertEqual(ts.tagName, 'testsuite')
+ self.assertEqual(ts.attributes['package'].value, package)
+ self.assertEqual(ts.attributes['timestamp'].value, str(timestamp))
+ self.assertEqual(
+ ts.childNodes[0].childNodes[0].attributes['name'].value,
+ decode('foö', 'utf-8'))
+ self.assertEqual(
+ ts.childNodes[0].childNodes[0].attributes['value'].value,
+ decode('bär', 'utf-8'))
+
+ def test_single_suite_to_file(self):
+ (ts, tcs) = serialize_and_read(
+ TestSuite('test', [TestCase('Test1')]), to_file=True)[0]
+ verify_test_case(self, tcs[0], {'name': 'Test1'})
+
+ def test_single_suite_to_file_prettyprint(self):
+ (ts, tcs) = serialize_and_read(TestSuite(
+ 'test', [TestCase('Test1')]), to_file=True, prettyprint=True)[0]
+ verify_test_case(self, tcs[0], {'name': 'Test1'})
+
+ def test_single_suite_prettyprint(self):
+ (ts, tcs) = serialize_and_read(
+ TestSuite('test', [TestCase('Test1')]),
+ to_file=False, prettyprint=True)[0]
+ verify_test_case(self, tcs[0], {'name': 'Test1'})
+
+ def test_single_suite_to_file_no_prettyprint(self):
+ (ts, tcs) = serialize_and_read(
+ TestSuite('test', [TestCase('Test1')]),
+ to_file=True, prettyprint=False)[0]
+ verify_test_case(self, tcs[0], {'name': 'Test1'})
+
+ def test_multiple_suites_to_file(self):
+ tss = [TestSuite('suite1', [TestCase('Test1')]),
+ TestSuite('suite2', [TestCase('Test2')])]
+ suites = serialize_and_read(tss, to_file=True)
+
+ self.assertEqual('suite1', suites[0][0].attributes['name'].value)
+ verify_test_case(self, suites[0][1][0], {'name': 'Test1'})
+
+ self.assertEqual('suite2', suites[1][0].attributes['name'].value)
+ verify_test_case(self, suites[1][1][0], {'name': 'Test2'})
+
+ def test_multiple_suites_to_string(self):
+ tss = [TestSuite('suite1', [TestCase('Test1')]),
+ TestSuite('suite2', [TestCase('Test2')])]
+ suites = serialize_and_read(tss)
+
+ self.assertEqual('suite1', suites[0][0].attributes['name'].value)
+ verify_test_case(self, suites[0][1][0], {'name': 'Test1'})
+
+ self.assertEqual('suite2', suites[1][0].attributes['name'].value)
+ verify_test_case(self, suites[1][1][0], {'name': 'Test2'})
+
+ def test_attribute_time(self):
+ tss = [TestSuite('suite1',
+ [TestCase('Test1', 'some.class.name', 123.345),
+ TestCase('Test2', 'some2.class.name', 123.345)]),
+ TestSuite('suite2', [TestCase('Test2')])]
+ suites = serialize_and_read(tss)
+
+ self.assertEqual('suite1', suites[0][0].attributes['name'].value)
+ self.assertEqual('246.69', suites[0][0].attributes['time'].value)
+
+ self.assertEqual('suite2', suites[1][0].attributes['name'].value)
+ # here the time in testsuite is "0" even there is no attribute time for
+ # testcase
+ self.assertEqual('0', suites[1][0].attributes['time'].value)
+
+ # @todo: add more tests for the other attributes and properties
+
+ def test_to_xml_string(self):
+ test_suites = [TestSuite('suite1', [TestCase('Test1')]),
+ TestSuite('suite2', [TestCase('Test2')])]
+ xml_string = TestSuite.to_xml_string(test_suites)
+ if PY2:
+ self.assertTrue(isinstance(xml_string, unicode))
+ expected_xml_string = textwrap.dedent("""
+ <?xml version="1.0" ?>
+ <testsuites errors="0" failures="0" skipped="0" tests="2" time="0.0">
+ \t<testsuite errors="0" failures="0" name="suite1" skipped="0" tests="1" time="0">
+ \t\t<testcase name="Test1"/>
+ \t</testsuite>
+ \t<testsuite errors="0" failures="0" name="suite2" skipped="0" tests="1" time="0">
+ \t\t<testcase name="Test2"/>
+ \t</testsuite>
+ </testsuites>
+ """.strip("\n")) # NOQA
+ self.assertEqual(xml_string, expected_xml_string)
+
+ def test_to_xml_string_test_suites_not_a_list(self):
+ test_suites = TestSuite('suite1', [TestCase('Test1')])
+
+ try:
+ TestSuite.to_xml_string(test_suites)
+ except Exception as exc:
+ self.assertEqual(
+ str(exc), 'test_suites must be a list of test suites')
+
+
+class TestCaseTests(unittest.TestCase):
+ def test_init(self):
+ (ts, tcs) = serialize_and_read(
+ TestSuite('test', [TestCase('Test1')]))[0]
+ verify_test_case(self, tcs[0], {'name': 'Test1'})
+
+ def test_init_classname(self):
+ (ts, tcs) = serialize_and_read(
+ TestSuite('test', [TestCase('Test1', 'some.class.name')]))[0]
+ verify_test_case(
+ self, tcs[0], {'name': 'Test1', 'classname': 'some.class.name'})
+
+ def test_init_classname_time(self):
+ (ts, tcs) = serialize_and_read(
+ TestSuite('test',
+ [TestCase('Test1', 'some.class.name', 123.345)]))[0]
+ verify_test_case(
+ self, tcs[0], {'name': 'Test1', 'classname': 'some.class.name',
+ 'time': ("%f" % 123.345)})
+
+ def test_init_stderr(self):
+ (ts, tcs) = serialize_and_read(
+ TestSuite(
+ 'test', [TestCase('Test1', 'some.class.name', 123.345,
+ stderr='I am stderr!')]))[0]
+ verify_test_case(
+ self, tcs[0],
+ {'name': 'Test1', 'classname': 'some.class.name',
+ 'time': ("%f" % 123.345)}, stderr='I am stderr!')
+
+ def test_init_stdout_stderr(self):
+ (ts, tcs) = serialize_and_read(
+ TestSuite(
+ 'test', [TestCase(
+ 'Test1', 'some.class.name', 123.345, 'I am stdout!',
+ 'I am stderr!')]))[0]
+ verify_test_case(
+ self, tcs[0],
+ {'name': 'Test1', 'classname': 'some.class.name',
+ 'time': ("%f" % 123.345)},
+ stdout='I am stdout!', stderr='I am stderr!')
+
+ def test_init_failure_message(self):
+ tc = TestCase('Failure-Message')
+ tc.add_failure_info("failure message")
+ (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0]
+ verify_test_case(
+ self, tcs[0], {'name': 'Failure-Message'},
+ failure_message="failure message")
+
+ def test_init_failure_output(self):
+ tc = TestCase('Failure-Output')
+ tc.add_failure_info(output="I failed!")
+ (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0]
+ verify_test_case(
+ self, tcs[0], {'name': 'Failure-Output'},
+ failure_output="I failed!")
+
+ def test_init_failure(self):
+ tc = TestCase('Failure-Message-and-Output')
+ tc.add_failure_info("failure message", "I failed!")
+ (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0]
+ verify_test_case(
+ self, tcs[0], {'name': 'Failure-Message-and-Output'},
+ failure_message="failure message", failure_output="I failed!")
+
+ def test_init_error_message(self):
+ tc = TestCase('Error-Message')
+ tc.add_error_info("error message")
+ (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0]
+ verify_test_case(
+ self, tcs[0], {'name': 'Error-Message'},
+ error_message="error message")
+
+ def test_init_error_output(self):
+ tc = TestCase('Error-Output')
+ tc.add_error_info(output="I errored!")
+ (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0]
+ verify_test_case(
+ self, tcs[0], {'name': 'Error-Output'}, error_output="I errored!")
+
+ def test_init_error(self):
+ tc = TestCase('Error-Message-and-Output')
+ tc.add_error_info("error message", "I errored!")
+ (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0]
+ verify_test_case(
+ self, tcs[0], {'name': 'Error-Message-and-Output'},
+ error_message="error message", error_output="I errored!")
+
+ def test_init_skipped_message(self):
+ tc = TestCase('Skipped-Message')
+ tc.add_skipped_info("skipped message")
+ (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0]
+ verify_test_case(
+ self, tcs[0], {'name': 'Skipped-Message'},
+ skipped_message="skipped message")
+
+ def test_init_skipped_output(self):
+ tc = TestCase('Skipped-Output')
+ tc.add_skipped_info(output="I skipped!")
+ (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0]
+ verify_test_case(
+ self, tcs[0], {'name': 'Skipped-Output'},
+ skipped_output="I skipped!")
+
+ def test_init_skipped_err_output(self):
+ tc = TestCase('Skipped-Output')
+ tc.add_skipped_info(output="I skipped!")
+ tc.add_error_info(output="I skipped with an error!")
+ (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0]
+ verify_test_case(
+ self, tcs[0],
+ {'name': 'Skipped-Output'},
+ skipped_output="I skipped!",
+ error_output="I skipped with an error!")
+
+ def test_init_skipped(self):
+ tc = TestCase('Skipped-Message-and-Output')
+ tc.add_skipped_info("skipped message", "I skipped!")
+ (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0]
+ verify_test_case(
+ self, tcs[0], {'name': 'Skipped-Message-and-Output'},
+ skipped_message="skipped message", skipped_output="I skipped!")
+
+ def test_init_legal_unicode_char(self):
+ tc = TestCase('Failure-Message')
+ tc.add_failure_info(
+ u("failure message with legal unicode char: [\x22]"))
+ (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0]
+ verify_test_case(
+ self, tcs[0], {'name': 'Failure-Message'}, failure_message=u(
+ "failure message with legal unicode char: [\x22]"))
+
+ def test_init_illegal_unicode_char(self):
+ tc = TestCase('Failure-Message')
+ tc.add_failure_info(
+ u("failure message with illegal unicode char: [\x02]"))
+ (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0]
+ verify_test_case(
+ self, tcs[0], {'name': 'Failure-Message'}, failure_message=u(
+ "failure message with illegal unicode char: []"))
+
+ def test_init_utf8(self):
+ tc = TestCase('Test äöü', 'some.class.name.äöü', 123.345, 'I am stdöüt!', 'I am stdärr!')
+ tc.add_skipped_info(message='Skipped äöü', output="I skippäd!")
+ tc.add_error_info(message='Skipped error äöü', output="I skippäd with an error!")
+ test_suite = TestSuite('Test UTF-8', [tc])
+ (ts, tcs) = serialize_and_read(test_suite, encoding='utf-8')[0]
+ verify_test_case(self, tcs[0], {'name': decode('Test äöü', 'utf-8'),
+ 'classname': decode('some.class.name.äöü', 'utf-8'),
+ 'time': ("%f" % 123.345)},
+ stdout=decode('I am stdöüt!', 'utf-8'), stderr=decode('I am stdärr!', 'utf-8'),
+ skipped_message=decode('Skipped äöü', 'utf-8'),
+ skipped_output=decode('I skippäd!', 'utf-8'),
+ error_message=decode('Skipped error äöü', 'utf-8'),
+ error_output=decode('I skippäd with an error!', 'utf-8'))
+
+ def test_init_unicode(self):
+ tc = TestCase(decode('Test äöü', 'utf-8'), decode('some.class.name.äöü', 'utf-8'), 123.345,
+ decode('I am stdöüt!', 'utf-8'), decode('I am stdärr!', 'utf-8'))
+ tc.add_skipped_info(message=decode('Skipped äöü', 'utf-8'),
+ output=decode('I skippäd!', 'utf-8'))
+ tc.add_error_info(message=decode('Skipped error äöü', 'utf-8'),
+ output=decode('I skippäd with an error!', 'utf-8'))
+
+ (ts, tcs) = serialize_and_read(TestSuite('Test Unicode',
+ [tc]))[0]
+ verify_test_case(self, tcs[0], {'name': decode('Test äöü', 'utf-8'),
+ 'classname': decode('some.class.name.äöü', 'utf-8'),
+ 'time': ("%f" % 123.345)},
+ stdout=decode('I am stdöüt!', 'utf-8'), stderr=decode('I am stdärr!', 'utf-8'),
+ skipped_message=decode('Skipped äöü', 'utf-8'),
+ skipped_output=decode('I skippäd!', 'utf-8'),
+ error_message=decode('Skipped error äöü', 'utf-8'),
+ error_output=decode('I skippäd with an error!', 'utf-8'))
+
+
+def verify_test_case(tc, test_case_element, expected_attributes,
+ error_message=None, error_output=None,
+ failure_message=None, failure_output=None,
+ skipped_message=None, skipped_output=None,
+ stdout=None, stderr=None):
+ for k, v in expected_attributes.items():
+ tc.assertEqual(v, test_case_element.attributes[k].value)
+
+ for k in test_case_element.attributes.keys():
+ tc.assertTrue(k in expected_attributes.keys())
+
+ if stderr:
+ tc.assertEqual(
+ stderr, test_case_element.getElementsByTagName(
+ 'system-err')[0].firstChild.nodeValue.strip())
+ if stdout:
+ tc.assertEqual(
+ stdout, test_case_element.getElementsByTagName(
+ 'system-out')[0].firstChild.nodeValue.strip())
+
+ errors = test_case_element.getElementsByTagName('error')
+ if error_message or error_output:
+ tc.assertTrue(len(errors) > 0)
+ else:
+ tc.assertEqual(0, len(errors))
+
+ if error_message:
+ tc.assertEqual(
+ error_message, errors[0].attributes['message'].value)
+
+ if error_output:
+ tc.assertEqual(
+ error_output, errors[0].firstChild.nodeValue.strip())
+
+ failures = test_case_element.getElementsByTagName('failure')
+ if failure_message or failure_output:
+ tc.assertTrue(len(failures) > 0)
+ else:
+ tc.assertEqual(0, len(failures))
+
+ if failure_message:
+ tc.assertEqual(
+ failure_message, failures[0].attributes['message'].value)
+
+ if failure_output:
+ tc.assertEqual(
+ failure_output, failures[0].firstChild.nodeValue.strip())
+
+ skipped = test_case_element.getElementsByTagName('skipped')
+ if skipped_message or skipped_output:
+ tc.assertTrue(len(skipped) > 0)
+ else:
+ tc.assertEqual(0, len(skipped))
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..4ccdde0
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,38 @@
+[tox]
+envlist = py26, py27, pypy, py32, py33, py34, cover, flake8
+sitepackages = False
+
+[testenv]
+deps =
+ pytest
+ pytest-sugar
+ six
+commands =
+ py.test \
+ --junitxml={envlogdir}/junit-{envname}.xml \
+ {posargs}
+
+[testenv:cover]
+deps =
+ pytest
+ pytest-sugar
+ pytest-cov
+ six
+commands =
+ py.test \
+ --cov=junit_xml \
+ --cov-report=term-missing \
+ --cov-report=xml \
+ --cov-report=html \
+ {posargs}
+
+[testenv:flake8]
+deps =
+ pytest
+ pytest-sugar
+ pytest-flake8
+ six
+commands =
+ py.test \
+ --flake8 \
+ {posargs}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-junit-xml.git
More information about the Python-modules-commits
mailing list