blob: fa38d3047c7dee56c688819769e642143be7c1ff [file] [log] [blame]
Fred Drake0099ba72001-10-03 21:15:32 +00001from __future__ import generators
2
Neal Norwitz290d31e2002-03-03 15:12:58 +00003from test_support import TestFailed
4
Fred Drake3208d4b2001-09-22 04:28:19 +00005import pprint
6import sys
7import unittest
8
9import test_support
10
11
12class HookWatcher:
13 def __init__(self):
14 self.frames = []
15 self.events = []
16
17 def callback(self, frame, event, arg):
18 self.add_event(event, frame)
19
20 def add_event(self, event, frame=None):
21 """Add an event to the log."""
22 if frame is None:
23 frame = sys._getframe(1)
24
25 try:
26 frameno = self.frames.index(frame)
27 except ValueError:
28 frameno = len(self.frames)
29 self.frames.append(frame)
30
31 self.events.append((frameno, event, ident(frame)))
32
33 def get_events(self):
34 """Remove calls to add_event()."""
Fred Drake2d879012001-09-24 18:44:11 +000035 disallowed = [ident(self.add_event.im_func), ident(ident)]
36 self.frames = None
Fred Drake3208d4b2001-09-22 04:28:19 +000037
Fred Drake2d879012001-09-24 18:44:11 +000038 return [item for item in self.events if item[2] not in disallowed]
Fred Drake3208d4b2001-09-22 04:28:19 +000039
40
Fred Drake39cd6032001-09-26 21:00:33 +000041class ProfileSimulator(HookWatcher):
Fred Drake7c0a93d2001-10-04 14:49:46 +000042 def __init__(self, testcase):
43 self.testcase = testcase
Fred Drake39cd6032001-09-26 21:00:33 +000044 self.stack = []
45 HookWatcher.__init__(self)
Fred Drake3208d4b2001-09-22 04:28:19 +000046
Fred Drake39cd6032001-09-26 21:00:33 +000047 def callback(self, frame, event, arg):
Fred Drake0099ba72001-10-03 21:15:32 +000048 # Callback registered with sys.setprofile()/sys.settrace()
Fred Drake39cd6032001-09-26 21:00:33 +000049 self.dispatch[event](self, frame)
50
51 def trace_call(self, frame):
52 self.add_event('call', frame)
53 self.stack.append(frame)
54
55 def trace_return(self, frame):
56 self.add_event('return', frame)
57 self.stack.pop()
58
59 def trace_exception(self, frame):
Fred Drake7c0a93d2001-10-04 14:49:46 +000060 self.testcase.fail(
61 "the profiler should never receive exception events")
Fred Drake39cd6032001-09-26 21:00:33 +000062
63 dispatch = {
64 'call': trace_call,
65 'exception': trace_exception,
66 'return': trace_return,
67 }
68
69
70class TestCaseBase(unittest.TestCase):
Fred Drake3208d4b2001-09-22 04:28:19 +000071 def check_events(self, callable, expected):
Fred Drake39cd6032001-09-26 21:00:33 +000072 events = capture_events(callable, self.new_watcher())
Fred Drake3208d4b2001-09-22 04:28:19 +000073 if events != expected:
74 self.fail("Expected events:\n%s\nReceived events:\n%s"
75 % (pprint.pformat(expected), pprint.pformat(events)))
76
Fred Drake39cd6032001-09-26 21:00:33 +000077
78class ProfileHookTestCase(TestCaseBase):
79 def new_watcher(self):
80 return HookWatcher()
81
Fred Drake3208d4b2001-09-22 04:28:19 +000082 def test_simple(self):
83 def f(p):
84 pass
85 f_ident = ident(f)
Fred Drakecc91ac02001-09-25 20:48:14 +000086 self.check_events(f, [(1, 'call', f_ident),
87 (1, 'return', f_ident),
Fred Drake3208d4b2001-09-22 04:28:19 +000088 ])
89
90 def test_exception(self):
91 def f(p):
Fred Drakecc91ac02001-09-25 20:48:14 +000092 1/0
93 f_ident = ident(f)
94 self.check_events(f, [(1, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +000095 (1, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +000096 ])
97
98 def test_caught_exception(self):
99 def f(p):
Fred Drake2d879012001-09-24 18:44:11 +0000100 try: 1/0
101 except: pass
Fred Drake3208d4b2001-09-22 04:28:19 +0000102 f_ident = ident(f)
Fred Drakecc91ac02001-09-25 20:48:14 +0000103 self.check_events(f, [(1, 'call', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000104 (1, 'return', f_ident),
Fred Drake3208d4b2001-09-22 04:28:19 +0000105 ])
106
Fred Drake2d879012001-09-24 18:44:11 +0000107 def test_caught_nested_exception(self):
108 def f(p):
109 try: 1/0
110 except: pass
Fred Drake2d879012001-09-24 18:44:11 +0000111 f_ident = ident(f)
Fred Drakecc91ac02001-09-25 20:48:14 +0000112 self.check_events(f, [(1, 'call', f_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000113 (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 # This isn't what I expected:
Fred Drake7c0a93d2001-10-04 14:49:46 +0000122 # (0, 'exception', protect_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000123 # I expected this again:
Fred Drake7c0a93d2001-10-04 14:49:46 +0000124 (1, 'return', f_ident),
Fred Drake3208d4b2001-09-22 04:28:19 +0000125 ])
126
Fred Drake2d879012001-09-24 18:44:11 +0000127 def test_exception_in_except_clause(self):
128 def f(p):
129 1/0
130 def g(p):
131 try:
132 f(p)
133 except:
134 try: f(p)
135 except: pass
136 f_ident = ident(f)
137 g_ident = ident(g)
Fred Drakecc91ac02001-09-25 20:48:14 +0000138 self.check_events(g, [(1, 'call', g_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000139 (2, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000140 (2, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000141 (3, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000142 (3, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000143 (1, 'return', g_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000144 ])
145
146 def test_exception_propogation(self):
147 def f(p):
148 1/0
149 def g(p):
150 try: f(p)
151 finally: p.add_event("falling through")
Fred Drake2d879012001-09-24 18:44:11 +0000152 f_ident = ident(f)
153 g_ident = ident(g)
Fred Drakecc91ac02001-09-25 20:48:14 +0000154 self.check_events(g, [(1, 'call', g_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000155 (2, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000156 (2, 'return', f_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000157 (1, 'falling through', g_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000158 (1, 'return', g_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000159 ])
Fred Drake3208d4b2001-09-22 04:28:19 +0000160
Fred Drakecc91ac02001-09-25 20:48:14 +0000161 def test_raise_twice(self):
162 def f(p):
163 try: 1/0
164 except: 1/0
165 f_ident = ident(f)
166 self.check_events(f, [(1, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000167 (1, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000168 ])
169
170 def test_raise_reraise(self):
171 def f(p):
172 try: 1/0
173 except: raise
174 f_ident = ident(f)
175 self.check_events(f, [(1, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000176 (1, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000177 ])
178
179 def test_raise(self):
180 def f(p):
181 raise Exception()
182 f_ident = ident(f)
183 self.check_events(f, [(1, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000184 (1, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000185 ])
186
Fred Drake0099ba72001-10-03 21:15:32 +0000187 def test_distant_exception(self):
188 def f():
189 1/0
190 def g():
191 f()
192 def h():
193 g()
194 def i():
195 h()
196 def j(p):
197 i()
198 f_ident = ident(f)
199 g_ident = ident(g)
200 h_ident = ident(h)
201 i_ident = ident(i)
202 j_ident = ident(j)
203 self.check_events(j, [(1, 'call', j_ident),
204 (2, 'call', i_ident),
205 (3, 'call', h_ident),
206 (4, 'call', g_ident),
207 (5, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000208 (5, 'return', f_ident),
209 (4, 'return', g_ident),
210 (3, 'return', h_ident),
211 (2, 'return', i_ident),
212 (1, 'return', j_ident),
Fred Drake0099ba72001-10-03 21:15:32 +0000213 ])
214
215 def test_generator(self):
216 def f():
217 for i in range(2):
218 yield i
219 def g(p):
220 for i in f():
221 pass
222 f_ident = ident(f)
223 g_ident = ident(g)
224 self.check_events(g, [(1, 'call', g_ident),
225 # call the iterator twice to generate values
226 (2, 'call', f_ident),
227 (2, 'return', f_ident),
228 (2, 'call', f_ident),
229 (2, 'return', f_ident),
230 # once more; returns end-of-iteration with
231 # actually raising an exception
232 (2, 'call', f_ident),
233 (2, 'return', f_ident),
234 (1, 'return', g_ident),
235 ])
236
237 def test_stop_iteration(self):
238 def f():
239 for i in range(2):
240 yield i
241 raise StopIteration
242 def g(p):
243 for i in f():
244 pass
245 f_ident = ident(f)
246 g_ident = ident(g)
247 self.check_events(g, [(1, 'call', g_ident),
248 # call the iterator twice to generate values
249 (2, 'call', f_ident),
250 (2, 'return', f_ident),
251 (2, 'call', f_ident),
252 (2, 'return', f_ident),
253 # once more to hit the raise:
254 (2, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000255 (2, 'return', f_ident),
Fred Drake0099ba72001-10-03 21:15:32 +0000256 (1, 'return', g_ident),
257 ])
258
Fred Drakecc91ac02001-09-25 20:48:14 +0000259
Fred Drake39cd6032001-09-26 21:00:33 +0000260class ProfileSimulatorTestCase(TestCaseBase):
261 def new_watcher(self):
Fred Drake7c0a93d2001-10-04 14:49:46 +0000262 return ProfileSimulator(self)
Fred Drake39cd6032001-09-26 21:00:33 +0000263
264 def test_simple(self):
265 def f(p):
266 pass
267 f_ident = ident(f)
268 self.check_events(f, [(1, 'call', f_ident),
269 (1, 'return', f_ident),
270 ])
271
272 def test_basic_exception(self):
273 def f(p):
274 1/0
275 f_ident = ident(f)
276 self.check_events(f, [(1, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000277 (1, 'return', f_ident),
Fred Drake39cd6032001-09-26 21:00:33 +0000278 ])
279
Fred Drake0099ba72001-10-03 21:15:32 +0000280 def test_caught_exception(self):
281 def f(p):
282 try: 1/0
283 except: pass
284 f_ident = ident(f)
285 self.check_events(f, [(1, 'call', f_ident),
Fred Drake0099ba72001-10-03 21:15:32 +0000286 (1, 'return', f_ident),
287 ])
288
289 def test_distant_exception(self):
290 def f():
291 1/0
292 def g():
293 f()
294 def h():
295 g()
296 def i():
297 h()
298 def j(p):
299 i()
300 f_ident = ident(f)
301 g_ident = ident(g)
302 h_ident = ident(h)
303 i_ident = ident(i)
304 j_ident = ident(j)
305 self.check_events(j, [(1, 'call', j_ident),
306 (2, 'call', i_ident),
307 (3, 'call', h_ident),
308 (4, 'call', g_ident),
309 (5, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000310 (5, 'return', f_ident),
311 (4, 'return', g_ident),
312 (3, 'return', h_ident),
313 (2, 'return', i_ident),
314 (1, 'return', j_ident),
Fred Drake0099ba72001-10-03 21:15:32 +0000315 ])
316
Fred Drake39cd6032001-09-26 21:00:33 +0000317
Fred Drake3208d4b2001-09-22 04:28:19 +0000318def ident(function):
319 if hasattr(function, "f_code"):
320 code = function.f_code
321 else:
322 code = function.func_code
323 return code.co_firstlineno, code.co_name
324
325
Fred Drakecc91ac02001-09-25 20:48:14 +0000326def protect(f, p):
327 try: f(p)
328 except: pass
329
330protect_ident = ident(protect)
331
332
Fred Drake39cd6032001-09-26 21:00:33 +0000333def capture_events(callable, p=None):
Neal Norwitz290d31e2002-03-03 15:12:58 +0000334 try: sys.setprofile()
335 except TypeError: pass
336 else: raise TestFailed, 'sys.setprofile() did not raise TypeError'
337
Fred Drake39cd6032001-09-26 21:00:33 +0000338 if p is None:
339 p = HookWatcher()
Fred Drake3208d4b2001-09-22 04:28:19 +0000340 sys.setprofile(p.callback)
Fred Drakecc91ac02001-09-25 20:48:14 +0000341 protect(callable, p)
Fred Drake3208d4b2001-09-22 04:28:19 +0000342 sys.setprofile(None)
Fred Drakecc91ac02001-09-25 20:48:14 +0000343 return p.get_events()[1:-1]
Fred Drake3208d4b2001-09-22 04:28:19 +0000344
345
346def show_events(callable):
347 import pprint
348 pprint.pprint(capture_events(callable))
349
350
351def test_main():
Fred Drake39cd6032001-09-26 21:00:33 +0000352 loader = unittest.TestLoader()
353 suite = unittest.TestSuite()
354 suite.addTest(loader.loadTestsFromTestCase(ProfileHookTestCase))
355 suite.addTest(loader.loadTestsFromTestCase(ProfileSimulatorTestCase))
356 test_support.run_suite(suite)
Fred Drake3208d4b2001-09-22 04:28:19 +0000357
358
359if __name__ == "__main__":
360 test_main()