diff --git a/.gitignore b/.gitignore
index 3a5c919..f783efa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,41 +1,11 @@
-*.py[cod]
-
-# C extensions
-*.so
-
-# Packages
-*.egg
-*.egg-info
-dist
-build
-eggs
-parts
-bin
-var
-venv
-sdist
-develop-eggs
-.installed.cfg
-lib
-lib64
-
-# Installer logs
-pip-log.txt
-
-# Unit test / coverage reports
+.idea/
+__pycache__/
+.cache/
+**/*.user
.coverage
-.tox
-nosetests.xml
-coverage.xml
+venv/
+*egg-info/*
+htmlcov/
htmlcov/
-
-# Translations
-*.mo
-
-# Mr Developer
-.mr.developer.cfg
-.project
-.pydevproject
-
-# Pycharm
-.idea/**
+dist
+reports/
diff --git a/Makefile b/Makefile
deleted file mode 100644
index 121ce12..0000000
--- a/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-ACTIVATE=venv/bin/activate
-
-venv: $(ACTIVATE)
-$(ACTIVATE): requirements.txt requirements_dev.txt
- test -d venv || virtualenv venv
- . $(ACTIVATE); pip install -r requirements_dev.txt
-
-.PHONY : dist
-dist:
- python setup.py sdist bdist_wheel
-
-.PHONY : clean
-clean:
- find . -name "*.pyc" -delete
- find . -name "__pycache__" -delete
- rm -rf build
- rm -rf dist
diff --git a/junit_xml/__init__.py b/junit_xml/__init__.py
index 0cfef29..a92cfc9 100644
--- a/junit_xml/__init__.py
+++ b/junit_xml/__init__.py
@@ -1,22 +1,4 @@
-#!/usr/bin/env python
-# -*- coding: UTF-8 -*-
-import warnings
-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
-
-"""
+"""junit xml module
Based on the understanding of what Jenkins can parse for JUnit XML files.
@@ -54,258 +36,36 @@
"""
+import sys
+import re
+from typing import List
+from xml.etree import ElementTree
+import xml.dom.minidom
-def decode(var, encoding):
- """
- If not already unicode, decode it.
- """
- if PY2:
- if isinstance(var, unicode): # noqa: F821
- ret = var
- elif isinstance(var, str):
- if encoding:
- ret = var.decode(encoding)
- else:
- ret = unicode(var) # noqa: F821
- else:
- ret = unicode(var) # noqa: F821
- 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 TypeError("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()
- 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["errors"] = str(len([c for c in self.test_cases if c.is_error()]))
- test_suite_attributes["failures"] = str(len([c for c in self.test_cases if c.is_failure()]))
- test_suite_attributes["name"] = decode(self.name, encoding)
- test_suite_attributes["skipped"] = str(len([c for c in self.test_cases if c.is_skipped()]))
- test_suite_attributes["tests"] = str(len(self.test_cases))
- test_suite_attributes["time"] = str(sum(c.elapsed_sec for c in self.test_cases if c.elapsed_sec))
-
- 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.file:
- test_suite_attributes["file"] = decode(self.file, encoding)
- if self.log:
- test_suite_attributes["log"] = decode(self.log, encoding)
- if self.url:
- 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
- for failure in case.failures:
- if failure["output"] or failure["message"]:
- attrs = {"type": "failure"}
- if failure["message"]:
- attrs["message"] = decode(failure["message"], encoding)
- if failure["type"]:
- attrs["type"] = decode(failure["type"], encoding)
- failure_element = ET.Element("failure", attrs)
- if failure["output"]:
- failure_element.text = decode(failure["output"], encoding)
- test_case_element.append(failure_element)
-
- # errors
- for error in case.errors:
- if error["message"] or error["output"]:
- attrs = {"type": "error"}
- if error["message"]:
- attrs["message"] = decode(error["message"], encoding)
- if error["type"]:
- attrs["type"] = decode(error["type"], encoding)
- error_element = ET.Element("error", attrs)
- if error["output"]:
- error_element.text = decode(error["output"], encoding)
- test_case_element.append(error_element)
-
- # skippeds
- for skipped in case.skipped:
- attrs = {"type": "skipped"}
- if skipped["message"]:
- attrs["message"] = decode(skipped["message"], encoding)
- skipped_element = ET.Element("skipped", attrs)
- if skipped["output"]:
- skipped_element.text = decode(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
- """
- warnings.warn(
- "Testsuite.to_xml_string is deprecated. It will be removed in version 2.0.0. "
- "Use function to_xml_report_string",
- DeprecationWarning,
- )
- return to_xml_report_string(test_suites, prettyprint, encoding)
-
- @staticmethod
- def to_file(file_descriptor, test_suites, prettyprint=True, encoding=None):
- """
- Writes the JUnit XML document to a file.
- """
- warnings.warn(
- "Testsuite.to_file is deprecated. It will be removed in version 2.0.0. Use function to_xml_report_file",
- DeprecationWarning,
- )
- to_xml_report_file(file_descriptor, test_suites, prettyprint, encoding)
+from junit_xml.root_element import TestSuite, build_xml_root
-def to_xml_report_string(test_suites, prettyprint=True, encoding=None):
+def to_xml_report_string(test_suites: List[TestSuite], prettyprint=True, encoding=None):
"""
Returns the string representation of the JUnit XML document.
+ @param test_suites: input for xml string generation
+ @param prettyprint: flag to request formatted output, default=True
@param encoding: The encoding of the input.
- @return: unicode string
+ @return: xml unicode string
"""
+ xml_element = build_xml_root(test_suites)
- try:
- iter(test_suites)
- except TypeError:
- raise TypeError("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 ["disabled", "errors", "failures", "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 = ElementTree.tostring(xml_element, encoding=encoding)
# is encoded now
- xml_string = _clean_illegal_xml_chars(xml_string.decode(encoding or "utf-8"))
+ xml_string = 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
+ # 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)
@@ -313,20 +73,12 @@ def to_xml_report_string(test_suites, prettyprint=True, encoding=None):
return xml_string
-def to_xml_report_file(file_descriptor, test_suites, prettyprint=True, encoding=None):
- """
- Writes the JUnit XML document to a file.
- """
- xml_string = to_xml_report_string(test_suites, prettyprint=prettyprint, encoding=encoding)
- # has problems with encoded str with non-ASCII (non-default-encoding) characters!
- file_descriptor.write(xml_string)
-
-
-def _clean_illegal_xml_chars(string_to_clean):
+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
+ @see: http://stackoverflow.com/questions/1707890/
+ fast-way-to-filter-illegal-xml-unicode-chars-in-python
"""
illegal_unichrs = [
@@ -355,114 +107,10 @@ def _clean_illegal_xml_chars(string_to_clean):
(0x10FFFE, 0x10FFFF),
]
- illegal_ranges = ["%s-%s" % (unichr(low), unichr(high)) for (low, high) in illegal_unichrs if low < sys.maxunicode]
+ illegal_ranges = [
+ f"{chr(low)}-{chr(high)}" for (low, high) in illegal_unichrs if low < sys.maxunicode
+ ]
- illegal_xml_re = re.compile(u("[%s]") % u("").join(illegal_ranges))
+ joined = "".join(illegal_ranges)
+ illegal_xml_re = re.compile(f"[{joined}]")
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,
- url=None,
- allow_multiple_subelements=False,
- ):
- 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.errors = []
- self.failures = []
- self.skipped = []
- self.allow_multiple_subalements = allow_multiple_subelements
-
- def add_error_info(self, message=None, output=None, error_type=None):
- """Adds an error message, output, or both to the test case"""
- error = {}
- error["message"] = message
- error["output"] = output
- error["type"] = error_type
- if self.allow_multiple_subalements:
- if message or output:
- self.errors.append(error)
- elif not len(self.errors):
- self.errors.append(error)
- else:
- if message:
- self.errors[0]["message"] = message
- if output:
- self.errors[0]["output"] = output
- if error_type:
- self.errors[0]["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"""
- failure = {}
- failure["message"] = message
- failure["output"] = output
- failure["type"] = failure_type
- if self.allow_multiple_subalements:
- if message or output:
- self.failures.append(failure)
- elif not len(self.failures):
- self.failures.append(failure)
- else:
- if message:
- self.failures[0]["message"] = message
- if output:
- self.failures[0]["output"] = output
- if failure_type:
- self.failures[0]["type"] = failure_type
-
- def add_skipped_info(self, message=None, output=None):
- """Adds a skipped message, output, or both to the test case"""
- skipped = {}
- skipped["message"] = message
- skipped["output"] = output
- if self.allow_multiple_subalements:
- if message or output:
- self.skipped.append(skipped)
- elif not len(self.skipped):
- self.skipped.append(skipped)
- else:
- if message:
- self.skipped[0]["message"] = message
- if output:
- self.skipped[0]["output"] = output
-
- def is_failure(self):
- """returns true if this test case is a failure"""
- return sum(1 for f in self.failures if f["message"] or f["output"]) > 0
-
- def is_error(self):
- """returns true if this test case is an error"""
- return sum(1 for e in self.errors if e["message"] or e["output"]) > 0
-
- def is_skipped(self):
- """returns true if this test case has been skipped"""
- return len(self.skipped) > 0
diff --git a/pyproject.toml b/pyproject.toml
index 55ec8d7..833f042 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,2 +1,9 @@
+[build-system]
+requires = [
+ "setuptools>=42",
+ "wheel"
+]
+build-backend = "setuptools.build_meta"
+
[tool.black]
-line-length = 120
+line-length = 100
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index ffe2fce..8ce6ae1 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1 +1,7 @@
-six
+pylint==2.13.8
+pytest~=7.1.2
+flake8-black
+pytest-sugar==0.9.4
+pytest-cov==3.0.0
+pytest-flake8
+icecream==2.1.2
diff --git a/requirements_dev.txt b/requirements_dev.txt
deleted file mode 100644
index 69269df..0000000
--- a/requirements_dev.txt
+++ /dev/null
@@ -1,4 +0,0 @@
--r requirements.txt
-flake8-black
-pytest-sugar
-pytest-flake8
diff --git a/setup.cfg b/setup.cfg
index 3fcc1e7..f3b3562 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,3 @@
[flake8]
max-line-length = 120
-exclude = .git,.tox,build,dist,venv
-
-[wheel]
-universal = 1
+exclude = .git,.tox,build,dist,venv
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 8aba068..ce6b93d 100644
--- a/setup.py
+++ b/setup.py
@@ -1,7 +1,7 @@
-#!/usr/bin/env python
-from setuptools import setup, find_packages
import os
+from setuptools import setup, find_packages
+
def read(fname):
return open(os.path.join(os.path.dirname(__file__), fname)).read()
@@ -9,14 +9,14 @@ def read(fname):
setup(
name="junit-xml",
- author="Brian Beyer",
- author_email="brian@kyr.us",
- url="https://github.com/kyrus/python-junit-xml",
+ author="Tikani",
+ author_email="",
+ url="https://github.com/gitiJumi/python-junit-xml",
license="MIT",
packages=find_packages(exclude=["tests"]),
description="Creates JUnit XML test result documents that can be read by tools such as Jenkins",
long_description=read("README.rst"),
- version="1.9",
+ version="2.2",
classifiers=[
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
@@ -28,5 +28,5 @@ def read(fname):
"Topic :: Software Development :: Build Tools",
"Topic :: Software Development :: Testing",
],
- install_requires=["six"],
+ python_requires=">=3.8",
)
diff --git a/tests/asserts.py b/tests/asserts.py
deleted file mode 100644
index 82c48b4..0000000
--- a/tests/asserts.py
+++ /dev/null
@@ -1,83 +0,0 @@
-def verify_test_case( # noqa: E302
- 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,
- errors=None,
- failures=None,
- skipped=None,
-):
- for k, v in expected_attributes.items():
- assert test_case_element.attributes[k].value == v
-
- for k in test_case_element.attributes.keys():
- assert k in expected_attributes.keys()
-
- if stderr:
- assert test_case_element.getElementsByTagName("system-err")[0].firstChild.nodeValue.strip() == stderr
- if stdout:
- assert test_case_element.getElementsByTagName("system-out")[0].firstChild.nodeValue.strip() == stdout
-
- _errors = test_case_element.getElementsByTagName("error")
- if error_message or error_output:
- assert len(_errors) > 0
- elif errors:
- assert len(errors) == len(_errors)
- else:
- assert len(_errors) == 0
-
- if error_message:
- assert _errors[0].attributes["message"].value == error_message
-
- if error_type and _errors:
- assert _errors[0].attributes["type"].value == error_type
-
- if error_output:
- assert _errors[0].firstChild.nodeValue.strip() == error_output
-
- for error_exp, error_r in zip(errors or [], _errors):
- assert error_r.attributes["message"].value == error_exp["message"]
- assert error_r.firstChild.nodeValue.strip() == error_exp["output"]
- assert error_r.attributes["type"].value == error_exp["type"]
-
- _failures = test_case_element.getElementsByTagName("failure")
- if failure_message or failure_output:
- assert len(_failures) > 0
- elif failures:
- assert len(failures) == len(_failures)
- else:
- assert len(_failures) == 0
-
- if failure_message:
- assert _failures[0].attributes["message"].value == failure_message
-
- if failure_type and _failures:
- assert _failures[0].attributes["type"].value == failure_type
-
- if failure_output:
- assert _failures[0].firstChild.nodeValue.strip() == failure_output
-
- for failure_exp, failure_r in zip(failures or [], _failures):
- assert failure_r.attributes["message"].value == failure_exp["message"]
- assert failure_r.firstChild.nodeValue.strip() == failure_exp["output"]
- assert failure_r.attributes["type"].value == failure_exp["type"]
-
- _skipped = test_case_element.getElementsByTagName("skipped")
- if skipped_message or skipped_output:
- assert len(_skipped) > 0
- elif skipped:
- assert len(skipped) == len(_skipped)
- else:
- assert len(_skipped) == 0
-
- for skipped_exp, skipped_r in zip(skipped or [], _skipped):
- assert skipped_r.attributes["message"].value == skipped_exp["message"]
- assert skipped_r.firstChild.nodeValue.strip() == skipped_exp["output"]
diff --git a/tests/serializer.py b/tests/serializer.py
index 8a06200..5b5d24e 100644
--- a/tests/serializer.py
+++ b/tests/serializer.py
@@ -1,52 +1,32 @@
-import codecs
-import os
-import tempfile
+import logging
from xml.dom import minidom
-from six import PY2
+from junit_xml import to_xml_report_string
-from junit_xml import to_xml_report_file, to_xml_report_string
+logger = logging.getLogger("Serializer")
-def serialize_and_read(test_suites, to_file=False, prettyprint=False, encoding=None):
+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)
+
+
+def read_testsuites_root(test_suites, prettyprint=False):
"""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:
+ returning => (test suite element, list of test case elements)"""
+ if not isinstance(test_suites, list):
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:
- to_xml_report_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 = to_xml_report_string(test_suites, prettyprint=prettyprint, encoding=encoding)
- if PY2:
- assert isinstance(xml_string, unicode) # noqa: F821
- 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)
+ xml_string = to_xml_report_string(test_suites, prettyprint=prettyprint, encoding="utf-8")
+ logger.debug("Serialized XML to string:\n%s", xml_string)
+
+ xmldoc = minidom.parseString(xml_string)
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
+ return xmldoc.getElementsByTagName("testsuites")
diff --git a/tests/test_test_case.py b/tests/test_test_case.py
index b9817de..b3d5b24 100644
--- a/tests/test_test_case.py
+++ b/tests/test_test_case.py
@@ -1,324 +1,193 @@
# -*- coding: UTF-8 -*-
-from __future__ import with_statement
-
-from six import u
-
-from .asserts import verify_test_case
-from junit_xml import TestCase as Case
-from junit_xml import TestSuite as Suite
-from junit_xml import decode
-from .serializer import serialize_and_read
-
-
-def test_init():
- ts, tcs = serialize_and_read(Suite("test", [Case("Test1")]))[0]
- verify_test_case(tcs[0], {"name": "Test1"})
-
-
-def test_init_classname():
- ts, tcs = serialize_and_read(Suite("test", [Case(name="Test1", classname="some.class.name")]))[0]
- verify_test_case(tcs[0], {"name": "Test1", "classname": "some.class.name"})
-
-
-def test_init_classname_time():
- ts, tcs = serialize_and_read(Suite("test", [Case(name="Test1", classname="some.class.name", elapsed_sec=123.345)]))[
- 0
- ]
- verify_test_case(tcs[0], {"name": "Test1", "classname": "some.class.name", "time": ("%f" % 123.345)})
-
-
-def test_init_classname_time_timestamp():
- ts, tcs = serialize_and_read(
- Suite("test", [Case(name="Test1", classname="some.class.name", elapsed_sec=123.345, timestamp=99999)])
- )[0]
- verify_test_case(
- tcs[0], {"name": "Test1", "classname": "some.class.name", "time": ("%f" % 123.345), "timestamp": ("%s" % 99999)}
- )
-
-
-def test_init_stderr():
- ts, tcs = serialize_and_read(
- Suite("test", [Case(name="Test1", classname="some.class.name", elapsed_sec=123.345, stderr="I am stderr!")])
- )[0]
- verify_test_case(
- tcs[0], {"name": "Test1", "classname": "some.class.name", "time": ("%f" % 123.345)}, stderr="I am stderr!"
- )
-
-
-def test_init_stdout_stderr():
- ts, tcs = serialize_and_read(
- Suite(
- "test",
- [
- Case(
- name="Test1",
- classname="some.class.name",
- elapsed_sec=123.345,
- stdout="I am stdout!",
- stderr="I am stderr!",
- )
- ],
- )
- )[0]
- verify_test_case(
- tcs[0],
- {"name": "Test1", "classname": "some.class.name", "time": ("%f" % 123.345)},
- stdout="I am stdout!",
- stderr="I am stderr!",
- )
-
-
-def test_init_disable():
- tc = Case("Disabled-Test")
- tc.is_enabled = False
- ts, tcs = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(tcs[0], {"name": "Disabled-Test"})
-
-
-def test_init_failure_message():
- tc = Case("Failure-Message")
- tc.add_failure_info("failure message")
- ts, tcs = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(tcs[0], {"name": "Failure-Message"}, failure_message="failure message")
-
-
-def test_init_failure_output():
- tc = Case("Failure-Output")
- tc.add_failure_info(output="I failed!")
- ts, tcs = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(tcs[0], {"name": "Failure-Output"}, failure_output="I failed!")
-
-
-def test_init_failure_type():
- tc = Case("Failure-Type")
- tc.add_failure_info(failure_type="com.example.Error")
- ts, tcs = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(tcs[0], {"name": "Failure-Type"})
-
- tc.add_failure_info("failure message")
- ts, tcs = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(
- tcs[0], {"name": "Failure-Type"}, failure_message="failure message", failure_type="com.example.Error"
- )
-
-
-def test_init_failure():
- tc = Case("Failure-Message-and-Output")
- tc.add_failure_info("failure message", "I failed!")
- ts, tcs = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(
- tcs[0],
- {"name": "Failure-Message-and-Output"},
- failure_message="failure message",
- failure_output="I failed!",
- failure_type="failure",
- )
-
-
-def test_init_error_message():
- tc = Case("Error-Message")
- tc.add_error_info("error message")
- ts, tcs = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(tcs[0], {"name": "Error-Message"}, error_message="error message")
-
-
-def test_init_error_output():
- tc = Case("Error-Output")
- tc.add_error_info(output="I errored!")
- ts, tcs = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(tcs[0], {"name": "Error-Output"}, error_output="I errored!")
-
-
-def test_init_error_type():
- tc = Case("Error-Type")
- tc.add_error_info(error_type="com.example.Error")
- ts, tcs = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(tcs[0], {"name": "Error-Type"})
-
- tc.add_error_info("error message")
- ts, tcs = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(tcs[0], {"name": "Error-Type"}, error_message="error message", error_type="com.example.Error")
-
-
-def test_init_error():
- tc = Case("Error-Message-and-Output")
- tc.add_error_info("error message", "I errored!")
- ts, tcs = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(
- tcs[0],
- {"name": "Error-Message-and-Output"},
- error_message="error message",
- error_output="I errored!",
- error_type="error",
- )
-
-
-def test_init_skipped_message():
- tc = Case("Skipped-Message")
- tc.add_skipped_info("skipped message")
- ts, tcs = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(tcs[0], {"name": "Skipped-Message"}, skipped_message="skipped message")
-
-
-def test_init_skipped_output():
- tc = Case("Skipped-Output")
- tc.add_skipped_info(output="I skipped!")
- ts, tcs = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(tcs[0], {"name": "Skipped-Output"}, skipped_output="I skipped!")
-
-
-def test_init_skipped_err_output():
- tc = Case("Skipped-Output")
- tc.add_skipped_info(output="I skipped!")
- tc.add_error_info(output="I skipped with an error!")
- ts, tcs = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(
- tcs[0], {"name": "Skipped-Output"}, skipped_output="I skipped!", error_output="I skipped with an error!"
- )
-
-
-def test_init_skipped():
- tc = Case("Skipped-Message-and-Output")
- tc.add_skipped_info("skipped message", "I skipped!")
- ts, tcs = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(
- tcs[0], {"name": "Skipped-Message-and-Output"}, skipped_message="skipped message", skipped_output="I skipped!"
- )
-
-
-def test_init_legal_unicode_char():
- tc = Case("Failure-Message")
- tc.add_failure_info(u("failure message with legal unicode char: [\x22]"))
- ts, tcs = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(
- tcs[0], {"name": "Failure-Message"}, failure_message=u("failure message with legal unicode char: [\x22]")
- )
-
-
-def test_init_illegal_unicode_char():
- tc = Case("Failure-Message")
- tc.add_failure_info(u("failure message with illegal unicode char: [\x02]"))
- ts, tcs = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(
- tcs[0], {"name": "Failure-Message"}, failure_message=u("failure message with illegal unicode char: []")
- )
-
-
-def test_init_utf8():
- tc = Case(
- 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 = Suite("Test UTF-8", [tc])
- ts, tcs = serialize_and_read(test_suite, encoding="utf-8")[0]
- verify_test_case(
- 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():
- tc = Case(
- 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(Suite("Test Unicode", [tc]))[0]
- verify_test_case(
- 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"),
- )
+
+import pytest
+
+from junit_xml.root_element import TestSuite as Suite
+from junit_xml.single_entry import TestCase as Case
+from .serializer import read_testsuites_root
+
+sample_testsuite_name = "Banane"
+
+sample_testcase_name = "Test1"
+sample_classname = "some.class.name"
+sample_time = 123.345
+
+sample_failure_msg = "failure message: something bad happened"
+sample_failure_output = "I failed!"
+
+sample_error_message = "error message"
+sample_error_output = "I errored!"
+
+sample_skipped_message = "skipped message"
+sample_skipped_output = "I skipped!"
+
+
+def read_testcases(test_suites, prettyprint=False):
+ suites = read_testsuites_root(test_suites, prettyprint)[0]
+ return suites.getElementsByTagName("testsuite")[0].getElementsByTagName("testcase")
+
+
+@pytest.mark.parametrize("_input, expected_output",
+ [
+ (Case(sample_testcase_name),
+ {"name": sample_testcase_name}),
+
+ (Case(name=sample_testcase_name, classname=sample_classname),
+ {"name": sample_testcase_name, "classname": sample_classname}),
+
+ (Case(name=sample_testcase_name, classname=sample_classname,
+ time=sample_time),
+ {"name": sample_testcase_name, "classname": sample_classname,
+ "time": "%.3f" % sample_time})
+ ])
+def test_report_passing_test(_input, expected_output):
+ test_case_element = read_testcases(Suite(sample_testsuite_name, [_input]))
+
+ for _key, _value in expected_output.items():
+ assert test_case_element[0].attributes[_key].value == _value, \
+ f"key: {_key} value: {_value} vs. {test_case_element[0].attributes[_key].value}"
+
+ for act_key in test_case_element[0].attributes.keys():
+ assert act_key in expected_output.keys()
+
+ _failures = test_case_element[0].getElementsByTagName("failure")
+ _errors = test_case_element[0].getElementsByTagName("error")
+ _skipped = test_case_element[0].getElementsByTagName("skipped")
+
+ assert not _failures
+ assert not _errors
+ assert not _skipped
+
+
+@pytest.mark.parametrize("_input_error_message,_input_error_output,_default_type,_error_type",
+ [(sample_error_message, sample_error_output, True, "error"),
+ (sample_error_message, sample_error_output, False, "com.example.Error")
+ ])
+def test_error_message_and_output_default_error_type(_input_error_message, _input_error_output,
+ _default_type, _error_type):
+ tc = Case(sample_testcase_name)
+ if _default_type:
+ tc.add_error_info(_input_error_message, _input_error_output)
+ else:
+ tc.add_error_info(_input_error_message, _input_error_output, _error_type)
+
+ tcs = read_testcases(Suite(sample_testsuite_name, [tc]))
+
+ _errors = tcs[0].getElementsByTagName("error")
+ assert _errors[0].attributes["message"].value == _input_error_message
+ assert _errors[0].attributes["type"].value == _error_type
+ assert _errors[0].firstChild.nodeValue.strip() == _input_error_output
+
+
+def test_skipped_message_only():
+ tc = Case(sample_testcase_name)
+
+ tc.add_skipped_info(sample_skipped_message)
+
+ tcs = read_testcases(Suite(sample_testsuite_name, [tc]))
+
+ _skipped = tcs[0].getElementsByTagName("skipped")
+ assert _skipped[0].attributes["message"].value == sample_skipped_message
+ assert _skipped[0].attributes["type"].value == "skipped"
+ assert not _skipped[0].firstChild
+
+
+def test_skipped_message_and_output():
+ tc = Case(sample_testcase_name)
+ tc.add_skipped_info(sample_skipped_message, sample_skipped_output)
+
+ tcs = read_testcases(Suite(sample_testsuite_name, [tc]))
+
+ _skipped = tcs[0].getElementsByTagName("skipped")
+
+ assert _skipped[0].attributes["message"].value == sample_skipped_message
+ assert _skipped[0].attributes["type"].value == "skipped"
+ assert _skipped[0].firstChild.nodeValue.strip() == sample_skipped_output
+
+
+def test_mixed_skipped_and_err_output():
+ tc = Case(sample_testcase_name)
+ tc.add_skipped_info(output=sample_skipped_output)
+ tc.add_error_info(output=sample_error_output)
+
+ tcs = read_testcases(Suite(sample_testsuite_name, [tc]))
+
+ _skipped = tcs[0].getElementsByTagName("skipped")
+ assert _skipped[0].firstChild.nodeValue.strip() == sample_skipped_output
+ assert _skipped[0].attributes["type"].value == "skipped"
+
+ _errors = tcs[0].getElementsByTagName("error")
+ assert _errors[0].firstChild.nodeValue.strip() == sample_error_output
+ assert _errors[0].attributes["type"].value == "error"
def test_multiple_errors():
"""Tests multiple errors in one test case"""
- tc = Case("Multiple error", allow_multiple_subelements=True)
- tc.add_error_info("First error", "First error message")
- (_, tcs) = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(
- tcs[0],
- {"name": "Multiple error"},
- errors=[{"message": "First error", "output": "First error message", "type": "error"}],
- )
- tc.add_error_info("Second error", "Second error message")
- (_, tcs) = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(
- tcs[0],
- {"name": "Multiple error"},
- errors=[
- {"message": "First error", "output": "First error message", "type": "error"},
- {"message": "Second error", "output": "Second error message", "type": "error"},
- ],
- )
+ tc = Case(sample_testcase_name, allow_multiple_subelements=True)
+ tc.add_error_info(sample_error_message, sample_error_output)
+
+ tcs = read_testcases(Suite(sample_testsuite_name, [tc]))
+
+ _errors = tcs[0].getElementsByTagName("error")
+ assert _errors[0].attributes["message"].value == sample_error_message
+ assert _errors[0].attributes["type"].value == "error"
+ assert _errors[0].firstChild.nodeValue.strip() == sample_error_output
+
+ error_entry = ("Second error message", "Second error output")
+ tc.add_error_info(error_entry[0], error_entry[1])
+
+ tcs = read_testcases(Suite(sample_testsuite_name, [tc]))
+
+ _errors = tcs[0].getElementsByTagName("error")
+ assert len(_errors) == 2
+ assert _errors[1].attributes["message"].value == error_entry[0]
+ assert _errors[1].attributes["type"].value == "error"
+ assert _errors[1].firstChild.nodeValue.strip() == error_entry[1]
def test_multiple_failures():
"""Tests multiple failures in one test case"""
- tc = Case("Multiple failures", allow_multiple_subelements=True)
- tc.add_failure_info("First failure", "First failure message")
- (_, tcs) = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(
- tcs[0],
- {"name": "Multiple failures"},
- failures=[{"message": "First failure", "output": "First failure message", "type": "failure"}],
- )
- tc.add_failure_info("Second failure", "Second failure message")
- (_, tcs) = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(
- tcs[0],
- {"name": "Multiple failures"},
- failures=[
- {"message": "First failure", "output": "First failure message", "type": "failure"},
- {"message": "Second failure", "output": "Second failure message", "type": "failure"},
- ],
- )
+ tc = Case(sample_testcase_name, allow_multiple_subelements=True)
+ tc.add_failure_info(sample_failure_msg, sample_failure_output)
+
+ tcs = read_testcases(Suite(sample_testsuite_name, [tc]))
+
+ _failures = tcs[0].getElementsByTagName("failure")
+ assert _failures[0].attributes["message"].value == sample_failure_msg
+ assert _failures[0].attributes["type"].value == "failure"
+ assert _failures[0].firstChild.nodeValue.strip() == sample_failure_output
+
+ second_failure_entry = ("Second failure message", "Second failure output")
+
+ tc.add_failure_info(second_failure_entry[0], second_failure_entry[1])
+
+ tcs = read_testcases(Suite(sample_testsuite_name, [tc]))
+
+ _failures = tcs[0].getElementsByTagName("failure")
+ assert len(_failures) == 2
+ assert _failures[1].attributes["message"].value == second_failure_entry[0]
+ assert _failures[1].attributes["type"].value == "failure"
+ assert _failures[1].firstChild.nodeValue.strip() == second_failure_entry[1]
def test_multiple_skipped():
"""Tests multiple skipped messages in one test case"""
- tc = Case("Multiple skipped", allow_multiple_subelements=True)
- tc.add_skipped_info("First skipped", "First skipped message")
- (_, tcs) = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(
- tcs[0], {"name": "Multiple skipped"}, skipped=[{"message": "First skipped", "output": "First skipped message"}]
- )
- tc.add_skipped_info("Second skipped", "Second skipped message")
- (_, tcs) = serialize_and_read(Suite("test", [tc]))[0]
- verify_test_case(
- tcs[0],
- {"name": "Multiple skipped"},
- skipped=[
- {"message": "First skipped", "output": "First skipped message"},
- {"message": "Second skipped", "output": "Second skipped message"},
- ],
- )
+ testcase_under_test = Case(sample_testcase_name, allow_multiple_subelements=True)
+ testcase_under_test.add_skipped_info(sample_skipped_message, sample_skipped_output)
+
+ tcs = read_testcases(Suite(sample_testsuite_name, [testcase_under_test]))
+
+ _skipped = tcs[0].getElementsByTagName("skipped")
+ assert _skipped[0].firstChild.nodeValue.strip() == sample_skipped_output
+ assert _skipped[0].attributes["message"].value == sample_skipped_message
+
+ sample_skip_2 = ("Second skipped message", "Second skipped output")
+
+ testcase_under_test.add_skipped_info(sample_skip_2[0], sample_skip_2[1])
+
+ tcs = read_testcases(Suite(sample_testsuite_name, [testcase_under_test]))
+
+ _skipped = tcs[0].getElementsByTagName("skipped")
+ assert len(_skipped) == 2
+ assert _skipped[1].firstChild.nodeValue.strip() == sample_skip_2[1]
+ assert _skipped[1].attributes["message"].value == sample_skip_2[0]
diff --git a/tests/test_test_suite.py b/tests/test_test_suite.py
index a6591fe..fee5ed8 100644
--- a/tests/test_test_suite.py
+++ b/tests/test_test_suite.py
@@ -1,241 +1,167 @@
# -*- coding: UTF-8 -*-
-from __future__ import with_statement
-import textwrap
-import warnings
+from unittest import mock
import pytest
-from six import PY2, StringIO
-from .asserts import verify_test_case
-from junit_xml import TestCase as Case
-from junit_xml import TestSuite as Suite
-from junit_xml import decode, to_xml_report_string
-from .serializer import serialize_and_read
+from junit_xml import to_xml_report_string
+from junit_xml.root_element import TestSuite
+from junit_xml.single_entry import TestCase
+from .serializer import read_testsuites_root
+sample_testsuite_name = "suite"
-def test_single_suite_single_test_case():
- with pytest.raises(TypeError) as excinfo:
- serialize_and_read(Suite("test", Case("Test1")), to_file=True)[0]
- assert str(excinfo.value) == "test_cases must be a list of test cases"
-
+sample_hostname = "localhost"
+sample_id = 42
-def test_single_suite_no_test_cases():
- properties = {"foo": "bar"}
- package = "mypackage"
- timestamp = 1398382805
+sample_property_entry = ("foo", "bar")
+sample_package = "sample.mypackage"
- ts, tcs = serialize_and_read(
- Suite(
- name="test",
- test_cases=[],
- hostname="localhost",
- id=1,
- properties=properties,
- package=package,
- timestamp=timestamp,
- ),
- to_file=True,
- prettyprint=True,
- )[0]
- assert ts.tagName == "testsuite"
- assert ts.attributes["package"].value == package
- assert ts.attributes["timestamp"].value == str(timestamp)
- assert ts.childNodes[0].childNodes[0].attributes["name"].value == "foo"
- assert ts.childNodes[0].childNodes[0].attributes["value"].value == "bar"
-
-
-def test_single_suite_no_test_cases_utf8():
- properties = {"foö": "bär"}
- package = "mypäckage"
- timestamp = 1398382805
-
- test_suite = Suite(
- 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]
- assert ts.tagName == "testsuite"
- assert ts.attributes["package"].value == decode(package, "utf-8")
- assert ts.attributes["timestamp"].value == str(timestamp)
- assert ts.childNodes[0].childNodes[0].attributes["name"].value == decode("foö", "utf-8")
- assert ts.childNodes[0].childNodes[0].attributes["value"].value == decode("bär", "utf-8")
+sample_timestamp = 1398382805
+suite_name_1 = "suite1"
+testcase_name_1 = "Test1"
-def test_single_suite_no_test_cases_unicode():
- properties = {decode("foö", "utf-8"): decode("bär", "utf-8")}
- package = decode("mypäckage", "utf-8")
- timestamp = 1398382805
+suite_name_2 = "suite2"
+testcase_name_2 = "Test2"
- ts, tcs = serialize_and_read(
- Suite(
- 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]
- assert ts.tagName == "testsuite"
- assert ts.attributes["package"].value == package
- assert ts.attributes["timestamp"].value, str(timestamp)
- assert ts.childNodes[0].childNodes[0].attributes["name"].value == decode("foö", "utf-8")
- assert ts.childNodes[0].childNodes[0].attributes["value"].value == decode("bär", "utf-8")
+sample_testcase_name = "SomeTest"
+generated_timestamp = "2022-05-12T09:19:42"
-def test_single_suite_to_file():
- ts, tcs = serialize_and_read(Suite("test", [Case("Test1")]), to_file=True)[0]
- verify_test_case(tcs[0], {"name": "Test1"})
+def read_first_testsuite(test_suites, prettyprint=False):
+ res = read_testsuites_root(test_suites, prettyprint)[0].getElementsByTagName("testsuite")[0]
+ return res
-def test_single_suite_to_file_prettyprint():
- ts, tcs = serialize_and_read(Suite("test", [Case("Test1")]), to_file=True, prettyprint=True)[0]
- verify_test_case(tcs[0], {"name": "Test1"})
+def test_single_testsuite_wrong_testcase_type():
+ with pytest.raises(TypeError) as exc_info:
+ TestSuite("test", TestCase("Test1"))
+ assert str(exc_info.value) == "test_cases must be a list of test cases"
-def test_single_suite_prettyprint():
- ts, tcs = serialize_and_read(Suite("test", [Case("Test1")]), to_file=False, prettyprint=True)[0]
- verify_test_case(tcs[0], {"name": "Test1"})
-
-
-def test_single_suite_to_file_no_prettyprint():
- ts, tcs = serialize_and_read(Suite("test", [Case("Test1")]), to_file=True, prettyprint=False)[0]
- verify_test_case(tcs[0], {"name": "Test1"})
-
-
-def test_multiple_suites_to_file():
- tss = [Suite("suite1", [Case("Test1")]), Suite("suite2", [Case("Test2")])]
- suites = serialize_and_read(tss, to_file=True)
-
- assert suites[0][0].attributes["name"].value == "suite1"
- verify_test_case(suites[0][1][0], {"name": "Test1"})
-
- assert suites[1][0].attributes["name"].value == "suite2"
- verify_test_case(suites[1][1][0], {"name": "Test2"})
-
-
-def test_multiple_suites_to_string():
- tss = [Suite("suite1", [Case("Test1")]), Suite("suite2", [Case("Test2")])]
- suites = serialize_and_read(tss)
-
- assert suites[0][0].attributes["name"].value == "suite1"
- verify_test_case(suites[0][1][0], {"name": "Test1"})
+def test_single_testsuite_no_testcases():
+ ts = read_first_testsuite(
+ TestSuite(
+ name=sample_testsuite_name,
+ test_cases=[],
+ hostname=sample_hostname,
+ properties={sample_property_entry[0]: sample_property_entry[1]},
+ package=sample_package,
+ timestamp=sample_timestamp,
+ ),
+ prettyprint=True,
+ )
- assert suites[1][0].attributes["name"].value == "suite2"
- verify_test_case(suites[1][1][0], {"name": "Test2"})
+ assert ts.tagName == "testsuite"
+ assert ts.attributes["name"].value == sample_testsuite_name
+ assert ts.attributes["hostname"].value == sample_hostname
+
+ assert ts.attributes["package"].value == sample_package
+ assert ts.attributes["timestamp"].value == str(sample_timestamp)
+ assert ts.childNodes[0].childNodes[0].attributes["name"].value == sample_property_entry[0]
+ assert ts.childNodes[0].childNodes[0].attributes["value"].value == sample_property_entry[1]
+
+
+exp_output_pretty_p = '\n'
+exp_output_pretty_p += '\n'
+exp_output_pretty_p += f'\t\n'
+exp_output_pretty_p += f'\t\t\n'
+exp_output_pretty_p += '\t\n'
+exp_output_pretty_p += '\n'
+
+exp_output_no_pretty = ''
+
+expected_xml_string = '\n'
+expected_xml_string += '\n'
+expected_xml_string += '\t\n'
+expected_xml_string += '\t\t\n'
+expected_xml_string += '\t\n'
+expected_xml_string += '\t\n'
+expected_xml_string += '\t\t\n'
+expected_xml_string += '\t\n'
+expected_xml_string += '\n'
+
+
+@pytest.mark.parametrize("pretty_print, expected_output",
+ [(True, exp_output_pretty_p),
+ (False, exp_output_no_pretty)])
+@mock.patch("junit_xml.root_element.get_new_id", create=True)
+@mock.patch("junit_xml.root_element.get_current_timestamp", create=True)
+def test_single_suite_with_prettyprint(time_provider_mock: mock.Mock, id_provider: mock.Mock,
+ pretty_print, expected_output):
+ time_provider_mock.return_value = generated_timestamp
+ id_provider.return_value = "42"
+
+ input_testsuite = TestSuite(sample_testsuite_name, [TestCase(sample_testcase_name)])
+
+ act_output = to_xml_report_string([input_testsuite], prettyprint=pretty_print, encoding="utf-8")
+
+ assert act_output == expected_output
+
+
+@mock.patch("junit_xml.root_element.get_new_id", create=True)
+@mock.patch("junit_xml.root_element.get_current_timestamp", create=True)
+def test_to_xml_string(time_provider_mock: mock.Mock, id_provider: mock.Mock):
+ time_provider_mock.return_value = generated_timestamp
+ id_provider.return_value = "1"
-def test_attribute_time():
- tss = [
- Suite(
- "suite1",
- [
- Case(name="Test1", classname="some.class.name", elapsed_sec=123.345),
- Case(name="Test2", classname="some2.class.name", elapsed_sec=123.345),
- ],
- ),
- Suite("suite2", [Case("Test2")]),
+ test_suites = [
+ TestSuite(name="suite1", test_cases=[TestCase(name="Test1")]),
+ TestSuite(name="suite2", test_cases=[TestCase(name="Test2")]),
]
- suites = serialize_and_read(tss)
-
- assert suites[0][0].attributes["name"].value == "suite1"
- assert suites[0][0].attributes["time"].value == "246.69"
+ xml_string = to_xml_report_string(test_suites)
- assert suites[1][0].attributes["name"].value == "suite2"
- # here the time in testsuite is "0" even there is no attribute time for
- # testcase
- assert suites[1][0].attributes["time"].value == "0"
+ assert xml_string == expected_xml_string
def test_attribute_disable():
- tc = Case("Disabled-Test")
+ tc = TestCase("Disabled-Test")
tc.is_enabled = False
- tss = [Suite("suite1", [tc])]
- suites = serialize_and_read(tss)
-
- assert suites[0][0].attributes["disabled"].value == "1"
+ tss = [TestSuite(sample_testsuite_name, [tc])]
+ # res = to_xml_report_string(tss)
+ # print(f"\n{res}")
+ suite = read_testsuites_root(tss)[0].getElementsByTagName("testsuite")
-
-def test_stderr():
- suites = serialize_and_read(Suite(name="test", stderr="I am stderr!", test_cases=[Case(name="Test1")]))[0]
- assert suites[0].getElementsByTagName("system-err")[0].firstChild.data == "I am stderr!"
+ assert suite[0].attributes["disabled"].value == "1"
def test_stdout_stderr():
- suites = serialize_and_read(
- Suite(name="test", stdout="I am stdout!", stderr="I am stderr!", test_cases=[Case(name="Test1")])
- )[0]
- assert suites[0].getElementsByTagName("system-err")[0].firstChild.data == "I am stderr!"
- assert suites[0].getElementsByTagName("system-out")[0].firstChild.data == "I am stdout!"
+ suite = read_first_testsuite(
+ TestSuite(name=sample_testsuite_name, stdout="I am stdout!",
+ stderr="I am stderr!", test_cases=[TestCase(name=sample_testcase_name)])
+ )
+ assert suite.getElementsByTagName("system-err")[0].firstChild.data == "I am stderr!"
+ assert suite.getElementsByTagName("system-out")[0].firstChild.data == "I am stdout!"
def test_no_assertions():
- suites = serialize_and_read(Suite(name="test", test_cases=[Case(name="Test1")]))[0]
- assert not suites[0].getElementsByTagName("testcase")[0].hasAttribute("assertions")
+ suite = read_first_testsuite(
+ TestSuite(name=sample_testsuite_name, test_cases=[TestCase(name=sample_testcase_name)]))
+ assert not suite.getElementsByTagName("testcase")[0].hasAttribute("assertions")
def test_assertions():
- suites = serialize_and_read(Suite(name="test", test_cases=[Case(name="Test1", assertions=5)]))[0]
- assert suites[0].getElementsByTagName("testcase")[0].attributes["assertions"].value == "5"
+ suite = read_first_testsuite(
+ TestSuite(name=sample_testsuite_name,
+ test_cases=[TestCase(name=sample_testcase_name, assertions=5)]))
- # @todo: add more tests for the other attributes and properties
+ assert suite.getElementsByTagName("testcase")[0].attributes["assertions"].value == "5"
-def test_to_xml_string():
- test_suites = [
- Suite(name="suite1", test_cases=[Case(name="Test1")]),
- Suite(name="suite2", test_cases=[Case(name="Test2")]),
- ]
- xml_string = to_xml_report_string(test_suites)
- if PY2:
- assert isinstance(xml_string, unicode) # noqa: F821
- expected_xml_string = textwrap.dedent(
- """
-
-
- \t
- \t\t
- \t
- \t
- \t\t
- \t
-
- """.strip(
- "\n"
- )
- )
- assert xml_string == expected_xml_string
-
-
-def test_to_xml_string_test_suites_not_a_list():
- test_suites = Suite("suite1", [Case("Test1")])
+def test_to_xml_string_wrong_input_type():
+ test_suites = TestSuite(sample_testsuite_name, [TestCase(sample_testcase_name)])
with pytest.raises(TypeError) as excinfo:
to_xml_report_string(test_suites)
assert str(excinfo.value) == "test_suites must be a list of test suites"
-
-
-def test_deprecated_to_xml_string():
- with warnings.catch_warnings(record=True) as w:
- Suite.to_xml_string([])
- assert len(w) == 1
- assert issubclass(w[0].category, DeprecationWarning)
- assert "Testsuite.to_xml_string is deprecated" in str(w[0].message)
-
-
-def test_deprecated_to_file():
- with warnings.catch_warnings(record=True) as w:
- Suite.to_file(StringIO(), [])
- assert len(w) == 1
- assert issubclass(w[0].category, DeprecationWarning)
- assert "Testsuite.to_file is deprecated" in str(w[0].message)
diff --git a/tox.ini b/tox.ini
index 3fdb993..6ebd1c6 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,39 +1,58 @@
[tox]
-envlist = py27, pypy, py35, py36, py37, py38, cover, flake8
+envlist = dev-pylint,dev,black-check
+#isolated_build = true
sitepackages = False
[testenv]
+basepython = python3
+# "usedevelop = true" is short cut to "python setup.py develop"
+#usedevelop = true
deps =
- pytest
- pytest-sugar
- six
+ black: black
+ dev: -rrequirements.txt
+
+[testenv:dev-pylint]
+whitelist_externals = cat
commands =
- py.test \
- --junitxml={envlogdir}/junit-{envname}.xml \
- {posargs}
+ pylint --exit-zero --output=pylint.log junit_xml/
+ cat pylint.log
-[testenv:cover]
-deps =
- pytest
- pytest-sugar
- pytest-cov
- six
+[testenv:dev]
+commands =
+ pytest -s --junitxml=reports/summary.xml --cov=junit_xml \
+ --cov-report=term-missing --cov-report=xml --cov-report=html -W ignore {posargs}
+ coverage xml
+
+[testenv:black-format]
+changedir = {toxinidir}/junit_xml
+commands = black --line-length 100 .
+
+[testenv:black-check]
+changedir = {toxinidir}/junit_xml
+commands = black --check --diff --line-length 100 .
+
+[testenv:dev-flake8]
commands =
- py.test \
- --cov=junit_xml \
- --cov-report=term-missing \
- --cov-report=xml \
- --cov-report=html \
- {posargs}
-
-[testenv:flake8]
+ pytest --flake8 {posargs}
+
+# Release tooling
+[testenv:do-wheel]
+skip_install = true
deps =
- flake8-black
- pytest
- pytest-sugar
- pytest-flake8
- six
+ wheel
+ setuptools
+ build
commands =
- py.test \
- --flake8 \
- {posargs}
+ python -m build .
+
+[tool:pytest]
+testpaths = tests
+norecursedirs = .git .tox build dist venv
+
+[coverage:paths]
+source =
+ src
+ */site-packages
+
+[tool:black]
+line-length = 100
\ No newline at end of file