17db96d56Sopenharmony_ci"""TestSuite""" 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ciimport sys 47db96d56Sopenharmony_ci 57db96d56Sopenharmony_cifrom . import case 67db96d56Sopenharmony_cifrom . import util 77db96d56Sopenharmony_ci 87db96d56Sopenharmony_ci__unittest = True 97db96d56Sopenharmony_ci 107db96d56Sopenharmony_ci 117db96d56Sopenharmony_cidef _call_if_exists(parent, attr): 127db96d56Sopenharmony_ci func = getattr(parent, attr, lambda: None) 137db96d56Sopenharmony_ci func() 147db96d56Sopenharmony_ci 157db96d56Sopenharmony_ci 167db96d56Sopenharmony_ciclass BaseTestSuite(object): 177db96d56Sopenharmony_ci """A simple test suite that doesn't provide class or module shared fixtures. 187db96d56Sopenharmony_ci """ 197db96d56Sopenharmony_ci _cleanup = True 207db96d56Sopenharmony_ci 217db96d56Sopenharmony_ci def __init__(self, tests=()): 227db96d56Sopenharmony_ci self._tests = [] 237db96d56Sopenharmony_ci self._removed_tests = 0 247db96d56Sopenharmony_ci self.addTests(tests) 257db96d56Sopenharmony_ci 267db96d56Sopenharmony_ci def __repr__(self): 277db96d56Sopenharmony_ci return "<%s tests=%s>" % (util.strclass(self.__class__), list(self)) 287db96d56Sopenharmony_ci 297db96d56Sopenharmony_ci def __eq__(self, other): 307db96d56Sopenharmony_ci if not isinstance(other, self.__class__): 317db96d56Sopenharmony_ci return NotImplemented 327db96d56Sopenharmony_ci return list(self) == list(other) 337db96d56Sopenharmony_ci 347db96d56Sopenharmony_ci def __iter__(self): 357db96d56Sopenharmony_ci return iter(self._tests) 367db96d56Sopenharmony_ci 377db96d56Sopenharmony_ci def countTestCases(self): 387db96d56Sopenharmony_ci cases = self._removed_tests 397db96d56Sopenharmony_ci for test in self: 407db96d56Sopenharmony_ci if test: 417db96d56Sopenharmony_ci cases += test.countTestCases() 427db96d56Sopenharmony_ci return cases 437db96d56Sopenharmony_ci 447db96d56Sopenharmony_ci def addTest(self, test): 457db96d56Sopenharmony_ci # sanity checks 467db96d56Sopenharmony_ci if not callable(test): 477db96d56Sopenharmony_ci raise TypeError("{} is not callable".format(repr(test))) 487db96d56Sopenharmony_ci if isinstance(test, type) and issubclass(test, 497db96d56Sopenharmony_ci (case.TestCase, TestSuite)): 507db96d56Sopenharmony_ci raise TypeError("TestCases and TestSuites must be instantiated " 517db96d56Sopenharmony_ci "before passing them to addTest()") 527db96d56Sopenharmony_ci self._tests.append(test) 537db96d56Sopenharmony_ci 547db96d56Sopenharmony_ci def addTests(self, tests): 557db96d56Sopenharmony_ci if isinstance(tests, str): 567db96d56Sopenharmony_ci raise TypeError("tests must be an iterable of tests, not a string") 577db96d56Sopenharmony_ci for test in tests: 587db96d56Sopenharmony_ci self.addTest(test) 597db96d56Sopenharmony_ci 607db96d56Sopenharmony_ci def run(self, result): 617db96d56Sopenharmony_ci for index, test in enumerate(self): 627db96d56Sopenharmony_ci if result.shouldStop: 637db96d56Sopenharmony_ci break 647db96d56Sopenharmony_ci test(result) 657db96d56Sopenharmony_ci if self._cleanup: 667db96d56Sopenharmony_ci self._removeTestAtIndex(index) 677db96d56Sopenharmony_ci return result 687db96d56Sopenharmony_ci 697db96d56Sopenharmony_ci def _removeTestAtIndex(self, index): 707db96d56Sopenharmony_ci """Stop holding a reference to the TestCase at index.""" 717db96d56Sopenharmony_ci try: 727db96d56Sopenharmony_ci test = self._tests[index] 737db96d56Sopenharmony_ci except TypeError: 747db96d56Sopenharmony_ci # support for suite implementations that have overridden self._tests 757db96d56Sopenharmony_ci pass 767db96d56Sopenharmony_ci else: 777db96d56Sopenharmony_ci # Some unittest tests add non TestCase/TestSuite objects to 787db96d56Sopenharmony_ci # the suite. 797db96d56Sopenharmony_ci if hasattr(test, 'countTestCases'): 807db96d56Sopenharmony_ci self._removed_tests += test.countTestCases() 817db96d56Sopenharmony_ci self._tests[index] = None 827db96d56Sopenharmony_ci 837db96d56Sopenharmony_ci def __call__(self, *args, **kwds): 847db96d56Sopenharmony_ci return self.run(*args, **kwds) 857db96d56Sopenharmony_ci 867db96d56Sopenharmony_ci def debug(self): 877db96d56Sopenharmony_ci """Run the tests without collecting errors in a TestResult""" 887db96d56Sopenharmony_ci for test in self: 897db96d56Sopenharmony_ci test.debug() 907db96d56Sopenharmony_ci 917db96d56Sopenharmony_ci 927db96d56Sopenharmony_ciclass TestSuite(BaseTestSuite): 937db96d56Sopenharmony_ci """A test suite is a composite test consisting of a number of TestCases. 947db96d56Sopenharmony_ci 957db96d56Sopenharmony_ci For use, create an instance of TestSuite, then add test case instances. 967db96d56Sopenharmony_ci When all tests have been added, the suite can be passed to a test 977db96d56Sopenharmony_ci runner, such as TextTestRunner. It will run the individual test cases 987db96d56Sopenharmony_ci in the order in which they were added, aggregating the results. When 997db96d56Sopenharmony_ci subclassing, do not forget to call the base class constructor. 1007db96d56Sopenharmony_ci """ 1017db96d56Sopenharmony_ci 1027db96d56Sopenharmony_ci def run(self, result, debug=False): 1037db96d56Sopenharmony_ci topLevel = False 1047db96d56Sopenharmony_ci if getattr(result, '_testRunEntered', False) is False: 1057db96d56Sopenharmony_ci result._testRunEntered = topLevel = True 1067db96d56Sopenharmony_ci 1077db96d56Sopenharmony_ci for index, test in enumerate(self): 1087db96d56Sopenharmony_ci if result.shouldStop: 1097db96d56Sopenharmony_ci break 1107db96d56Sopenharmony_ci 1117db96d56Sopenharmony_ci if _isnotsuite(test): 1127db96d56Sopenharmony_ci self._tearDownPreviousClass(test, result) 1137db96d56Sopenharmony_ci self._handleModuleFixture(test, result) 1147db96d56Sopenharmony_ci self._handleClassSetUp(test, result) 1157db96d56Sopenharmony_ci result._previousTestClass = test.__class__ 1167db96d56Sopenharmony_ci 1177db96d56Sopenharmony_ci if (getattr(test.__class__, '_classSetupFailed', False) or 1187db96d56Sopenharmony_ci getattr(result, '_moduleSetUpFailed', False)): 1197db96d56Sopenharmony_ci continue 1207db96d56Sopenharmony_ci 1217db96d56Sopenharmony_ci if not debug: 1227db96d56Sopenharmony_ci test(result) 1237db96d56Sopenharmony_ci else: 1247db96d56Sopenharmony_ci test.debug() 1257db96d56Sopenharmony_ci 1267db96d56Sopenharmony_ci if self._cleanup: 1277db96d56Sopenharmony_ci self._removeTestAtIndex(index) 1287db96d56Sopenharmony_ci 1297db96d56Sopenharmony_ci if topLevel: 1307db96d56Sopenharmony_ci self._tearDownPreviousClass(None, result) 1317db96d56Sopenharmony_ci self._handleModuleTearDown(result) 1327db96d56Sopenharmony_ci result._testRunEntered = False 1337db96d56Sopenharmony_ci return result 1347db96d56Sopenharmony_ci 1357db96d56Sopenharmony_ci def debug(self): 1367db96d56Sopenharmony_ci """Run the tests without collecting errors in a TestResult""" 1377db96d56Sopenharmony_ci debug = _DebugResult() 1387db96d56Sopenharmony_ci self.run(debug, True) 1397db96d56Sopenharmony_ci 1407db96d56Sopenharmony_ci ################################ 1417db96d56Sopenharmony_ci 1427db96d56Sopenharmony_ci def _handleClassSetUp(self, test, result): 1437db96d56Sopenharmony_ci previousClass = getattr(result, '_previousTestClass', None) 1447db96d56Sopenharmony_ci currentClass = test.__class__ 1457db96d56Sopenharmony_ci if currentClass == previousClass: 1467db96d56Sopenharmony_ci return 1477db96d56Sopenharmony_ci if result._moduleSetUpFailed: 1487db96d56Sopenharmony_ci return 1497db96d56Sopenharmony_ci if getattr(currentClass, "__unittest_skip__", False): 1507db96d56Sopenharmony_ci return 1517db96d56Sopenharmony_ci 1527db96d56Sopenharmony_ci failed = False 1537db96d56Sopenharmony_ci try: 1547db96d56Sopenharmony_ci currentClass._classSetupFailed = False 1557db96d56Sopenharmony_ci except TypeError: 1567db96d56Sopenharmony_ci # test may actually be a function 1577db96d56Sopenharmony_ci # so its class will be a builtin-type 1587db96d56Sopenharmony_ci pass 1597db96d56Sopenharmony_ci 1607db96d56Sopenharmony_ci setUpClass = getattr(currentClass, 'setUpClass', None) 1617db96d56Sopenharmony_ci doClassCleanups = getattr(currentClass, 'doClassCleanups', None) 1627db96d56Sopenharmony_ci if setUpClass is not None: 1637db96d56Sopenharmony_ci _call_if_exists(result, '_setupStdout') 1647db96d56Sopenharmony_ci try: 1657db96d56Sopenharmony_ci try: 1667db96d56Sopenharmony_ci setUpClass() 1677db96d56Sopenharmony_ci except Exception as e: 1687db96d56Sopenharmony_ci if isinstance(result, _DebugResult): 1697db96d56Sopenharmony_ci raise 1707db96d56Sopenharmony_ci failed = True 1717db96d56Sopenharmony_ci try: 1727db96d56Sopenharmony_ci currentClass._classSetupFailed = True 1737db96d56Sopenharmony_ci except TypeError: 1747db96d56Sopenharmony_ci pass 1757db96d56Sopenharmony_ci className = util.strclass(currentClass) 1767db96d56Sopenharmony_ci self._createClassOrModuleLevelException(result, e, 1777db96d56Sopenharmony_ci 'setUpClass', 1787db96d56Sopenharmony_ci className) 1797db96d56Sopenharmony_ci if failed and doClassCleanups is not None: 1807db96d56Sopenharmony_ci doClassCleanups() 1817db96d56Sopenharmony_ci for exc_info in currentClass.tearDown_exceptions: 1827db96d56Sopenharmony_ci self._createClassOrModuleLevelException( 1837db96d56Sopenharmony_ci result, exc_info[1], 'setUpClass', className, 1847db96d56Sopenharmony_ci info=exc_info) 1857db96d56Sopenharmony_ci finally: 1867db96d56Sopenharmony_ci _call_if_exists(result, '_restoreStdout') 1877db96d56Sopenharmony_ci 1887db96d56Sopenharmony_ci def _get_previous_module(self, result): 1897db96d56Sopenharmony_ci previousModule = None 1907db96d56Sopenharmony_ci previousClass = getattr(result, '_previousTestClass', None) 1917db96d56Sopenharmony_ci if previousClass is not None: 1927db96d56Sopenharmony_ci previousModule = previousClass.__module__ 1937db96d56Sopenharmony_ci return previousModule 1947db96d56Sopenharmony_ci 1957db96d56Sopenharmony_ci 1967db96d56Sopenharmony_ci def _handleModuleFixture(self, test, result): 1977db96d56Sopenharmony_ci previousModule = self._get_previous_module(result) 1987db96d56Sopenharmony_ci currentModule = test.__class__.__module__ 1997db96d56Sopenharmony_ci if currentModule == previousModule: 2007db96d56Sopenharmony_ci return 2017db96d56Sopenharmony_ci 2027db96d56Sopenharmony_ci self._handleModuleTearDown(result) 2037db96d56Sopenharmony_ci 2047db96d56Sopenharmony_ci 2057db96d56Sopenharmony_ci result._moduleSetUpFailed = False 2067db96d56Sopenharmony_ci try: 2077db96d56Sopenharmony_ci module = sys.modules[currentModule] 2087db96d56Sopenharmony_ci except KeyError: 2097db96d56Sopenharmony_ci return 2107db96d56Sopenharmony_ci setUpModule = getattr(module, 'setUpModule', None) 2117db96d56Sopenharmony_ci if setUpModule is not None: 2127db96d56Sopenharmony_ci _call_if_exists(result, '_setupStdout') 2137db96d56Sopenharmony_ci try: 2147db96d56Sopenharmony_ci try: 2157db96d56Sopenharmony_ci setUpModule() 2167db96d56Sopenharmony_ci except Exception as e: 2177db96d56Sopenharmony_ci if isinstance(result, _DebugResult): 2187db96d56Sopenharmony_ci raise 2197db96d56Sopenharmony_ci result._moduleSetUpFailed = True 2207db96d56Sopenharmony_ci self._createClassOrModuleLevelException(result, e, 2217db96d56Sopenharmony_ci 'setUpModule', 2227db96d56Sopenharmony_ci currentModule) 2237db96d56Sopenharmony_ci if result._moduleSetUpFailed: 2247db96d56Sopenharmony_ci try: 2257db96d56Sopenharmony_ci case.doModuleCleanups() 2267db96d56Sopenharmony_ci except Exception as e: 2277db96d56Sopenharmony_ci self._createClassOrModuleLevelException(result, e, 2287db96d56Sopenharmony_ci 'setUpModule', 2297db96d56Sopenharmony_ci currentModule) 2307db96d56Sopenharmony_ci finally: 2317db96d56Sopenharmony_ci _call_if_exists(result, '_restoreStdout') 2327db96d56Sopenharmony_ci 2337db96d56Sopenharmony_ci def _createClassOrModuleLevelException(self, result, exc, method_name, 2347db96d56Sopenharmony_ci parent, info=None): 2357db96d56Sopenharmony_ci errorName = f'{method_name} ({parent})' 2367db96d56Sopenharmony_ci self._addClassOrModuleLevelException(result, exc, errorName, info) 2377db96d56Sopenharmony_ci 2387db96d56Sopenharmony_ci def _addClassOrModuleLevelException(self, result, exception, errorName, 2397db96d56Sopenharmony_ci info=None): 2407db96d56Sopenharmony_ci error = _ErrorHolder(errorName) 2417db96d56Sopenharmony_ci addSkip = getattr(result, 'addSkip', None) 2427db96d56Sopenharmony_ci if addSkip is not None and isinstance(exception, case.SkipTest): 2437db96d56Sopenharmony_ci addSkip(error, str(exception)) 2447db96d56Sopenharmony_ci else: 2457db96d56Sopenharmony_ci if not info: 2467db96d56Sopenharmony_ci result.addError(error, sys.exc_info()) 2477db96d56Sopenharmony_ci else: 2487db96d56Sopenharmony_ci result.addError(error, info) 2497db96d56Sopenharmony_ci 2507db96d56Sopenharmony_ci def _handleModuleTearDown(self, result): 2517db96d56Sopenharmony_ci previousModule = self._get_previous_module(result) 2527db96d56Sopenharmony_ci if previousModule is None: 2537db96d56Sopenharmony_ci return 2547db96d56Sopenharmony_ci if result._moduleSetUpFailed: 2557db96d56Sopenharmony_ci return 2567db96d56Sopenharmony_ci 2577db96d56Sopenharmony_ci try: 2587db96d56Sopenharmony_ci module = sys.modules[previousModule] 2597db96d56Sopenharmony_ci except KeyError: 2607db96d56Sopenharmony_ci return 2617db96d56Sopenharmony_ci 2627db96d56Sopenharmony_ci _call_if_exists(result, '_setupStdout') 2637db96d56Sopenharmony_ci try: 2647db96d56Sopenharmony_ci tearDownModule = getattr(module, 'tearDownModule', None) 2657db96d56Sopenharmony_ci if tearDownModule is not None: 2667db96d56Sopenharmony_ci try: 2677db96d56Sopenharmony_ci tearDownModule() 2687db96d56Sopenharmony_ci except Exception as e: 2697db96d56Sopenharmony_ci if isinstance(result, _DebugResult): 2707db96d56Sopenharmony_ci raise 2717db96d56Sopenharmony_ci self._createClassOrModuleLevelException(result, e, 2727db96d56Sopenharmony_ci 'tearDownModule', 2737db96d56Sopenharmony_ci previousModule) 2747db96d56Sopenharmony_ci try: 2757db96d56Sopenharmony_ci case.doModuleCleanups() 2767db96d56Sopenharmony_ci except Exception as e: 2777db96d56Sopenharmony_ci if isinstance(result, _DebugResult): 2787db96d56Sopenharmony_ci raise 2797db96d56Sopenharmony_ci self._createClassOrModuleLevelException(result, e, 2807db96d56Sopenharmony_ci 'tearDownModule', 2817db96d56Sopenharmony_ci previousModule) 2827db96d56Sopenharmony_ci finally: 2837db96d56Sopenharmony_ci _call_if_exists(result, '_restoreStdout') 2847db96d56Sopenharmony_ci 2857db96d56Sopenharmony_ci def _tearDownPreviousClass(self, test, result): 2867db96d56Sopenharmony_ci previousClass = getattr(result, '_previousTestClass', None) 2877db96d56Sopenharmony_ci currentClass = test.__class__ 2887db96d56Sopenharmony_ci if currentClass == previousClass or previousClass is None: 2897db96d56Sopenharmony_ci return 2907db96d56Sopenharmony_ci if getattr(previousClass, '_classSetupFailed', False): 2917db96d56Sopenharmony_ci return 2927db96d56Sopenharmony_ci if getattr(result, '_moduleSetUpFailed', False): 2937db96d56Sopenharmony_ci return 2947db96d56Sopenharmony_ci if getattr(previousClass, "__unittest_skip__", False): 2957db96d56Sopenharmony_ci return 2967db96d56Sopenharmony_ci 2977db96d56Sopenharmony_ci tearDownClass = getattr(previousClass, 'tearDownClass', None) 2987db96d56Sopenharmony_ci doClassCleanups = getattr(previousClass, 'doClassCleanups', None) 2997db96d56Sopenharmony_ci if tearDownClass is None and doClassCleanups is None: 3007db96d56Sopenharmony_ci return 3017db96d56Sopenharmony_ci 3027db96d56Sopenharmony_ci _call_if_exists(result, '_setupStdout') 3037db96d56Sopenharmony_ci try: 3047db96d56Sopenharmony_ci if tearDownClass is not None: 3057db96d56Sopenharmony_ci try: 3067db96d56Sopenharmony_ci tearDownClass() 3077db96d56Sopenharmony_ci except Exception as e: 3087db96d56Sopenharmony_ci if isinstance(result, _DebugResult): 3097db96d56Sopenharmony_ci raise 3107db96d56Sopenharmony_ci className = util.strclass(previousClass) 3117db96d56Sopenharmony_ci self._createClassOrModuleLevelException(result, e, 3127db96d56Sopenharmony_ci 'tearDownClass', 3137db96d56Sopenharmony_ci className) 3147db96d56Sopenharmony_ci if doClassCleanups is not None: 3157db96d56Sopenharmony_ci doClassCleanups() 3167db96d56Sopenharmony_ci for exc_info in previousClass.tearDown_exceptions: 3177db96d56Sopenharmony_ci if isinstance(result, _DebugResult): 3187db96d56Sopenharmony_ci raise exc_info[1] 3197db96d56Sopenharmony_ci className = util.strclass(previousClass) 3207db96d56Sopenharmony_ci self._createClassOrModuleLevelException(result, exc_info[1], 3217db96d56Sopenharmony_ci 'tearDownClass', 3227db96d56Sopenharmony_ci className, 3237db96d56Sopenharmony_ci info=exc_info) 3247db96d56Sopenharmony_ci finally: 3257db96d56Sopenharmony_ci _call_if_exists(result, '_restoreStdout') 3267db96d56Sopenharmony_ci 3277db96d56Sopenharmony_ci 3287db96d56Sopenharmony_ciclass _ErrorHolder(object): 3297db96d56Sopenharmony_ci """ 3307db96d56Sopenharmony_ci Placeholder for a TestCase inside a result. As far as a TestResult 3317db96d56Sopenharmony_ci is concerned, this looks exactly like a unit test. Used to insert 3327db96d56Sopenharmony_ci arbitrary errors into a test suite run. 3337db96d56Sopenharmony_ci """ 3347db96d56Sopenharmony_ci # Inspired by the ErrorHolder from Twisted: 3357db96d56Sopenharmony_ci # http://twistedmatrix.com/trac/browser/trunk/twisted/trial/runner.py 3367db96d56Sopenharmony_ci 3377db96d56Sopenharmony_ci # attribute used by TestResult._exc_info_to_string 3387db96d56Sopenharmony_ci failureException = None 3397db96d56Sopenharmony_ci 3407db96d56Sopenharmony_ci def __init__(self, description): 3417db96d56Sopenharmony_ci self.description = description 3427db96d56Sopenharmony_ci 3437db96d56Sopenharmony_ci def id(self): 3447db96d56Sopenharmony_ci return self.description 3457db96d56Sopenharmony_ci 3467db96d56Sopenharmony_ci def shortDescription(self): 3477db96d56Sopenharmony_ci return None 3487db96d56Sopenharmony_ci 3497db96d56Sopenharmony_ci def __repr__(self): 3507db96d56Sopenharmony_ci return "<ErrorHolder description=%r>" % (self.description,) 3517db96d56Sopenharmony_ci 3527db96d56Sopenharmony_ci def __str__(self): 3537db96d56Sopenharmony_ci return self.id() 3547db96d56Sopenharmony_ci 3557db96d56Sopenharmony_ci def run(self, result): 3567db96d56Sopenharmony_ci # could call result.addError(...) - but this test-like object 3577db96d56Sopenharmony_ci # shouldn't be run anyway 3587db96d56Sopenharmony_ci pass 3597db96d56Sopenharmony_ci 3607db96d56Sopenharmony_ci def __call__(self, result): 3617db96d56Sopenharmony_ci return self.run(result) 3627db96d56Sopenharmony_ci 3637db96d56Sopenharmony_ci def countTestCases(self): 3647db96d56Sopenharmony_ci return 0 3657db96d56Sopenharmony_ci 3667db96d56Sopenharmony_cidef _isnotsuite(test): 3677db96d56Sopenharmony_ci "A crude way to tell apart testcases and suites with duck-typing" 3687db96d56Sopenharmony_ci try: 3697db96d56Sopenharmony_ci iter(test) 3707db96d56Sopenharmony_ci except TypeError: 3717db96d56Sopenharmony_ci return True 3727db96d56Sopenharmony_ci return False 3737db96d56Sopenharmony_ci 3747db96d56Sopenharmony_ci 3757db96d56Sopenharmony_ciclass _DebugResult(object): 3767db96d56Sopenharmony_ci "Used by the TestSuite to hold previous class when running in debug." 3777db96d56Sopenharmony_ci _previousTestClass = None 3787db96d56Sopenharmony_ci _moduleSetUpFailed = False 3797db96d56Sopenharmony_ci shouldStop = False 380