1
# Testing the line trace facility.
3
from test import test_support
9
# A very basic example. If this fails, we're in deep trouble.
13
basic.events = [(0, 'call'),
17
# Many of the tests below are tricky because they involve pass statements.
18
# If there is implicit control flow around a pass statement (in an except
19
# clause or else caluse) under what conditions do you set a line number
20
# following that clause?
23
# The entire "while 0:" statement is optimized away. No code
24
# exists for it, so the line numbers skip directly from "del x"
33
arigo_example.events = [(0, 'call'),
39
# check that lines consisting of just one instruction get traced:
45
one_instr_line.events = [(0, 'call'),
51
def no_pop_tops(): # 0
53
for a in range(2): # 2
59
no_pop_tops.events = [(0, 'call'),
76
no_pop_blocks.events = [(0, 'call'),
82
def called(): # line -3
88
call.events = [(0, 'call'),
101
except Exception, exc:
104
test_raise.events = [(0, 'call'),
116
def _settrace_and_return(tracefunc):
117
sys.settrace(tracefunc)
118
sys._getframe().f_back.f_trace = tracefunc
119
def settrace_and_return(tracefunc):
120
_settrace_and_return(tracefunc)
122
settrace_and_return.events = [(1, 'return')]
124
def _settrace_and_raise(tracefunc):
125
sys.settrace(tracefunc)
126
sys._getframe().f_back.f_trace = tracefunc
128
def settrace_and_raise(tracefunc):
130
_settrace_and_raise(tracefunc)
131
except RuntimeError, exc:
134
settrace_and_raise.events = [(2, 'exception'),
139
# implicit return example
140
# This test is interesting because of the else: pass
141
# part of the code. The code generate for the true
142
# part of the if contains a jump past the else branch.
143
# The compiler then generates an implicit "return None"
144
# Internally, the compiler visits the pass statement
145
# and stores its line number for use on the next instruction.
146
# The next instruction is the implicit return None.
147
def ireturn_example():
155
ireturn_example.events = [(0, 'call'),
163
# Tight loop with while(1) example (SF #765624)
164
def tightloop_example():
173
tightloop_example.events = [(0, 'call'),
187
def tighterloop_example():
191
while 1: i = items[i]
195
tighterloop_example.events = [(0, 'call'),
208
def generator_function():
214
def generator_example():
215
# any() will leave the generator before its end
216
x = any(generator_function())
218
# the following lines were not traced
222
generator_example.events = ([(0, 'call'),
232
[(5, 'line'), (6, 'line')] * 10 +
233
[(5, 'line'), (5, 'return')])
239
def trace(self, frame, event, arg):
240
self.events.append((frame.f_lineno, event))
242
def traceWithGenexp(self, frame, event, arg):
244
self.events.append((frame.f_lineno, event))
247
class TraceTestCase(unittest.TestCase):
249
# Disable gc collection when tracing, otherwise the
250
# deallocators may be traced as well.
252
self.using_gc = gc.isenabled()
259
def compare_events(self, line_offset, events, expected_events):
260
events = [(l - line_offset, e) for (l, e) in events]
261
if events != expected_events:
263
"events did not match expectation:\n" +
264
"\n".join(difflib.ndiff([str(x) for x in expected_events],
265
[str(x) for x in events])))
267
def run_and_compare(self, func, events):
269
sys.settrace(tracer.trace)
272
self.compare_events(func.func_code.co_firstlineno,
273
tracer.events, events)
275
def run_test(self, func):
276
self.run_and_compare(func, func.events)
278
def run_test2(self, func):
282
self.compare_events(func.func_code.co_firstlineno,
283
tracer.events, func.events)
285
def set_and_retrieve_none(self):
287
assert sys.gettrace() is None
289
def set_and_retrieve_func(self):
295
assert sys.gettrace() is fn
299
def test_01_basic(self):
301
def test_02_arigo(self):
302
self.run_test(arigo_example)
303
def test_03_one_instr(self):
304
self.run_test(one_instr_line)
305
def test_04_no_pop_blocks(self):
306
self.run_test(no_pop_blocks)
307
def test_05_no_pop_tops(self):
308
self.run_test(no_pop_tops)
309
def test_06_call(self):
311
def test_07_raise(self):
312
self.run_test(test_raise)
314
def test_08_settrace_and_return(self):
315
self.run_test2(settrace_and_return)
316
def test_09_settrace_and_raise(self):
317
self.run_test2(settrace_and_raise)
318
def test_10_ireturn(self):
319
self.run_test(ireturn_example)
320
def test_11_tightloop(self):
321
self.run_test(tightloop_example)
322
def test_12_tighterloop(self):
323
self.run_test(tighterloop_example)
325
def test_13_genexp(self):
326
self.run_test(generator_example)
327
# issue1265: if the trace function contains a generator,
328
# and if the traced function contains another generator
329
# that is not completely exhausted, the trace stopped.
330
# Worse: the 'finally' clause was not invoked.
332
sys.settrace(tracer.traceWithGenexp)
335
self.compare_events(generator_example.__code__.co_firstlineno,
336
tracer.events, generator_example.events)
338
def test_14_onliner_if(self):
343
self.run_and_compare(
350
def test_15_loops(self):
351
# issue1750076: "while" expression is skipped by debugger
355
self.run_and_compare(
366
# While expression should be traced on every loop
370
self.run_and_compare(
381
def test_16_blank_lines(self):
382
exec("def f():\n" + "\n" * 256 + " pass")
383
self.run_and_compare(
390
class RaisingTraceFuncTestCase(unittest.TestCase):
391
def trace(self, frame, event, arg):
392
"""A trace function that raises an exception in response to a
393
specific trace event."""
394
if event == self.raiseOnEvent:
395
raise ValueError # just something that isn't RuntimeError
400
"""The function to trace; raises an exception if that's the case
401
we're testing, so that the 'exception' trace event fires."""
402
if self.raiseOnEvent == 'exception':
408
def run_test_for_event(self, event):
409
"""Tests that an exception raised in response to the given event is
411
self.raiseOnEvent = event
413
for i in xrange(sys.getrecursionlimit() + 1):
414
sys.settrace(self.trace)
420
self.fail("exception not thrown!")
422
self.fail("recursion counter not reset")
424
# Test the handling of exceptions raised by each kind of trace event.
426
self.run_test_for_event('call')
428
self.run_test_for_event('line')
429
def test_return(self):
430
self.run_test_for_event('return')
431
def test_exception(self):
432
self.run_test_for_event('exception')
434
def test_trash_stack(self):
437
print i # line tracing will raise an exception at this line
439
def g(frame, why, extra):
440
if (why == 'line' and
441
frame.f_lineno == f.func_code.co_firstlineno + 2):
442
raise RuntimeError, "i am crashing"
449
# the test is really that this doesn't segfault:
453
self.fail("exception not propagated")
456
# 'Jump' tests: assigning to frame.f_lineno within a trace function
457
# moves the execution position - it's how debuggers implement a Jump
458
# command (aka. "Set next statement").
461
"""Defines a trace function that jumps from one place to another,
462
with the source and destination lines of the jump being defined by
463
the 'jump' property of the function under test."""
465
def __init__(self, function):
466
self.function = function
467
self.jumpFrom = function.jump[0]
468
self.jumpTo = function.jump[1]
471
def trace(self, frame, event, arg):
472
if not self.done and frame.f_code == self.function.func_code:
473
firstLine = frame.f_code.co_firstlineno
474
if frame.f_lineno == firstLine + self.jumpFrom:
475
# Cope with non-integer self.jumpTo (because of
476
# no_jump_to_non_integers below).
478
frame.f_lineno = firstLine + self.jumpTo
480
frame.f_lineno = self.jumpTo
484
# The first set of 'jump' tests are for things that are allowed:
486
def jump_simple_forwards(output):
491
jump_simple_forwards.jump = (1, 3)
492
jump_simple_forwards.output = [3]
494
def jump_simple_backwards(output):
498
jump_simple_backwards.jump = (2, 1)
499
jump_simple_backwards.output = [1, 1, 2]
501
def jump_out_of_block_forwards(output):
504
for j in [3]: # Also tests jumping over a block
508
jump_out_of_block_forwards.jump = (3, 5)
509
jump_out_of_block_forwards.output = [2, 5]
511
def jump_out_of_block_backwards(output):
515
for j in [2]: # Also tests jumping over a block
520
jump_out_of_block_backwards.jump = (6, 1)
521
jump_out_of_block_backwards.output = [1, 3, 5, 1, 3, 5, 6, 7]
523
def jump_to_codeless_line(output):
525
# Jumping to this line should skip to the next one.
528
jump_to_codeless_line.jump = (1, 2)
529
jump_to_codeless_line.output = [3]
531
def jump_to_same_line(output):
536
jump_to_same_line.jump = (2, 2)
537
jump_to_same_line.output = [1, 2, 3]
539
# Tests jumping within a finally block, and over one.
540
def jump_in_nested_finally(output):
551
jump_in_nested_finally.jump = (4, 9)
552
jump_in_nested_finally.output = [2, 9]
554
# The second set of 'jump' tests are for things that are not allowed:
556
def no_jump_too_far_forwards(output):
560
except ValueError, e:
561
output.append('after' in str(e))
563
no_jump_too_far_forwards.jump = (3, 6)
564
no_jump_too_far_forwards.output = [2, True]
566
def no_jump_too_far_backwards(output):
570
except ValueError, e:
571
output.append('before' in str(e))
573
no_jump_too_far_backwards.jump = (3, -1)
574
no_jump_too_far_backwards.output = [2, True]
576
# Test each kind of 'except' line.
577
def no_jump_to_except_1(output):
581
e = sys.exc_info()[1]
582
output.append('except' in str(e))
584
no_jump_to_except_1.jump = (2, 3)
585
no_jump_to_except_1.output = [True]
587
def no_jump_to_except_2(output):
591
e = sys.exc_info()[1]
592
output.append('except' in str(e))
594
no_jump_to_except_2.jump = (2, 3)
595
no_jump_to_except_2.output = [True]
597
def no_jump_to_except_3(output):
600
except ValueError, e:
601
output.append('except' in str(e))
603
no_jump_to_except_3.jump = (2, 3)
604
no_jump_to_except_3.output = [True]
606
def no_jump_to_except_4(output):
609
except (ValueError, RuntimeError), e:
610
output.append('except' in str(e))
612
no_jump_to_except_4.jump = (2, 3)
613
no_jump_to_except_4.output = [True]
615
def no_jump_forwards_into_block(output):
620
except ValueError, e:
621
output.append('into' in str(e))
623
no_jump_forwards_into_block.jump = (2, 4)
624
no_jump_forwards_into_block.output = [True]
626
def no_jump_backwards_into_block(output):
631
except ValueError, e:
632
output.append('into' in str(e))
634
no_jump_backwards_into_block.jump = (4, 3)
635
no_jump_backwards_into_block.output = [3, 3, True]
637
def no_jump_into_finally_block(output):
644
except ValueError, e:
645
output.append('finally' in str(e))
647
no_jump_into_finally_block.jump = (4, 6)
648
no_jump_into_finally_block.output = [3, 6, True] # The 'finally' still runs
650
def no_jump_out_of_finally_block(output):
657
except ValueError, e:
658
output.append('finally' in str(e))
660
no_jump_out_of_finally_block.jump = (5, 1)
661
no_jump_out_of_finally_block.output = [3, True]
663
# This verifies the line-numbers-must-be-integers rule.
664
def no_jump_to_non_integers(output):
667
except ValueError, e:
668
output.append('integer' in str(e))
670
no_jump_to_non_integers.jump = (2, "Spam")
671
no_jump_to_non_integers.output = [True]
673
# This verifies that you can't set f_lineno via _getframe or similar
675
def no_jump_without_trace_function():
677
previous_frame = sys._getframe().f_back
678
previous_frame.f_lineno = previous_frame.f_lineno
679
except ValueError, e:
680
# This is the exception we wanted; make sure the error message
681
# talks about trace functions.
682
if 'trace' not in str(e):
685
# Something's wrong - the expected exception wasn't raised.
686
raise RuntimeError, "Trace-function-less jump failed to fail"
689
class JumpTestCase(unittest.TestCase):
690
def compare_jump_output(self, expected, received):
691
if received != expected:
692
self.fail( "Outputs don't match:\n" +
693
"Expected: " + repr(expected) + "\n" +
694
"Received: " + repr(received))
696
def run_test(self, func):
697
tracer = JumpTracer(func)
698
sys.settrace(tracer.trace)
702
self.compare_jump_output(func.output, output)
704
def test_01_jump_simple_forwards(self):
705
self.run_test(jump_simple_forwards)
706
def test_02_jump_simple_backwards(self):
707
self.run_test(jump_simple_backwards)
708
def test_03_jump_out_of_block_forwards(self):
709
self.run_test(jump_out_of_block_forwards)
710
def test_04_jump_out_of_block_backwards(self):
711
self.run_test(jump_out_of_block_backwards)
712
def test_05_jump_to_codeless_line(self):
713
self.run_test(jump_to_codeless_line)
714
def test_06_jump_to_same_line(self):
715
self.run_test(jump_to_same_line)
716
def test_07_jump_in_nested_finally(self):
717
self.run_test(jump_in_nested_finally)
718
def test_08_no_jump_too_far_forwards(self):
719
self.run_test(no_jump_too_far_forwards)
720
def test_09_no_jump_too_far_backwards(self):
721
self.run_test(no_jump_too_far_backwards)
722
def test_10_no_jump_to_except_1(self):
723
self.run_test(no_jump_to_except_1)
724
def test_11_no_jump_to_except_2(self):
725
self.run_test(no_jump_to_except_2)
726
def test_12_no_jump_to_except_3(self):
727
self.run_test(no_jump_to_except_3)
728
def test_13_no_jump_to_except_4(self):
729
self.run_test(no_jump_to_except_4)
730
def test_14_no_jump_forwards_into_block(self):
731
self.run_test(no_jump_forwards_into_block)
732
def test_15_no_jump_backwards_into_block(self):
733
self.run_test(no_jump_backwards_into_block)
734
def test_16_no_jump_into_finally_block(self):
735
self.run_test(no_jump_into_finally_block)
736
def test_17_no_jump_out_of_finally_block(self):
737
self.run_test(no_jump_out_of_finally_block)
738
def test_18_no_jump_to_non_integers(self):
739
self.run_test(no_jump_to_non_integers)
740
def test_19_no_jump_without_trace_function(self):
741
no_jump_without_trace_function()
744
test_support.run_unittest(
746
RaisingTraceFuncTestCase,
750
if __name__ == "__main__":