387 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			387 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
| # 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()
 |