3 from test
.test_support
import (run_unittest
, TESTFN
, rmtree
, unlink
,
8 from trace
import CoverageResults
, Trace
10 from test
.tracedmodules
import testmod
13 #------------------------------- Utilities -----------------------------------#
15 def fix_ext_py(filename
):
16 """Given a .pyc/.pyo filename converts it to the appropriate .py"""
17 if filename
.endswith(('.pyc', '.pyo')):
18 filename
= filename
[:-1]
21 def my_file_and_modname():
22 """The .py file and module name of this file (__file__)"""
23 modname
= os
.path
.splitext(os
.path
.basename(__file__
))[0]
24 return fix_ext_py(__file__
), modname
26 def get_firstlineno(func
):
27 return func
.__code
__.co_firstlineno
29 #-------------------- Target functions for tracing ---------------------------#
31 # The relative line numbers of lines in these functions matter for verifying
32 # tracing. Please modify the appropriate tests if you change one of the
33 # functions. Absolute line numbers don't matter.
36 def traced_func_linear(x
, y
):
42 def traced_func_loop(x
, y
):
48 def traced_func_importing(x
, y
):
49 return x
+ y
+ testmod
.func(1)
51 def traced_func_simple_caller(x
):
52 c
= traced_func_linear(x
, x
)
55 def traced_func_importing_caller(x
):
56 k
= traced_func_simple_caller(x
)
57 k
+= traced_func_importing(k
, x
)
60 def traced_func_generator(num
):
65 def traced_func_calling_generator():
67 for i
in traced_func_generator(10):
70 def traced_doubler(num
):
73 def traced_caller_list_comprehension():
75 mylist
= [traced_doubler(i
) for i
in range(k
)]
79 class TracedClass(object):
80 def __init__(self
, x
):
83 def inst_method_linear(self
, y
):
86 def inst_method_calling(self
, x
):
87 c
= self
.inst_method_linear(x
)
88 return c
+ traced_func_linear(x
, c
)
91 def class_method_linear(cls
, y
):
95 def static_method_linear(y
):
99 #------------------------------ Test cases -----------------------------------#
102 class TestLineCounts(unittest
.TestCase
):
103 """White-box testing of line-counting, via runfunc"""
105 self
.tracer
= Trace(count
=1, trace
=0, countfuncs
=0, countcallers
=0)
106 self
.my_py_filename
= fix_ext_py(__file__
)
108 def test_traced_func_linear(self
):
109 result
= self
.tracer
.runfunc(traced_func_linear
, 2, 5)
110 self
.assertEqual(result
, 7)
112 # all lines are executed once
114 firstlineno
= get_firstlineno(traced_func_linear
)
115 for i
in range(1, 5):
116 expected
[(self
.my_py_filename
, firstlineno
+ i
)] = 1
118 self
.assertEqual(self
.tracer
.results().counts
, expected
)
120 def test_traced_func_loop(self
):
121 self
.tracer
.runfunc(traced_func_loop
, 2, 3)
123 firstlineno
= get_firstlineno(traced_func_loop
)
125 (self
.my_py_filename
, firstlineno
+ 1): 1,
126 (self
.my_py_filename
, firstlineno
+ 2): 6,
127 (self
.my_py_filename
, firstlineno
+ 3): 5,
128 (self
.my_py_filename
, firstlineno
+ 4): 1,
130 self
.assertEqual(self
.tracer
.results().counts
, expected
)
132 def test_traced_func_importing(self
):
133 self
.tracer
.runfunc(traced_func_importing
, 2, 5)
135 firstlineno
= get_firstlineno(traced_func_importing
)
137 (self
.my_py_filename
, firstlineno
+ 1): 1,
138 (fix_ext_py(testmod
.__file
__), 2): 1,
139 (fix_ext_py(testmod
.__file
__), 3): 1,
142 self
.assertEqual(self
.tracer
.results().counts
, expected
)
144 def test_trace_func_generator(self
):
145 self
.tracer
.runfunc(traced_func_calling_generator
)
147 firstlineno_calling
= get_firstlineno(traced_func_calling_generator
)
148 firstlineno_gen
= get_firstlineno(traced_func_generator
)
150 (self
.my_py_filename
, firstlineno_calling
+ 1): 1,
151 (self
.my_py_filename
, firstlineno_calling
+ 2): 11,
152 (self
.my_py_filename
, firstlineno_calling
+ 3): 10,
153 (self
.my_py_filename
, firstlineno_gen
+ 1): 1,
154 (self
.my_py_filename
, firstlineno_gen
+ 2): 11,
155 (self
.my_py_filename
, firstlineno_gen
+ 3): 10,
157 self
.assertEqual(self
.tracer
.results().counts
, expected
)
159 def test_trace_list_comprehension(self
):
160 self
.tracer
.runfunc(traced_caller_list_comprehension
)
162 firstlineno_calling
= get_firstlineno(traced_caller_list_comprehension
)
163 firstlineno_called
= get_firstlineno(traced_doubler
)
165 (self
.my_py_filename
, firstlineno_calling
+ 1): 1,
166 (self
.my_py_filename
, firstlineno_calling
+ 2): 11,
167 (self
.my_py_filename
, firstlineno_calling
+ 3): 1,
168 (self
.my_py_filename
, firstlineno_called
+ 1): 10,
170 self
.assertEqual(self
.tracer
.results().counts
, expected
)
173 def test_linear_methods(self
):
174 # XXX todo: later add 'static_method_linear' and 'class_method_linear'
175 # here, once issue1764286 is resolved
177 for methname
in ['inst_method_linear',]:
178 tracer
= Trace(count
=1, trace
=0, countfuncs
=0, countcallers
=0)
179 traced_obj
= TracedClass(25)
180 method
= getattr(traced_obj
, methname
)
181 tracer
.runfunc(method
, 20)
183 firstlineno
= get_firstlineno(method
)
185 (self
.my_py_filename
, firstlineno
+ 1): 1,
187 self
.assertEqual(tracer
.results().counts
, expected
)
189 class TestRunExecCounts(unittest
.TestCase
):
190 """A simple sanity test of line-counting, via runctx (exec)"""
192 self
.my_py_filename
= fix_ext_py(__file__
)
194 def test_exec_counts(self
):
195 self
.tracer
= Trace(count
=1, trace
=0, countfuncs
=0, countcallers
=0)
196 code
= r
'''traced_func_loop(2, 5)'''
197 code
= compile(code
, __file__
, 'exec')
198 self
.tracer
.runctx(code
, globals(), vars())
200 firstlineno
= get_firstlineno(traced_func_loop
)
202 (self
.my_py_filename
, firstlineno
+ 1): 1,
203 (self
.my_py_filename
, firstlineno
+ 2): 6,
204 (self
.my_py_filename
, firstlineno
+ 3): 5,
205 (self
.my_py_filename
, firstlineno
+ 4): 1,
208 # When used through 'run', some other spurious counts are produced, like
209 # the settrace of threading, which we ignore, just making sure that the
210 # counts fo traced_func_loop were right.
212 for k
in expected
.keys():
213 self
.assertEqual(self
.tracer
.results().counts
[k
], expected
[k
])
216 class TestFuncs(unittest
.TestCase
):
217 """White-box testing of funcs tracing"""
219 self
.tracer
= Trace(count
=0, trace
=0, countfuncs
=1)
220 self
.filemod
= my_file_and_modname()
222 def test_simple_caller(self
):
223 self
.tracer
.runfunc(traced_func_simple_caller
, 1)
226 self
.filemod
+ ('traced_func_simple_caller',): 1,
227 self
.filemod
+ ('traced_func_linear',): 1,
229 self
.assertEqual(self
.tracer
.results().calledfuncs
, expected
)
231 def test_loop_caller_importing(self
):
232 self
.tracer
.runfunc(traced_func_importing_caller
, 1)
235 self
.filemod
+ ('traced_func_simple_caller',): 1,
236 self
.filemod
+ ('traced_func_linear',): 1,
237 self
.filemod
+ ('traced_func_importing_caller',): 1,
238 self
.filemod
+ ('traced_func_importing',): 1,
239 (fix_ext_py(testmod
.__file
__), 'testmod', 'func'): 1,
241 self
.assertEqual(self
.tracer
.results().calledfuncs
, expected
)
243 def test_inst_method_calling(self
):
244 obj
= TracedClass(20)
245 self
.tracer
.runfunc(obj
.inst_method_calling
, 1)
248 self
.filemod
+ ('TracedClass.inst_method_calling',): 1,
249 self
.filemod
+ ('TracedClass.inst_method_linear',): 1,
250 self
.filemod
+ ('traced_func_linear',): 1,
252 self
.assertEqual(self
.tracer
.results().calledfuncs
, expected
)
255 class TestCallers(unittest
.TestCase
):
256 """White-box testing of callers tracing"""
258 self
.tracer
= Trace(count
=0, trace
=0, countcallers
=1)
259 self
.filemod
= my_file_and_modname()
261 def test_loop_caller_importing(self
):
262 self
.tracer
.runfunc(traced_func_importing_caller
, 1)
265 ((os
.path
.splitext(trace
.__file
__)[0] + '.py', 'trace', 'Trace.runfunc'),
266 (self
.filemod
+ ('traced_func_importing_caller',))): 1,
267 ((self
.filemod
+ ('traced_func_simple_caller',)),
268 (self
.filemod
+ ('traced_func_linear',))): 1,
269 ((self
.filemod
+ ('traced_func_importing_caller',)),
270 (self
.filemod
+ ('traced_func_simple_caller',))): 1,
271 ((self
.filemod
+ ('traced_func_importing_caller',)),
272 (self
.filemod
+ ('traced_func_importing',))): 1,
273 ((self
.filemod
+ ('traced_func_importing',)),
274 (fix_ext_py(testmod
.__file
__), 'testmod', 'func')): 1,
276 self
.assertEqual(self
.tracer
.results().callers
, expected
)
279 # Created separately for issue #3821
280 class TestCoverage(unittest
.TestCase
):
285 def _coverage(self
, tracer
,
286 cmd
='from test import test_pprint; test_pprint.test_main()'):
289 r
.write_results(show_missing
=True, summary
=True, coverdir
=TESTFN
)
291 def test_coverage(self
):
292 tracer
= trace
.Trace(trace
=0, count
=1)
293 with
captured_stdout() as stdout
:
294 self
._coverage
(tracer
)
295 stdout
= stdout
.getvalue()
296 self
.assertTrue("pprint.py" in stdout
)
297 self
.assertTrue("case.py" in stdout
) # from unittest
298 files
= os
.listdir(TESTFN
)
299 self
.assertTrue("pprint.cover" in files
)
300 self
.assertTrue("unittest.case.cover" in files
)
302 def test_coverage_ignore(self
):
303 # Ignore all files, nothing should be traced nor printed
304 libpath
= os
.path
.normpath(os
.path
.dirname(os
.__file
__))
305 # sys.prefix does not work when running from a checkout
306 tracer
= trace
.Trace(ignoredirs
=[sys
.prefix
, sys
.exec_prefix
, libpath
],
308 with
captured_stdout() as stdout
:
309 self
._coverage
(tracer
)
310 if os
.path
.exists(TESTFN
):
311 files
= os
.listdir(TESTFN
)
312 self
.assertEqual(files
, [])
314 def test_issue9936(self
):
315 tracer
= trace
.Trace(trace
=0, count
=1)
316 modname
= 'test.tracedmodules.testmod'
317 # Ensure that the module is executed in import
318 if modname
in sys
.modules
:
319 del sys
.modules
[modname
]
320 cmd
= ("import test.tracedmodules.testmod as t;"
321 "t.func(0); t.func2();")
322 with
captured_stdout() as stdout
:
323 self
._coverage
(tracer
, cmd
)
328 lines
, cov
, module
= line
.split()[:3]
329 coverage
[module
] = (int(lines
), int(cov
[:-1]))
330 # XXX This is needed to run regrtest.py as a script
331 modname
= trace
.fullmodname(sys
.modules
[modname
].__file
__)
332 self
.assertIn(modname
, coverage
)
333 self
.assertEqual(coverage
[modname
], (5, 100))
337 run_unittest(__name__
)
340 if __name__
== '__main__':