home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 June / PCWorld_2005-06_cd.bin / software / vyzkuste / firewally / firewally.exe / framework-2.3.exe / test_profilehooks.py < prev    next >
Text File  |  2003-12-30  |  11KB  |  360 lines

  1. import pprint
  2. import sys
  3. import unittest
  4.  
  5. from test import test_support
  6.  
  7.  
  8. class HookWatcher:
  9.     def __init__(self):
  10.         self.frames = []
  11.         self.events = []
  12.  
  13.     def callback(self, frame, event, arg):
  14.         self.add_event(event, frame)
  15.  
  16.     def add_event(self, event, frame=None):
  17.         """Add an event to the log."""
  18.         if frame is None:
  19.             frame = sys._getframe(1)
  20.  
  21.         try:
  22.             frameno = self.frames.index(frame)
  23.         except ValueError:
  24.             frameno = len(self.frames)
  25.             self.frames.append(frame)
  26.  
  27.         self.events.append((frameno, event, ident(frame)))
  28.  
  29.     def get_events(self):
  30.         """Remove calls to add_event()."""
  31.         disallowed = [ident(self.add_event.im_func), ident(ident)]
  32.         self.frames = None
  33.  
  34.         return [item for item in self.events if item[2] not in disallowed]
  35.  
  36.  
  37. class ProfileSimulator(HookWatcher):
  38.     def __init__(self, testcase):
  39.         self.testcase = testcase
  40.         self.stack = []
  41.         HookWatcher.__init__(self)
  42.  
  43.     def callback(self, frame, event, arg):
  44.         # Callback registered with sys.setprofile()/sys.settrace()
  45.         self.dispatch[event](self, frame)
  46.  
  47.     def trace_call(self, frame):
  48.         self.add_event('call', frame)
  49.         self.stack.append(frame)
  50.  
  51.     def trace_return(self, frame):
  52.         self.add_event('return', frame)
  53.         self.stack.pop()
  54.  
  55.     def trace_exception(self, frame):
  56.         self.testcase.fail(
  57.             "the profiler should never receive exception events")
  58.  
  59.     dispatch = {
  60.         'call': trace_call,
  61.         'exception': trace_exception,
  62.         'return': trace_return,
  63.         }
  64.  
  65.  
  66. class TestCaseBase(unittest.TestCase):
  67.     def check_events(self, callable, expected):
  68.         events = capture_events(callable, self.new_watcher())
  69.         if events != expected:
  70.             self.fail("Expected events:\n%s\nReceived events:\n%s"
  71.                       % (pprint.pformat(expected), pprint.pformat(events)))
  72.  
  73.  
  74. class ProfileHookTestCase(TestCaseBase):
  75.     def new_watcher(self):
  76.         return HookWatcher()
  77.  
  78.     def test_simple(self):
  79.         def f(p):
  80.             pass
  81.         f_ident = ident(f)
  82.         self.check_events(f, [(1, 'call', f_ident),
  83.                               (1, 'return', f_ident),
  84.                               ])
  85.  
  86.     def test_exception(self):
  87.         def f(p):
  88.             1/0
  89.         f_ident = ident(f)
  90.         self.check_events(f, [(1, 'call', f_ident),
  91.                               (1, 'return', f_ident),
  92.                               ])
  93.  
  94.     def test_caught_exception(self):
  95.         def f(p):
  96.             try: 1/0
  97.             except: pass
  98.         f_ident = ident(f)
  99.         self.check_events(f, [(1, 'call', f_ident),
  100.                               (1, 'return', f_ident),
  101.                               ])
  102.  
  103.     def test_caught_nested_exception(self):
  104.         def f(p):
  105.             try: 1/0
  106.             except: pass
  107.         f_ident = ident(f)
  108.         self.check_events(f, [(1, 'call', f_ident),
  109.                               (1, 'return', f_ident),
  110.                               ])
  111.  
  112.     def test_nested_exception(self):
  113.         def f(p):
  114.             1/0
  115.         f_ident = ident(f)
  116.         self.check_events(f, [(1, 'call', f_ident),
  117.                               # This isn't what I expected:
  118.                               # (0, 'exception', protect_ident),
  119.                               # I expected this again:
  120.                               (1, 'return', f_ident),
  121.                               ])
  122.  
  123.     def test_exception_in_except_clause(self):
  124.         def f(p):
  125.             1/0
  126.         def g(p):
  127.             try:
  128.                 f(p)
  129.             except:
  130.                 try: f(p)
  131.                 except: pass
  132.         f_ident = ident(f)
  133.         g_ident = ident(g)
  134.         self.check_events(g, [(1, 'call', g_ident),
  135.                               (2, 'call', f_ident),
  136.                               (2, 'return', f_ident),
  137.                               (3, 'call', f_ident),
  138.                               (3, 'return', f_ident),
  139.                               (1, 'return', g_ident),
  140.                               ])
  141.  
  142.     def test_exception_propogation(self):
  143.         def f(p):
  144.             1/0
  145.         def g(p):
  146.             try: f(p)
  147.             finally: p.add_event("falling through")
  148.         f_ident = ident(f)
  149.         g_ident = ident(g)
  150.         self.check_events(g, [(1, 'call', g_ident),
  151.                               (2, 'call', f_ident),
  152.                               (2, 'return', f_ident),
  153.                               (1, 'falling through', g_ident),
  154.                               (1, 'return', g_ident),
  155.                               ])
  156.  
  157.     def test_raise_twice(self):
  158.         def f(p):
  159.             try: 1/0
  160.             except: 1/0
  161.         f_ident = ident(f)
  162.         self.check_events(f, [(1, 'call', f_ident),
  163.                               (1, 'return', f_ident),
  164.                               ])
  165.  
  166.     def test_raise_reraise(self):
  167.         def f(p):
  168.             try: 1/0
  169.             except: raise
  170.         f_ident = ident(f)
  171.         self.check_events(f, [(1, 'call', f_ident),
  172.                               (1, 'return', f_ident),
  173.                               ])
  174.  
  175.     def test_raise(self):
  176.         def f(p):
  177.             raise Exception()
  178.         f_ident = ident(f)
  179.         self.check_events(f, [(1, 'call', f_ident),
  180.                               (1, 'return', f_ident),
  181.                               ])
  182.  
  183.     def test_distant_exception(self):
  184.         def f():
  185.             1/0
  186.         def g():
  187.             f()
  188.         def h():
  189.             g()
  190.         def i():
  191.             h()
  192.         def j(p):
  193.             i()
  194.         f_ident = ident(f)
  195.         g_ident = ident(g)
  196.         h_ident = ident(h)
  197.         i_ident = ident(i)
  198.         j_ident = ident(j)
  199.         self.check_events(j, [(1, 'call', j_ident),
  200.                               (2, 'call', i_ident),
  201.                               (3, 'call', h_ident),
  202.                               (4, 'call', g_ident),
  203.                               (5, 'call', f_ident),
  204.                               (5, 'return', f_ident),
  205.                               (4, 'return', g_ident),
  206.                               (3, 'return', h_ident),
  207.                               (2, 'return', i_ident),
  208.                               (1, 'return', j_ident),
  209.                               ])
  210.  
  211.     def test_generator(self):
  212.         def f():
  213.             for i in range(2):
  214.                 yield i
  215.         def g(p):
  216.             for i in f():
  217.                 pass
  218.         f_ident = ident(f)
  219.         g_ident = ident(g)
  220.         self.check_events(g, [(1, 'call', g_ident),
  221.                               # call the iterator twice to generate values
  222.                               (2, 'call', f_ident),
  223.                               (2, 'return', f_ident),
  224.                               (2, 'call', f_ident),
  225.                               (2, 'return', f_ident),
  226.                               # once more; returns end-of-iteration with
  227.                               # actually raising an exception
  228.                               (2, 'call', f_ident),
  229.                               (2, 'return', f_ident),
  230.                               (1, 'return', g_ident),
  231.                               ])
  232.  
  233.     def test_stop_iteration(self):
  234.         def f():
  235.             for i in range(2):
  236.                 yield i
  237.             raise StopIteration
  238.         def g(p):
  239.             for i in f():
  240.                 pass
  241.         f_ident = ident(f)
  242.         g_ident = ident(g)
  243.         self.check_events(g, [(1, 'call', g_ident),
  244.                               # call the iterator twice to generate values
  245.                               (2, 'call', f_ident),
  246.                               (2, 'return', f_ident),
  247.                               (2, 'call', f_ident),
  248.                               (2, 'return', f_ident),
  249.                               # once more to hit the raise:
  250.                               (2, 'call', f_ident),
  251.                               (2, 'return', f_ident),
  252.                               (1, 'return', g_ident),
  253.                               ])
  254.  
  255.  
  256. class ProfileSimulatorTestCase(TestCaseBase):
  257.     def new_watcher(self):
  258.         return ProfileSimulator(self)
  259.  
  260.     def test_simple(self):
  261.         def f(p):
  262.             pass
  263.         f_ident = ident(f)
  264.         self.check_events(f, [(1, 'call', f_ident),
  265.                               (1, 'return', f_ident),
  266.                               ])
  267.  
  268.     def test_basic_exception(self):
  269.         def f(p):
  270.             1/0
  271.         f_ident = ident(f)
  272.         self.check_events(f, [(1, 'call', f_ident),
  273.                               (1, 'return', f_ident),
  274.                               ])
  275.  
  276.     def test_caught_exception(self):
  277.         def f(p):
  278.             try: 1/0
  279.             except: pass
  280.         f_ident = ident(f)
  281.         self.check_events(f, [(1, 'call', f_ident),
  282.                               (1, 'return', f_ident),
  283.                               ])
  284.  
  285.     def test_distant_exception(self):
  286.         def f():
  287.             1/0
  288.         def g():
  289.             f()
  290.         def h():
  291.             g()
  292.         def i():
  293.             h()
  294.         def j(p):
  295.             i()
  296.         f_ident = ident(f)
  297.         g_ident = ident(g)
  298.         h_ident = ident(h)
  299.         i_ident = ident(i)
  300.         j_ident = ident(j)
  301.         self.check_events(j, [(1, 'call', j_ident),
  302.                               (2, 'call', i_ident),
  303.                               (3, 'call', h_ident),
  304.                               (4, 'call', g_ident),
  305.                               (5, 'call', f_ident),
  306.                               (5, 'return', f_ident),
  307.                               (4, 'return', g_ident),
  308.                               (3, 'return', h_ident),
  309.                               (2, 'return', i_ident),
  310.                               (1, 'return', j_ident),
  311.                               ])
  312.  
  313.  
  314. def ident(function):
  315.     if hasattr(function, "f_code"):
  316.         code = function.f_code
  317.     else:
  318.         code = function.func_code
  319.     return code.co_firstlineno, code.co_name
  320.  
  321.  
  322. def protect(f, p):
  323.     try: f(p)
  324.     except: pass
  325.  
  326. protect_ident = ident(protect)
  327.  
  328.  
  329. def capture_events(callable, p=None):
  330.     try:
  331.         sys.setprofile()
  332.     except TypeError:
  333.         pass
  334.     else:
  335.         raise test_support.TestFailed(
  336.             'sys.setprofile() did not raise TypeError')
  337.  
  338.     if p is None:
  339.         p = HookWatcher()
  340.     sys.setprofile(p.callback)
  341.     protect(callable, p)
  342.     sys.setprofile(None)
  343.     return p.get_events()[1:-1]
  344.  
  345.  
  346. def show_events(callable):
  347.     import pprint
  348.     pprint.pprint(capture_events(callable))
  349.  
  350.  
  351. def test_main():
  352.     test_support.run_unittest(
  353.         ProfileHookTestCase,
  354.         ProfileSimulatorTestCase
  355.     )
  356.  
  357.  
  358. if __name__ == "__main__":
  359.     test_main()
  360.