(root)/
Python-3.11.7/
Lib/
unittest/
suite.py
       1  """TestSuite"""
       2  
       3  import sys
       4  
       5  from . import case
       6  from . import util
       7  
       8  __unittest = True
       9  
      10  
      11  def _call_if_exists(parent, attr):
      12      func = getattr(parent, attr, lambda: None)
      13      func()
      14  
      15  
      16  class ESC[4;38;5;81mBaseTestSuite(ESC[4;38;5;149mobject):
      17      """A simple test suite that doesn't provide class or module shared fixtures.
      18      """
      19      _cleanup = True
      20  
      21      def __init__(self, tests=()):
      22          self._tests = []
      23          self._removed_tests = 0
      24          self.addTests(tests)
      25  
      26      def __repr__(self):
      27          return "<%s tests=%s>" % (util.strclass(self.__class__), list(self))
      28  
      29      def __eq__(self, other):
      30          if not isinstance(other, self.__class__):
      31              return NotImplemented
      32          return list(self) == list(other)
      33  
      34      def __iter__(self):
      35          return iter(self._tests)
      36  
      37      def countTestCases(self):
      38          cases = self._removed_tests
      39          for test in self:
      40              if test:
      41                  cases += test.countTestCases()
      42          return cases
      43  
      44      def addTest(self, test):
      45          # sanity checks
      46          if not callable(test):
      47              raise TypeError("{} is not callable".format(repr(test)))
      48          if isinstance(test, type) and issubclass(test,
      49                                                   (case.TestCase, TestSuite)):
      50              raise TypeError("TestCases and TestSuites must be instantiated "
      51                              "before passing them to addTest()")
      52          self._tests.append(test)
      53  
      54      def addTests(self, tests):
      55          if isinstance(tests, str):
      56              raise TypeError("tests must be an iterable of tests, not a string")
      57          for test in tests:
      58              self.addTest(test)
      59  
      60      def run(self, result):
      61          for index, test in enumerate(self):
      62              if result.shouldStop:
      63                  break
      64              test(result)
      65              if self._cleanup:
      66                  self._removeTestAtIndex(index)
      67          return result
      68  
      69      def _removeTestAtIndex(self, index):
      70          """Stop holding a reference to the TestCase at index."""
      71          try:
      72              test = self._tests[index]
      73          except TypeError:
      74              # support for suite implementations that have overridden self._tests
      75              pass
      76          else:
      77              # Some unittest tests add non TestCase/TestSuite objects to
      78              # the suite.
      79              if hasattr(test, 'countTestCases'):
      80                  self._removed_tests += test.countTestCases()
      81              self._tests[index] = None
      82  
      83      def __call__(self, *args, **kwds):
      84          return self.run(*args, **kwds)
      85  
      86      def debug(self):
      87          """Run the tests without collecting errors in a TestResult"""
      88          for test in self:
      89              test.debug()
      90  
      91  
      92  class ESC[4;38;5;81mTestSuite(ESC[4;38;5;149mBaseTestSuite):
      93      """A test suite is a composite test consisting of a number of TestCases.
      94  
      95      For use, create an instance of TestSuite, then add test case instances.
      96      When all tests have been added, the suite can be passed to a test
      97      runner, such as TextTestRunner. It will run the individual test cases
      98      in the order in which they were added, aggregating the results. When
      99      subclassing, do not forget to call the base class constructor.
     100      """
     101  
     102      def run(self, result, debug=False):
     103          topLevel = False
     104          if getattr(result, '_testRunEntered', False) is False:
     105              result._testRunEntered = topLevel = True
     106  
     107          for index, test in enumerate(self):
     108              if result.shouldStop:
     109                  break
     110  
     111              if _isnotsuite(test):
     112                  self._tearDownPreviousClass(test, result)
     113                  self._handleModuleFixture(test, result)
     114                  self._handleClassSetUp(test, result)
     115                  result._previousTestClass = test.__class__
     116  
     117                  if (getattr(test.__class__, '_classSetupFailed', False) or
     118                      getattr(result, '_moduleSetUpFailed', False)):
     119                      continue
     120  
     121              if not debug:
     122                  test(result)
     123              else:
     124                  test.debug()
     125  
     126              if self._cleanup:
     127                  self._removeTestAtIndex(index)
     128  
     129          if topLevel:
     130              self._tearDownPreviousClass(None, result)
     131              self._handleModuleTearDown(result)
     132              result._testRunEntered = False
     133          return result
     134  
     135      def debug(self):
     136          """Run the tests without collecting errors in a TestResult"""
     137          debug = _DebugResult()
     138          self.run(debug, True)
     139  
     140      ################################
     141  
     142      def _handleClassSetUp(self, test, result):
     143          previousClass = getattr(result, '_previousTestClass', None)
     144          currentClass = test.__class__
     145          if currentClass == previousClass:
     146              return
     147          if result._moduleSetUpFailed:
     148              return
     149          if getattr(currentClass, "__unittest_skip__", False):
     150              return
     151  
     152          failed = False
     153          try:
     154              currentClass._classSetupFailed = False
     155          except TypeError:
     156              # test may actually be a function
     157              # so its class will be a builtin-type
     158              pass
     159  
     160          setUpClass = getattr(currentClass, 'setUpClass', None)
     161          doClassCleanups = getattr(currentClass, 'doClassCleanups', None)
     162          if setUpClass is not None:
     163              _call_if_exists(result, '_setupStdout')
     164              try:
     165                  try:
     166                      setUpClass()
     167                  except Exception as e:
     168                      if isinstance(result, _DebugResult):
     169                          raise
     170                      failed = True
     171                      try:
     172                          currentClass._classSetupFailed = True
     173                      except TypeError:
     174                          pass
     175                      className = util.strclass(currentClass)
     176                      self._createClassOrModuleLevelException(result, e,
     177                                                              'setUpClass',
     178                                                              className)
     179                  if failed and doClassCleanups is not None:
     180                      doClassCleanups()
     181                      for exc_info in currentClass.tearDown_exceptions:
     182                          self._createClassOrModuleLevelException(
     183                                  result, exc_info[1], 'setUpClass', className,
     184                                  info=exc_info)
     185              finally:
     186                  _call_if_exists(result, '_restoreStdout')
     187  
     188      def _get_previous_module(self, result):
     189          previousModule = None
     190          previousClass = getattr(result, '_previousTestClass', None)
     191          if previousClass is not None:
     192              previousModule = previousClass.__module__
     193          return previousModule
     194  
     195  
     196      def _handleModuleFixture(self, test, result):
     197          previousModule = self._get_previous_module(result)
     198          currentModule = test.__class__.__module__
     199          if currentModule == previousModule:
     200              return
     201  
     202          self._handleModuleTearDown(result)
     203  
     204  
     205          result._moduleSetUpFailed = False
     206          try:
     207              module = sys.modules[currentModule]
     208          except KeyError:
     209              return
     210          setUpModule = getattr(module, 'setUpModule', None)
     211          if setUpModule is not None:
     212              _call_if_exists(result, '_setupStdout')
     213              try:
     214                  try:
     215                      setUpModule()
     216                  except Exception as e:
     217                      if isinstance(result, _DebugResult):
     218                          raise
     219                      result._moduleSetUpFailed = True
     220                      self._createClassOrModuleLevelException(result, e,
     221                                                              'setUpModule',
     222                                                              currentModule)
     223                  if result._moduleSetUpFailed:
     224                      try:
     225                          case.doModuleCleanups()
     226                      except Exception as e:
     227                          self._createClassOrModuleLevelException(result, e,
     228                                                                  'setUpModule',
     229                                                                  currentModule)
     230              finally:
     231                  _call_if_exists(result, '_restoreStdout')
     232  
     233      def _createClassOrModuleLevelException(self, result, exc, method_name,
     234                                             parent, info=None):
     235          errorName = f'{method_name} ({parent})'
     236          self._addClassOrModuleLevelException(result, exc, errorName, info)
     237  
     238      def _addClassOrModuleLevelException(self, result, exception, errorName,
     239                                          info=None):
     240          error = _ErrorHolder(errorName)
     241          addSkip = getattr(result, 'addSkip', None)
     242          if addSkip is not None and isinstance(exception, case.SkipTest):
     243              addSkip(error, str(exception))
     244          else:
     245              if not info:
     246                  result.addError(error, sys.exc_info())
     247              else:
     248                  result.addError(error, info)
     249  
     250      def _handleModuleTearDown(self, result):
     251          previousModule = self._get_previous_module(result)
     252          if previousModule is None:
     253              return
     254          if result._moduleSetUpFailed:
     255              return
     256  
     257          try:
     258              module = sys.modules[previousModule]
     259          except KeyError:
     260              return
     261  
     262          _call_if_exists(result, '_setupStdout')
     263          try:
     264              tearDownModule = getattr(module, 'tearDownModule', None)
     265              if tearDownModule is not None:
     266                  try:
     267                      tearDownModule()
     268                  except Exception as e:
     269                      if isinstance(result, _DebugResult):
     270                          raise
     271                      self._createClassOrModuleLevelException(result, e,
     272                                                              'tearDownModule',
     273                                                              previousModule)
     274              try:
     275                  case.doModuleCleanups()
     276              except Exception as e:
     277                  if isinstance(result, _DebugResult):
     278                      raise
     279                  self._createClassOrModuleLevelException(result, e,
     280                                                          'tearDownModule',
     281                                                          previousModule)
     282          finally:
     283              _call_if_exists(result, '_restoreStdout')
     284  
     285      def _tearDownPreviousClass(self, test, result):
     286          previousClass = getattr(result, '_previousTestClass', None)
     287          currentClass = test.__class__
     288          if currentClass == previousClass or previousClass is None:
     289              return
     290          if getattr(previousClass, '_classSetupFailed', False):
     291              return
     292          if getattr(result, '_moduleSetUpFailed', False):
     293              return
     294          if getattr(previousClass, "__unittest_skip__", False):
     295              return
     296  
     297          tearDownClass = getattr(previousClass, 'tearDownClass', None)
     298          doClassCleanups = getattr(previousClass, 'doClassCleanups', None)
     299          if tearDownClass is None and doClassCleanups is None:
     300              return
     301  
     302          _call_if_exists(result, '_setupStdout')
     303          try:
     304              if tearDownClass is not None:
     305                  try:
     306                      tearDownClass()
     307                  except Exception as e:
     308                      if isinstance(result, _DebugResult):
     309                          raise
     310                      className = util.strclass(previousClass)
     311                      self._createClassOrModuleLevelException(result, e,
     312                                                              'tearDownClass',
     313                                                              className)
     314              if doClassCleanups is not None:
     315                  doClassCleanups()
     316                  for exc_info in previousClass.tearDown_exceptions:
     317                      if isinstance(result, _DebugResult):
     318                          raise exc_info[1]
     319                      className = util.strclass(previousClass)
     320                      self._createClassOrModuleLevelException(result, exc_info[1],
     321                                                              'tearDownClass',
     322                                                              className,
     323                                                              info=exc_info)
     324          finally:
     325              _call_if_exists(result, '_restoreStdout')
     326  
     327  
     328  class ESC[4;38;5;81m_ErrorHolder(ESC[4;38;5;149mobject):
     329      """
     330      Placeholder for a TestCase inside a result. As far as a TestResult
     331      is concerned, this looks exactly like a unit test. Used to insert
     332      arbitrary errors into a test suite run.
     333      """
     334      # Inspired by the ErrorHolder from Twisted:
     335      # http://twistedmatrix.com/trac/browser/trunk/twisted/trial/runner.py
     336  
     337      # attribute used by TestResult._exc_info_to_string
     338      failureException = None
     339  
     340      def __init__(self, description):
     341          self.description = description
     342  
     343      def id(self):
     344          return self.description
     345  
     346      def shortDescription(self):
     347          return None
     348  
     349      def __repr__(self):
     350          return "<ErrorHolder description=%r>" % (self.description,)
     351  
     352      def __str__(self):
     353          return self.id()
     354  
     355      def run(self, result):
     356          # could call result.addError(...) - but this test-like object
     357          # shouldn't be run anyway
     358          pass
     359  
     360      def __call__(self, result):
     361          return self.run(result)
     362  
     363      def countTestCases(self):
     364          return 0
     365  
     366  def _isnotsuite(test):
     367      "A crude way to tell apart testcases and suites with duck-typing"
     368      try:
     369          iter(test)
     370      except TypeError:
     371          return True
     372      return False
     373  
     374  
     375  class ESC[4;38;5;81m_DebugResult(ESC[4;38;5;149mobject):
     376      "Used by the TestSuite to hold previous class when running in debug."
     377      _previousTestClass = None
     378      _moduleSetUpFailed = False
     379      shouldStop = False