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