# A test suite for pdb; at the moment, this only validates skipping of | |
# specified test modules (RFE #5142). | |
import imp | |
import sys | |
from test import test_support | |
# This little helper class is essential for testing pdb under doctest. | |
from test_doctest import _FakeInput | |
class PdbTestInput(object): | |
"""Context manager that makes testing Pdb in doctests easier.""" | |
def __init__(self, input): | |
self.input = input | |
def __enter__(self): | |
self.real_stdin = sys.stdin | |
sys.stdin = _FakeInput(self.input) | |
def __exit__(self, *exc): | |
sys.stdin = self.real_stdin | |
def write(x): | |
print x | |
def test_pdb_displayhook(): | |
"""This tests the custom displayhook for pdb. | |
>>> def test_function(foo, bar): | |
... import pdb; pdb.Pdb().set_trace() | |
... pass | |
>>> with PdbTestInput([ | |
... 'foo', | |
... 'bar', | |
... 'for i in range(5): write(i)', | |
... 'continue', | |
... ]): | |
... test_function(1, None) | |
> <doctest test.test_pdb.test_pdb_displayhook[0]>(3)test_function() | |
-> pass | |
(Pdb) foo | |
1 | |
(Pdb) bar | |
(Pdb) for i in range(5): write(i) | |
0 | |
1 | |
2 | |
3 | |
4 | |
(Pdb) continue | |
""" | |
def test_pdb_breakpoint_commands(): | |
"""Test basic commands related to breakpoints. | |
>>> def test_function(): | |
... import pdb; pdb.Pdb().set_trace() | |
... print(1) | |
... print(2) | |
... print(3) | |
... print(4) | |
First, need to clear bdb state that might be left over from previous tests. | |
Otherwise, the new breakpoints might get assigned different numbers. | |
>>> from bdb import Breakpoint | |
>>> Breakpoint.next = 1 | |
>>> Breakpoint.bplist = {} | |
>>> Breakpoint.bpbynumber = [None] | |
Now test the breakpoint commands. NORMALIZE_WHITESPACE is needed because | |
the breakpoint list outputs a tab for the "stop only" and "ignore next" | |
lines, which we don't want to put in here. | |
>>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE | |
... 'break 3', | |
... 'disable 1', | |
... 'ignore 1 10', | |
... 'condition 1 1 < 2', | |
... 'break 4', | |
... 'break 4', | |
... 'break', | |
... 'clear 3', | |
... 'break', | |
... 'condition 1', | |
... 'enable 1', | |
... 'clear 1', | |
... 'commands 2', | |
... 'print 42', | |
... 'end', | |
... 'continue', # will stop at breakpoint 2 (line 4) | |
... 'clear', # clear all! | |
... 'y', | |
... 'tbreak 5', | |
... 'continue', # will stop at temporary breakpoint | |
... 'break', # make sure breakpoint is gone | |
... 'continue', | |
... ]): | |
... test_function() | |
> <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>(3)test_function() | |
-> print(1) | |
(Pdb) break 3 | |
Breakpoint 1 at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:3 | |
(Pdb) disable 1 | |
(Pdb) ignore 1 10 | |
Will ignore next 10 crossings of breakpoint 1. | |
(Pdb) condition 1 1 < 2 | |
(Pdb) break 4 | |
Breakpoint 2 at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:4 | |
(Pdb) break 4 | |
Breakpoint 3 at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:4 | |
(Pdb) break | |
Num Type Disp Enb Where | |
1 breakpoint keep no at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:3 | |
stop only if 1 < 2 | |
ignore next 10 hits | |
2 breakpoint keep yes at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:4 | |
3 breakpoint keep yes at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:4 | |
(Pdb) clear 3 | |
Deleted breakpoint 3 | |
(Pdb) break | |
Num Type Disp Enb Where | |
1 breakpoint keep no at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:3 | |
stop only if 1 < 2 | |
ignore next 10 hits | |
2 breakpoint keep yes at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:4 | |
(Pdb) condition 1 | |
Breakpoint 1 is now unconditional. | |
(Pdb) enable 1 | |
(Pdb) clear 1 | |
Deleted breakpoint 1 | |
(Pdb) commands 2 | |
(com) print 42 | |
(com) end | |
(Pdb) continue | |
1 | |
42 | |
> <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>(4)test_function() | |
-> print(2) | |
(Pdb) clear | |
Clear all breaks? y | |
(Pdb) tbreak 5 | |
Breakpoint 4 at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:5 | |
(Pdb) continue | |
2 | |
Deleted breakpoint 4 | |
> <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>(5)test_function() | |
-> print(3) | |
(Pdb) break | |
(Pdb) continue | |
3 | |
4 | |
""" | |
def test_pdb_skip_modules(): | |
"""This illustrates the simple case of module skipping. | |
>>> def skip_module(): | |
... import string | |
... import pdb; pdb.Pdb(skip=['string*']).set_trace() | |
... string.lower('FOO') | |
>>> with PdbTestInput([ | |
... 'step', | |
... 'continue', | |
... ]): | |
... skip_module() | |
> <doctest test.test_pdb.test_pdb_skip_modules[0]>(4)skip_module() | |
-> string.lower('FOO') | |
(Pdb) step | |
--Return-- | |
> <doctest test.test_pdb.test_pdb_skip_modules[0]>(4)skip_module()->None | |
-> string.lower('FOO') | |
(Pdb) continue | |
""" | |
# Module for testing skipping of module that makes a callback | |
mod = imp.new_module('module_to_skip') | |
exec 'def foo_pony(callback): x = 1; callback(); return None' in mod.__dict__ | |
def test_pdb_skip_modules_with_callback(): | |
"""This illustrates skipping of modules that call into other code. | |
>>> def skip_module(): | |
... def callback(): | |
... return None | |
... import pdb; pdb.Pdb(skip=['module_to_skip*']).set_trace() | |
... mod.foo_pony(callback) | |
>>> with PdbTestInput([ | |
... 'step', | |
... 'step', | |
... 'step', | |
... 'step', | |
... 'step', | |
... 'continue', | |
... ]): | |
... skip_module() | |
... pass # provides something to "step" to | |
> <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(5)skip_module() | |
-> mod.foo_pony(callback) | |
(Pdb) step | |
--Call-- | |
> <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(2)callback() | |
-> def callback(): | |
(Pdb) step | |
> <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(3)callback() | |
-> return None | |
(Pdb) step | |
--Return-- | |
> <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(3)callback()->None | |
-> return None | |
(Pdb) step | |
--Return-- | |
> <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(5)skip_module()->None | |
-> mod.foo_pony(callback) | |
(Pdb) step | |
> <doctest test.test_pdb.test_pdb_skip_modules_with_callback[1]>(10)<module>() | |
-> pass # provides something to "step" to | |
(Pdb) continue | |
""" | |
def test_pdb_continue_in_bottomframe(): | |
"""Test that "continue" and "next" work properly in bottom frame (issue #5294). | |
>>> def test_function(): | |
... import pdb, sys; inst = pdb.Pdb() | |
... inst.set_trace() | |
... inst.botframe = sys._getframe() # hackery to get the right botframe | |
... print(1) | |
... print(2) | |
... print(3) | |
... print(4) | |
First, need to clear bdb state that might be left over from previous tests. | |
Otherwise, the new breakpoints might get assigned different numbers. | |
>>> from bdb import Breakpoint | |
>>> Breakpoint.next = 1 | |
>>> Breakpoint.bplist = {} | |
>>> Breakpoint.bpbynumber = [None] | |
>>> with PdbTestInput([ | |
... 'next', | |
... 'break 7', | |
... 'continue', | |
... 'next', | |
... 'continue', | |
... 'continue', | |
... ]): | |
... test_function() | |
> <doctest test.test_pdb.test_pdb_continue_in_bottomframe[0]>(4)test_function() | |
-> inst.botframe = sys._getframe() # hackery to get the right botframe | |
(Pdb) next | |
> <doctest test.test_pdb.test_pdb_continue_in_bottomframe[0]>(5)test_function() | |
-> print(1) | |
(Pdb) break 7 | |
Breakpoint 1 at <doctest test.test_pdb.test_pdb_continue_in_bottomframe[0]>:7 | |
(Pdb) continue | |
1 | |
2 | |
> <doctest test.test_pdb.test_pdb_continue_in_bottomframe[0]>(7)test_function() | |
-> print(3) | |
(Pdb) next | |
3 | |
> <doctest test.test_pdb.test_pdb_continue_in_bottomframe[0]>(8)test_function() | |
-> print(4) | |
(Pdb) continue | |
4 | |
""" | |
def test_main(): | |
from test import test_pdb | |
test_support.run_doctest(test_pdb, verbosity=True) | |
if __name__ == '__main__': | |
test_main() |