|
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 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_main(): |
|
744 test_support.run_unittest( |
|
745 TraceTestCase, |
|
746 RaisingTraceFuncTestCase, |
|
747 JumpTestCase |
|
748 ) |
|
749 |
|
750 if __name__ == "__main__": |
|
751 test_main() |