123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386 |
- # A test suite for pdb; at the moment, this only validates skipping of
- # specified test modules (RFE #5142).
- import imp
- import sys
- import os
- import unittest
- import subprocess
- import textwrap
- from test import test_support
- # This little helper class is essential for testing pdb under doctest.
- from test_doctest import _FakeInput
- class PdbTestCase(unittest.TestCase):
- def run_pdb(self, script, commands):
- """Run 'script' lines with pdb and the pdb 'commands'."""
- filename = 'main.py'
- with open(filename, 'w') as f:
- f.write(textwrap.dedent(script))
- self.addCleanup(test_support.unlink, filename)
- cmd = [sys.executable, '-m', 'pdb', filename]
- stdout = stderr = None
- proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
- stdin=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- )
- stdout, stderr = proc.communicate(commands)
- proc.stdout.close()
- proc.stdin.close()
- return stdout, stderr
- def test_issue13183(self):
- script = """
- from bar import bar
- def foo():
- bar()
- def nope():
- pass
- def foobar():
- foo()
- nope()
- foobar()
- """
- commands = """
- from bar import bar
- break bar
- continue
- step
- step
- quit
- """
- bar = """
- def bar():
- pass
- """
- with open('bar.py', 'w') as f:
- f.write(textwrap.dedent(bar))
- self.addCleanup(test_support.unlink, 'bar.py')
- self.addCleanup(test_support.unlink, 'bar.pyc')
- stdout, stderr = self.run_pdb(script, commands)
- self.assertTrue(
- any('main.py(5)foo()->None' in l for l in stdout.splitlines()),
- 'Fail to step into the caller after a return')
- def test_issue16180(self):
- # A syntax error in the debuggee.
- script = "def f: pass\n"
- commands = ''
- expected = "SyntaxError:"
- stdout, stderr = self.run_pdb(script, commands)
- self.assertIn(expected, stdout,
- '\n\nExpected:\n{}\nGot:\n{}\n'
- 'Fail to handle a syntax error in the debuggee.'
- .format(expected, stdout))
- 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
- """
- class ModuleInitTester(unittest.TestCase):
- def test_filename_correct(self):
- """
- In issue 7750, it was found that if the filename has a sequence that
- resolves to an escape character in a Python string (such as \t), it
- will be treated as the escaped character.
- """
- # the test_fn must contain something like \t
- # on Windows, this will create 'test_mod.py' in the current directory.
- # on Unix, this will create '.\test_mod.py' in the current directory.
- test_fn = '.\\test_mod.py'
- code = 'print("testing pdb")'
- with open(test_fn, 'w') as f:
- f.write(code)
- self.addCleanup(os.remove, test_fn)
- cmd = [sys.executable, '-m', 'pdb', test_fn,]
- proc = subprocess.Popen(cmd,
- stdout=subprocess.PIPE,
- stdin=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- )
- stdout, stderr = proc.communicate('quit\n')
- self.assertIn(code, stdout, "pdb munged the filename")
- def test_main():
- from test import test_pdb
- test_support.run_doctest(test_pdb, verbosity=True)
- test_support.run_unittest(
- PdbTestCase,
- ModuleInitTester)
- if __name__ == '__main__':
- test_main()
|