blob: 75599d907b04f7fbf93a7acff6af209bbcf02e5f [file] [log] [blame]
Fred Drake3208d4b2001-09-22 04:28:19 +00001import pprint
2import sys
3import unittest
4
Barry Warsaw04f357c2002-07-23 19:04:11 +00005from test import test_support
Fred Drake3208d4b2001-09-22 04:28:19 +00006
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):
Fred Drake7c0a93d2001-10-04 14:49:46 +000038 def __init__(self, testcase):
39 self.testcase = testcase
Fred Drake39cd6032001-09-26 21:00:33 +000040 self.stack = []
41 HookWatcher.__init__(self)
Fred Drake3208d4b2001-09-22 04:28:19 +000042
Fred Drake39cd6032001-09-26 21:00:33 +000043 def callback(self, frame, event, arg):
Fred Drake0099ba72001-10-03 21:15:32 +000044 # Callback registered with sys.setprofile()/sys.settrace()
Fred Drake39cd6032001-09-26 21:00:33 +000045 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):
Fred Drake7c0a93d2001-10-04 14:49:46 +000056 self.testcase.fail(
57 "the profiler should never receive exception events")
Fred Drake39cd6032001-09-26 21:00:33 +000058
59 dispatch = {
60 'call': trace_call,
61 'exception': trace_exception,
62 'return': trace_return,
63 }
64
65
66class TestCaseBase(unittest.TestCase):
Fred Drake3208d4b2001-09-22 04:28:19 +000067 def check_events(self, callable, expected):
Fred Drake39cd6032001-09-26 21:00:33 +000068 events = capture_events(callable, self.new_watcher())
Fred Drake3208d4b2001-09-22 04:28:19 +000069 if events != expected:
70 self.fail("Expected events:\n%s\nReceived events:\n%s"
71 % (pprint.pformat(expected), pprint.pformat(events)))
72
Fred Drake39cd6032001-09-26 21:00:33 +000073
74class ProfileHookTestCase(TestCaseBase):
75 def new_watcher(self):
76 return HookWatcher()
77
Fred Drake3208d4b2001-09-22 04:28:19 +000078 def test_simple(self):
79 def f(p):
80 pass
81 f_ident = ident(f)
Fred Drakecc91ac02001-09-25 20:48:14 +000082 self.check_events(f, [(1, 'call', f_ident),
83 (1, 'return', f_ident),
Fred Drake3208d4b2001-09-22 04:28:19 +000084 ])
85
86 def test_exception(self):
87 def f(p):
Fred Drakecc91ac02001-09-25 20:48:14 +000088 1/0
89 f_ident = ident(f)
90 self.check_events(f, [(1, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +000091 (1, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +000092 ])
93
94 def test_caught_exception(self):
95 def f(p):
Fred Drake2d879012001-09-24 18:44:11 +000096 try: 1/0
97 except: pass
Fred Drake3208d4b2001-09-22 04:28:19 +000098 f_ident = ident(f)
Fred Drakecc91ac02001-09-25 20:48:14 +000099 self.check_events(f, [(1, 'call', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000100 (1, 'return', f_ident),
Fred Drake3208d4b2001-09-22 04:28:19 +0000101 ])
102
Fred Drake2d879012001-09-24 18:44:11 +0000103 def test_caught_nested_exception(self):
104 def f(p):
105 try: 1/0
106 except: pass
Fred Drake2d879012001-09-24 18:44:11 +0000107 f_ident = ident(f)
Fred Drakecc91ac02001-09-25 20:48:14 +0000108 self.check_events(f, [(1, 'call', f_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000109 (1, 'return', f_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000110 ])
111
Fred Drake3208d4b2001-09-22 04:28:19 +0000112 def test_nested_exception(self):
113 def f(p):
114 1/0
Fred Drake3208d4b2001-09-22 04:28:19 +0000115 f_ident = ident(f)
Fred Drakecc91ac02001-09-25 20:48:14 +0000116 self.check_events(f, [(1, 'call', f_ident),
Fred Drake3208d4b2001-09-22 04:28:19 +0000117 # This isn't what I expected:
Fred Drake7c0a93d2001-10-04 14:49:46 +0000118 # (0, 'exception', protect_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000119 # I expected this again:
Fred Drake7c0a93d2001-10-04 14:49:46 +0000120 (1, 'return', f_ident),
Fred Drake3208d4b2001-09-22 04:28:19 +0000121 ])
122
Fred Drake2d879012001-09-24 18:44:11 +0000123 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)
Fred Drakecc91ac02001-09-25 20:48:14 +0000134 self.check_events(g, [(1, 'call', g_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000135 (2, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000136 (2, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000137 (3, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000138 (3, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000139 (1, 'return', g_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000140 ])
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")
Fred Drake2d879012001-09-24 18:44:11 +0000148 f_ident = ident(f)
149 g_ident = ident(g)
Fred Drakecc91ac02001-09-25 20:48:14 +0000150 self.check_events(g, [(1, 'call', g_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000151 (2, 'call', f_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000152 (2, 'return', f_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000153 (1, 'falling through', g_ident),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000154 (1, 'return', g_ident),
Fred Drake2d879012001-09-24 18:44:11 +0000155 ])
Fred Drake3208d4b2001-09-22 04:28:19 +0000156
Fred Drakecc91ac02001-09-25 20:48:14 +0000157 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),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000163 (1, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000164 ])
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),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000172 (1, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000173 ])
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),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000180 (1, 'return', f_ident),
Fred Drakecc91ac02001-09-25 20:48:14 +0000181 ])
182
Fred Drake0099ba72001-10-03 21:15:32 +0000183 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),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000204 (5, 'return', f_ident),
205 (4, 'return', g_ident),
206 (3, 'return', h_ident),
207 (2, 'return', i_ident),
208 (1, 'return', j_ident),
Fred Drake0099ba72001-10-03 21:15:32 +0000209 ])
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),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000251 (2, 'return', f_ident),
Fred Drake0099ba72001-10-03 21:15:32 +0000252 (1, 'return', g_ident),
253 ])
254
Fred Drakecc91ac02001-09-25 20:48:14 +0000255
Fred Drake39cd6032001-09-26 21:00:33 +0000256class ProfileSimulatorTestCase(TestCaseBase):
257 def new_watcher(self):
Fred Drake7c0a93d2001-10-04 14:49:46 +0000258 return ProfileSimulator(self)
Fred Drake39cd6032001-09-26 21:00:33 +0000259
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),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000273 (1, 'return', f_ident),
Fred Drake39cd6032001-09-26 21:00:33 +0000274 ])
275
Fred Drake0099ba72001-10-03 21:15:32 +0000276 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),
Fred Drake0099ba72001-10-03 21:15:32 +0000282 (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),
Fred Drake7c0a93d2001-10-04 14:49:46 +0000306 (5, 'return', f_ident),
307 (4, 'return', g_ident),
308 (3, 'return', h_ident),
309 (2, 'return', i_ident),
310 (1, 'return', j_ident),
Fred Drake0099ba72001-10-03 21:15:32 +0000311 ])
312
Fred Drake39cd6032001-09-26 21:00:33 +0000313
Fred Drake3208d4b2001-09-22 04:28:19 +0000314def 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
Fred Drakecc91ac02001-09-25 20:48:14 +0000322def protect(f, p):
323 try: f(p)
324 except: pass
325
326protect_ident = ident(protect)
327
328
Fred Drake39cd6032001-09-26 21:00:33 +0000329def capture_events(callable, p=None):
Barry Warsaw04f357c2002-07-23 19:04:11 +0000330 try:
331 sys.setprofile()
332 except TypeError:
333 pass
334 else:
335 raise test_support.TestFailed(
336 'sys.setprofile() did not raise TypeError')
Neal Norwitz290d31e2002-03-03 15:12:58 +0000337
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()