junit-xml-1.8/0000755000076500000240000000000013151421437013020 5ustar bbstaff00000000000000junit-xml-1.8/junit_xml/0000755000076500000240000000000013151421437015031 5ustar bbstaff00000000000000junit-xml-1.8/junit_xml/__init__.py0000644000076500000240000003536113110601464017145 0ustar bbstaff00000000000000#!/usr/bin/env python # -*- 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, iteritems, PY2 try: # Python 2 unichr except NameError: # pragma: nocover # Python 3 unichr = chr """ Based on the understanding of what Jenkins can parse for JUnit XML files. the output of the testcase the output of the testcase the output of the testcase I am system output I am the error output """ 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. Can handle unicode strings or binary strings if their encoding is provided. """ def __init__(self, name, test_cases=None, hostname=None, id=None, package=None, timestamp=None, properties=None, file=None, log=None, url=None, stdout=None, stderr=None): self.name = name if not test_cases: test_cases = [] try: iter(test_cases) except TypeError: raise Exception('test_cases must be a list of test cases') self.test_cases = test_cases self.timestamp = timestamp self.hostname = hostname self.id = id self.package = package self.file = file self.log = log self.url = url self.stdout = stdout self.stderr = stderr self.properties = properties 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'] = decode(self.name, encoding) if any(c.assertions for c in self.test_cases): test_suite_attributes['assertions'] = \ str(sum([int(c.assertions) for c in self.test_cases if c.assertions])) test_suite_attributes['disabled'] = \ str(len([c for c in self.test_cases if not c.is_enabled])) 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'] = decode(self.hostname, encoding) if self.id: test_suite_attributes['id'] = decode(self.id, encoding) if self.package: test_suite_attributes['package'] = decode(self.package, encoding) if self.timestamp: test_suite_attributes['timestamp'] = decode(self.timestamp, encoding) if self.timestamp: test_suite_attributes['file'] = decode(self.file, encoding) if self.timestamp: test_suite_attributes['log'] = decode(self.log, encoding) if self.timestamp: test_suite_attributes['url'] = decode(self.url, encoding) xml_element = ET.Element("testsuite", test_suite_attributes) # add any properties if self.properties: props_element = ET.SubElement(xml_element, "properties") for k, v in self.properties.items(): attrs = {'name': decode(k, encoding), 'value': decode(v, encoding)} ET.SubElement(props_element, "property", attrs) # add test suite stdout if self.stdout: stdout_element = ET.SubElement(xml_element, "system-out") stdout_element.text = decode(self.stdout, encoding) # add test suite stderr if self.stderr: stderr_element = ET.SubElement(xml_element, "system-err") stderr_element.text = decode(self.stderr, encoding) # test cases for case in self.test_cases: test_case_attributes = dict() test_case_attributes['name'] = decode(case.name, encoding) if case.assertions: # Number of assertions in the test case test_case_attributes['assertions'] = "%d" % case.assertions if case.elapsed_sec: test_case_attributes['time'] = "%f" % case.elapsed_sec if case.timestamp: test_case_attributes['timestamp'] = decode(case.timestamp, encoding) if case.classname: test_case_attributes['classname'] = decode(case.classname, encoding) if case.status: test_case_attributes['status'] = decode(case.status, encoding) if case.category: test_case_attributes['class'] = decode(case.category, encoding) if case.file: test_case_attributes['file'] = decode(case.file, encoding) if case.line: test_case_attributes['line'] = decode(case.line, encoding) if case.log: test_case_attributes['log'] = decode(case.log, encoding) if case.url: test_case_attributes['url'] = decode(case.url, encoding) 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'] = decode(case.failure_message, encoding) if case.failure_type: attrs['type'] = decode(case.failure_type, encoding) failure_element = ET.Element("failure", attrs) if 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'] = decode(case.error_message, encoding) if case.error_type: attrs['type'] = decode(case.error_type, encoding) error_element = ET.Element("error", attrs) if 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'] = decode(case.skipped_message, encoding) skipped_element = ET.Element("skipped", attrs) 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 = decode(case.stdout, encoding) test_case_element.append(stdout_element) # test stderr if case.stderr: stderr_element = ET.Element("system-err") 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. @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: ts_xml = ts.build_xml_doc(encoding=encoding) for key in ['failures', 'errors', 'tests', 'disabled']: 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) # is encoded now xml_string = TestSuite._clean_illegal_xml_chars( xml_string.decode(encoding or 'utf-8')) # is unicode now if prettyprint: # 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 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)] illegal_ranges = ["%s-%s" % (unichr(low), unichr(high)) for (low, high) in illegal_unichrs if low < sys.maxunicode] illegal_xml_re = re.compile(u('[%s]') % u('').join(illegal_ranges)) return illegal_xml_re.sub('', string_to_clean) 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, assertions=None, timestamp=None, status=None, category=None, file=None, line=None, log=None, group=None, url=None): self.name = name self.assertions = assertions self.elapsed_sec = elapsed_sec self.timestamp = timestamp self.classname = classname self.status = status self.category = category self.file = file self.line = line self.log = log self.url = url self.stdout = stdout self.stderr = stderr self.is_enabled = True self.error_message = None self.error_output = None self.error_type = None self.failure_message = None self.failure_output = None self.failure_type = None self.skipped_message = None self.skipped_output = None def add_error_info(self, message=None, output=None, error_type=None): """Adds an error message, output, or both to the test case""" if message: self.error_message = message if output: self.error_output = output if error_type: self.error_type = error_type def add_failure_info(self, message=None, output=None, failure_type=None): """Adds a failure message, output, or both to the test case""" if message: self.failure_message = message if output: self.failure_output = output if failure_type: self.failure_type = failure_type def add_skipped_info(self, message=None, output=None): """Adds a skipped message, output, or both to the test case""" if message: self.skipped_message = message if output: self.skipped_output = output def is_failure(self): """returns true if this test case is a failure""" return self.failure_output or self.failure_message def is_error(self): """returns true if this test case is an error""" return self.error_output or self.error_message def is_skipped(self): """returns true if this test case has been skipped""" return self.skipped_output or self.skipped_message junit-xml-1.8/junit_xml.egg-info/0000755000076500000240000000000013151421437016523 5ustar bbstaff00000000000000junit-xml-1.8/junit_xml.egg-info/dependency_links.txt0000644000076500000240000000000113151421437022571 0ustar bbstaff00000000000000 junit-xml-1.8/junit_xml.egg-info/PKG-INFO0000644000076500000240000000737213151421437017631 0ustar bbstaff00000000000000Metadata-Version: 1.1 Name: junit-xml Version: 1.8 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 Author-email: brian@kyr.us License: MIT Description: python-junit-xml ================ .. image:: https://travis-ci.org/kyrus/python-junit-xml.png?branch=master About ----- A Python module for creating JUnit XML test result documents that can be read by tools such as Jenkins. If you are ever working with test tool or test suite written in Python and want to take advantage of Jenkins' pretty graphs and test reporting capabilities, this module will let you generate the XML test reports. *As there is no definitive Jenkins JUnit XSD that I could find, the XML documents created by this module support a schema based on Google searches and the Jenkins JUnit XML reader source code. File a bug if something doesn't work like you expect it to.* Installation ------------ Install using pip or easy_install: :: pip install junit-xml or easy_install junit-xml You can also clone the Git repository from Github and install it manually: :: git clone https://github.com/kyrus/python-junit-xml.git python setup.py install Using ----- Create a test suite, add a test case, and print it to the screen: .. code-block:: python from junit_xml import TestSuite, TestCase test_cases = [TestCase('Test1', 'some.class.name', 123.345, 'I am stdout!', 'I am stderr!')] ts = TestSuite("my test suite", test_cases) # pretty printing is on by default but can be disabled using prettyprint=False print(TestSuite.to_xml_string([ts])) Produces the following output .. code-block:: xml I am stdout! I am stderr! Writing XML to a file: .. code-block:: python # you can also write the XML to a file and not pretty print it with open('output.xml', 'w') as f: TestSuite.to_file(f, [ts], prettyprint=False) See the docs and unit tests for more examples. NOTE: Unicode characters identified as "illegal or discouraged" are automatically stripped from the XML string or file. Running the tests ----------------- :: # activate your virtualenv pip install tox tox Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: Freely Distributable Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development :: Build Tools Classifier: Topic :: Software Development :: Testing junit-xml-1.8/junit_xml.egg-info/requires.txt0000644000076500000240000000000413151421437021115 0ustar bbstaff00000000000000six junit-xml-1.8/junit_xml.egg-info/SOURCES.txt0000644000076500000240000000037713151421437020416 0ustar bbstaff00000000000000LICENSE.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 junit_xml.egg-info/dependency_links.txt junit_xml.egg-info/requires.txt junit_xml.egg-info/top_level.txtjunit-xml-1.8/junit_xml.egg-info/top_level.txt0000644000076500000240000000001213151421437021246 0ustar bbstaff00000000000000junit_xml junit-xml-1.8/LICENSE.txt0000644000076500000240000000210112771244233014641 0ustar bbstaff00000000000000The MIT License Copyright (c) 2013 Kyrus Tech, Inc., Brian Beyer Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.junit-xml-1.8/MANIFEST.in0000644000076500000240000000014212771244233014557 0ustar bbstaff00000000000000include LICENSE.txt include README.rst include setup.py include test_junit_xml.py include tox.ini junit-xml-1.8/PKG-INFO0000644000076500000240000000737213151421437014126 0ustar bbstaff00000000000000Metadata-Version: 1.1 Name: junit-xml Version: 1.8 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 Author-email: brian@kyr.us License: MIT Description: python-junit-xml ================ .. image:: https://travis-ci.org/kyrus/python-junit-xml.png?branch=master About ----- A Python module for creating JUnit XML test result documents that can be read by tools such as Jenkins. If you are ever working with test tool or test suite written in Python and want to take advantage of Jenkins' pretty graphs and test reporting capabilities, this module will let you generate the XML test reports. *As there is no definitive Jenkins JUnit XSD that I could find, the XML documents created by this module support a schema based on Google searches and the Jenkins JUnit XML reader source code. File a bug if something doesn't work like you expect it to.* Installation ------------ Install using pip or easy_install: :: pip install junit-xml or easy_install junit-xml You can also clone the Git repository from Github and install it manually: :: git clone https://github.com/kyrus/python-junit-xml.git python setup.py install Using ----- Create a test suite, add a test case, and print it to the screen: .. code-block:: python from junit_xml import TestSuite, TestCase test_cases = [TestCase('Test1', 'some.class.name', 123.345, 'I am stdout!', 'I am stderr!')] ts = TestSuite("my test suite", test_cases) # pretty printing is on by default but can be disabled using prettyprint=False print(TestSuite.to_xml_string([ts])) Produces the following output .. code-block:: xml I am stdout! I am stderr! Writing XML to a file: .. code-block:: python # you can also write the XML to a file and not pretty print it with open('output.xml', 'w') as f: TestSuite.to_file(f, [ts], prettyprint=False) See the docs and unit tests for more examples. NOTE: Unicode characters identified as "illegal or discouraged" are automatically stripped from the XML string or file. Running the tests ----------------- :: # activate your virtualenv pip install tox tox Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: Freely Distributable Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development :: Build Tools Classifier: Topic :: Software Development :: Testing junit-xml-1.8/README.rst0000644000076500000240000000452012771244233014514 0ustar bbstaff00000000000000python-junit-xml ================ .. image:: https://travis-ci.org/kyrus/python-junit-xml.png?branch=master About ----- A Python module for creating JUnit XML test result documents that can be read by tools such as Jenkins. If you are ever working with test tool or test suite written in Python and want to take advantage of Jenkins' pretty graphs and test reporting capabilities, this module will let you generate the XML test reports. *As there is no definitive Jenkins JUnit XSD that I could find, the XML documents created by this module support a schema based on Google searches and the Jenkins JUnit XML reader source code. File a bug if something doesn't work like you expect it to.* Installation ------------ Install using pip or easy_install: :: pip install junit-xml or easy_install junit-xml You can also clone the Git repository from Github and install it manually: :: git clone https://github.com/kyrus/python-junit-xml.git python setup.py install Using ----- Create a test suite, add a test case, and print it to the screen: .. code-block:: python from junit_xml import TestSuite, TestCase test_cases = [TestCase('Test1', 'some.class.name', 123.345, 'I am stdout!', 'I am stderr!')] ts = TestSuite("my test suite", test_cases) # pretty printing is on by default but can be disabled using prettyprint=False print(TestSuite.to_xml_string([ts])) Produces the following output .. code-block:: xml I am stdout! I am stderr! Writing XML to a file: .. code-block:: python # you can also write the XML to a file and not pretty print it with open('output.xml', 'w') as f: TestSuite.to_file(f, [ts], prettyprint=False) See the docs and unit tests for more examples. NOTE: Unicode characters identified as "illegal or discouraged" are automatically stripped from the XML string or file. Running the tests ----------------- :: # activate your virtualenv pip install tox tox junit-xml-1.8/setup.cfg0000644000076500000240000000004613151421437014641 0ustar bbstaff00000000000000[egg_info] tag_build = tag_date = 0 junit-xml-1.8/setup.py0000644000076500000240000000207613151421415014533 0ustar bbstaff00000000000000#!/usr/bin/env python from setuptools import setup, find_packages import os def read(fname): return open(os.path.join(os.path.dirname(__file__), fname)).read() setup( name='junit-xml', author='Brian Beyer', author_email='brian@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.8', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: Freely Distributable', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Topic :: Software Development :: Build Tools', 'Topic :: Software Development :: Testing', ], install_requires=[ 'six' ] ) junit-xml-1.8/test_junit_xml.py0000644000076500000240000005740713110601464016452 0ustar bbstaff00000000000000# -*- 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( name='test', test_cases=[], 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( name='äöü', test_cases=[], 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( name=decode('äöü', 'utf-8'), test_cases=[], 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(name='Test1', classname='some.class.name', elapsed_sec=123.345), TestCase(name='Test2', classname='some2.class.name', elapsed_sec=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) def test_attribute_disable(self): tc = TestCase('Disabled-Test') tc.is_enabled = False tss = [TestSuite('suite1', [tc])] suites = serialize_and_read(tss) self.assertEqual('1', suites[0][0].attributes['disabled'].value) def test_stderr(self): suites = serialize_and_read( TestSuite(name='test', stderr='I am stderr!', test_cases=[TestCase(name='Test1')]))[0] self.assertEqual('I am stderr!', suites[0].getElementsByTagName('system-err')[0].firstChild.data) def test_stdout_stderr(self): suites = serialize_and_read( TestSuite(name='test', stdout='I am stdout!', stderr='I am stderr!', test_cases=[TestCase(name='Test1')]))[0] self.assertEqual('I am stderr!', suites[0].getElementsByTagName('system-err')[0].firstChild.data) self.assertEqual('I am stdout!', suites[0].getElementsByTagName('system-out')[0].firstChild.data) def test_no_assertions(self): suites = serialize_and_read( TestSuite(name='test', test_cases=[TestCase(name='Test1')]))[0] self.assertFalse(suites[0].getElementsByTagName('testcase')[0].hasAttribute('assertions')) def test_assertions(self): suites = serialize_and_read( TestSuite(name='test', test_cases=[TestCase(name='Test1', assertions=5)]))[0] self.assertEquals('5', suites[0].getElementsByTagName('testcase')[0].attributes['assertions'].value) # @todo: add more tests for the other attributes and properties def test_to_xml_string(self): test_suites = [TestSuite(name='suite1', test_cases=[TestCase(name='Test1')]), TestSuite(name='suite2', test_cases=[TestCase(name='Test2')])] xml_string = TestSuite.to_xml_string(test_suites) if PY2: self.assertTrue(isinstance(xml_string, unicode)) expected_xml_string = textwrap.dedent(""" \t \t\t \t \t \t\t \t """.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(name='Test1', classname='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(name='Test1', classname='some.class.name', elapsed_sec=123.345)]))[0] verify_test_case( self, tcs[0], {'name': 'Test1', 'classname': 'some.class.name', 'time': ("%f" % 123.345)}) def test_init_classname_time_timestamp(self): (ts, tcs) = serialize_and_read( TestSuite('test', [TestCase(name='Test1', classname='some.class.name', elapsed_sec=123.345, timestamp=99999)]))[0] verify_test_case( self, tcs[0], {'name': 'Test1', 'classname': 'some.class.name', 'time': ("%f" % 123.345), 'timestamp': ("%s" % 99999)}) def test_init_stderr(self): (ts, tcs) = serialize_and_read( TestSuite( 'test', [TestCase(name='Test1', classname='some.class.name', elapsed_sec=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( name='Test1', classname='some.class.name', elapsed_sec=123.345, stdout='I am stdout!', stderr='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_disable(self): tc = TestCase('Disabled-Test') tc.is_enabled = False (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0] verify_test_case(self, tcs[0], {'name': 'Disabled-Test'}) 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_type(self): tc = TestCase('Failure-Type') tc.add_failure_info(failure_type='com.example.Error') (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0] verify_test_case(self, tcs[0], {'name': 'Failure-Type'}) tc.add_failure_info("failure message") (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0] verify_test_case( self, tcs[0], {'name': 'Failure-Type'}, failure_message="failure message", failure_type='com.example.Error') 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!", failure_type='failure') 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_type(self): tc = TestCase('Error-Type') tc.add_error_info(error_type='com.example.Error') (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0] verify_test_case(self, tcs[0], {'name': 'Error-Type'}) tc.add_error_info("error message") (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0] verify_test_case( self, tcs[0], {'name': 'Error-Type'}, error_message="error message", error_type='com.example.Error') 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!", error_type="error") 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(name='Test äöü', classname='some.class.name.äöü', elapsed_sec=123.345, stdout='I am stdöüt!', stderr='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(name=decode('Test äöü', 'utf-8'), classname=decode('some.class.name.äöü', 'utf-8'), elapsed_sec=123.345, stdout=decode('I am stdöüt!', 'utf-8'), stderr=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, error_type=None, failure_message=None, failure_output=None, failure_type=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_type and errors: tc.assertEqual( error_type, errors[0].attributes['type'].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_type and failures: tc.assertEqual( failure_type, failures[0].attributes['type'].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() junit-xml-1.8/tox.ini0000644000076500000240000000114512771244233014340 0ustar bbstaff00000000000000[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}