(root)/
Python-3.12.0/
Lib/
test/
support/
testresult.py
       1  '''Test runner and result class for the regression test suite.
       2  
       3  '''
       4  
       5  import functools
       6  import io
       7  import sys
       8  import time
       9  import traceback
      10  import unittest
      11  from test import support
      12  
      13  class ESC[4;38;5;81mRegressionTestResult(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTextTestResult):
      14      USE_XML = False
      15  
      16      def __init__(self, stream, descriptions, verbosity):
      17          super().__init__(stream=stream, descriptions=descriptions,
      18                           verbosity=2 if verbosity else 0)
      19          self.buffer = True
      20          if self.USE_XML:
      21              from xml.etree import ElementTree as ET
      22              from datetime import datetime, UTC
      23              self.__ET = ET
      24              self.__suite = ET.Element('testsuite')
      25              self.__suite.set('start',
      26                               datetime.now(UTC)
      27                                       .replace(tzinfo=None)
      28                                       .isoformat(' '))
      29              self.__e = None
      30          self.__start_time = None
      31  
      32      @classmethod
      33      def __getId(cls, test):
      34          try:
      35              test_id = test.id
      36          except AttributeError:
      37              return str(test)
      38          try:
      39              return test_id()
      40          except TypeError:
      41              return str(test_id)
      42          return repr(test)
      43  
      44      def startTest(self, test):
      45          super().startTest(test)
      46          if self.USE_XML:
      47              self.__e = e = self.__ET.SubElement(self.__suite, 'testcase')
      48          self.__start_time = time.perf_counter()
      49  
      50      def _add_result(self, test, capture=False, **args):
      51          if not self.USE_XML:
      52              return
      53          e = self.__e
      54          self.__e = None
      55          if e is None:
      56              return
      57          ET = self.__ET
      58  
      59          e.set('name', args.pop('name', self.__getId(test)))
      60          e.set('status', args.pop('status', 'run'))
      61          e.set('result', args.pop('result', 'completed'))
      62          if self.__start_time:
      63              e.set('time', f'{time.perf_counter() - self.__start_time:0.6f}')
      64  
      65          if capture:
      66              if self._stdout_buffer is not None:
      67                  stdout = self._stdout_buffer.getvalue().rstrip()
      68                  ET.SubElement(e, 'system-out').text = stdout
      69              if self._stderr_buffer is not None:
      70                  stderr = self._stderr_buffer.getvalue().rstrip()
      71                  ET.SubElement(e, 'system-err').text = stderr
      72  
      73          for k, v in args.items():
      74              if not k or not v:
      75                  continue
      76              e2 = ET.SubElement(e, k)
      77              if hasattr(v, 'items'):
      78                  for k2, v2 in v.items():
      79                      if k2:
      80                          e2.set(k2, str(v2))
      81                      else:
      82                          e2.text = str(v2)
      83              else:
      84                  e2.text = str(v)
      85  
      86      @classmethod
      87      def __makeErrorDict(cls, err_type, err_value, err_tb):
      88          if isinstance(err_type, type):
      89              if err_type.__module__ == 'builtins':
      90                  typename = err_type.__name__
      91              else:
      92                  typename = f'{err_type.__module__}.{err_type.__name__}'
      93          else:
      94              typename = repr(err_type)
      95  
      96          msg = traceback.format_exception(err_type, err_value, None)
      97          tb = traceback.format_exception(err_type, err_value, err_tb)
      98  
      99          return {
     100              'type': typename,
     101              'message': ''.join(msg),
     102              '': ''.join(tb),
     103          }
     104  
     105      def addError(self, test, err):
     106          self._add_result(test, True, error=self.__makeErrorDict(*err))
     107          super().addError(test, err)
     108  
     109      def addExpectedFailure(self, test, err):
     110          self._add_result(test, True, output=self.__makeErrorDict(*err))
     111          super().addExpectedFailure(test, err)
     112  
     113      def addFailure(self, test, err):
     114          self._add_result(test, True, failure=self.__makeErrorDict(*err))
     115          super().addFailure(test, err)
     116          if support.failfast:
     117              self.stop()
     118  
     119      def addSkip(self, test, reason):
     120          self._add_result(test, skipped=reason)
     121          super().addSkip(test, reason)
     122  
     123      def addSuccess(self, test):
     124          self._add_result(test)
     125          super().addSuccess(test)
     126  
     127      def addUnexpectedSuccess(self, test):
     128          self._add_result(test, outcome='UNEXPECTED_SUCCESS')
     129          super().addUnexpectedSuccess(test)
     130  
     131      def get_xml_element(self):
     132          if not self.USE_XML:
     133              raise ValueError("USE_XML is false")
     134          e = self.__suite
     135          e.set('tests', str(self.testsRun))
     136          e.set('errors', str(len(self.errors)))
     137          e.set('failures', str(len(self.failures)))
     138          return e
     139  
     140  class ESC[4;38;5;81mQuietRegressionTestRunner:
     141      def __init__(self, stream, buffer=False):
     142          self.result = RegressionTestResult(stream, None, 0)
     143          self.result.buffer = buffer
     144  
     145      def run(self, test):
     146          test(self.result)
     147          return self.result
     148  
     149  def get_test_runner_class(verbosity, buffer=False):
     150      if verbosity:
     151          return functools.partial(unittest.TextTestRunner,
     152                                   resultclass=RegressionTestResult,
     153                                   buffer=buffer,
     154                                   verbosity=verbosity)
     155      return functools.partial(QuietRegressionTestRunner, buffer=buffer)
     156  
     157  def get_test_runner(stream, verbosity, capture_output=False):
     158      return get_test_runner_class(verbosity, capture_output)(stream)
     159  
     160  if __name__ == '__main__':
     161      import xml.etree.ElementTree as ET
     162      RegressionTestResult.USE_XML = True
     163  
     164      class ESC[4;38;5;81mTestTests(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     165          def test_pass(self):
     166              pass
     167  
     168          def test_pass_slow(self):
     169              time.sleep(1.0)
     170  
     171          def test_fail(self):
     172              print('stdout', file=sys.stdout)
     173              print('stderr', file=sys.stderr)
     174              self.fail('failure message')
     175  
     176          def test_error(self):
     177              print('stdout', file=sys.stdout)
     178              print('stderr', file=sys.stderr)
     179              raise RuntimeError('error message')
     180  
     181      suite = unittest.TestSuite()
     182      suite.addTest(unittest.TestLoader().loadTestsFromTestCase(TestTests))
     183      stream = io.StringIO()
     184      runner_cls = get_test_runner_class(sum(a == '-v' for a in sys.argv))
     185      runner = runner_cls(sys.stdout)
     186      result = runner.run(suite)
     187      print('Output:', stream.getvalue())
     188      print('XML: ', end='')
     189      for s in ET.tostringlist(result.get_xml_element()):
     190          print(s.decode(), end='')
     191      print()