blob: c24772856b8e0444bd04210046fb54ce39a82faf [file] [log] [blame]
Fred Drake3208d4b2001-09-22 04:28:19 +00001import pprint
2import sys
3import unittest
4
5import test_support
6
7
8class 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()."""
Fred Drake2d879012001-09-24 18:44:11 +000031 disallowed = [ident(self.add_event.im_func), ident(ident)]
32 self.frames = None
Fred Drake3208d4b2001-09-22 04:28:19 +000033
Fred Drake2d879012001-09-24 18:44:11 +000034 return [item for item in self.events if item[2] not in disallowed]
Fred Drake3208d4b2001-09-22 04:28:19 +000035
36
37class ProfileHookTestCase(unittest.TestCase):
38
39 def check_events(self, callable, expected):
40 events = capture_events(callable)
41 if events != expected:
42 self.fail("Expected events:\n%s\nReceived events:\n%s"
43 % (pprint.pformat(expected), pprint.pformat(events)))
44
45 def test_simple(self):
46 def f(p):
47 pass
48 f_ident = ident(f)
49 self.check_events(f, [(0, 'call', f_ident),
50 (0, 'return', f_ident),
51 ])
52
53 def test_exception(self):
54 def f(p):
Fred Drake2d879012001-09-24 18:44:11 +000055 try: 1/0
56 except: pass
Fred Drake3208d4b2001-09-22 04:28:19 +000057 f_ident = ident(f)
58 self.check_events(f, [(0, 'call', f_ident),
59 (0, 'exception', f_ident),
60 (0, 'return', f_ident),
61 ])
62
Fred Drake2d879012001-09-24 18:44:11 +000063 def test_caught_nested_exception(self):
64 def f(p):
65 try: 1/0
66 except: pass
67 def g(p):
68 f(p)
69 f_ident = ident(f)
70 g_ident = ident(g)
71 self.check_events(g, [(0, 'call', g_ident),
72 (1, 'call', f_ident),
73 (1, 'exception', f_ident),
74 (1, 'return', f_ident),
75 (0, 'return', g_ident),
76 ])
77
Fred Drake3208d4b2001-09-22 04:28:19 +000078 def test_nested_exception(self):
79 def f(p):
80 1/0
81 def g(p):
Fred Drake2d879012001-09-24 18:44:11 +000082 try: f(p)
83 except: pass
Fred Drake3208d4b2001-09-22 04:28:19 +000084 f_ident = ident(f)
85 g_ident = ident(g)
86 self.check_events(g, [(0, 'call', g_ident),
87 (1, 'call', f_ident),
88 (1, 'exception', f_ident),
89 # This isn't what I expected:
90 (0, 'exception', g_ident),
Fred Drake2d879012001-09-24 18:44:11 +000091 # I expected this again:
92 # (1, 'exception', f_ident),
Fred Drake3208d4b2001-09-22 04:28:19 +000093 (0, 'return', g_ident),
94 ])
95
Fred Drake2d879012001-09-24 18:44:11 +000096 def test_exception_in_except_clause(self):
97 def f(p):
98 1/0
99 def g(p):
100 try:
101 f(p)
102 except:
103 try: f(p)
104 except: pass
105 f_ident = ident(f)
106 g_ident = ident(g)
107 self.check_events(g, [(0, 'call', g_ident),
108 (1, 'call', f_ident),
109 (1, 'exception', f_ident),
110 (0, 'exception', g_ident),
111 (2, 'call', f_ident),
112 (2, 'exception', f_ident),
113 (0, 'exception', g_ident),
114 (0, 'return', g_ident),
115 ])
116
117 def test_exception_propogation(self):
118 def f(p):
119 1/0
120 def g(p):
121 try: f(p)
122 finally: p.add_event("falling through")
123 def h(p):
124 try: g(p)
125 except: pass
126 f_ident = ident(f)
127 g_ident = ident(g)
128 h_ident = ident(h)
129 self.check_events(h, [(0, 'call', h_ident),
130 (1, 'call', g_ident),
131 (2, 'call', f_ident),
132 (2, 'exception', f_ident),
133 (1, 'exception', g_ident),
134 (1, 'falling through', g_ident),
135 (0, 'exception', h_ident),
136 (0, 'return', h_ident),
137 ])
Fred Drake3208d4b2001-09-22 04:28:19 +0000138
139def ident(function):
140 if hasattr(function, "f_code"):
141 code = function.f_code
142 else:
143 code = function.func_code
144 return code.co_firstlineno, code.co_name
145
146
147def capture_events(callable):
148 p = HookWatcher()
149 sys.setprofile(p.callback)
150 callable(p)
151 sys.setprofile(None)
152 return p.get_events()
153
154
155def show_events(callable):
156 import pprint
157 pprint.pprint(capture_events(callable))
158
159
160def test_main():
161 test_support.run_unittest(ProfileHookTestCase)
162
163
164if __name__ == "__main__":
165 test_main()