blob: 579443ea74ebd4f3d3a166d93003fdf85e5b6d99 [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
Fred Drake39cd6032001-09-26 21:00:33 +000037class ProfileSimulator(HookWatcher):
38 def __init__(self):
39 self.stack = []
40 HookWatcher.__init__(self)
Fred Drake3208d4b2001-09-22 04:28:19 +000041
Fred Drake39cd6032001-09-26 21:00:33 +000042 def callback(self, frame, event, arg):
43 self.dispatch[event](self, frame)
44
45 def trace_call(self, frame):
46 self.add_event('call', frame)
47 self.stack.append(frame)
48
49 def trace_return(self, frame):
50 self.add_event('return', frame)
51 self.stack.pop()
52
53 def trace_exception(self, frame):
54 if len(self.stack) >= 2 and frame is self.stack[-2]:
55 self.add_event('propogate-from', self.stack[-1])
56 self.stack.pop()
57 else:
58 self.add_event('ignore', frame)
59
60 dispatch = {
61 'call': trace_call,
62 'exception': trace_exception,
63 'return': trace_return,
64 }
65
66
67class TestCaseBase(unittest.TestCase):
Fred Drake3208d4b2001-09-22 04:28:19 +000068 def check_events(self, callable, expected):
Fred Drake39cd6032001-09-26 21:00:33 +000069 events = capture_events(callable, self.new_watcher())
Fred Drake3208d4b2001-09-22 04:28:19 +000070 if events != expected:
71 self.fail("Expected events:\n%s\nReceived events:\n%s"
72 % (pprint.pformat(expected), pprint.pformat(events)))
73
Fred Drake39cd6032001-09-26 21:00:33 +000074
75class ProfileHookTestCase(TestCaseBase):
76 def new_watcher(self):
77 return HookWatcher()
78
Fred Drake3208d4b2001-09-22 04:28:19 +000079 def test_simple(self):
80 def f(p):
81 pass
82 f_ident = ident(f)
Fred Drakecc91ac02001-09-25 20:48:14 +000083 self.check_events(f, [(1, 'call', f_ident),
84 (1, 'return', f_ident),
Fred Drake3208d4b2001-09-22 04:28:19 +000085 ])
86
87 def test_exception(self):
88 def f(p):
Fred Drakecc91ac02001-09-25 20:48:14 +000089 1/0
90 f_ident = ident(f)
91 self.check_events(f, [(1, 'call', f_ident),
92 (1, 'exception', f_ident),
93 (0, 'exception', protect_ident),
94 ])
95
96 def test_caught_exception(self):
97 def f(p):
Fred Drake2d879012001-09-24 18:44:11 +000098 try: 1/0
99 except: pass
Fred Drake3208d4b2001-09-22 04:28:19 +0000100 f_ident = ident(f)
Fred Drakecc91ac02001-09-25 20:48:14 +0000101 self.check_events(f, [(1, 'call', f_ident),
102 (1, 'exception', f_ident),
103 (1, 'return', f_ident),
Fred Drake3208d4b2001-09-22 04:28:19 +0000104 ])
105
Fred Drake2d879012001-09-24 18:44:11 +0000106 def test_caught_nested_exception(self):
107 def f(p):
108 try: 1/0
109 except: pass
Fred Drake2d879012001-09-24 18:44:11 +0000110 f_ident = ident(f)
Fred Drakecc91ac02001-09-25 20:48:14 +0000111 self.check_events(f, [(1, 'call', f_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000112 (1, 'exception', f_ident),
113 (1, 'return', f_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000114 ])
115
Fred Drake3208d4b2001-09-22 04:28:19 +0000116 def test_nested_exception(self):
117 def f(p):
118 1/0
Fred Drake3208d4b2001-09-22 04:28:19 +0000119 f_ident = ident(f)
Fred Drakecc91ac02001-09-25 20:48:14 +0000120 self.check_events(f, [(1, 'call', f_ident),
Fred Drake3208d4b2001-09-22 04:28:19 +0000121 (1, 'exception', f_ident),
122 # This isn't what I expected:
Fred Drakecc91ac02001-09-25 20:48:14 +0000123 (0, 'exception', protect_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000124 # I expected this again:
125 # (1, 'exception', f_ident),
Fred Drake3208d4b2001-09-22 04:28:19 +0000126 ])
127
Fred Drake2d879012001-09-24 18:44:11 +0000128 def test_exception_in_except_clause(self):
129 def f(p):
130 1/0
131 def g(p):
132 try:
133 f(p)
134 except:
135 try: f(p)
136 except: pass
137 f_ident = ident(f)
138 g_ident = ident(g)
Fred Drakecc91ac02001-09-25 20:48:14 +0000139 self.check_events(g, [(1, 'call', g_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000140 (2, 'call', f_ident),
141 (2, 'exception', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000142 (1, 'exception', g_ident),
143 (3, 'call', f_ident),
144 (3, 'exception', f_ident),
145 (1, 'exception', g_ident),
146 (1, 'return', g_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000147 ])
148
149 def test_exception_propogation(self):
150 def f(p):
151 1/0
152 def g(p):
153 try: f(p)
154 finally: p.add_event("falling through")
Fred Drake2d879012001-09-24 18:44:11 +0000155 f_ident = ident(f)
156 g_ident = ident(g)
Fred Drakecc91ac02001-09-25 20:48:14 +0000157 self.check_events(g, [(1, 'call', g_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000158 (2, 'call', f_ident),
159 (2, 'exception', f_ident),
160 (1, 'exception', g_ident),
161 (1, 'falling through', g_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000162 (0, 'exception', protect_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000163 ])
Fred Drake3208d4b2001-09-22 04:28:19 +0000164
Fred Drakecc91ac02001-09-25 20:48:14 +0000165 def test_raise_twice(self):
166 def f(p):
167 try: 1/0
168 except: 1/0
169 f_ident = ident(f)
170 self.check_events(f, [(1, 'call', f_ident),
171 (1, 'exception', f_ident),
172 (1, 'exception', f_ident),
173 (0, 'exception', protect_ident)
174 ])
175
176 def test_raise_reraise(self):
177 def f(p):
178 try: 1/0
179 except: raise
180 f_ident = ident(f)
181 self.check_events(f, [(1, 'call', f_ident),
182 (1, 'exception', f_ident),
183 (0, 'exception', protect_ident)
184 ])
185
186 def test_raise(self):
187 def f(p):
188 raise Exception()
189 f_ident = ident(f)
190 self.check_events(f, [(1, 'call', f_ident),
191 (1, 'exception', f_ident),
192 (0, 'exception', protect_ident)
193 ])
194
195
Fred Drake39cd6032001-09-26 21:00:33 +0000196class ProfileSimulatorTestCase(TestCaseBase):
197 def new_watcher(self):
198 return ProfileSimulator()
199
200 def test_simple(self):
201 def f(p):
202 pass
203 f_ident = ident(f)
204 self.check_events(f, [(1, 'call', f_ident),
205 (1, 'return', f_ident),
206 ])
207
208 def test_basic_exception(self):
209 def f(p):
210 1/0
211 f_ident = ident(f)
212 self.check_events(f, [(1, 'call', f_ident),
213 (1, 'ignore', f_ident),
214 (1, 'propogate-from', f_ident),
215 ])
216
217
Fred Drake3208d4b2001-09-22 04:28:19 +0000218def ident(function):
219 if hasattr(function, "f_code"):
220 code = function.f_code
221 else:
222 code = function.func_code
223 return code.co_firstlineno, code.co_name
224
225
Fred Drakecc91ac02001-09-25 20:48:14 +0000226def protect(f, p):
227 try: f(p)
228 except: pass
229
230protect_ident = ident(protect)
231
232
Fred Drake39cd6032001-09-26 21:00:33 +0000233def capture_events(callable, p=None):
234 if p is None:
235 p = HookWatcher()
Fred Drake3208d4b2001-09-22 04:28:19 +0000236 sys.setprofile(p.callback)
Fred Drakecc91ac02001-09-25 20:48:14 +0000237 protect(callable, p)
Fred Drake3208d4b2001-09-22 04:28:19 +0000238 sys.setprofile(None)
Fred Drakecc91ac02001-09-25 20:48:14 +0000239 return p.get_events()[1:-1]
Fred Drake3208d4b2001-09-22 04:28:19 +0000240
241
242def show_events(callable):
243 import pprint
244 pprint.pprint(capture_events(callable))
245
246
247def test_main():
Fred Drake39cd6032001-09-26 21:00:33 +0000248 loader = unittest.TestLoader()
249 suite = unittest.TestSuite()
250 suite.addTest(loader.loadTestsFromTestCase(ProfileHookTestCase))
251 suite.addTest(loader.loadTestsFromTestCase(ProfileSimulatorTestCase))
252 test_support.run_suite(suite)
Fred Drake3208d4b2001-09-22 04:28:19 +0000253
254
255if __name__ == "__main__":
256 test_main()