17db96d56Sopenharmony_ciimport faulthandler 27db96d56Sopenharmony_ciimport functools 37db96d56Sopenharmony_ciimport gc 47db96d56Sopenharmony_ciimport importlib 57db96d56Sopenharmony_ciimport io 67db96d56Sopenharmony_ciimport os 77db96d56Sopenharmony_ciimport sys 87db96d56Sopenharmony_ciimport time 97db96d56Sopenharmony_ciimport traceback 107db96d56Sopenharmony_ciimport unittest 117db96d56Sopenharmony_ci 127db96d56Sopenharmony_cifrom test import support 137db96d56Sopenharmony_cifrom test.support import os_helper 147db96d56Sopenharmony_cifrom test.support import threading_helper 157db96d56Sopenharmony_cifrom test.libregrtest.cmdline import Namespace 167db96d56Sopenharmony_cifrom test.libregrtest.save_env import saved_test_environment 177db96d56Sopenharmony_cifrom test.libregrtest.utils import clear_caches, format_duration, print_warning 187db96d56Sopenharmony_ci 197db96d56Sopenharmony_ci 207db96d56Sopenharmony_ciclass TestResult: 217db96d56Sopenharmony_ci def __init__( 227db96d56Sopenharmony_ci self, 237db96d56Sopenharmony_ci name: str, 247db96d56Sopenharmony_ci duration_sec: float = 0.0, 257db96d56Sopenharmony_ci xml_data: list[str] | None = None, 267db96d56Sopenharmony_ci ) -> None: 277db96d56Sopenharmony_ci self.name = name 287db96d56Sopenharmony_ci self.duration_sec = duration_sec 297db96d56Sopenharmony_ci self.xml_data = xml_data 307db96d56Sopenharmony_ci 317db96d56Sopenharmony_ci def __str__(self) -> str: 327db96d56Sopenharmony_ci return f"{self.name} finished" 337db96d56Sopenharmony_ci 347db96d56Sopenharmony_ci 357db96d56Sopenharmony_ciclass Passed(TestResult): 367db96d56Sopenharmony_ci def __str__(self) -> str: 377db96d56Sopenharmony_ci return f"{self.name} passed" 387db96d56Sopenharmony_ci 397db96d56Sopenharmony_ci 407db96d56Sopenharmony_ciclass Failed(TestResult): 417db96d56Sopenharmony_ci def __init__( 427db96d56Sopenharmony_ci self, 437db96d56Sopenharmony_ci name: str, 447db96d56Sopenharmony_ci duration_sec: float = 0.0, 457db96d56Sopenharmony_ci xml_data: list[str] | None = None, 467db96d56Sopenharmony_ci errors: list[tuple[str, str]] | None = None, 477db96d56Sopenharmony_ci failures: list[tuple[str, str]] | None = None, 487db96d56Sopenharmony_ci ) -> None: 497db96d56Sopenharmony_ci super().__init__(name, duration_sec=duration_sec, xml_data=xml_data) 507db96d56Sopenharmony_ci self.errors = errors 517db96d56Sopenharmony_ci self.failures = failures 527db96d56Sopenharmony_ci 537db96d56Sopenharmony_ci def __str__(self) -> str: 547db96d56Sopenharmony_ci if self.errors and self.failures: 557db96d56Sopenharmony_ci le = len(self.errors) 567db96d56Sopenharmony_ci lf = len(self.failures) 577db96d56Sopenharmony_ci error_s = "error" + ("s" if le > 1 else "") 587db96d56Sopenharmony_ci failure_s = "failure" + ("s" if lf > 1 else "") 597db96d56Sopenharmony_ci return f"{self.name} failed ({le} {error_s}, {lf} {failure_s})" 607db96d56Sopenharmony_ci 617db96d56Sopenharmony_ci if self.errors: 627db96d56Sopenharmony_ci le = len(self.errors) 637db96d56Sopenharmony_ci error_s = "error" + ("s" if le > 1 else "") 647db96d56Sopenharmony_ci return f"{self.name} failed ({le} {error_s})" 657db96d56Sopenharmony_ci 667db96d56Sopenharmony_ci if self.failures: 677db96d56Sopenharmony_ci lf = len(self.failures) 687db96d56Sopenharmony_ci failure_s = "failure" + ("s" if lf > 1 else "") 697db96d56Sopenharmony_ci return f"{self.name} failed ({lf} {failure_s})" 707db96d56Sopenharmony_ci 717db96d56Sopenharmony_ci return f"{self.name} failed" 727db96d56Sopenharmony_ci 737db96d56Sopenharmony_ci 747db96d56Sopenharmony_ciclass UncaughtException(Failed): 757db96d56Sopenharmony_ci def __str__(self) -> str: 767db96d56Sopenharmony_ci return f"{self.name} failed (uncaught exception)" 777db96d56Sopenharmony_ci 787db96d56Sopenharmony_ci 797db96d56Sopenharmony_ciclass EnvChanged(Failed): 807db96d56Sopenharmony_ci def __str__(self) -> str: 817db96d56Sopenharmony_ci return f"{self.name} failed (env changed)" 827db96d56Sopenharmony_ci 837db96d56Sopenharmony_ci 847db96d56Sopenharmony_ciclass RefLeak(Failed): 857db96d56Sopenharmony_ci def __str__(self) -> str: 867db96d56Sopenharmony_ci return f"{self.name} failed (reference leak)" 877db96d56Sopenharmony_ci 887db96d56Sopenharmony_ci 897db96d56Sopenharmony_ciclass Skipped(TestResult): 907db96d56Sopenharmony_ci def __str__(self) -> str: 917db96d56Sopenharmony_ci return f"{self.name} skipped" 927db96d56Sopenharmony_ci 937db96d56Sopenharmony_ci 947db96d56Sopenharmony_ciclass ResourceDenied(Skipped): 957db96d56Sopenharmony_ci def __str__(self) -> str: 967db96d56Sopenharmony_ci return f"{self.name} skipped (resource denied)" 977db96d56Sopenharmony_ci 987db96d56Sopenharmony_ci 997db96d56Sopenharmony_ciclass Interrupted(TestResult): 1007db96d56Sopenharmony_ci def __str__(self) -> str: 1017db96d56Sopenharmony_ci return f"{self.name} interrupted" 1027db96d56Sopenharmony_ci 1037db96d56Sopenharmony_ci 1047db96d56Sopenharmony_ciclass ChildError(Failed): 1057db96d56Sopenharmony_ci def __str__(self) -> str: 1067db96d56Sopenharmony_ci return f"{self.name} crashed" 1077db96d56Sopenharmony_ci 1087db96d56Sopenharmony_ci 1097db96d56Sopenharmony_ciclass DidNotRun(TestResult): 1107db96d56Sopenharmony_ci def __str__(self) -> str: 1117db96d56Sopenharmony_ci return f"{self.name} ran no tests" 1127db96d56Sopenharmony_ci 1137db96d56Sopenharmony_ci 1147db96d56Sopenharmony_ciclass Timeout(Failed): 1157db96d56Sopenharmony_ci def __str__(self) -> str: 1167db96d56Sopenharmony_ci return f"{self.name} timed out ({format_duration(self.duration_sec)})" 1177db96d56Sopenharmony_ci 1187db96d56Sopenharmony_ci 1197db96d56Sopenharmony_ci# Minimum duration of a test to display its duration or to mention that 1207db96d56Sopenharmony_ci# the test is running in background 1217db96d56Sopenharmony_ciPROGRESS_MIN_TIME = 30.0 # seconds 1227db96d56Sopenharmony_ci 1237db96d56Sopenharmony_ci# small set of tests to determine if we have a basically functioning interpreter 1247db96d56Sopenharmony_ci# (i.e. if any of these fail, then anything else is likely to follow) 1257db96d56Sopenharmony_ciSTDTESTS = [ 1267db96d56Sopenharmony_ci 'test_grammar', 1277db96d56Sopenharmony_ci 'test_opcodes', 1287db96d56Sopenharmony_ci 'test_dict', 1297db96d56Sopenharmony_ci 'test_builtin', 1307db96d56Sopenharmony_ci 'test_exceptions', 1317db96d56Sopenharmony_ci 'test_types', 1327db96d56Sopenharmony_ci 'test_unittest', 1337db96d56Sopenharmony_ci 'test_doctest', 1347db96d56Sopenharmony_ci 'test_doctest2', 1357db96d56Sopenharmony_ci 'test_support' 1367db96d56Sopenharmony_ci] 1377db96d56Sopenharmony_ci 1387db96d56Sopenharmony_ci# set of tests that we don't want to be executed when using regrtest 1397db96d56Sopenharmony_ciNOTTESTS = set() 1407db96d56Sopenharmony_ci 1417db96d56Sopenharmony_ci 1427db96d56Sopenharmony_ci# Storage of uncollectable objects 1437db96d56Sopenharmony_ciFOUND_GARBAGE = [] 1447db96d56Sopenharmony_ci 1457db96d56Sopenharmony_ci 1467db96d56Sopenharmony_cidef is_failed(result: TestResult, ns: Namespace) -> bool: 1477db96d56Sopenharmony_ci if isinstance(result, EnvChanged): 1487db96d56Sopenharmony_ci return ns.fail_env_changed 1497db96d56Sopenharmony_ci return isinstance(result, Failed) 1507db96d56Sopenharmony_ci 1517db96d56Sopenharmony_ci 1527db96d56Sopenharmony_cidef findtestdir(path=None): 1537db96d56Sopenharmony_ci return path or os.path.dirname(os.path.dirname(__file__)) or os.curdir 1547db96d56Sopenharmony_ci 1557db96d56Sopenharmony_ci 1567db96d56Sopenharmony_cidef findtests(testdir=None, stdtests=STDTESTS, nottests=NOTTESTS): 1577db96d56Sopenharmony_ci """Return a list of all applicable test modules.""" 1587db96d56Sopenharmony_ci testdir = findtestdir(testdir) 1597db96d56Sopenharmony_ci names = os.listdir(testdir) 1607db96d56Sopenharmony_ci tests = [] 1617db96d56Sopenharmony_ci others = set(stdtests) | nottests 1627db96d56Sopenharmony_ci for name in names: 1637db96d56Sopenharmony_ci mod, ext = os.path.splitext(name) 1647db96d56Sopenharmony_ci if mod[:5] == "test_" and ext in (".py", "") and mod not in others: 1657db96d56Sopenharmony_ci tests.append(mod) 1667db96d56Sopenharmony_ci return stdtests + sorted(tests) 1677db96d56Sopenharmony_ci 1687db96d56Sopenharmony_ci 1697db96d56Sopenharmony_cidef get_abs_module(ns: Namespace, test_name: str) -> str: 1707db96d56Sopenharmony_ci if test_name.startswith('test.') or ns.testdir: 1717db96d56Sopenharmony_ci return test_name 1727db96d56Sopenharmony_ci else: 1737db96d56Sopenharmony_ci # Import it from the test package 1747db96d56Sopenharmony_ci return 'test.' + test_name 1757db96d56Sopenharmony_ci 1767db96d56Sopenharmony_ci 1777db96d56Sopenharmony_cidef _runtest(ns: Namespace, test_name: str) -> TestResult: 1787db96d56Sopenharmony_ci # Handle faulthandler timeout, capture stdout+stderr, XML serialization 1797db96d56Sopenharmony_ci # and measure time. 1807db96d56Sopenharmony_ci 1817db96d56Sopenharmony_ci output_on_failure = ns.verbose3 1827db96d56Sopenharmony_ci 1837db96d56Sopenharmony_ci use_timeout = ( 1847db96d56Sopenharmony_ci ns.timeout is not None and threading_helper.can_start_thread 1857db96d56Sopenharmony_ci ) 1867db96d56Sopenharmony_ci if use_timeout: 1877db96d56Sopenharmony_ci faulthandler.dump_traceback_later(ns.timeout, exit=True) 1887db96d56Sopenharmony_ci 1897db96d56Sopenharmony_ci start_time = time.perf_counter() 1907db96d56Sopenharmony_ci try: 1917db96d56Sopenharmony_ci support.set_match_tests(ns.match_tests, ns.ignore_tests) 1927db96d56Sopenharmony_ci support.junit_xml_list = xml_list = [] if ns.xmlpath else None 1937db96d56Sopenharmony_ci if ns.failfast: 1947db96d56Sopenharmony_ci support.failfast = True 1957db96d56Sopenharmony_ci 1967db96d56Sopenharmony_ci if output_on_failure: 1977db96d56Sopenharmony_ci support.verbose = True 1987db96d56Sopenharmony_ci 1997db96d56Sopenharmony_ci stream = io.StringIO() 2007db96d56Sopenharmony_ci orig_stdout = sys.stdout 2017db96d56Sopenharmony_ci orig_stderr = sys.stderr 2027db96d56Sopenharmony_ci print_warning = support.print_warning 2037db96d56Sopenharmony_ci orig_print_warnings_stderr = print_warning.orig_stderr 2047db96d56Sopenharmony_ci 2057db96d56Sopenharmony_ci output = None 2067db96d56Sopenharmony_ci try: 2077db96d56Sopenharmony_ci sys.stdout = stream 2087db96d56Sopenharmony_ci sys.stderr = stream 2097db96d56Sopenharmony_ci # print_warning() writes into the temporary stream to preserve 2107db96d56Sopenharmony_ci # messages order. If support.environment_altered becomes true, 2117db96d56Sopenharmony_ci # warnings will be written to sys.stderr below. 2127db96d56Sopenharmony_ci print_warning.orig_stderr = stream 2137db96d56Sopenharmony_ci 2147db96d56Sopenharmony_ci result = _runtest_inner(ns, test_name, 2157db96d56Sopenharmony_ci display_failure=False) 2167db96d56Sopenharmony_ci if not isinstance(result, Passed): 2177db96d56Sopenharmony_ci output = stream.getvalue() 2187db96d56Sopenharmony_ci finally: 2197db96d56Sopenharmony_ci sys.stdout = orig_stdout 2207db96d56Sopenharmony_ci sys.stderr = orig_stderr 2217db96d56Sopenharmony_ci print_warning.orig_stderr = orig_print_warnings_stderr 2227db96d56Sopenharmony_ci 2237db96d56Sopenharmony_ci if output is not None: 2247db96d56Sopenharmony_ci sys.stderr.write(output) 2257db96d56Sopenharmony_ci sys.stderr.flush() 2267db96d56Sopenharmony_ci else: 2277db96d56Sopenharmony_ci # Tell tests to be moderately quiet 2287db96d56Sopenharmony_ci support.verbose = ns.verbose 2297db96d56Sopenharmony_ci 2307db96d56Sopenharmony_ci result = _runtest_inner(ns, test_name, 2317db96d56Sopenharmony_ci display_failure=not ns.verbose) 2327db96d56Sopenharmony_ci 2337db96d56Sopenharmony_ci if xml_list: 2347db96d56Sopenharmony_ci import xml.etree.ElementTree as ET 2357db96d56Sopenharmony_ci result.xml_data = [ 2367db96d56Sopenharmony_ci ET.tostring(x).decode('us-ascii') 2377db96d56Sopenharmony_ci for x in xml_list 2387db96d56Sopenharmony_ci ] 2397db96d56Sopenharmony_ci 2407db96d56Sopenharmony_ci result.duration_sec = time.perf_counter() - start_time 2417db96d56Sopenharmony_ci return result 2427db96d56Sopenharmony_ci finally: 2437db96d56Sopenharmony_ci if use_timeout: 2447db96d56Sopenharmony_ci faulthandler.cancel_dump_traceback_later() 2457db96d56Sopenharmony_ci support.junit_xml_list = None 2467db96d56Sopenharmony_ci 2477db96d56Sopenharmony_ci 2487db96d56Sopenharmony_cidef runtest(ns: Namespace, test_name: str) -> TestResult: 2497db96d56Sopenharmony_ci """Run a single test. 2507db96d56Sopenharmony_ci 2517db96d56Sopenharmony_ci ns -- regrtest namespace of options 2527db96d56Sopenharmony_ci test_name -- the name of the test 2537db96d56Sopenharmony_ci 2547db96d56Sopenharmony_ci Returns a TestResult sub-class depending on the kind of result received. 2557db96d56Sopenharmony_ci 2567db96d56Sopenharmony_ci If ns.xmlpath is not None, xml_data is a list containing each 2577db96d56Sopenharmony_ci generated testsuite element. 2587db96d56Sopenharmony_ci """ 2597db96d56Sopenharmony_ci try: 2607db96d56Sopenharmony_ci return _runtest(ns, test_name) 2617db96d56Sopenharmony_ci except: 2627db96d56Sopenharmony_ci if not ns.pgo: 2637db96d56Sopenharmony_ci msg = traceback.format_exc() 2647db96d56Sopenharmony_ci print(f"test {test_name} crashed -- {msg}", 2657db96d56Sopenharmony_ci file=sys.stderr, flush=True) 2667db96d56Sopenharmony_ci return Failed(test_name) 2677db96d56Sopenharmony_ci 2687db96d56Sopenharmony_ci 2697db96d56Sopenharmony_cidef _test_module(the_module): 2707db96d56Sopenharmony_ci loader = unittest.TestLoader() 2717db96d56Sopenharmony_ci tests = loader.loadTestsFromModule(the_module) 2727db96d56Sopenharmony_ci for error in loader.errors: 2737db96d56Sopenharmony_ci print(error, file=sys.stderr) 2747db96d56Sopenharmony_ci if loader.errors: 2757db96d56Sopenharmony_ci raise Exception("errors while loading tests") 2767db96d56Sopenharmony_ci support.run_unittest(tests) 2777db96d56Sopenharmony_ci 2787db96d56Sopenharmony_ci 2797db96d56Sopenharmony_cidef save_env(ns: Namespace, test_name: str): 2807db96d56Sopenharmony_ci return saved_test_environment(test_name, ns.verbose, ns.quiet, pgo=ns.pgo) 2817db96d56Sopenharmony_ci 2827db96d56Sopenharmony_ci 2837db96d56Sopenharmony_cidef _runtest_inner2(ns: Namespace, test_name: str) -> bool: 2847db96d56Sopenharmony_ci # Load the test function, run the test function, handle huntrleaks 2857db96d56Sopenharmony_ci # to detect leaks. 2867db96d56Sopenharmony_ci 2877db96d56Sopenharmony_ci abstest = get_abs_module(ns, test_name) 2887db96d56Sopenharmony_ci 2897db96d56Sopenharmony_ci # remove the module from sys.module to reload it if it was already imported 2907db96d56Sopenharmony_ci try: 2917db96d56Sopenharmony_ci del sys.modules[abstest] 2927db96d56Sopenharmony_ci except KeyError: 2937db96d56Sopenharmony_ci pass 2947db96d56Sopenharmony_ci 2957db96d56Sopenharmony_ci the_module = importlib.import_module(abstest) 2967db96d56Sopenharmony_ci 2977db96d56Sopenharmony_ci if ns.huntrleaks: 2987db96d56Sopenharmony_ci from test.libregrtest.refleak import dash_R 2997db96d56Sopenharmony_ci 3007db96d56Sopenharmony_ci # If the test has a test_main, that will run the appropriate 3017db96d56Sopenharmony_ci # tests. If not, use normal unittest test loading. 3027db96d56Sopenharmony_ci test_runner = getattr(the_module, "test_main", None) 3037db96d56Sopenharmony_ci if test_runner is None: 3047db96d56Sopenharmony_ci test_runner = functools.partial(_test_module, the_module) 3057db96d56Sopenharmony_ci 3067db96d56Sopenharmony_ci try: 3077db96d56Sopenharmony_ci with save_env(ns, test_name): 3087db96d56Sopenharmony_ci if ns.huntrleaks: 3097db96d56Sopenharmony_ci # Return True if the test leaked references 3107db96d56Sopenharmony_ci refleak = dash_R(ns, test_name, test_runner) 3117db96d56Sopenharmony_ci else: 3127db96d56Sopenharmony_ci test_runner() 3137db96d56Sopenharmony_ci refleak = False 3147db96d56Sopenharmony_ci finally: 3157db96d56Sopenharmony_ci # First kill any dangling references to open files etc. 3167db96d56Sopenharmony_ci # This can also issue some ResourceWarnings which would otherwise get 3177db96d56Sopenharmony_ci # triggered during the following test run, and possibly produce 3187db96d56Sopenharmony_ci # failures. 3197db96d56Sopenharmony_ci support.gc_collect() 3207db96d56Sopenharmony_ci 3217db96d56Sopenharmony_ci cleanup_test_droppings(test_name, ns.verbose) 3227db96d56Sopenharmony_ci 3237db96d56Sopenharmony_ci if gc.garbage: 3247db96d56Sopenharmony_ci support.environment_altered = True 3257db96d56Sopenharmony_ci print_warning(f"{test_name} created {len(gc.garbage)} " 3267db96d56Sopenharmony_ci f"uncollectable object(s).") 3277db96d56Sopenharmony_ci 3287db96d56Sopenharmony_ci # move the uncollectable objects somewhere, 3297db96d56Sopenharmony_ci # so we don't see them again 3307db96d56Sopenharmony_ci FOUND_GARBAGE.extend(gc.garbage) 3317db96d56Sopenharmony_ci gc.garbage.clear() 3327db96d56Sopenharmony_ci 3337db96d56Sopenharmony_ci support.reap_children() 3347db96d56Sopenharmony_ci 3357db96d56Sopenharmony_ci return refleak 3367db96d56Sopenharmony_ci 3377db96d56Sopenharmony_ci 3387db96d56Sopenharmony_cidef _runtest_inner( 3397db96d56Sopenharmony_ci ns: Namespace, test_name: str, display_failure: bool = True 3407db96d56Sopenharmony_ci) -> TestResult: 3417db96d56Sopenharmony_ci # Detect environment changes, handle exceptions. 3427db96d56Sopenharmony_ci 3437db96d56Sopenharmony_ci # Reset the environment_altered flag to detect if a test altered 3447db96d56Sopenharmony_ci # the environment 3457db96d56Sopenharmony_ci support.environment_altered = False 3467db96d56Sopenharmony_ci 3477db96d56Sopenharmony_ci if ns.pgo: 3487db96d56Sopenharmony_ci display_failure = False 3497db96d56Sopenharmony_ci 3507db96d56Sopenharmony_ci try: 3517db96d56Sopenharmony_ci clear_caches() 3527db96d56Sopenharmony_ci support.gc_collect() 3537db96d56Sopenharmony_ci 3547db96d56Sopenharmony_ci with save_env(ns, test_name): 3557db96d56Sopenharmony_ci refleak = _runtest_inner2(ns, test_name) 3567db96d56Sopenharmony_ci except support.ResourceDenied as msg: 3577db96d56Sopenharmony_ci if not ns.quiet and not ns.pgo: 3587db96d56Sopenharmony_ci print(f"{test_name} skipped -- {msg}", flush=True) 3597db96d56Sopenharmony_ci return ResourceDenied(test_name) 3607db96d56Sopenharmony_ci except unittest.SkipTest as msg: 3617db96d56Sopenharmony_ci if not ns.quiet and not ns.pgo: 3627db96d56Sopenharmony_ci print(f"{test_name} skipped -- {msg}", flush=True) 3637db96d56Sopenharmony_ci return Skipped(test_name) 3647db96d56Sopenharmony_ci except support.TestFailedWithDetails as exc: 3657db96d56Sopenharmony_ci msg = f"test {test_name} failed" 3667db96d56Sopenharmony_ci if display_failure: 3677db96d56Sopenharmony_ci msg = f"{msg} -- {exc}" 3687db96d56Sopenharmony_ci print(msg, file=sys.stderr, flush=True) 3697db96d56Sopenharmony_ci return Failed(test_name, errors=exc.errors, failures=exc.failures) 3707db96d56Sopenharmony_ci except support.TestFailed as exc: 3717db96d56Sopenharmony_ci msg = f"test {test_name} failed" 3727db96d56Sopenharmony_ci if display_failure: 3737db96d56Sopenharmony_ci msg = f"{msg} -- {exc}" 3747db96d56Sopenharmony_ci print(msg, file=sys.stderr, flush=True) 3757db96d56Sopenharmony_ci return Failed(test_name) 3767db96d56Sopenharmony_ci except support.TestDidNotRun: 3777db96d56Sopenharmony_ci return DidNotRun(test_name) 3787db96d56Sopenharmony_ci except KeyboardInterrupt: 3797db96d56Sopenharmony_ci print() 3807db96d56Sopenharmony_ci return Interrupted(test_name) 3817db96d56Sopenharmony_ci except: 3827db96d56Sopenharmony_ci if not ns.pgo: 3837db96d56Sopenharmony_ci msg = traceback.format_exc() 3847db96d56Sopenharmony_ci print(f"test {test_name} crashed -- {msg}", 3857db96d56Sopenharmony_ci file=sys.stderr, flush=True) 3867db96d56Sopenharmony_ci return UncaughtException(test_name) 3877db96d56Sopenharmony_ci 3887db96d56Sopenharmony_ci if refleak: 3897db96d56Sopenharmony_ci return RefLeak(test_name) 3907db96d56Sopenharmony_ci if support.environment_altered: 3917db96d56Sopenharmony_ci return EnvChanged(test_name) 3927db96d56Sopenharmony_ci return Passed(test_name) 3937db96d56Sopenharmony_ci 3947db96d56Sopenharmony_ci 3957db96d56Sopenharmony_cidef cleanup_test_droppings(test_name: str, verbose: int) -> None: 3967db96d56Sopenharmony_ci # Try to clean up junk commonly left behind. While tests shouldn't leave 3977db96d56Sopenharmony_ci # any files or directories behind, when a test fails that can be tedious 3987db96d56Sopenharmony_ci # for it to arrange. The consequences can be especially nasty on Windows, 3997db96d56Sopenharmony_ci # since if a test leaves a file open, it cannot be deleted by name (while 4007db96d56Sopenharmony_ci # there's nothing we can do about that here either, we can display the 4017db96d56Sopenharmony_ci # name of the offending test, which is a real help). 4027db96d56Sopenharmony_ci for name in (os_helper.TESTFN,): 4037db96d56Sopenharmony_ci if not os.path.exists(name): 4047db96d56Sopenharmony_ci continue 4057db96d56Sopenharmony_ci 4067db96d56Sopenharmony_ci if os.path.isdir(name): 4077db96d56Sopenharmony_ci import shutil 4087db96d56Sopenharmony_ci kind, nuker = "directory", shutil.rmtree 4097db96d56Sopenharmony_ci elif os.path.isfile(name): 4107db96d56Sopenharmony_ci kind, nuker = "file", os.unlink 4117db96d56Sopenharmony_ci else: 4127db96d56Sopenharmony_ci raise RuntimeError(f"os.path says {name!r} exists but is neither " 4137db96d56Sopenharmony_ci f"directory nor file") 4147db96d56Sopenharmony_ci 4157db96d56Sopenharmony_ci if verbose: 4167db96d56Sopenharmony_ci print_warning(f"{test_name} left behind {kind} {name!r}") 4177db96d56Sopenharmony_ci support.environment_altered = True 4187db96d56Sopenharmony_ci 4197db96d56Sopenharmony_ci try: 4207db96d56Sopenharmony_ci import stat 4217db96d56Sopenharmony_ci # fix possible permissions problems that might prevent cleanup 4227db96d56Sopenharmony_ci os.chmod(name, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) 4237db96d56Sopenharmony_ci nuker(name) 4247db96d56Sopenharmony_ci except Exception as exc: 4257db96d56Sopenharmony_ci print_warning(f"{test_name} left behind {kind} {name!r} " 4267db96d56Sopenharmony_ci f"and it couldn't be removed: {exc}") 427