diff options
Diffstat (limited to 'lib/python2.7/test/test_pdb.py')
-rw-r--r-- | lib/python2.7/test/test_pdb.py | 374 |
1 files changed, 374 insertions, 0 deletions
diff --git a/lib/python2.7/test/test_pdb.py b/lib/python2.7/test/test_pdb.py new file mode 100644 index 0000000..559f756 --- /dev/null +++ b/lib/python2.7/test/test_pdb.py @@ -0,0 +1,374 @@ +# 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') + 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') + + +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() |