[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