"Fossies" - the Fresh Open Source Software Archive

Member "cheetah3-3.2.6.post2/Cheetah/Tests/xmlrunner.py" (20 Apr 2021, 12678 Bytes) of package /linux/www/cheetah3-3.2.6.post2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "xmlrunner.py": 3-3.1.0_vs_3-3.2.0.

    1 """
    2 XML Test Runner for PyUnit
    3 """
    4 
    5 # Written by Sebastian Rittau <srittau@jroger.in-berlin.de> and placed in
    6 # the Public Domain. With contributions by Paolo Borelli.
    7 
    8 import os.path
    9 import re
   10 import sys
   11 import time
   12 import traceback
   13 import unittest
   14 try:
   15     from StringIO import StringIO
   16 except ImportError:
   17     from io import StringIO
   18 from xml.sax.saxutils import escape
   19 
   20 
   21 class _TestInfo(object):
   22 
   23     """Information about a particular test.
   24 
   25     Used by _XMLTestResult.
   26 
   27     """
   28 
   29     def __init__(self, test, time):
   30         _pieces = test.id().split('.')
   31         (self._class, self._method) = ('.'.join(_pieces[:-1]), _pieces[-1])
   32         self._time = time
   33         self._error = None
   34         self._failure = None
   35 
   36     def print_report(self, stream):
   37         """Print information about this test case in XML format to the
   38         supplied stream.
   39 
   40         """
   41         stream.write(
   42             '  <testcase classname="%(class)s" name="%(method)s" '
   43             'time="%(time).4f">' % {
   44                 "class": self._class,
   45                 "method": self._method,
   46                 "time": self._time,
   47             })
   48         if self._failure is not None:
   49             self._print_error(stream, 'failure', self._failure)
   50         if self._error is not None:
   51             self._print_error(stream, 'error', self._error)
   52         stream.write('</testcase>\n')
   53 
   54     def _print_error(self, stream, tagname, error):
   55         """Print information from a failure or error to the supplied stream."""
   56         text = escape(str(error[1]))
   57         stream.write('\n')
   58         stream.write(
   59             '    <%s type="%s">%s\n'
   60             % (tagname,
   61                issubclass(error[0], Exception)
   62                and error[0].__name__ or str(error[0]), text))
   63         tb_stream = StringIO()
   64         traceback.print_tb(error[2], None, tb_stream)
   65         stream.write(escape(tb_stream.getvalue()))
   66         stream.write('    </%s>\n' % tagname)
   67         stream.write('  ')
   68 
   69 # Module level functions since Python 2.3 doesn't grok decorators
   70 
   71 
   72 def create_success(test, time):
   73     """Create a _TestInfo instance for a successful test."""
   74     return _TestInfo(test, time)
   75 
   76 
   77 def create_failure(test, time, failure):
   78     """Create a _TestInfo instance for a failed test."""
   79     info = _TestInfo(test, time)
   80     info._failure = failure
   81     return info
   82 
   83 
   84 def create_error(test, time, error):
   85     """Create a _TestInfo instance for an erroneous test."""
   86     info = _TestInfo(test, time)
   87     info._error = error
   88     return info
   89 
   90 
   91 class _XMLTestResult(unittest.TestResult):
   92 
   93     """A test result class that stores result as XML.
   94 
   95     Used by XMLTestRunner.
   96 
   97     """
   98 
   99     def __init__(self, classname):
  100         unittest.TestResult.__init__(self)
  101         self._test_name = classname
  102         self._start_time = None
  103         self._tests = []
  104         self._error = None
  105         self._failure = None
  106 
  107     def startTest(self, test):
  108         unittest.TestResult.startTest(self, test)
  109         self._error = None
  110         self._failure = None
  111         self._start_time = time.time()
  112 
  113     def stopTest(self, test):
  114         time_taken = time.time() - self._start_time
  115         unittest.TestResult.stopTest(self, test)
  116         if self._error:
  117             info = create_error(test, time_taken, self._error)
  118         elif self._failure:
  119             info = create_failure(test, time_taken, self._failure)
  120         else:
  121             info = create_success(test, time_taken)
  122         self._tests.append(info)
  123 
  124     def addError(self, test, err):
  125         unittest.TestResult.addError(self, test, err)
  126         self._error = err
  127 
  128     def addFailure(self, test, err):
  129         unittest.TestResult.addFailure(self, test, err)
  130         self._failure = err
  131 
  132     def print_report(self, stream, time_taken, out, err):
  133         """Prints the XML report to the supplied stream.
  134 
  135         The time the tests took to perform as well as the captured standard
  136         output and standard error streams must be passed in.a
  137 
  138         """
  139         stream.write('<testsuite errors="%(e)d" failures="%(f)d" ' %
  140                      {"e": len(self.errors), "f": len(self.failures)})
  141         stream.write('name="%(n)s" tests="%(t)d" time="%(time).3f">\n' % {
  142             "n": self._test_name,
  143             "t": self.testsRun,
  144             "time": time_taken,
  145         })
  146         for info in self._tests:
  147             info.print_report(stream)
  148         stream.write('  <system-out><![CDATA[%s]]></system-out>\n' % out)
  149         stream.write('  <system-err><![CDATA[%s]]></system-err>\n' % err)
  150         stream.write('</testsuite>\n')
  151 
  152 
  153 class XMLTestRunner(object):
  154 
  155     """A test runner that stores results in XML format compatible with JUnit.
  156 
  157     XMLTestRunner(stream=None) -> XML test runner
  158 
  159     The XML file is written to the supplied stream. If stream is None, the
  160     results are stored in a file called TEST-<module>.<class>.xml in the
  161     current working directory (if not overridden with the path property),
  162     where <module> and <class> are the module and class name of the test class.
  163 
  164     """
  165 
  166     def __init__(self, *args, **kwargs):
  167         self._stream = kwargs.get('stream')
  168         self._filename = kwargs.get('filename')
  169         self._path = "."
  170 
  171     def run(self, test):
  172         """Run the given test case or test suite."""
  173         class_ = test.__class__
  174         classname = class_.__module__ + "." + class_.__name__
  175         if self._stream is None:
  176             filename = "TEST-%s.xml" % classname
  177             if self._filename:
  178                 filename = self._filename
  179             stream = open(os.path.join(self._path, filename), "w")
  180             stream.write('<?xml version="1.0" encoding="utf-8"?>\n')
  181         else:
  182             stream = self._stream
  183 
  184         result = _XMLTestResult(classname)
  185         start_time = time.time()
  186 
  187         # TODO: Python 2.5: Use the with statement
  188         old_stdout = sys.stdout
  189         old_stderr = sys.stderr
  190         sys.stdout = StringIO()
  191         sys.stderr = StringIO()
  192 
  193         try:
  194             test(result)
  195             try:
  196                 out_s = sys.stdout.getvalue()
  197             except AttributeError:
  198                 out_s = ""
  199             try:
  200                 err_s = sys.stderr.getvalue()
  201             except AttributeError:
  202                 err_s = ""
  203         finally:
  204             sys.stdout = old_stdout
  205             sys.stderr = old_stderr
  206 
  207         time_taken = time.time() - start_time
  208         result.print_report(stream, time_taken, out_s, err_s)
  209         if self._stream is None:
  210             stream.close()
  211 
  212         return result
  213 
  214     def _set_path(self, path):
  215         self._path = path
  216 
  217     path = property(
  218         lambda self: self._path, _set_path, None,
  219         """The path where the XML files are stored
  220 
  221 This property is ignored when the XML file is written to a file stream.""")
  222 
  223 
  224 class XMLTestRunnerTest(unittest.TestCase):
  225     def setUp(self):
  226         self._stream = StringIO()
  227 
  228     def _try_test_run(self, test_class, expected):
  229 
  230         """Run the test suite against the supplied test class and compare the
  231         XML result against the expected XML string. Fail if the expected
  232         string doesn't match the actual string. All time attribute in the
  233         expected string should have the value "0.000". All error and failure
  234         messages are reduced to "Foobar".
  235 
  236         """
  237 
  238         runner = XMLTestRunner(self._stream)
  239         runner.run(unittest.makeSuite(test_class))
  240 
  241         got = self._stream.getvalue()
  242         # Replace all time="X.YYY" attributes by time="0.000" to enable a
  243         # simple string comparison.
  244         got = re.sub(r'time="\d+\.\d+"', 'time="0.000"', got)
  245         # Likewise, replace all failure and error messages by a simple "Foobar"
  246         # string.
  247         got = re.sub(
  248             r'(?s)<failure (.*?)>.*?</failure>',
  249             r'<failure \1>Foobar</failure>', got)
  250         got = re.sub(
  251             r'(?s)<error (.*?)>.*?</error>', r'<error \1>Foobar</error>', got)
  252 
  253         self.assertEqual(expected, got)
  254 
  255     def test_no_tests(self):
  256         """Regression test: Check whether a test run without any tests
  257         matches a previous run.
  258 
  259         """
  260         class TestTest(unittest.TestCase):
  261             pass
  262         self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="0" time="0.000">
  263   <system-out><![CDATA[]]></system-out>
  264   <system-err><![CDATA[]]></system-err>
  265 </testsuite>
  266 """)  # noqa
  267 
  268     def test_success(self):
  269         """Regression test: Check whether a test run with a successful test
  270         matches a previous run.
  271 
  272         """
  273         class TestTest(unittest.TestCase):
  274             def test_foo(self):
  275                 pass
  276         self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
  277   <testcase classname="__main__.TestTest" name="test_foo" time="0.000"></testcase>
  278   <system-out><![CDATA[]]></system-out>
  279   <system-err><![CDATA[]]></system-err>
  280 </testsuite>
  281 """)  # noqa
  282 
  283     def test_failure(self):
  284         """Regression test: Check whether a test run with a failing test
  285         matches a previous run.
  286 
  287         """
  288         class TestTest(unittest.TestCase):
  289             def test_foo(self):
  290                 self.assertTrue(False)
  291         self._try_test_run(TestTest, """<testsuite errors="0" failures="1" name="unittest.TestSuite" tests="1" time="0.000">
  292   <testcase classname="__main__.TestTest" name="test_foo" time="0.000">
  293     <failure type="exceptions.AssertionError">Foobar</failure>
  294   </testcase>
  295   <system-out><![CDATA[]]></system-out>
  296   <system-err><![CDATA[]]></system-err>
  297 </testsuite>
  298 """)  # noqa
  299 
  300     def test_error(self):
  301         """Regression test: Check whether a test run with a erroneous test
  302         matches a previous run.
  303 
  304         """
  305         class TestTest(unittest.TestCase):
  306             def test_foo(self):
  307                 raise IndexError()
  308         self._try_test_run(TestTest, """<testsuite errors="1" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
  309   <testcase classname="__main__.TestTest" name="test_foo" time="0.000">
  310     <error type="exceptions.IndexError">Foobar</error>
  311   </testcase>
  312   <system-out><![CDATA[]]></system-out>
  313   <system-err><![CDATA[]]></system-err>
  314 </testsuite>
  315 """)  # noqa
  316 
  317     def test_stdout_capture(self):
  318         """Regression test: Check whether a test run with output to stdout
  319         matches a previous run.
  320 
  321         """
  322         class TestTest(unittest.TestCase):
  323             def test_foo(self):
  324                 print("Test")
  325         self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
  326   <testcase classname="__main__.TestTest" name="test_foo" time="0.000"></testcase>
  327   <system-out><![CDATA[Test
  328 ]]></system-out>
  329   <system-err><![CDATA[]]></system-err>
  330 </testsuite>
  331 """)  # noqa
  332 
  333     def test_stderr_capture(self):
  334         """Regression test: Check whether a test run with output to stderr
  335         matches a previous run.
  336 
  337         """
  338         class TestTest(unittest.TestCase):
  339             def test_foo(self):
  340                 sys.stderr.write('Test\n')
  341         self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
  342   <testcase classname="__main__.TestTest" name="test_foo" time="0.000"></testcase>
  343   <system-out><![CDATA[]]></system-out>
  344   <system-err><![CDATA[Test
  345 ]]></system-err>
  346 </testsuite>
  347 """)  # noqa
  348 
  349     class NullStream(object):
  350         """A file-like object that discards everything written to it."""
  351         def write(self, buffer):
  352             pass
  353 
  354     def test_unittests_changing_stdout(self):
  355         """Check whether the XMLTestRunner recovers gracefully from unit tests
  356         that change stdout, but don't change it back properly.
  357 
  358         """
  359         class TestTest(unittest.TestCase):
  360             def test_foo(self):
  361                 sys.stdout = XMLTestRunnerTest.NullStream()
  362 
  363         runner = XMLTestRunner(self._stream)
  364         runner.run(unittest.makeSuite(TestTest))
  365 
  366     def test_unittests_changing_stderr(self):
  367         """Check whether the XMLTestRunner recovers gracefully from unit tests
  368         that change stderr, but don't change it back properly.
  369 
  370         """
  371         class TestTest(unittest.TestCase):
  372             def test_foo(self):
  373                 sys.stderr = XMLTestRunnerTest.NullStream()
  374 
  375         runner = XMLTestRunner(self._stream)
  376         runner.run(unittest.makeSuite(TestTest))
  377 
  378 
  379 class XMLTestProgram(unittest.TestProgram):
  380     def runTests(self):
  381         if self.testRunner is None:
  382             self.testRunner = XMLTestRunner()
  383         unittest.TestProgram.runTests(self)
  384 
  385 
  386 main = XMLTestProgram
  387 
  388 
  389 if __name__ == "__main__":
  390     main(module=None)