]> git.proxmox.com Git - mirror_edk2.git/blob - AppPkg/Applications/Python/Python-2.7.2/Lib/test/test_sys_settrace.py
EmbeddedPkg: Extend NvVarStoreFormattedLib LIBRARY_CLASS
[mirror_edk2.git] / AppPkg / Applications / Python / Python-2.7.2 / Lib / test / test_sys_settrace.py
1 # Testing the line trace facility.
2
3 from test import test_support
4 import unittest
5 import sys
6 import difflib
7 import gc
8
9 # A very basic example. If this fails, we're in deep trouble.
10 def basic():
11 return 1
12
13 basic.events = [(0, 'call'),
14 (1, 'line'),
15 (1, 'return')]
16
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?
21
22
23 # The entire "while 0:" statement is optimized away. No code
24 # exists for it, so the line numbers skip directly from "del x"
25 # to "x = 1".
26 def arigo_example():
27 x = 1
28 del x
29 while 0:
30 pass
31 x = 1
32
33 arigo_example.events = [(0, 'call'),
34 (1, 'line'),
35 (2, 'line'),
36 (5, 'line'),
37 (5, 'return')]
38
39 # check that lines consisting of just one instruction get traced:
40 def one_instr_line():
41 x = 1
42 del x
43 x = 1
44
45 one_instr_line.events = [(0, 'call'),
46 (1, 'line'),
47 (2, 'line'),
48 (3, 'line'),
49 (3, 'return')]
50
51 def no_pop_tops(): # 0
52 x = 1 # 1
53 for a in range(2): # 2
54 if a: # 3
55 x = 1 # 4
56 else: # 5
57 x = 1 # 6
58
59 no_pop_tops.events = [(0, 'call'),
60 (1, 'line'),
61 (2, 'line'),
62 (3, 'line'),
63 (6, 'line'),
64 (2, 'line'),
65 (3, 'line'),
66 (4, 'line'),
67 (2, 'line'),
68 (2, 'return')]
69
70 def no_pop_blocks():
71 y = 1
72 while not y:
73 bla
74 x = 1
75
76 no_pop_blocks.events = [(0, 'call'),
77 (1, 'line'),
78 (2, 'line'),
79 (4, 'line'),
80 (4, 'return')]
81
82 def called(): # line -3
83 x = 1
84
85 def call(): # line 0
86 called()
87
88 call.events = [(0, 'call'),
89 (1, 'line'),
90 (-3, 'call'),
91 (-2, 'line'),
92 (-2, 'return'),
93 (1, 'return')]
94
95 def raises():
96 raise Exception
97
98 def test_raise():
99 try:
100 raises()
101 except Exception, exc:
102 x = 1
103
104 test_raise.events = [(0, 'call'),
105 (1, 'line'),
106 (2, 'line'),
107 (-3, 'call'),
108 (-2, 'line'),
109 (-2, 'exception'),
110 (-2, 'return'),
111 (2, 'exception'),
112 (3, 'line'),
113 (4, 'line'),
114 (4, 'return')]
115
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)
121
122 settrace_and_return.events = [(1, 'return')]
123
124 def _settrace_and_raise(tracefunc):
125 sys.settrace(tracefunc)
126 sys._getframe().f_back.f_trace = tracefunc
127 raise RuntimeError
128 def settrace_and_raise(tracefunc):
129 try:
130 _settrace_and_raise(tracefunc)
131 except RuntimeError, exc:
132 pass
133
134 settrace_and_raise.events = [(2, 'exception'),
135 (3, 'line'),
136 (4, 'line'),
137 (4, 'return')]
138
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():
148 a = 5
149 b = 5
150 if a == b:
151 b = a+1
152 else:
153 pass
154
155 ireturn_example.events = [(0, 'call'),
156 (1, 'line'),
157 (2, 'line'),
158 (3, 'line'),
159 (4, 'line'),
160 (6, 'line'),
161 (6, 'return')]
162
163 # Tight loop with while(1) example (SF #765624)
164 def tightloop_example():
165 items = range(0, 3)
166 try:
167 i = 0
168 while 1:
169 b = items[i]; i+=1
170 except IndexError:
171 pass
172
173 tightloop_example.events = [(0, 'call'),
174 (1, 'line'),
175 (2, 'line'),
176 (3, 'line'),
177 (4, 'line'),
178 (5, 'line'),
179 (5, 'line'),
180 (5, 'line'),
181 (5, 'line'),
182 (5, 'exception'),
183 (6, 'line'),
184 (7, 'line'),
185 (7, 'return')]
186
187 def tighterloop_example():
188 items = range(1, 4)
189 try:
190 i = 0
191 while 1: i = items[i]
192 except IndexError:
193 pass
194
195 tighterloop_example.events = [(0, 'call'),
196 (1, 'line'),
197 (2, 'line'),
198 (3, 'line'),
199 (4, 'line'),
200 (4, 'line'),
201 (4, 'line'),
202 (4, 'line'),
203 (4, 'exception'),
204 (5, 'line'),
205 (6, 'line'),
206 (6, 'return')]
207
208 def generator_function():
209 try:
210 yield True
211 "continued"
212 finally:
213 "finally"
214 def generator_example():
215 # any() will leave the generator before its end
216 x = any(generator_function())
217
218 # the following lines were not traced
219 for x in range(10):
220 y = x
221
222 generator_example.events = ([(0, 'call'),
223 (2, 'line'),
224 (-6, 'call'),
225 (-5, 'line'),
226 (-4, 'line'),
227 (-4, 'return'),
228 (-4, 'call'),
229 (-4, 'exception'),
230 (-1, 'line'),
231 (-1, 'return')] +
232 [(5, 'line'), (6, 'line')] * 10 +
233 [(5, 'line'), (5, 'return')])
234
235
236 class Tracer:
237 def __init__(self):
238 self.events = []
239 def trace(self, frame, event, arg):
240 self.events.append((frame.f_lineno, event))
241 return self.trace
242 def traceWithGenexp(self, frame, event, arg):
243 (o for o in [1])
244 self.events.append((frame.f_lineno, event))
245 return self.trace
246
247 class TraceTestCase(unittest.TestCase):
248
249 # Disable gc collection when tracing, otherwise the
250 # deallocators may be traced as well.
251 def setUp(self):
252 self.using_gc = gc.isenabled()
253 gc.disable()
254
255 def tearDown(self):
256 if self.using_gc:
257 gc.enable()
258
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:
262 self.fail(
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])))
266
267 def run_and_compare(self, func, events):
268 tracer = Tracer()
269 sys.settrace(tracer.trace)
270 func()
271 sys.settrace(None)
272 self.compare_events(func.func_code.co_firstlineno,
273 tracer.events, events)
274
275 def run_test(self, func):
276 self.run_and_compare(func, func.events)
277
278 def run_test2(self, func):
279 tracer = Tracer()
280 func(tracer.trace)
281 sys.settrace(None)
282 self.compare_events(func.func_code.co_firstlineno,
283 tracer.events, func.events)
284
285 def set_and_retrieve_none(self):
286 sys.settrace(None)
287 assert sys.gettrace() is None
288
289 def set_and_retrieve_func(self):
290 def fn(*args):
291 pass
292
293 sys.settrace(fn)
294 try:
295 assert sys.gettrace() is fn
296 finally:
297 sys.settrace(None)
298
299 def test_01_basic(self):
300 self.run_test(basic)
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):
310 self.run_test(call)
311 def test_07_raise(self):
312 self.run_test(test_raise)
313
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)
324
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.
331 tracer = Tracer()
332 sys.settrace(tracer.traceWithGenexp)
333 generator_example()
334 sys.settrace(None)
335 self.compare_events(generator_example.__code__.co_firstlineno,
336 tracer.events, generator_example.events)
337
338 def test_14_onliner_if(self):
339 def onliners():
340 if True: False
341 else: True
342 return 0
343 self.run_and_compare(
344 onliners,
345 [(0, 'call'),
346 (1, 'line'),
347 (3, 'line'),
348 (3, 'return')])
349
350 def test_15_loops(self):
351 # issue1750076: "while" expression is skipped by debugger
352 def for_example():
353 for x in range(2):
354 pass
355 self.run_and_compare(
356 for_example,
357 [(0, 'call'),
358 (1, 'line'),
359 (2, 'line'),
360 (1, 'line'),
361 (2, 'line'),
362 (1, 'line'),
363 (1, 'return')])
364
365 def while_example():
366 # While expression should be traced on every loop
367 x = 2
368 while x > 0:
369 x -= 1
370 self.run_and_compare(
371 while_example,
372 [(0, 'call'),
373 (2, 'line'),
374 (3, 'line'),
375 (4, 'line'),
376 (3, 'line'),
377 (4, 'line'),
378 (3, 'line'),
379 (3, 'return')])
380
381 def test_16_blank_lines(self):
382 exec("def f():\n" + "\n" * 256 + " pass")
383 self.run_and_compare(
384 f,
385 [(0, 'call'),
386 (257, 'line'),
387 (257, 'return')])
388
389
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
396 else:
397 return self.trace
398
399 def f(self):
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':
403 x = 0
404 y = 1 // x
405 else:
406 return 1
407
408 def run_test_for_event(self, event):
409 """Tests that an exception raised in response to the given event is
410 handled OK."""
411 self.raiseOnEvent = event
412 try:
413 for i in xrange(sys.getrecursionlimit() + 1):
414 sys.settrace(self.trace)
415 try:
416 self.f()
417 except ValueError:
418 pass
419 else:
420 self.fail("exception not thrown!")
421 except RuntimeError:
422 self.fail("recursion counter not reset")
423
424 # Test the handling of exceptions raised by each kind of trace event.
425 def test_call(self):
426 self.run_test_for_event('call')
427 def test_line(self):
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')
433
434 def test_trash_stack(self):
435 def f():
436 for i in range(5):
437 print i # line tracing will raise an exception at this line
438
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"
443 return g
444
445 sys.settrace(g)
446 try:
447 f()
448 except RuntimeError:
449 # the test is really that this doesn't segfault:
450 import gc
451 gc.collect()
452 else:
453 self.fail("exception not propagated")
454
455
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").
459
460 class JumpTracer:
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."""
464
465 def __init__(self, function):
466 self.function = function
467 self.jumpFrom = function.jump[0]
468 self.jumpTo = function.jump[1]
469 self.done = False
470
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 event == 'line' and frame.f_lineno == firstLine + self.jumpFrom:
475 # Cope with non-integer self.jumpTo (because of
476 # no_jump_to_non_integers below).
477 try:
478 frame.f_lineno = firstLine + self.jumpTo
479 except TypeError:
480 frame.f_lineno = self.jumpTo
481 self.done = True
482 return self.trace
483
484 # The first set of 'jump' tests are for things that are allowed:
485
486 def jump_simple_forwards(output):
487 output.append(1)
488 output.append(2)
489 output.append(3)
490
491 jump_simple_forwards.jump = (1, 3)
492 jump_simple_forwards.output = [3]
493
494 def jump_simple_backwards(output):
495 output.append(1)
496 output.append(2)
497
498 jump_simple_backwards.jump = (2, 1)
499 jump_simple_backwards.output = [1, 1, 2]
500
501 def jump_out_of_block_forwards(output):
502 for i in 1, 2:
503 output.append(2)
504 for j in [3]: # Also tests jumping over a block
505 output.append(4)
506 output.append(5)
507
508 jump_out_of_block_forwards.jump = (3, 5)
509 jump_out_of_block_forwards.output = [2, 5]
510
511 def jump_out_of_block_backwards(output):
512 output.append(1)
513 for i in [1]:
514 output.append(3)
515 for j in [2]: # Also tests jumping over a block
516 output.append(5)
517 output.append(6)
518 output.append(7)
519
520 jump_out_of_block_backwards.jump = (6, 1)
521 jump_out_of_block_backwards.output = [1, 3, 5, 1, 3, 5, 6, 7]
522
523 def jump_to_codeless_line(output):
524 output.append(1)
525 # Jumping to this line should skip to the next one.
526 output.append(3)
527
528 jump_to_codeless_line.jump = (1, 2)
529 jump_to_codeless_line.output = [3]
530
531 def jump_to_same_line(output):
532 output.append(1)
533 output.append(2)
534 output.append(3)
535
536 jump_to_same_line.jump = (2, 2)
537 jump_to_same_line.output = [1, 2, 3]
538
539 # Tests jumping within a finally block, and over one.
540 def jump_in_nested_finally(output):
541 try:
542 output.append(2)
543 finally:
544 output.append(4)
545 try:
546 output.append(6)
547 finally:
548 output.append(8)
549 output.append(9)
550
551 jump_in_nested_finally.jump = (4, 9)
552 jump_in_nested_finally.output = [2, 9]
553
554 # The second set of 'jump' tests are for things that are not allowed:
555
556 def no_jump_too_far_forwards(output):
557 try:
558 output.append(2)
559 output.append(3)
560 except ValueError, e:
561 output.append('after' in str(e))
562
563 no_jump_too_far_forwards.jump = (3, 6)
564 no_jump_too_far_forwards.output = [2, True]
565
566 def no_jump_too_far_backwards(output):
567 try:
568 output.append(2)
569 output.append(3)
570 except ValueError, e:
571 output.append('before' in str(e))
572
573 no_jump_too_far_backwards.jump = (3, -1)
574 no_jump_too_far_backwards.output = [2, True]
575
576 # Test each kind of 'except' line.
577 def no_jump_to_except_1(output):
578 try:
579 output.append(2)
580 except:
581 e = sys.exc_info()[1]
582 output.append('except' in str(e))
583
584 no_jump_to_except_1.jump = (2, 3)
585 no_jump_to_except_1.output = [True]
586
587 def no_jump_to_except_2(output):
588 try:
589 output.append(2)
590 except ValueError:
591 e = sys.exc_info()[1]
592 output.append('except' in str(e))
593
594 no_jump_to_except_2.jump = (2, 3)
595 no_jump_to_except_2.output = [True]
596
597 def no_jump_to_except_3(output):
598 try:
599 output.append(2)
600 except ValueError, e:
601 output.append('except' in str(e))
602
603 no_jump_to_except_3.jump = (2, 3)
604 no_jump_to_except_3.output = [True]
605
606 def no_jump_to_except_4(output):
607 try:
608 output.append(2)
609 except (ValueError, RuntimeError), e:
610 output.append('except' in str(e))
611
612 no_jump_to_except_4.jump = (2, 3)
613 no_jump_to_except_4.output = [True]
614
615 def no_jump_forwards_into_block(output):
616 try:
617 output.append(2)
618 for i in 1, 2:
619 output.append(4)
620 except ValueError, e:
621 output.append('into' in str(e))
622
623 no_jump_forwards_into_block.jump = (2, 4)
624 no_jump_forwards_into_block.output = [True]
625
626 def no_jump_backwards_into_block(output):
627 try:
628 for i in 1, 2:
629 output.append(3)
630 output.append(4)
631 except ValueError, e:
632 output.append('into' in str(e))
633
634 no_jump_backwards_into_block.jump = (4, 3)
635 no_jump_backwards_into_block.output = [3, 3, True]
636
637 def no_jump_into_finally_block(output):
638 try:
639 try:
640 output.append(3)
641 x = 1
642 finally:
643 output.append(6)
644 except ValueError, e:
645 output.append('finally' in str(e))
646
647 no_jump_into_finally_block.jump = (4, 6)
648 no_jump_into_finally_block.output = [3, 6, True] # The 'finally' still runs
649
650 def no_jump_out_of_finally_block(output):
651 try:
652 try:
653 output.append(3)
654 finally:
655 output.append(5)
656 output.append(6)
657 except ValueError, e:
658 output.append('finally' in str(e))
659
660 no_jump_out_of_finally_block.jump = (5, 1)
661 no_jump_out_of_finally_block.output = [3, True]
662
663 # This verifies the line-numbers-must-be-integers rule.
664 def no_jump_to_non_integers(output):
665 try:
666 output.append(2)
667 except ValueError, e:
668 output.append('integer' in str(e))
669
670 no_jump_to_non_integers.jump = (2, "Spam")
671 no_jump_to_non_integers.output = [True]
672
673 # This verifies that you can't set f_lineno via _getframe or similar
674 # trickery.
675 def no_jump_without_trace_function():
676 try:
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):
683 raise
684 else:
685 # Something's wrong - the expected exception wasn't raised.
686 raise RuntimeError, "Trace-function-less jump failed to fail"
687
688
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))
695
696 def run_test(self, func):
697 tracer = JumpTracer(func)
698 sys.settrace(tracer.trace)
699 output = []
700 func(output)
701 sys.settrace(None)
702 self.compare_jump_output(func.output, output)
703
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()
742
743 def test_20_large_function(self):
744 d = {}
745 exec("""def f(output): # line 0
746 x = 0 # line 1
747 y = 1 # line 2
748 ''' # line 3
749 %s # lines 4-1004
750 ''' # line 1005
751 x += 1 # line 1006
752 output.append(x) # line 1007
753 return""" % ('\n' * 1000,), d)
754 f = d['f']
755
756 f.jump = (2, 1007)
757 f.output = [0]
758 self.run_test(f)
759
760 def test_jump_to_firstlineno(self):
761 # This tests that PDB can jump back to the first line in a
762 # file. See issue #1689458. It can only be triggered in a
763 # function call if the function is defined on a single line.
764 code = compile("""
765 # Comments don't count.
766 output.append(2) # firstlineno is here.
767 output.append(3)
768 output.append(4)
769 """, "<fake module>", "exec")
770 class fake_function:
771 func_code = code
772 jump = (2, 0)
773 tracer = JumpTracer(fake_function)
774 sys.settrace(tracer.trace)
775 namespace = {"output": []}
776 exec code in namespace
777 sys.settrace(None)
778 self.compare_jump_output([2, 3, 2, 3, 4], namespace["output"])
779
780
781 def test_main():
782 test_support.run_unittest(
783 TraceTestCase,
784 RaisingTraceFuncTestCase,
785 JumpTestCase
786 )
787
788 if __name__ == "__main__":
789 test_main()