summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_trace.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_trace.py')
-rw-r--r--Lib/test/test_trace.py214
1 files changed, 214 insertions, 0 deletions
diff --git a/Lib/test/test_trace.py b/Lib/test/test_trace.py
new file mode 100644
index 0000000..c04be50
--- /dev/null
+++ b/Lib/test/test_trace.py
@@ -0,0 +1,214 @@
+import imp
+import os
+import sys
+from test import test_support
+import unittest
+
+import trace
+from trace import CoverageResults, Trace
+
+
+#------------------------------- Utilities -----------------------------------#
+
+def make_fake_module():
+ """Creates a fake module named 'fakemodule'.
+
+ The new module has a single function named 'foo', and it's placed in
+ sys.modules
+ The file this fake module "comes from" is fakefile.py
+
+ """
+
+ # Prepare the function to import from the fake module
+ #
+ _fake_foo_src = r'''
+def foo(a_):
+ b = a_ + 1
+ return b + 2
+'''.lstrip()
+
+ _fake_foo = compile(_fake_foo_src, 'fakefile.py', 'exec')
+
+ # Create a new module, place the function into it and add it to sys.modules
+ #
+ fakemodule = imp.new_module('fakemodule')
+ exec _fake_foo in fakemodule.__dict__
+ fakemodule.__file__ = 'fakefile.py'
+ sys.modules['fakemodule'] = fakemodule
+
+
+def modname(filename):
+ """Infer a module name from a containing file name"""
+ base = os.path.basename(filename)
+ mod, ext = os.path.splitext(base)
+ return mod
+
+
+def my_file_and_modname():
+ """The file and module name of this file (__file__)"""
+ return __file__, modname(__file__)
+
+
+#-------------------- Target functions for tracing ---------------------------#
+
+def _traced_func_linear(a_, b_):
+ a = a_
+ b = b_
+ c = a + b
+ return c
+
+def _traced_func_loop(a_, b_):
+ c = a_
+ for i in range(5):
+ c += b_
+ return c
+
+# Expects the 'fakemodule' module to exist and have a 'foo' function in it
+#
+def _traced_func_importing(a_, b_):
+ from fakemodule import foo
+ return a_ + b_ + foo(1)
+
+def _traced_func_simple_caller(a_):
+ c = _traced_func_linear(a_, a_)
+ return c + a_
+
+def _traced_func_importing_caller(a_):
+ k = _traced_func_simple_caller(a_)
+ k += _traced_func_importing(k, a_)
+ return k
+
+
+#------------------------------ Test cases -----------------------------------#
+
+
+class TestLineCounts(unittest.TestCase):
+ """White-box testing of line-counting, via runfunc"""
+ def setUp(self):
+ self.tr = Trace(count=1, trace=0, countfuncs=0, countcallers=0)
+
+ def test_traced_func_linear(self):
+ result = self.tr.runfunc(_traced_func_linear, 2, 5)
+ self.assertEqual(result, 7)
+
+ # all lines are executed once
+ expected = {}
+ firstlineno = _traced_func_linear.__code__.co_firstlineno
+ for i in range(1, 5):
+ expected[(__file__, firstlineno + i)] = 1
+
+ self.assertEqual(self.tr.results().counts, expected)
+
+ def test_traced_func_loop(self):
+ self.tr.runfunc(_traced_func_loop, 2, 3)
+
+ firstlineno = _traced_func_loop.__code__.co_firstlineno
+ expected = {
+ (__file__, firstlineno + 1): 1,
+ (__file__, firstlineno + 2): 6,
+ (__file__, firstlineno + 3): 5,
+ (__file__, firstlineno + 4): 1,
+ }
+ self.assertEqual(self.tr.results().counts, expected)
+
+ def test_traced_func_importing(self):
+ make_fake_module()
+ self.tr.runfunc(_traced_func_importing, 2, 5)
+
+ firstlineno = _traced_func_importing.__code__.co_firstlineno
+ expected = {
+ (__file__, firstlineno + 1): 1,
+ (__file__, firstlineno + 2): 1,
+ ('fakefile.py', 2): 1,
+ ('fakefile.py', 3): 1,
+ }
+ self.assertEqual(self.tr.results().counts, expected)
+
+
+class TestRunExecCounts(unittest.TestCase):
+ """A simple sanity test of line-counting, via run (exec)"""
+ def test_tt(self):
+ self.tr = Trace(count=1, trace=0, countfuncs=0, countcallers=0)
+ code = r'''_traced_func_loop(2, 5)'''
+ code = compile(code, __file__, 'exec')
+ self.tr.run(code)
+
+ firstlineno = _traced_func_loop.__code__.co_firstlineno
+ expected = {
+ (__file__, firstlineno + 1): 1,
+ (__file__, firstlineno + 2): 6,
+ (__file__, firstlineno + 3): 5,
+ (__file__, firstlineno + 4): 1,
+ }
+
+ # When used through 'run', some other spurios counts are produced, like
+ # the settrace of threading, which we ignore, just making sure that the
+ # counts fo _traced_func_loop were right.
+ #
+ for k in expected.keys():
+ self.assertEqual(self.tr.results().counts[k], expected[k])
+
+
+class TestFuncs(unittest.TestCase):
+ """White-box testing of funcs tracing"""
+ def setUp(self):
+ self.tr = Trace(count=0, trace=0, countfuncs=1)
+ self.filemod = my_file_and_modname()
+
+ def test_simple_caller(self):
+ self.tr.runfunc(_traced_func_simple_caller, 1)
+
+ expected = {
+ self.filemod + ('_traced_func_simple_caller',): 1,
+ self.filemod + ('_traced_func_linear',): 1,
+ }
+ self.assertEqual(self.tr.results().calledfuncs, expected)
+
+ def test_loop_caller_importing(self):
+ make_fake_module()
+ self.tr.runfunc(_traced_func_importing_caller, 1)
+
+ expected = {
+ self.filemod + ('_traced_func_simple_caller',): 1,
+ self.filemod + ('_traced_func_linear',): 1,
+ self.filemod + ('_traced_func_importing_caller',): 1,
+ self.filemod + ('_traced_func_importing',): 1,
+ ('fakefile.py', 'fakefile', 'foo'): 1,
+ }
+ self.assertEqual(self.tr.results().calledfuncs, expected)
+
+
+class TestCallers(unittest.TestCase):
+ """White-box testing of callers tracing"""
+ def setUp(self):
+ self.tr = Trace(count=0, trace=0, countcallers=1)
+ self.filemod = my_file_and_modname()
+
+ def test_loop_caller_importing(self):
+ make_fake_module()
+ self.tr.runfunc(_traced_func_importing_caller, 1)
+
+ expected = {
+ ((os.path.splitext(trace.__file__)[0] + '.py', 'trace', 'Trace.runfunc'),
+ (self.filemod + ('_traced_func_importing_caller',))): 1,
+ ((self.filemod + ('_traced_func_simple_caller',)),
+ (self.filemod + ('_traced_func_linear',))): 1,
+ ((self.filemod + ('_traced_func_importing_caller',)),
+ (self.filemod + ('_traced_func_simple_caller',))): 1,
+ ((self.filemod + ('_traced_func_importing_caller',)),
+ (self.filemod + ('_traced_func_importing',))): 1,
+ ((self.filemod + ('_traced_func_importing',)),
+ ('fakefile.py', 'fakefile', 'foo')): 1,
+ }
+ self.assertEqual(self.tr.results().callers, expected)
+
+
+#------------------------------ Driver ---------------------------------------#
+
+def test_main():
+ print(__name__, type(__name__))
+ test_support.run_unittest(__name__)
+
+
+if __name__ == '__main__':
+ test_main()