1 | # A test suite for pdb; at the moment, this only validates skipping of
|
---|
2 | # specified test modules (RFE #5142).
|
---|
3 |
|
---|
4 | import imp
|
---|
5 | import sys
|
---|
6 | import os
|
---|
7 | import unittest
|
---|
8 | import subprocess
|
---|
9 | import textwrap
|
---|
10 |
|
---|
11 | from test import test_support
|
---|
12 | # This little helper class is essential for testing pdb under doctest.
|
---|
13 | from test_doctest import _FakeInput
|
---|
14 |
|
---|
15 |
|
---|
16 | class PdbTestCase(unittest.TestCase):
|
---|
17 |
|
---|
18 | def run_pdb(self, script, commands):
|
---|
19 | """Run 'script' lines with pdb and the pdb 'commands'."""
|
---|
20 | filename = 'main.py'
|
---|
21 | with open(filename, 'w') as f:
|
---|
22 | f.write(textwrap.dedent(script))
|
---|
23 | self.addCleanup(test_support.unlink, filename)
|
---|
24 | cmd = [sys.executable, '-m', 'pdb', filename]
|
---|
25 | stdout = stderr = None
|
---|
26 | proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
---|
27 | stdin=subprocess.PIPE,
|
---|
28 | stderr=subprocess.STDOUT,
|
---|
29 | )
|
---|
30 | stdout, stderr = proc.communicate(commands)
|
---|
31 | proc.stdout.close()
|
---|
32 | proc.stdin.close()
|
---|
33 | return stdout, stderr
|
---|
34 |
|
---|
35 | def test_issue13183(self):
|
---|
36 | script = """
|
---|
37 | from bar import bar
|
---|
38 |
|
---|
39 | def foo():
|
---|
40 | bar()
|
---|
41 |
|
---|
42 | def nope():
|
---|
43 | pass
|
---|
44 |
|
---|
45 | def foobar():
|
---|
46 | foo()
|
---|
47 | nope()
|
---|
48 |
|
---|
49 | foobar()
|
---|
50 | """
|
---|
51 | commands = """
|
---|
52 | from bar import bar
|
---|
53 | break bar
|
---|
54 | continue
|
---|
55 | step
|
---|
56 | step
|
---|
57 | quit
|
---|
58 | """
|
---|
59 | bar = """
|
---|
60 | def bar():
|
---|
61 | pass
|
---|
62 | """
|
---|
63 | with open('bar.py', 'w') as f:
|
---|
64 | f.write(textwrap.dedent(bar))
|
---|
65 | self.addCleanup(test_support.unlink, 'bar.py')
|
---|
66 | stdout, stderr = self.run_pdb(script, commands)
|
---|
67 | self.assertTrue(
|
---|
68 | any('main.py(5)foo()->None' in l for l in stdout.splitlines()),
|
---|
69 | 'Fail to step into the caller after a return')
|
---|
70 |
|
---|
71 |
|
---|
72 | class PdbTestInput(object):
|
---|
73 | """Context manager that makes testing Pdb in doctests easier."""
|
---|
74 |
|
---|
75 | def __init__(self, input):
|
---|
76 | self.input = input
|
---|
77 |
|
---|
78 | def __enter__(self):
|
---|
79 | self.real_stdin = sys.stdin
|
---|
80 | sys.stdin = _FakeInput(self.input)
|
---|
81 |
|
---|
82 | def __exit__(self, *exc):
|
---|
83 | sys.stdin = self.real_stdin
|
---|
84 |
|
---|
85 |
|
---|
86 | def write(x):
|
---|
87 | print x
|
---|
88 |
|
---|
89 | def test_pdb_displayhook():
|
---|
90 | """This tests the custom displayhook for pdb.
|
---|
91 |
|
---|
92 | >>> def test_function(foo, bar):
|
---|
93 | ... import pdb; pdb.Pdb().set_trace()
|
---|
94 | ... pass
|
---|
95 |
|
---|
96 | >>> with PdbTestInput([
|
---|
97 | ... 'foo',
|
---|
98 | ... 'bar',
|
---|
99 | ... 'for i in range(5): write(i)',
|
---|
100 | ... 'continue',
|
---|
101 | ... ]):
|
---|
102 | ... test_function(1, None)
|
---|
103 | > <doctest test.test_pdb.test_pdb_displayhook[0]>(3)test_function()
|
---|
104 | -> pass
|
---|
105 | (Pdb) foo
|
---|
106 | 1
|
---|
107 | (Pdb) bar
|
---|
108 | (Pdb) for i in range(5): write(i)
|
---|
109 | 0
|
---|
110 | 1
|
---|
111 | 2
|
---|
112 | 3
|
---|
113 | 4
|
---|
114 | (Pdb) continue
|
---|
115 | """
|
---|
116 |
|
---|
117 | def test_pdb_breakpoint_commands():
|
---|
118 | """Test basic commands related to breakpoints.
|
---|
119 |
|
---|
120 | >>> def test_function():
|
---|
121 | ... import pdb; pdb.Pdb().set_trace()
|
---|
122 | ... print(1)
|
---|
123 | ... print(2)
|
---|
124 | ... print(3)
|
---|
125 | ... print(4)
|
---|
126 |
|
---|
127 | First, need to clear bdb state that might be left over from previous tests.
|
---|
128 | Otherwise, the new breakpoints might get assigned different numbers.
|
---|
129 |
|
---|
130 | >>> from bdb import Breakpoint
|
---|
131 | >>> Breakpoint.next = 1
|
---|
132 | >>> Breakpoint.bplist = {}
|
---|
133 | >>> Breakpoint.bpbynumber = [None]
|
---|
134 |
|
---|
135 | Now test the breakpoint commands. NORMALIZE_WHITESPACE is needed because
|
---|
136 | the breakpoint list outputs a tab for the "stop only" and "ignore next"
|
---|
137 | lines, which we don't want to put in here.
|
---|
138 |
|
---|
139 | >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE
|
---|
140 | ... 'break 3',
|
---|
141 | ... 'disable 1',
|
---|
142 | ... 'ignore 1 10',
|
---|
143 | ... 'condition 1 1 < 2',
|
---|
144 | ... 'break 4',
|
---|
145 | ... 'break 4',
|
---|
146 | ... 'break',
|
---|
147 | ... 'clear 3',
|
---|
148 | ... 'break',
|
---|
149 | ... 'condition 1',
|
---|
150 | ... 'enable 1',
|
---|
151 | ... 'clear 1',
|
---|
152 | ... 'commands 2',
|
---|
153 | ... 'print 42',
|
---|
154 | ... 'end',
|
---|
155 | ... 'continue', # will stop at breakpoint 2 (line 4)
|
---|
156 | ... 'clear', # clear all!
|
---|
157 | ... 'y',
|
---|
158 | ... 'tbreak 5',
|
---|
159 | ... 'continue', # will stop at temporary breakpoint
|
---|
160 | ... 'break', # make sure breakpoint is gone
|
---|
161 | ... 'continue',
|
---|
162 | ... ]):
|
---|
163 | ... test_function()
|
---|
164 | > <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>(3)test_function()
|
---|
165 | -> print(1)
|
---|
166 | (Pdb) break 3
|
---|
167 | Breakpoint 1 at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:3
|
---|
168 | (Pdb) disable 1
|
---|
169 | (Pdb) ignore 1 10
|
---|
170 | Will ignore next 10 crossings of breakpoint 1.
|
---|
171 | (Pdb) condition 1 1 < 2
|
---|
172 | (Pdb) break 4
|
---|
173 | Breakpoint 2 at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:4
|
---|
174 | (Pdb) break 4
|
---|
175 | Breakpoint 3 at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:4
|
---|
176 | (Pdb) break
|
---|
177 | Num Type Disp Enb Where
|
---|
178 | 1 breakpoint keep no at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:3
|
---|
179 | stop only if 1 < 2
|
---|
180 | ignore next 10 hits
|
---|
181 | 2 breakpoint keep yes at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:4
|
---|
182 | 3 breakpoint keep yes at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:4
|
---|
183 | (Pdb) clear 3
|
---|
184 | Deleted breakpoint 3
|
---|
185 | (Pdb) break
|
---|
186 | Num Type Disp Enb Where
|
---|
187 | 1 breakpoint keep no at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:3
|
---|
188 | stop only if 1 < 2
|
---|
189 | ignore next 10 hits
|
---|
190 | 2 breakpoint keep yes at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:4
|
---|
191 | (Pdb) condition 1
|
---|
192 | Breakpoint 1 is now unconditional.
|
---|
193 | (Pdb) enable 1
|
---|
194 | (Pdb) clear 1
|
---|
195 | Deleted breakpoint 1
|
---|
196 | (Pdb) commands 2
|
---|
197 | (com) print 42
|
---|
198 | (com) end
|
---|
199 | (Pdb) continue
|
---|
200 | 1
|
---|
201 | 42
|
---|
202 | > <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>(4)test_function()
|
---|
203 | -> print(2)
|
---|
204 | (Pdb) clear
|
---|
205 | Clear all breaks? y
|
---|
206 | (Pdb) tbreak 5
|
---|
207 | Breakpoint 4 at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:5
|
---|
208 | (Pdb) continue
|
---|
209 | 2
|
---|
210 | Deleted breakpoint 4
|
---|
211 | > <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>(5)test_function()
|
---|
212 | -> print(3)
|
---|
213 | (Pdb) break
|
---|
214 | (Pdb) continue
|
---|
215 | 3
|
---|
216 | 4
|
---|
217 | """
|
---|
218 |
|
---|
219 |
|
---|
220 | def test_pdb_skip_modules():
|
---|
221 | """This illustrates the simple case of module skipping.
|
---|
222 |
|
---|
223 | >>> def skip_module():
|
---|
224 | ... import string
|
---|
225 | ... import pdb; pdb.Pdb(skip=['string*']).set_trace()
|
---|
226 | ... string.lower('FOO')
|
---|
227 |
|
---|
228 | >>> with PdbTestInput([
|
---|
229 | ... 'step',
|
---|
230 | ... 'continue',
|
---|
231 | ... ]):
|
---|
232 | ... skip_module()
|
---|
233 | > <doctest test.test_pdb.test_pdb_skip_modules[0]>(4)skip_module()
|
---|
234 | -> string.lower('FOO')
|
---|
235 | (Pdb) step
|
---|
236 | --Return--
|
---|
237 | > <doctest test.test_pdb.test_pdb_skip_modules[0]>(4)skip_module()->None
|
---|
238 | -> string.lower('FOO')
|
---|
239 | (Pdb) continue
|
---|
240 | """
|
---|
241 |
|
---|
242 |
|
---|
243 | # Module for testing skipping of module that makes a callback
|
---|
244 | mod = imp.new_module('module_to_skip')
|
---|
245 | exec 'def foo_pony(callback): x = 1; callback(); return None' in mod.__dict__
|
---|
246 |
|
---|
247 |
|
---|
248 | def test_pdb_skip_modules_with_callback():
|
---|
249 | """This illustrates skipping of modules that call into other code.
|
---|
250 |
|
---|
251 | >>> def skip_module():
|
---|
252 | ... def callback():
|
---|
253 | ... return None
|
---|
254 | ... import pdb; pdb.Pdb(skip=['module_to_skip*']).set_trace()
|
---|
255 | ... mod.foo_pony(callback)
|
---|
256 |
|
---|
257 | >>> with PdbTestInput([
|
---|
258 | ... 'step',
|
---|
259 | ... 'step',
|
---|
260 | ... 'step',
|
---|
261 | ... 'step',
|
---|
262 | ... 'step',
|
---|
263 | ... 'continue',
|
---|
264 | ... ]):
|
---|
265 | ... skip_module()
|
---|
266 | ... pass # provides something to "step" to
|
---|
267 | > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(5)skip_module()
|
---|
268 | -> mod.foo_pony(callback)
|
---|
269 | (Pdb) step
|
---|
270 | --Call--
|
---|
271 | > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(2)callback()
|
---|
272 | -> def callback():
|
---|
273 | (Pdb) step
|
---|
274 | > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(3)callback()
|
---|
275 | -> return None
|
---|
276 | (Pdb) step
|
---|
277 | --Return--
|
---|
278 | > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(3)callback()->None
|
---|
279 | -> return None
|
---|
280 | (Pdb) step
|
---|
281 | --Return--
|
---|
282 | > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(5)skip_module()->None
|
---|
283 | -> mod.foo_pony(callback)
|
---|
284 | (Pdb) step
|
---|
285 | > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[1]>(10)<module>()
|
---|
286 | -> pass # provides something to "step" to
|
---|
287 | (Pdb) continue
|
---|
288 | """
|
---|
289 |
|
---|
290 |
|
---|
291 | def test_pdb_continue_in_bottomframe():
|
---|
292 | """Test that "continue" and "next" work properly in bottom frame (issue #5294).
|
---|
293 |
|
---|
294 | >>> def test_function():
|
---|
295 | ... import pdb, sys; inst = pdb.Pdb()
|
---|
296 | ... inst.set_trace()
|
---|
297 | ... inst.botframe = sys._getframe() # hackery to get the right botframe
|
---|
298 | ... print(1)
|
---|
299 | ... print(2)
|
---|
300 | ... print(3)
|
---|
301 | ... print(4)
|
---|
302 |
|
---|
303 | First, need to clear bdb state that might be left over from previous tests.
|
---|
304 | Otherwise, the new breakpoints might get assigned different numbers.
|
---|
305 |
|
---|
306 | >>> from bdb import Breakpoint
|
---|
307 | >>> Breakpoint.next = 1
|
---|
308 | >>> Breakpoint.bplist = {}
|
---|
309 | >>> Breakpoint.bpbynumber = [None]
|
---|
310 |
|
---|
311 | >>> with PdbTestInput([
|
---|
312 | ... 'next',
|
---|
313 | ... 'break 7',
|
---|
314 | ... 'continue',
|
---|
315 | ... 'next',
|
---|
316 | ... 'continue',
|
---|
317 | ... 'continue',
|
---|
318 | ... ]):
|
---|
319 | ... test_function()
|
---|
320 | > <doctest test.test_pdb.test_pdb_continue_in_bottomframe[0]>(4)test_function()
|
---|
321 | -> inst.botframe = sys._getframe() # hackery to get the right botframe
|
---|
322 | (Pdb) next
|
---|
323 | > <doctest test.test_pdb.test_pdb_continue_in_bottomframe[0]>(5)test_function()
|
---|
324 | -> print(1)
|
---|
325 | (Pdb) break 7
|
---|
326 | Breakpoint 1 at <doctest test.test_pdb.test_pdb_continue_in_bottomframe[0]>:7
|
---|
327 | (Pdb) continue
|
---|
328 | 1
|
---|
329 | 2
|
---|
330 | > <doctest test.test_pdb.test_pdb_continue_in_bottomframe[0]>(7)test_function()
|
---|
331 | -> print(3)
|
---|
332 | (Pdb) next
|
---|
333 | 3
|
---|
334 | > <doctest test.test_pdb.test_pdb_continue_in_bottomframe[0]>(8)test_function()
|
---|
335 | -> print(4)
|
---|
336 | (Pdb) continue
|
---|
337 | 4
|
---|
338 | """
|
---|
339 |
|
---|
340 | class ModuleInitTester(unittest.TestCase):
|
---|
341 |
|
---|
342 | def test_filename_correct(self):
|
---|
343 | """
|
---|
344 | In issue 7750, it was found that if the filename has a sequence that
|
---|
345 | resolves to an escape character in a Python string (such as \t), it
|
---|
346 | will be treated as the escaped character.
|
---|
347 | """
|
---|
348 | # the test_fn must contain something like \t
|
---|
349 | # on Windows, this will create 'test_mod.py' in the current directory.
|
---|
350 | # on Unix, this will create '.\test_mod.py' in the current directory.
|
---|
351 | test_fn = '.\\test_mod.py'
|
---|
352 | code = 'print("testing pdb")'
|
---|
353 | with open(test_fn, 'w') as f:
|
---|
354 | f.write(code)
|
---|
355 | self.addCleanup(os.remove, test_fn)
|
---|
356 | cmd = [sys.executable, '-m', 'pdb', test_fn,]
|
---|
357 | proc = subprocess.Popen(cmd,
|
---|
358 | stdout=subprocess.PIPE,
|
---|
359 | stdin=subprocess.PIPE,
|
---|
360 | stderr=subprocess.STDOUT,
|
---|
361 | )
|
---|
362 | stdout, stderr = proc.communicate('quit\n')
|
---|
363 | self.assertIn(code, stdout, "pdb munged the filename")
|
---|
364 |
|
---|
365 |
|
---|
366 | def test_main():
|
---|
367 | from test import test_pdb
|
---|
368 | test_support.run_doctest(test_pdb, verbosity=True)
|
---|
369 | test_support.run_unittest(
|
---|
370 | PdbTestCase,
|
---|
371 | ModuleInitTester)
|
---|
372 |
|
---|
373 | if __name__ == '__main__':
|
---|
374 | test_main()
|
---|