xref: /third_party/python/Lib/test/test_trace.py (revision 7db96d56)
17db96d56Sopenharmony_ciimport os
27db96d56Sopenharmony_cifrom pickle import dump
37db96d56Sopenharmony_ciimport sys
47db96d56Sopenharmony_cifrom test.support import captured_stdout
57db96d56Sopenharmony_cifrom test.support.os_helper import (TESTFN, rmtree, unlink)
67db96d56Sopenharmony_cifrom test.support.script_helper import assert_python_ok, assert_python_failure
77db96d56Sopenharmony_ciimport textwrap
87db96d56Sopenharmony_ciimport unittest
97db96d56Sopenharmony_ci
107db96d56Sopenharmony_ciimport trace
117db96d56Sopenharmony_cifrom trace import Trace
127db96d56Sopenharmony_ci
137db96d56Sopenharmony_cifrom test.tracedmodules import testmod
147db96d56Sopenharmony_ci
157db96d56Sopenharmony_ci##
167db96d56Sopenharmony_ci## See also test_sys_settrace.py, which contains tests that cover
177db96d56Sopenharmony_ci## tracing of many more code blocks.
187db96d56Sopenharmony_ci##
197db96d56Sopenharmony_ci
207db96d56Sopenharmony_ci#------------------------------- Utilities -----------------------------------#
217db96d56Sopenharmony_ci
227db96d56Sopenharmony_cidef fix_ext_py(filename):
237db96d56Sopenharmony_ci    """Given a .pyc filename converts it to the appropriate .py"""
247db96d56Sopenharmony_ci    if filename.endswith('.pyc'):
257db96d56Sopenharmony_ci        filename = filename[:-1]
267db96d56Sopenharmony_ci    return filename
277db96d56Sopenharmony_ci
287db96d56Sopenharmony_cidef my_file_and_modname():
297db96d56Sopenharmony_ci    """The .py file and module name of this file (__file__)"""
307db96d56Sopenharmony_ci    modname = os.path.splitext(os.path.basename(__file__))[0]
317db96d56Sopenharmony_ci    return fix_ext_py(__file__), modname
327db96d56Sopenharmony_ci
337db96d56Sopenharmony_cidef get_firstlineno(func):
347db96d56Sopenharmony_ci    return func.__code__.co_firstlineno
357db96d56Sopenharmony_ci
367db96d56Sopenharmony_ci#-------------------- Target functions for tracing ---------------------------#
377db96d56Sopenharmony_ci#
387db96d56Sopenharmony_ci# The relative line numbers of lines in these functions matter for verifying
397db96d56Sopenharmony_ci# tracing. Please modify the appropriate tests if you change one of the
407db96d56Sopenharmony_ci# functions. Absolute line numbers don't matter.
417db96d56Sopenharmony_ci#
427db96d56Sopenharmony_ci
437db96d56Sopenharmony_cidef traced_func_linear(x, y):
447db96d56Sopenharmony_ci    a = x
457db96d56Sopenharmony_ci    b = y
467db96d56Sopenharmony_ci    c = a + b
477db96d56Sopenharmony_ci    return c
487db96d56Sopenharmony_ci
497db96d56Sopenharmony_cidef traced_func_loop(x, y):
507db96d56Sopenharmony_ci    c = x
517db96d56Sopenharmony_ci    for i in range(5):
527db96d56Sopenharmony_ci        c += y
537db96d56Sopenharmony_ci    return c
547db96d56Sopenharmony_ci
557db96d56Sopenharmony_cidef traced_func_importing(x, y):
567db96d56Sopenharmony_ci    return x + y + testmod.func(1)
577db96d56Sopenharmony_ci
587db96d56Sopenharmony_cidef traced_func_simple_caller(x):
597db96d56Sopenharmony_ci    c = traced_func_linear(x, x)
607db96d56Sopenharmony_ci    return c + x
617db96d56Sopenharmony_ci
627db96d56Sopenharmony_cidef traced_func_importing_caller(x):
637db96d56Sopenharmony_ci    k = traced_func_simple_caller(x)
647db96d56Sopenharmony_ci    k += traced_func_importing(k, x)
657db96d56Sopenharmony_ci    return k
667db96d56Sopenharmony_ci
677db96d56Sopenharmony_cidef traced_func_generator(num):
687db96d56Sopenharmony_ci    c = 5       # executed once
697db96d56Sopenharmony_ci    for i in range(num):
707db96d56Sopenharmony_ci        yield i + c
717db96d56Sopenharmony_ci
727db96d56Sopenharmony_cidef traced_func_calling_generator():
737db96d56Sopenharmony_ci    k = 0
747db96d56Sopenharmony_ci    for i in traced_func_generator(10):
757db96d56Sopenharmony_ci        k += i
767db96d56Sopenharmony_ci
777db96d56Sopenharmony_cidef traced_doubler(num):
787db96d56Sopenharmony_ci    return num * 2
797db96d56Sopenharmony_ci
807db96d56Sopenharmony_cidef traced_capturer(*args, **kwargs):
817db96d56Sopenharmony_ci    return args, kwargs
827db96d56Sopenharmony_ci
837db96d56Sopenharmony_cidef traced_caller_list_comprehension():
847db96d56Sopenharmony_ci    k = 10
857db96d56Sopenharmony_ci    mylist = [traced_doubler(i) for i in range(k)]
867db96d56Sopenharmony_ci    return mylist
877db96d56Sopenharmony_ci
887db96d56Sopenharmony_cidef traced_decorated_function():
897db96d56Sopenharmony_ci    def decorator1(f):
907db96d56Sopenharmony_ci        return f
917db96d56Sopenharmony_ci    def decorator_fabric():
927db96d56Sopenharmony_ci        def decorator2(f):
937db96d56Sopenharmony_ci            return f
947db96d56Sopenharmony_ci        return decorator2
957db96d56Sopenharmony_ci    @decorator1
967db96d56Sopenharmony_ci    @decorator_fabric()
977db96d56Sopenharmony_ci    def func():
987db96d56Sopenharmony_ci        pass
997db96d56Sopenharmony_ci    func()
1007db96d56Sopenharmony_ci
1017db96d56Sopenharmony_ci
1027db96d56Sopenharmony_ciclass TracedClass(object):
1037db96d56Sopenharmony_ci    def __init__(self, x):
1047db96d56Sopenharmony_ci        self.a = x
1057db96d56Sopenharmony_ci
1067db96d56Sopenharmony_ci    def inst_method_linear(self, y):
1077db96d56Sopenharmony_ci        return self.a + y
1087db96d56Sopenharmony_ci
1097db96d56Sopenharmony_ci    def inst_method_calling(self, x):
1107db96d56Sopenharmony_ci        c = self.inst_method_linear(x)
1117db96d56Sopenharmony_ci        return c + traced_func_linear(x, c)
1127db96d56Sopenharmony_ci
1137db96d56Sopenharmony_ci    @classmethod
1147db96d56Sopenharmony_ci    def class_method_linear(cls, y):
1157db96d56Sopenharmony_ci        return y * 2
1167db96d56Sopenharmony_ci
1177db96d56Sopenharmony_ci    @staticmethod
1187db96d56Sopenharmony_ci    def static_method_linear(y):
1197db96d56Sopenharmony_ci        return y * 2
1207db96d56Sopenharmony_ci
1217db96d56Sopenharmony_ci
1227db96d56Sopenharmony_ci#------------------------------ Test cases -----------------------------------#
1237db96d56Sopenharmony_ci
1247db96d56Sopenharmony_ci
1257db96d56Sopenharmony_ciclass TestLineCounts(unittest.TestCase):
1267db96d56Sopenharmony_ci    """White-box testing of line-counting, via runfunc"""
1277db96d56Sopenharmony_ci    def setUp(self):
1287db96d56Sopenharmony_ci        self.addCleanup(sys.settrace, sys.gettrace())
1297db96d56Sopenharmony_ci        self.tracer = Trace(count=1, trace=0, countfuncs=0, countcallers=0)
1307db96d56Sopenharmony_ci        self.my_py_filename = fix_ext_py(__file__)
1317db96d56Sopenharmony_ci
1327db96d56Sopenharmony_ci    def test_traced_func_linear(self):
1337db96d56Sopenharmony_ci        result = self.tracer.runfunc(traced_func_linear, 2, 5)
1347db96d56Sopenharmony_ci        self.assertEqual(result, 7)
1357db96d56Sopenharmony_ci
1367db96d56Sopenharmony_ci        # all lines are executed once
1377db96d56Sopenharmony_ci        expected = {}
1387db96d56Sopenharmony_ci        firstlineno = get_firstlineno(traced_func_linear)
1397db96d56Sopenharmony_ci        for i in range(1, 5):
1407db96d56Sopenharmony_ci            expected[(self.my_py_filename, firstlineno +  i)] = 1
1417db96d56Sopenharmony_ci
1427db96d56Sopenharmony_ci        self.assertEqual(self.tracer.results().counts, expected)
1437db96d56Sopenharmony_ci
1447db96d56Sopenharmony_ci    def test_traced_func_loop(self):
1457db96d56Sopenharmony_ci        self.tracer.runfunc(traced_func_loop, 2, 3)
1467db96d56Sopenharmony_ci
1477db96d56Sopenharmony_ci        firstlineno = get_firstlineno(traced_func_loop)
1487db96d56Sopenharmony_ci        expected = {
1497db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno + 1): 1,
1507db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno + 2): 6,
1517db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno + 3): 5,
1527db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno + 4): 1,
1537db96d56Sopenharmony_ci        }
1547db96d56Sopenharmony_ci        self.assertEqual(self.tracer.results().counts, expected)
1557db96d56Sopenharmony_ci
1567db96d56Sopenharmony_ci    def test_traced_func_importing(self):
1577db96d56Sopenharmony_ci        self.tracer.runfunc(traced_func_importing, 2, 5)
1587db96d56Sopenharmony_ci
1597db96d56Sopenharmony_ci        firstlineno = get_firstlineno(traced_func_importing)
1607db96d56Sopenharmony_ci        expected = {
1617db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno + 1): 1,
1627db96d56Sopenharmony_ci            (fix_ext_py(testmod.__file__), 2): 1,
1637db96d56Sopenharmony_ci            (fix_ext_py(testmod.__file__), 3): 1,
1647db96d56Sopenharmony_ci        }
1657db96d56Sopenharmony_ci
1667db96d56Sopenharmony_ci        self.assertEqual(self.tracer.results().counts, expected)
1677db96d56Sopenharmony_ci
1687db96d56Sopenharmony_ci    def test_trace_func_generator(self):
1697db96d56Sopenharmony_ci        self.tracer.runfunc(traced_func_calling_generator)
1707db96d56Sopenharmony_ci
1717db96d56Sopenharmony_ci        firstlineno_calling = get_firstlineno(traced_func_calling_generator)
1727db96d56Sopenharmony_ci        firstlineno_gen = get_firstlineno(traced_func_generator)
1737db96d56Sopenharmony_ci        expected = {
1747db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno_calling + 1): 1,
1757db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno_calling + 2): 11,
1767db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno_calling + 3): 10,
1777db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno_gen + 1): 1,
1787db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno_gen + 2): 11,
1797db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno_gen + 3): 10,
1807db96d56Sopenharmony_ci        }
1817db96d56Sopenharmony_ci        self.assertEqual(self.tracer.results().counts, expected)
1827db96d56Sopenharmony_ci
1837db96d56Sopenharmony_ci    def test_trace_list_comprehension(self):
1847db96d56Sopenharmony_ci        self.tracer.runfunc(traced_caller_list_comprehension)
1857db96d56Sopenharmony_ci
1867db96d56Sopenharmony_ci        firstlineno_calling = get_firstlineno(traced_caller_list_comprehension)
1877db96d56Sopenharmony_ci        firstlineno_called = get_firstlineno(traced_doubler)
1887db96d56Sopenharmony_ci        expected = {
1897db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno_calling + 1): 1,
1907db96d56Sopenharmony_ci            # List comprehensions work differently in 3.x, so the count
1917db96d56Sopenharmony_ci            # below changed compared to 2.x.
1927db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno_calling + 2): 12,
1937db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno_calling + 3): 1,
1947db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno_called + 1): 10,
1957db96d56Sopenharmony_ci        }
1967db96d56Sopenharmony_ci        self.assertEqual(self.tracer.results().counts, expected)
1977db96d56Sopenharmony_ci
1987db96d56Sopenharmony_ci    def test_traced_decorated_function(self):
1997db96d56Sopenharmony_ci        self.tracer.runfunc(traced_decorated_function)
2007db96d56Sopenharmony_ci
2017db96d56Sopenharmony_ci        firstlineno = get_firstlineno(traced_decorated_function)
2027db96d56Sopenharmony_ci        expected = {
2037db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno + 1): 1,
2047db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno + 2): 1,
2057db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno + 3): 1,
2067db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno + 4): 1,
2077db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno + 5): 1,
2087db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno + 6): 1,
2097db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno + 7): 2,
2107db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno + 8): 2,
2117db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno + 9): 2,
2127db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno + 10): 1,
2137db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno + 11): 1,
2147db96d56Sopenharmony_ci        }
2157db96d56Sopenharmony_ci        self.assertEqual(self.tracer.results().counts, expected)
2167db96d56Sopenharmony_ci
2177db96d56Sopenharmony_ci    def test_linear_methods(self):
2187db96d56Sopenharmony_ci        # XXX todo: later add 'static_method_linear' and 'class_method_linear'
2197db96d56Sopenharmony_ci        # here, once issue1764286 is resolved
2207db96d56Sopenharmony_ci        #
2217db96d56Sopenharmony_ci        for methname in ['inst_method_linear',]:
2227db96d56Sopenharmony_ci            tracer = Trace(count=1, trace=0, countfuncs=0, countcallers=0)
2237db96d56Sopenharmony_ci            traced_obj = TracedClass(25)
2247db96d56Sopenharmony_ci            method = getattr(traced_obj, methname)
2257db96d56Sopenharmony_ci            tracer.runfunc(method, 20)
2267db96d56Sopenharmony_ci
2277db96d56Sopenharmony_ci            firstlineno = get_firstlineno(method)
2287db96d56Sopenharmony_ci            expected = {
2297db96d56Sopenharmony_ci                (self.my_py_filename, firstlineno + 1): 1,
2307db96d56Sopenharmony_ci            }
2317db96d56Sopenharmony_ci            self.assertEqual(tracer.results().counts, expected)
2327db96d56Sopenharmony_ci
2337db96d56Sopenharmony_ci
2347db96d56Sopenharmony_ciclass TestRunExecCounts(unittest.TestCase):
2357db96d56Sopenharmony_ci    """A simple sanity test of line-counting, via runctx (exec)"""
2367db96d56Sopenharmony_ci    def setUp(self):
2377db96d56Sopenharmony_ci        self.my_py_filename = fix_ext_py(__file__)
2387db96d56Sopenharmony_ci        self.addCleanup(sys.settrace, sys.gettrace())
2397db96d56Sopenharmony_ci
2407db96d56Sopenharmony_ci    def test_exec_counts(self):
2417db96d56Sopenharmony_ci        self.tracer = Trace(count=1, trace=0, countfuncs=0, countcallers=0)
2427db96d56Sopenharmony_ci        code = r'''traced_func_loop(2, 5)'''
2437db96d56Sopenharmony_ci        code = compile(code, __file__, 'exec')
2447db96d56Sopenharmony_ci        self.tracer.runctx(code, globals(), vars())
2457db96d56Sopenharmony_ci
2467db96d56Sopenharmony_ci        firstlineno = get_firstlineno(traced_func_loop)
2477db96d56Sopenharmony_ci        expected = {
2487db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno + 1): 1,
2497db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno + 2): 6,
2507db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno + 3): 5,
2517db96d56Sopenharmony_ci            (self.my_py_filename, firstlineno + 4): 1,
2527db96d56Sopenharmony_ci        }
2537db96d56Sopenharmony_ci
2547db96d56Sopenharmony_ci        # When used through 'run', some other spurious counts are produced, like
2557db96d56Sopenharmony_ci        # the settrace of threading, which we ignore, just making sure that the
2567db96d56Sopenharmony_ci        # counts fo traced_func_loop were right.
2577db96d56Sopenharmony_ci        #
2587db96d56Sopenharmony_ci        for k in expected.keys():
2597db96d56Sopenharmony_ci            self.assertEqual(self.tracer.results().counts[k], expected[k])
2607db96d56Sopenharmony_ci
2617db96d56Sopenharmony_ci
2627db96d56Sopenharmony_ciclass TestFuncs(unittest.TestCase):
2637db96d56Sopenharmony_ci    """White-box testing of funcs tracing"""
2647db96d56Sopenharmony_ci    def setUp(self):
2657db96d56Sopenharmony_ci        self.addCleanup(sys.settrace, sys.gettrace())
2667db96d56Sopenharmony_ci        self.tracer = Trace(count=0, trace=0, countfuncs=1)
2677db96d56Sopenharmony_ci        self.filemod = my_file_and_modname()
2687db96d56Sopenharmony_ci        self._saved_tracefunc = sys.gettrace()
2697db96d56Sopenharmony_ci
2707db96d56Sopenharmony_ci    def tearDown(self):
2717db96d56Sopenharmony_ci        if self._saved_tracefunc is not None:
2727db96d56Sopenharmony_ci            sys.settrace(self._saved_tracefunc)
2737db96d56Sopenharmony_ci
2747db96d56Sopenharmony_ci    def test_simple_caller(self):
2757db96d56Sopenharmony_ci        self.tracer.runfunc(traced_func_simple_caller, 1)
2767db96d56Sopenharmony_ci
2777db96d56Sopenharmony_ci        expected = {
2787db96d56Sopenharmony_ci            self.filemod + ('traced_func_simple_caller',): 1,
2797db96d56Sopenharmony_ci            self.filemod + ('traced_func_linear',): 1,
2807db96d56Sopenharmony_ci        }
2817db96d56Sopenharmony_ci        self.assertEqual(self.tracer.results().calledfuncs, expected)
2827db96d56Sopenharmony_ci
2837db96d56Sopenharmony_ci    def test_arg_errors(self):
2847db96d56Sopenharmony_ci        res = self.tracer.runfunc(traced_capturer, 1, 2, self=3, func=4)
2857db96d56Sopenharmony_ci        self.assertEqual(res, ((1, 2), {'self': 3, 'func': 4}))
2867db96d56Sopenharmony_ci        with self.assertRaises(TypeError):
2877db96d56Sopenharmony_ci            self.tracer.runfunc(func=traced_capturer, arg=1)
2887db96d56Sopenharmony_ci        with self.assertRaises(TypeError):
2897db96d56Sopenharmony_ci            self.tracer.runfunc()
2907db96d56Sopenharmony_ci
2917db96d56Sopenharmony_ci    def test_loop_caller_importing(self):
2927db96d56Sopenharmony_ci        self.tracer.runfunc(traced_func_importing_caller, 1)
2937db96d56Sopenharmony_ci
2947db96d56Sopenharmony_ci        expected = {
2957db96d56Sopenharmony_ci            self.filemod + ('traced_func_simple_caller',): 1,
2967db96d56Sopenharmony_ci            self.filemod + ('traced_func_linear',): 1,
2977db96d56Sopenharmony_ci            self.filemod + ('traced_func_importing_caller',): 1,
2987db96d56Sopenharmony_ci            self.filemod + ('traced_func_importing',): 1,
2997db96d56Sopenharmony_ci            (fix_ext_py(testmod.__file__), 'testmod', 'func'): 1,
3007db96d56Sopenharmony_ci        }
3017db96d56Sopenharmony_ci        self.assertEqual(self.tracer.results().calledfuncs, expected)
3027db96d56Sopenharmony_ci
3037db96d56Sopenharmony_ci    @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
3047db96d56Sopenharmony_ci                     'pre-existing trace function throws off measurements')
3057db96d56Sopenharmony_ci    def test_inst_method_calling(self):
3067db96d56Sopenharmony_ci        obj = TracedClass(20)
3077db96d56Sopenharmony_ci        self.tracer.runfunc(obj.inst_method_calling, 1)
3087db96d56Sopenharmony_ci
3097db96d56Sopenharmony_ci        expected = {
3107db96d56Sopenharmony_ci            self.filemod + ('TracedClass.inst_method_calling',): 1,
3117db96d56Sopenharmony_ci            self.filemod + ('TracedClass.inst_method_linear',): 1,
3127db96d56Sopenharmony_ci            self.filemod + ('traced_func_linear',): 1,
3137db96d56Sopenharmony_ci        }
3147db96d56Sopenharmony_ci        self.assertEqual(self.tracer.results().calledfuncs, expected)
3157db96d56Sopenharmony_ci
3167db96d56Sopenharmony_ci    def test_traced_decorated_function(self):
3177db96d56Sopenharmony_ci        self.tracer.runfunc(traced_decorated_function)
3187db96d56Sopenharmony_ci
3197db96d56Sopenharmony_ci        expected = {
3207db96d56Sopenharmony_ci            self.filemod + ('traced_decorated_function',): 1,
3217db96d56Sopenharmony_ci            self.filemod + ('decorator_fabric',): 1,
3227db96d56Sopenharmony_ci            self.filemod + ('decorator2',): 1,
3237db96d56Sopenharmony_ci            self.filemod + ('decorator1',): 1,
3247db96d56Sopenharmony_ci            self.filemod + ('func',): 1,
3257db96d56Sopenharmony_ci        }
3267db96d56Sopenharmony_ci        self.assertEqual(self.tracer.results().calledfuncs, expected)
3277db96d56Sopenharmony_ci
3287db96d56Sopenharmony_ci
3297db96d56Sopenharmony_ciclass TestCallers(unittest.TestCase):
3307db96d56Sopenharmony_ci    """White-box testing of callers tracing"""
3317db96d56Sopenharmony_ci    def setUp(self):
3327db96d56Sopenharmony_ci        self.addCleanup(sys.settrace, sys.gettrace())
3337db96d56Sopenharmony_ci        self.tracer = Trace(count=0, trace=0, countcallers=1)
3347db96d56Sopenharmony_ci        self.filemod = my_file_and_modname()
3357db96d56Sopenharmony_ci
3367db96d56Sopenharmony_ci    @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
3377db96d56Sopenharmony_ci                     'pre-existing trace function throws off measurements')
3387db96d56Sopenharmony_ci    def test_loop_caller_importing(self):
3397db96d56Sopenharmony_ci        self.tracer.runfunc(traced_func_importing_caller, 1)
3407db96d56Sopenharmony_ci
3417db96d56Sopenharmony_ci        expected = {
3427db96d56Sopenharmony_ci            ((os.path.splitext(trace.__file__)[0] + '.py', 'trace', 'Trace.runfunc'),
3437db96d56Sopenharmony_ci                (self.filemod + ('traced_func_importing_caller',))): 1,
3447db96d56Sopenharmony_ci            ((self.filemod + ('traced_func_simple_caller',)),
3457db96d56Sopenharmony_ci                (self.filemod + ('traced_func_linear',))): 1,
3467db96d56Sopenharmony_ci            ((self.filemod + ('traced_func_importing_caller',)),
3477db96d56Sopenharmony_ci                (self.filemod + ('traced_func_simple_caller',))): 1,
3487db96d56Sopenharmony_ci            ((self.filemod + ('traced_func_importing_caller',)),
3497db96d56Sopenharmony_ci                (self.filemod + ('traced_func_importing',))): 1,
3507db96d56Sopenharmony_ci            ((self.filemod + ('traced_func_importing',)),
3517db96d56Sopenharmony_ci                (fix_ext_py(testmod.__file__), 'testmod', 'func')): 1,
3527db96d56Sopenharmony_ci        }
3537db96d56Sopenharmony_ci        self.assertEqual(self.tracer.results().callers, expected)
3547db96d56Sopenharmony_ci
3557db96d56Sopenharmony_ci
3567db96d56Sopenharmony_ci# Created separately for issue #3821
3577db96d56Sopenharmony_ciclass TestCoverage(unittest.TestCase):
3587db96d56Sopenharmony_ci    def setUp(self):
3597db96d56Sopenharmony_ci        self.addCleanup(sys.settrace, sys.gettrace())
3607db96d56Sopenharmony_ci
3617db96d56Sopenharmony_ci    def tearDown(self):
3627db96d56Sopenharmony_ci        rmtree(TESTFN)
3637db96d56Sopenharmony_ci        unlink(TESTFN)
3647db96d56Sopenharmony_ci
3657db96d56Sopenharmony_ci    def _coverage(self, tracer,
3667db96d56Sopenharmony_ci                  cmd='import test.support, test.test_pprint;'
3677db96d56Sopenharmony_ci                      'test.support.run_unittest(test.test_pprint.QueryTestCase)'):
3687db96d56Sopenharmony_ci        tracer.run(cmd)
3697db96d56Sopenharmony_ci        r = tracer.results()
3707db96d56Sopenharmony_ci        r.write_results(show_missing=True, summary=True, coverdir=TESTFN)
3717db96d56Sopenharmony_ci
3727db96d56Sopenharmony_ci    def test_coverage(self):
3737db96d56Sopenharmony_ci        tracer = trace.Trace(trace=0, count=1)
3747db96d56Sopenharmony_ci        with captured_stdout() as stdout:
3757db96d56Sopenharmony_ci            self._coverage(tracer)
3767db96d56Sopenharmony_ci        stdout = stdout.getvalue()
3777db96d56Sopenharmony_ci        self.assertIn("pprint.py", stdout)
3787db96d56Sopenharmony_ci        self.assertIn("case.py", stdout)   # from unittest
3797db96d56Sopenharmony_ci        files = os.listdir(TESTFN)
3807db96d56Sopenharmony_ci        self.assertIn("pprint.cover", files)
3817db96d56Sopenharmony_ci        self.assertIn("unittest.case.cover", files)
3827db96d56Sopenharmony_ci
3837db96d56Sopenharmony_ci    def test_coverage_ignore(self):
3847db96d56Sopenharmony_ci        # Ignore all files, nothing should be traced nor printed
3857db96d56Sopenharmony_ci        libpath = os.path.normpath(os.path.dirname(os.path.dirname(__file__)))
3867db96d56Sopenharmony_ci        # sys.prefix does not work when running from a checkout
3877db96d56Sopenharmony_ci        tracer = trace.Trace(ignoredirs=[sys.base_prefix, sys.base_exec_prefix,
3887db96d56Sopenharmony_ci                             libpath], trace=0, count=1)
3897db96d56Sopenharmony_ci        with captured_stdout() as stdout:
3907db96d56Sopenharmony_ci            self._coverage(tracer)
3917db96d56Sopenharmony_ci        if os.path.exists(TESTFN):
3927db96d56Sopenharmony_ci            files = os.listdir(TESTFN)
3937db96d56Sopenharmony_ci            self.assertEqual(files, ['_importlib.cover'])  # Ignore __import__
3947db96d56Sopenharmony_ci
3957db96d56Sopenharmony_ci    def test_issue9936(self):
3967db96d56Sopenharmony_ci        tracer = trace.Trace(trace=0, count=1)
3977db96d56Sopenharmony_ci        modname = 'test.tracedmodules.testmod'
3987db96d56Sopenharmony_ci        # Ensure that the module is executed in import
3997db96d56Sopenharmony_ci        if modname in sys.modules:
4007db96d56Sopenharmony_ci            del sys.modules[modname]
4017db96d56Sopenharmony_ci        cmd = ("import test.tracedmodules.testmod as t;"
4027db96d56Sopenharmony_ci               "t.func(0); t.func2();")
4037db96d56Sopenharmony_ci        with captured_stdout() as stdout:
4047db96d56Sopenharmony_ci            self._coverage(tracer, cmd)
4057db96d56Sopenharmony_ci        stdout.seek(0)
4067db96d56Sopenharmony_ci        stdout.readline()
4077db96d56Sopenharmony_ci        coverage = {}
4087db96d56Sopenharmony_ci        for line in stdout:
4097db96d56Sopenharmony_ci            lines, cov, module = line.split()[:3]
4107db96d56Sopenharmony_ci            coverage[module] = (int(lines), int(cov[:-1]))
4117db96d56Sopenharmony_ci        # XXX This is needed to run regrtest.py as a script
4127db96d56Sopenharmony_ci        modname = trace._fullmodname(sys.modules[modname].__file__)
4137db96d56Sopenharmony_ci        self.assertIn(modname, coverage)
4147db96d56Sopenharmony_ci        self.assertEqual(coverage[modname], (5, 100))
4157db96d56Sopenharmony_ci
4167db96d56Sopenharmony_ci    def test_coverageresults_update(self):
4177db96d56Sopenharmony_ci        # Update empty CoverageResults with a non-empty infile.
4187db96d56Sopenharmony_ci        infile = TESTFN + '-infile'
4197db96d56Sopenharmony_ci        with open(infile, 'wb') as f:
4207db96d56Sopenharmony_ci            dump(({}, {}, {'caller': 1}), f, protocol=1)
4217db96d56Sopenharmony_ci        self.addCleanup(unlink, infile)
4227db96d56Sopenharmony_ci        results = trace.CoverageResults({}, {}, infile, {})
4237db96d56Sopenharmony_ci        self.assertEqual(results.callers, {'caller': 1})
4247db96d56Sopenharmony_ci
4257db96d56Sopenharmony_ci### Tests that don't mess with sys.settrace and can be traced
4267db96d56Sopenharmony_ci### themselves TODO: Skip tests that do mess with sys.settrace when
4277db96d56Sopenharmony_ci### regrtest is invoked with -T option.
4287db96d56Sopenharmony_ciclass Test_Ignore(unittest.TestCase):
4297db96d56Sopenharmony_ci    def test_ignored(self):
4307db96d56Sopenharmony_ci        jn = os.path.join
4317db96d56Sopenharmony_ci        ignore = trace._Ignore(['x', 'y.z'], [jn('foo', 'bar')])
4327db96d56Sopenharmony_ci        self.assertTrue(ignore.names('x.py', 'x'))
4337db96d56Sopenharmony_ci        self.assertFalse(ignore.names('xy.py', 'xy'))
4347db96d56Sopenharmony_ci        self.assertFalse(ignore.names('y.py', 'y'))
4357db96d56Sopenharmony_ci        self.assertTrue(ignore.names(jn('foo', 'bar', 'baz.py'), 'baz'))
4367db96d56Sopenharmony_ci        self.assertFalse(ignore.names(jn('bar', 'z.py'), 'z'))
4377db96d56Sopenharmony_ci        # Matched before.
4387db96d56Sopenharmony_ci        self.assertTrue(ignore.names(jn('bar', 'baz.py'), 'baz'))
4397db96d56Sopenharmony_ci
4407db96d56Sopenharmony_ci# Created for Issue 31908 -- CLI utility not writing cover files
4417db96d56Sopenharmony_ciclass TestCoverageCommandLineOutput(unittest.TestCase):
4427db96d56Sopenharmony_ci
4437db96d56Sopenharmony_ci    codefile = 'tmp.py'
4447db96d56Sopenharmony_ci    coverfile = 'tmp.cover'
4457db96d56Sopenharmony_ci
4467db96d56Sopenharmony_ci    def setUp(self):
4477db96d56Sopenharmony_ci        with open(self.codefile, 'w', encoding='iso-8859-15') as f:
4487db96d56Sopenharmony_ci            f.write(textwrap.dedent('''\
4497db96d56Sopenharmony_ci                # coding: iso-8859-15
4507db96d56Sopenharmony_ci                x = 'spœm'
4517db96d56Sopenharmony_ci                if []:
4527db96d56Sopenharmony_ci                    print('unreachable')
4537db96d56Sopenharmony_ci            '''))
4547db96d56Sopenharmony_ci
4557db96d56Sopenharmony_ci    def tearDown(self):
4567db96d56Sopenharmony_ci        unlink(self.codefile)
4577db96d56Sopenharmony_ci        unlink(self.coverfile)
4587db96d56Sopenharmony_ci
4597db96d56Sopenharmony_ci    def test_cover_files_written_no_highlight(self):
4607db96d56Sopenharmony_ci        # Test also that the cover file for the trace module is not created
4617db96d56Sopenharmony_ci        # (issue #34171).
4627db96d56Sopenharmony_ci        tracedir = os.path.dirname(os.path.abspath(trace.__file__))
4637db96d56Sopenharmony_ci        tracecoverpath = os.path.join(tracedir, 'trace.cover')
4647db96d56Sopenharmony_ci        unlink(tracecoverpath)
4657db96d56Sopenharmony_ci
4667db96d56Sopenharmony_ci        argv = '-m trace --count'.split() + [self.codefile]
4677db96d56Sopenharmony_ci        status, stdout, stderr = assert_python_ok(*argv)
4687db96d56Sopenharmony_ci        self.assertEqual(stderr, b'')
4697db96d56Sopenharmony_ci        self.assertFalse(os.path.exists(tracecoverpath))
4707db96d56Sopenharmony_ci        self.assertTrue(os.path.exists(self.coverfile))
4717db96d56Sopenharmony_ci        with open(self.coverfile, encoding='iso-8859-15') as f:
4727db96d56Sopenharmony_ci            self.assertEqual(f.read(),
4737db96d56Sopenharmony_ci                "       # coding: iso-8859-15\n"
4747db96d56Sopenharmony_ci                "    1: x = 'spœm'\n"
4757db96d56Sopenharmony_ci                "    1: if []:\n"
4767db96d56Sopenharmony_ci                "           print('unreachable')\n"
4777db96d56Sopenharmony_ci            )
4787db96d56Sopenharmony_ci
4797db96d56Sopenharmony_ci    def test_cover_files_written_with_highlight(self):
4807db96d56Sopenharmony_ci        argv = '-m trace --count --missing'.split() + [self.codefile]
4817db96d56Sopenharmony_ci        status, stdout, stderr = assert_python_ok(*argv)
4827db96d56Sopenharmony_ci        self.assertTrue(os.path.exists(self.coverfile))
4837db96d56Sopenharmony_ci        with open(self.coverfile, encoding='iso-8859-15') as f:
4847db96d56Sopenharmony_ci            self.assertEqual(f.read(), textwrap.dedent('''\
4857db96d56Sopenharmony_ci                       # coding: iso-8859-15
4867db96d56Sopenharmony_ci                    1: x = 'spœm'
4877db96d56Sopenharmony_ci                    1: if []:
4887db96d56Sopenharmony_ci                >>>>>>     print('unreachable')
4897db96d56Sopenharmony_ci            '''))
4907db96d56Sopenharmony_ci
4917db96d56Sopenharmony_ciclass TestCommandLine(unittest.TestCase):
4927db96d56Sopenharmony_ci
4937db96d56Sopenharmony_ci    def test_failures(self):
4947db96d56Sopenharmony_ci        _errors = (
4957db96d56Sopenharmony_ci            (b'progname is missing: required with the main options', '-l', '-T'),
4967db96d56Sopenharmony_ci            (b'cannot specify both --listfuncs and (--trace or --count)', '-lc'),
4977db96d56Sopenharmony_ci            (b'argument -R/--no-report: not allowed with argument -r/--report', '-rR'),
4987db96d56Sopenharmony_ci            (b'must specify one of --trace, --count, --report, --listfuncs, or --trackcalls', '-g'),
4997db96d56Sopenharmony_ci            (b'-r/--report requires -f/--file', '-r'),
5007db96d56Sopenharmony_ci            (b'--summary can only be used with --count or --report', '-sT'),
5017db96d56Sopenharmony_ci            (b'unrecognized arguments: -y', '-y'))
5027db96d56Sopenharmony_ci        for message, *args in _errors:
5037db96d56Sopenharmony_ci            *_, stderr = assert_python_failure('-m', 'trace', *args)
5047db96d56Sopenharmony_ci            self.assertIn(message, stderr)
5057db96d56Sopenharmony_ci
5067db96d56Sopenharmony_ci    def test_listfuncs_flag_success(self):
5077db96d56Sopenharmony_ci        filename = TESTFN + '.py'
5087db96d56Sopenharmony_ci        modulename = os.path.basename(TESTFN)
5097db96d56Sopenharmony_ci        with open(filename, 'w', encoding='utf-8') as fd:
5107db96d56Sopenharmony_ci            self.addCleanup(unlink, filename)
5117db96d56Sopenharmony_ci            fd.write("a = 1\n")
5127db96d56Sopenharmony_ci            status, stdout, stderr = assert_python_ok('-m', 'trace', '-l', filename,
5137db96d56Sopenharmony_ci                                                      PYTHONIOENCODING='utf-8')
5147db96d56Sopenharmony_ci            self.assertIn(b'functions called:', stdout)
5157db96d56Sopenharmony_ci            expected = f'filename: {filename}, modulename: {modulename}, funcname: <module>'
5167db96d56Sopenharmony_ci            self.assertIn(expected.encode(), stdout)
5177db96d56Sopenharmony_ci
5187db96d56Sopenharmony_ci    def test_sys_argv_list(self):
5197db96d56Sopenharmony_ci        with open(TESTFN, 'w', encoding='utf-8') as fd:
5207db96d56Sopenharmony_ci            self.addCleanup(unlink, TESTFN)
5217db96d56Sopenharmony_ci            fd.write("import sys\n")
5227db96d56Sopenharmony_ci            fd.write("print(type(sys.argv))\n")
5237db96d56Sopenharmony_ci
5247db96d56Sopenharmony_ci        status, direct_stdout, stderr = assert_python_ok(TESTFN)
5257db96d56Sopenharmony_ci        status, trace_stdout, stderr = assert_python_ok('-m', 'trace', '-l', TESTFN,
5267db96d56Sopenharmony_ci                                                        PYTHONIOENCODING='utf-8')
5277db96d56Sopenharmony_ci        self.assertIn(direct_stdout.strip(), trace_stdout)
5287db96d56Sopenharmony_ci
5297db96d56Sopenharmony_ci    def test_count_and_summary(self):
5307db96d56Sopenharmony_ci        filename = f'{TESTFN}.py'
5317db96d56Sopenharmony_ci        coverfilename = f'{TESTFN}.cover'
5327db96d56Sopenharmony_ci        modulename = os.path.basename(TESTFN)
5337db96d56Sopenharmony_ci        with open(filename, 'w', encoding='utf-8') as fd:
5347db96d56Sopenharmony_ci            self.addCleanup(unlink, filename)
5357db96d56Sopenharmony_ci            self.addCleanup(unlink, coverfilename)
5367db96d56Sopenharmony_ci            fd.write(textwrap.dedent("""\
5377db96d56Sopenharmony_ci                x = 1
5387db96d56Sopenharmony_ci                y = 2
5397db96d56Sopenharmony_ci
5407db96d56Sopenharmony_ci                def f():
5417db96d56Sopenharmony_ci                    return x + y
5427db96d56Sopenharmony_ci
5437db96d56Sopenharmony_ci                for i in range(10):
5447db96d56Sopenharmony_ci                    f()
5457db96d56Sopenharmony_ci            """))
5467db96d56Sopenharmony_ci        status, stdout, _ = assert_python_ok('-m', 'trace', '-cs', filename,
5477db96d56Sopenharmony_ci                                             PYTHONIOENCODING='utf-8')
5487db96d56Sopenharmony_ci        stdout = stdout.decode()
5497db96d56Sopenharmony_ci        self.assertEqual(status, 0)
5507db96d56Sopenharmony_ci        self.assertIn('lines   cov%   module   (path)', stdout)
5517db96d56Sopenharmony_ci        self.assertIn(f'6   100%   {modulename}   ({filename})', stdout)
5527db96d56Sopenharmony_ci
5537db96d56Sopenharmony_ci    def test_run_as_module(self):
5547db96d56Sopenharmony_ci        assert_python_ok('-m', 'trace', '-l', '--module', 'timeit', '-n', '1')
5557db96d56Sopenharmony_ci        assert_python_failure('-m', 'trace', '-l', '--module', 'not_a_module_zzz')
5567db96d56Sopenharmony_ci
5577db96d56Sopenharmony_ci
5587db96d56Sopenharmony_ciif __name__ == '__main__':
5597db96d56Sopenharmony_ci    unittest.main()
560