# A test suite for pdb; not very comprehensive at the moment. import imp import pdb import sys import unittest import subprocess from test import support # This little helper class is essential for testing pdb under doctest. from test.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 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): print(i)', ... 'continue', ... ]): ... test_function(1, None) > (3)test_function() -> pass (Pdb) foo 1 (Pdb) bar (Pdb) for i in range(5): print(i) 0 1 2 3 4 (Pdb) continue """ def test_pdb_skip_modules(): """This illustrates the simple case of module skipping. >>> def skip_module(): ... import string ... import pdb; pdb.Pdb(skip=['stri*']).set_trace() ... string.capwords('FOO') >>> with PdbTestInput([ ... 'step', ... 'continue', ... ]): ... skip_module() > (4)skip_module() -> string.capwords('FOO') (Pdb) step --Return-- > (4)skip_module()->None -> string.capwords('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', 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 > (5)skip_module() -> mod.foo_pony(callback) (Pdb) step --Call-- > (2)callback() -> def callback(): (Pdb) step > (3)callback() -> return None (Pdb) step --Return-- > (3)callback()->None -> return None (Pdb) step --Return-- > (5)skip_module()->None -> mod.foo_pony(callback) (Pdb) step > (10)() -> 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) >>> with PdbTestInput([ # doctest: +ELLIPSIS ... 'next', ... 'break 7', ... 'continue', ... 'next', ... 'continue', ... 'continue', ... ]): ... test_function() > (4)test_function() -> inst.botframe = sys._getframe() # hackery to get the right botframe (Pdb) next > (5)test_function() -> print(1) (Pdb) break 7 Breakpoint ... at :7 (Pdb) continue 1 2 > (7)test_function() -> print(3) (Pdb) next 3 > (8)test_function() -> print(4) (Pdb) continue 4 """ def test_pdb_breakpoints(): """Test handling of 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', ... 'condition 1', ... 'enable 1', ... 'clear 1', ... 'commands 2', ... 'print 42', ... 'end', ... 'continue', # will stop at breakpoint 2 ... 'continue', ... ]): ... test_function() > (3)test_function() -> print(1) (Pdb) break 3 Breakpoint 1 at :3 (Pdb) disable 1 Disabled breakpoint 1 at :3 (Pdb) ignore 1 10 Will ignore next 10 crossings of breakpoint 1. (Pdb) condition 1 1 < 2 New condition set for breakpoint 1. (Pdb) break 4 Breakpoint 2 at :4 (Pdb) break Num Type Disp Enb Where 1 breakpoint keep no at :3 stop only if 1 < 2 ignore next 10 hits 2 breakpoint keep yes at :4 (Pdb) condition 1 Breakpoint 1 is now unconditional. (Pdb) enable 1 Enabled breakpoint 1 at :3 (Pdb) clear 1 Deleted breakpoint 1 at :3 (Pdb) commands 2 (com) print 42 (com) end (Pdb) continue 1 42 > (4)test_function() -> print(2) (Pdb) continue 2 3 4 """ def pdb_invoke(method, arg): """Run pdb.method(arg).""" import pdb; getattr(pdb, method)(arg) def test_pdb_run_with_incorrect_argument(): """Testing run and runeval with incorrect first argument. >>> pti = PdbTestInput(['continue',]) >>> with pti: ... pdb_invoke('run', lambda x: x) Traceback (most recent call last): TypeError: exec() arg 1 must be a string, bytes or code object >>> with pti: ... pdb_invoke('runeval', lambda x: x) Traceback (most recent call last): TypeError: eval() arg 1 must be a string, bytes or code object """ def test_pdb_run_with_code_object(): """Testing run and runeval with code object as a first argument. >>> with PdbTestInput(['step','x', 'continue']): ... pdb_invoke('run', compile('x=1', '', 'exec')) > (1)() (Pdb) step --Return-- > (1)()->None (Pdb) x 1 (Pdb) continue >>> with PdbTestInput(['x', 'continue']): ... x=0 ... pdb_invoke('runeval', compile('x+1', '', 'eval')) > (1)()->None (Pdb) x 1 (Pdb) continue """ class PdbTestCase(unittest.TestCase): def test_issue7964(self): # open the file as binary so we can force \r\n newline with open(support.TESTFN, 'wb') as f: f.write(b'print("testing my pdb")\r\n') cmd = [sys.executable, '-m', 'pdb', support.TESTFN] proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, ) stdout, stderr = proc.communicate(b'quit\n') self.assertNotIn(b'SyntaxError', stdout, "Got a syntax error running test script under PDB") def tearDown(self): support.unlink(support.TESTFN) def test_main(): from test import test_pdb support.run_doctest(test_pdb, verbosity=True) support.run_unittest(PdbTestCase) if __name__ == '__main__': test_main()