PyXR

c:\python24\lib \ test \ test_trace.py



0001 # Testing the line trace facility.
0002 
0003 from test import test_support
0004 import unittest
0005 import sys
0006 import difflib
0007 
0008 # A very basic example.  If this fails, we're in deep trouble.
0009 def basic():
0010     return 1
0011 
0012 basic.events = [(0, 'call'),
0013                 (1, 'line'),
0014                 (1, 'return')]
0015 
0016 # Armin Rigo's failing example:
0017 def arigo_example():
0018     x = 1
0019     del x
0020     while 0:
0021         pass
0022     x = 1
0023 
0024 arigo_example.events = [(0, 'call'),
0025                         (1, 'line'),
0026                         (2, 'line'),
0027                         (3, 'line'),
0028                         (5, 'line'),
0029                         (5, 'return')]
0030 
0031 # check that lines consisting of just one instruction get traced:
0032 def one_instr_line():
0033     x = 1
0034     del x
0035     x = 1
0036 
0037 one_instr_line.events = [(0, 'call'),
0038                          (1, 'line'),
0039                          (2, 'line'),
0040                          (3, 'line'),
0041                          (3, 'return')]
0042 
0043 def no_pop_tops():      # 0
0044     x = 1               # 1
0045     for a in range(2):  # 2
0046         if a:           # 3
0047             x = 1       # 4
0048         else:           # 5
0049             x = 1       # 6
0050 
0051 no_pop_tops.events = [(0, 'call'),
0052                       (1, 'line'),
0053                       (2, 'line'),
0054                       (3, 'line'),
0055                       (6, 'line'),
0056                       (2, 'line'),
0057                       (3, 'line'),
0058                       (4, 'line'),
0059                       (2, 'line'),
0060                       (2, 'return')]
0061 
0062 def no_pop_blocks():
0063     while 0:
0064         bla
0065     x = 1
0066 
0067 no_pop_blocks.events = [(0, 'call'),
0068                         (1, 'line'),
0069                         (3, 'line'),
0070                         (3, 'return')]
0071 
0072 def called(): # line -3
0073     x = 1
0074 
0075 def call():   # line 0
0076     called()
0077 
0078 call.events = [(0, 'call'),
0079                (1, 'line'),
0080                (-3, 'call'),
0081                (-2, 'line'),
0082                (-2, 'return'),
0083                (1, 'return')]
0084 
0085 def raises():
0086     raise Exception
0087 
0088 def test_raise():
0089     try:
0090         raises()
0091     except Exception, exc:
0092         x = 1
0093 
0094 test_raise.events = [(0, 'call'),
0095                      (1, 'line'),
0096                      (2, 'line'),
0097                      (-3, 'call'),
0098                      (-2, 'line'),
0099                      (-2, 'exception'),
0100                      (2, 'exception'),
0101                      (3, 'line'),
0102                      (4, 'line'),
0103                      (4, 'return')]
0104 
0105 def _settrace_and_return(tracefunc):
0106     sys.settrace(tracefunc)
0107     sys._getframe().f_back.f_trace = tracefunc
0108 def settrace_and_return(tracefunc):
0109     _settrace_and_return(tracefunc)
0110 
0111 settrace_and_return.events = [(1, 'return')]
0112 
0113 def _settrace_and_raise(tracefunc):
0114     sys.settrace(tracefunc)
0115     sys._getframe().f_back.f_trace = tracefunc
0116     raise RuntimeError
0117 def settrace_and_raise(tracefunc):
0118     try:
0119         _settrace_and_raise(tracefunc)
0120     except RuntimeError, exc:
0121         pass
0122 
0123 settrace_and_raise.events = [(2, 'exception'),
0124                              (3, 'line'),
0125                              (4, 'line'),
0126                              (4, 'return')]
0127 
0128 # implicit return example
0129 def ireturn_example():
0130     a = 5
0131     b = 5
0132     if a == b:
0133         b = a+1
0134     else:
0135         pass
0136 
0137 ireturn_example.events = [(0, 'call'),
0138                           (1, 'line'),
0139                           (2, 'line'),
0140                           (3, 'line'),
0141                           (4, 'line'),
0142                           (4, 'return')]
0143 
0144 # Tight loop with while(1) example (SF #765624)
0145 def tightloop_example():
0146     items = range(0, 3)
0147     try:
0148         i = 0
0149         while 1:
0150             b = items[i]; i+=1
0151     except IndexError:
0152         pass
0153 
0154 tightloop_example.events = [(0, 'call'),
0155                             (1, 'line'),
0156                             (2, 'line'),
0157                             (3, 'line'),
0158                             (4, 'line'),
0159                             (5, 'line'),
0160                             (5, 'line'),
0161                             (5, 'line'),
0162                             (5, 'line'),
0163                             (5, 'exception'),
0164                             (6, 'line'),
0165                             (7, 'line'),
0166                             (7, 'return')]
0167 
0168 def tighterloop_example():
0169     items = range(1, 4)
0170     try:
0171         i = 0
0172         while 1: i = items[i]
0173     except IndexError:
0174         pass
0175 
0176 tighterloop_example.events = [(0, 'call'),
0177                             (1, 'line'),
0178                             (2, 'line'),
0179                             (3, 'line'),
0180                             (4, 'line'),
0181                             (4, 'line'),
0182                             (4, 'line'),
0183                             (4, 'line'),
0184                             (4, 'exception'),
0185                             (5, 'line'),
0186                             (6, 'line'),
0187                             (6, 'return')]
0188 
0189 class Tracer:
0190     def __init__(self):
0191         self.events = []
0192     def trace(self, frame, event, arg):
0193         self.events.append((frame.f_lineno, event))
0194         return self.trace
0195 
0196 class TraceTestCase(unittest.TestCase):
0197     def compare_events(self, line_offset, events, expected_events):
0198         events = [(l - line_offset, e) for (l, e) in events]
0199         if events != expected_events:
0200             self.fail(
0201                 "events did not match expectation:\n" +
0202                 "\n".join(difflib.ndiff(map(str, expected_events),
0203                                         map(str, events))))
0204 
0205 
0206     def run_test(self, func):
0207         tracer = Tracer()
0208         sys.settrace(tracer.trace)
0209         func()
0210         sys.settrace(None)
0211         self.compare_events(func.func_code.co_firstlineno,
0212                             tracer.events, func.events)
0213 
0214     def run_test2(self, func):
0215         tracer = Tracer()
0216         func(tracer.trace)
0217         sys.settrace(None)
0218         self.compare_events(func.func_code.co_firstlineno,
0219                             tracer.events, func.events)
0220 
0221     def test_01_basic(self):
0222         self.run_test(basic)
0223     def test_02_arigo(self):
0224         self.run_test(arigo_example)
0225     def test_03_one_instr(self):
0226         self.run_test(one_instr_line)
0227     def test_04_no_pop_blocks(self):
0228         self.run_test(no_pop_blocks)
0229     def test_05_no_pop_tops(self):
0230         self.run_test(no_pop_tops)
0231     def test_06_call(self):
0232         self.run_test(call)
0233     def test_07_raise(self):
0234         self.run_test(test_raise)
0235 
0236     def test_08_settrace_and_return(self):
0237         self.run_test2(settrace_and_return)
0238     def test_09_settrace_and_raise(self):
0239         self.run_test2(settrace_and_raise)
0240     def test_10_ireturn(self):
0241         self.run_test(ireturn_example)
0242     def test_11_tightloop(self):
0243         self.run_test(tightloop_example)
0244     def test_12_tighterloop(self):
0245         self.run_test(tighterloop_example)
0246 
0247 class RaisingTraceFuncTestCase(unittest.TestCase):
0248     def trace(self, frame, event, arg):
0249         """A trace function that raises an exception in response to a
0250         specific trace event."""
0251         if event == self.raiseOnEvent:
0252             raise ValueError # just something that isn't RuntimeError
0253         else:
0254             return self.trace
0255 
0256     def f(self):
0257         """The function to trace; raises an exception if that's the case
0258         we're testing, so that the 'exception' trace event fires."""
0259         if self.raiseOnEvent == 'exception':
0260             x = 0
0261             y = 1/x
0262         else:
0263             return 1
0264 
0265     def run_test_for_event(self, event):
0266         """Tests that an exception raised in response to the given event is
0267         handled OK."""
0268         self.raiseOnEvent = event
0269         try:
0270             for i in xrange(sys.getrecursionlimit() + 1):
0271                 sys.settrace(self.trace)
0272                 try:
0273                     self.f()
0274                 except ValueError:
0275                     pass
0276                 else:
0277                     self.fail("exception not thrown!")
0278         except RuntimeError:
0279             self.fail("recursion counter not reset")
0280 
0281     # Test the handling of exceptions raised by each kind of trace event.
0282     def test_call(self):
0283         self.run_test_for_event('call')
0284     def test_line(self):
0285         self.run_test_for_event('line')
0286     def test_return(self):
0287         self.run_test_for_event('return')
0288     def test_exception(self):
0289         self.run_test_for_event('exception')
0290 
0291     def test_trash_stack(self):
0292         def f():
0293             for i in range(5):
0294                 print i  # line tracing will raise an exception at this line
0295 
0296         def g(frame, why, extra):
0297             if (why == 'line' and
0298                 frame.f_lineno == f.func_code.co_firstlineno + 2):
0299                 raise RuntimeError, "i am crashing"
0300             return g
0301 
0302         sys.settrace(g)
0303         try:
0304             f()
0305         except RuntimeError:
0306             # the test is really that this doesn't segfault:
0307             import gc
0308             gc.collect()
0309         else:
0310             self.fail("exception not propagated")
0311 
0312 
0313 # 'Jump' tests: assigning to frame.f_lineno within a trace function
0314 # moves the execution position - it's how debuggers implement a Jump
0315 # command (aka. "Set next statement").
0316 
0317 class JumpTracer:
0318     """Defines a trace function that jumps from one place to another,
0319     with the source and destination lines of the jump being defined by
0320     the 'jump' property of the function under test."""
0321 
0322     def __init__(self, function):
0323         self.function = function
0324         self.jumpFrom = function.jump[0]
0325         self.jumpTo = function.jump[1]
0326         self.done = False
0327 
0328     def trace(self, frame, event, arg):
0329         if not self.done and frame.f_code == self.function.func_code:
0330             firstLine = frame.f_code.co_firstlineno
0331             if frame.f_lineno == firstLine + self.jumpFrom:
0332                 # Cope with non-integer self.jumpTo (because of
0333                 # no_jump_to_non_integers below).
0334                 try:
0335                     frame.f_lineno = firstLine + self.jumpTo
0336                 except TypeError:
0337                     frame.f_lineno = self.jumpTo
0338                 self.done = True
0339         return self.trace
0340 
0341 # The first set of 'jump' tests are for things that are allowed:
0342 
0343 def jump_simple_forwards(output):
0344     output.append(1)
0345     output.append(2)
0346     output.append(3)
0347 
0348 jump_simple_forwards.jump = (1, 3)
0349 jump_simple_forwards.output = [3]
0350 
0351 def jump_simple_backwards(output):
0352     output.append(1)
0353     output.append(2)
0354 
0355 jump_simple_backwards.jump = (2, 1)
0356 jump_simple_backwards.output = [1, 1, 2]
0357 
0358 def jump_out_of_block_forwards(output):
0359     for i in 1, 2:
0360         output.append(2)
0361         for j in [3]:  # Also tests jumping over a block
0362             output.append(4)
0363     output.append(5)
0364 
0365 jump_out_of_block_forwards.jump = (3, 5)
0366 jump_out_of_block_forwards.output = [2, 5]
0367 
0368 def jump_out_of_block_backwards(output):
0369     output.append(1)
0370     for i in [1]:
0371         output.append(3)
0372         for j in [2]:  # Also tests jumping over a block
0373             output.append(5)
0374         output.append(6)
0375     output.append(7)
0376 
0377 jump_out_of_block_backwards.jump = (6, 1)
0378 jump_out_of_block_backwards.output = [1, 3, 5, 1, 3, 5, 6, 7]
0379 
0380 def jump_to_codeless_line(output):
0381     output.append(1)
0382     # Jumping to this line should skip to the next one.
0383     output.append(3)
0384 
0385 jump_to_codeless_line.jump = (1, 2)
0386 jump_to_codeless_line.output = [3]
0387 
0388 def jump_to_same_line(output):
0389     output.append(1)
0390     output.append(2)
0391     output.append(3)
0392 
0393 jump_to_same_line.jump = (2, 2)
0394 jump_to_same_line.output = [1, 2, 3]
0395 
0396 # Tests jumping within a finally block, and over one.
0397 def jump_in_nested_finally(output):
0398     try:
0399         output.append(2)
0400     finally:
0401         output.append(4)
0402         try:
0403             output.append(6)
0404         finally:
0405             output.append(8)
0406         output.append(9)
0407 
0408 jump_in_nested_finally.jump = (4, 9)
0409 jump_in_nested_finally.output = [2, 9]
0410 
0411 # The second set of 'jump' tests are for things that are not allowed:
0412 
0413 def no_jump_too_far_forwards(output):
0414     try:
0415         output.append(2)
0416         output.append(3)
0417     except ValueError, e:
0418         output.append('after' in str(e))
0419 
0420 no_jump_too_far_forwards.jump = (3, 6)
0421 no_jump_too_far_forwards.output = [2, True]
0422 
0423 def no_jump_too_far_backwards(output):
0424     try:
0425         output.append(2)
0426         output.append(3)
0427     except ValueError, e:
0428         output.append('before' in str(e))
0429 
0430 no_jump_too_far_backwards.jump = (3, -1)
0431 no_jump_too_far_backwards.output = [2, True]
0432 
0433 # Test each kind of 'except' line.
0434 def no_jump_to_except_1(output):
0435     try:
0436         output.append(2)
0437     except:
0438         e = sys.exc_info()[1]
0439         output.append('except' in str(e))
0440 
0441 no_jump_to_except_1.jump = (2, 3)
0442 no_jump_to_except_1.output = [True]
0443 
0444 def no_jump_to_except_2(output):
0445     try:
0446         output.append(2)
0447     except ValueError:
0448         e = sys.exc_info()[1]
0449         output.append('except' in str(e))
0450 
0451 no_jump_to_except_2.jump = (2, 3)
0452 no_jump_to_except_2.output = [True]
0453 
0454 def no_jump_to_except_3(output):
0455     try:
0456         output.append(2)
0457     except ValueError, e:
0458         output.append('except' in str(e))
0459 
0460 no_jump_to_except_3.jump = (2, 3)
0461 no_jump_to_except_3.output = [True]
0462 
0463 def no_jump_to_except_4(output):
0464     try:
0465         output.append(2)
0466     except (ValueError, RuntimeError), e:
0467         output.append('except' in str(e))
0468 
0469 no_jump_to_except_4.jump = (2, 3)
0470 no_jump_to_except_4.output = [True]
0471 
0472 def no_jump_forwards_into_block(output):
0473     try:
0474         output.append(2)
0475         for i in 1, 2:
0476             output.append(4)
0477     except ValueError, e:
0478         output.append('into' in str(e))
0479 
0480 no_jump_forwards_into_block.jump = (2, 4)
0481 no_jump_forwards_into_block.output = [True]
0482 
0483 def no_jump_backwards_into_block(output):
0484     try:
0485         for i in 1, 2:
0486             output.append(3)
0487         output.append(4)
0488     except ValueError, e:
0489         output.append('into' in str(e))
0490 
0491 no_jump_backwards_into_block.jump = (4, 3)
0492 no_jump_backwards_into_block.output = [3, 3, True]
0493 
0494 def no_jump_into_finally_block(output):
0495     try:
0496         try:
0497             output.append(3)
0498             x = 1
0499         finally:
0500             output.append(6)
0501     except ValueError, e:
0502         output.append('finally' in str(e))
0503 
0504 no_jump_into_finally_block.jump = (4, 6)
0505 no_jump_into_finally_block.output = [3, 6, True]  # The 'finally' still runs
0506 
0507 def no_jump_out_of_finally_block(output):
0508     try:
0509         try:
0510             output.append(3)
0511         finally:
0512             output.append(5)
0513             output.append(6)
0514     except ValueError, e:
0515         output.append('finally' in str(e))
0516 
0517 no_jump_out_of_finally_block.jump = (5, 1)
0518 no_jump_out_of_finally_block.output = [3, True]
0519 
0520 # This verifies the line-numbers-must-be-integers rule.
0521 def no_jump_to_non_integers(output):
0522     try:
0523         output.append(2)
0524     except ValueError, e:
0525         output.append('integer' in str(e))
0526 
0527 no_jump_to_non_integers.jump = (2, "Spam")
0528 no_jump_to_non_integers.output = [True]
0529 
0530 # This verifies that you can't set f_lineno via _getframe or similar
0531 # trickery.
0532 def no_jump_without_trace_function():
0533     try:
0534         previous_frame = sys._getframe().f_back
0535         previous_frame.f_lineno = previous_frame.f_lineno
0536     except ValueError, e:
0537         # This is the exception we wanted; make sure the error message
0538         # talks about trace functions.
0539         if 'trace' not in str(e):
0540             raise
0541     else:
0542         # Something's wrong - the expected exception wasn't raised.
0543         raise RuntimeError, "Trace-function-less jump failed to fail"
0544 
0545 
0546 class JumpTestCase(unittest.TestCase):
0547     def compare_jump_output(self, expected, received):
0548         if received != expected:
0549             self.fail( "Outputs don't match:\n" +
0550                        "Expected: " + repr(expected) + "\n" +
0551                        "Received: " + repr(received))
0552 
0553     def run_test(self, func):
0554         tracer = JumpTracer(func)
0555         sys.settrace(tracer.trace)
0556         output = []
0557         func(output)
0558         sys.settrace(None)
0559         self.compare_jump_output(func.output, output)
0560 
0561     def test_01_jump_simple_forwards(self):
0562         self.run_test(jump_simple_forwards)
0563     def test_02_jump_simple_backwards(self):
0564         self.run_test(jump_simple_backwards)
0565     def test_03_jump_out_of_block_forwards(self):
0566         self.run_test(jump_out_of_block_forwards)
0567     def test_04_jump_out_of_block_backwards(self):
0568         self.run_test(jump_out_of_block_backwards)
0569     def test_05_jump_to_codeless_line(self):
0570         self.run_test(jump_to_codeless_line)
0571     def test_06_jump_to_same_line(self):
0572         self.run_test(jump_to_same_line)
0573     def test_07_jump_in_nested_finally(self):
0574         self.run_test(jump_in_nested_finally)
0575     def test_08_no_jump_too_far_forwards(self):
0576         self.run_test(no_jump_too_far_forwards)
0577     def test_09_no_jump_too_far_backwards(self):
0578         self.run_test(no_jump_too_far_backwards)
0579     def test_10_no_jump_to_except_1(self):
0580         self.run_test(no_jump_to_except_1)
0581     def test_11_no_jump_to_except_2(self):
0582         self.run_test(no_jump_to_except_2)
0583     def test_12_no_jump_to_except_3(self):
0584         self.run_test(no_jump_to_except_3)
0585     def test_13_no_jump_to_except_4(self):
0586         self.run_test(no_jump_to_except_4)
0587     def test_14_no_jump_forwards_into_block(self):
0588         self.run_test(no_jump_forwards_into_block)
0589     def test_15_no_jump_backwards_into_block(self):
0590         self.run_test(no_jump_backwards_into_block)
0591     def test_16_no_jump_into_finally_block(self):
0592         self.run_test(no_jump_into_finally_block)
0593     def test_17_no_jump_out_of_finally_block(self):
0594         self.run_test(no_jump_out_of_finally_block)
0595     def test_18_no_jump_to_non_integers(self):
0596         self.run_test(no_jump_to_non_integers)
0597     def test_19_no_jump_without_trace_function(self):
0598         no_jump_without_trace_function()
0599 
0600 def test_main():
0601     test_support.run_unittest(
0602         TraceTestCase,
0603         RaisingTraceFuncTestCase,
0604         JumpTestCase
0605     )
0606 
0607 if __name__ == "__main__":
0608     test_main()
0609 

Generated by PyXR 0.9.4
SourceForge.net Logo