Home | History | Annotate | Download | only in test
      1 # A test suite for pdb; at the moment, this only validates skipping of
      2 # specified test modules (RFE #5142).
      3 
      4 import imp
      5 import sys
      6 import os
      7 import unittest
      8 import subprocess
      9 import textwrap
     10 
     11 from test import test_support
     12 # This little helper class is essential for testing pdb under doctest.
     13 from test_doctest import _FakeInput
     14 
     15 
     16 class PdbTestCase(unittest.TestCase):
     17 
     18     def run_pdb(self, script, commands):
     19         """Run 'script' lines with pdb and the pdb 'commands'."""
     20         filename = 'main.py'
     21         with open(filename, 'w') as f:
     22             f.write(textwrap.dedent(script))
     23         self.addCleanup(test_support.unlink, filename)
     24         cmd = [sys.executable, '-m', 'pdb', filename]
     25         stdout = stderr = None
     26         proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
     27                                    stdin=subprocess.PIPE,
     28                                    stderr=subprocess.STDOUT,
     29                                    )
     30         stdout, stderr = proc.communicate(commands)
     31         proc.stdout.close()
     32         proc.stdin.close()
     33         return stdout, stderr
     34 
     35     def test_issue13183(self):
     36         script = """
     37             from bar import bar
     38 
     39             def foo():
     40                 bar()
     41 
     42             def nope():
     43                 pass
     44 
     45             def foobar():
     46                 foo()
     47                 nope()
     48 
     49             foobar()
     50         """
     51         commands = """
     52             from bar import bar
     53             break bar
     54             continue
     55             step
     56             step
     57             quit
     58         """
     59         bar = """
     60             def bar():
     61                 pass
     62         """
     63         with open('bar.py', 'w') as f:
     64             f.write(textwrap.dedent(bar))
     65         self.addCleanup(test_support.unlink, 'bar.py')
     66         self.addCleanup(test_support.unlink, 'bar.pyc')
     67         stdout, stderr = self.run_pdb(script, commands)
     68         self.assertTrue(
     69             any('main.py(5)foo()->None' in l for l in stdout.splitlines()),
     70             'Fail to step into the caller after a return')
     71 
     72     def test_issue16180(self):
     73         # A syntax error in the debuggee.
     74         script = "def f: pass\n"
     75         commands = ''
     76         expected = "SyntaxError:"
     77         stdout, stderr = self.run_pdb(script, commands)
     78         self.assertIn(expected, stdout,
     79             '\n\nExpected:\n{}\nGot:\n{}\n'
     80             'Fail to handle a syntax error in the debuggee.'
     81             .format(expected, stdout))
     82 
     83 
     84 class PdbTestInput(object):
     85     """Context manager that makes testing Pdb in doctests easier."""
     86 
     87     def __init__(self, input):
     88         self.input = input
     89 
     90     def __enter__(self):
     91         self.real_stdin = sys.stdin
     92         sys.stdin = _FakeInput(self.input)
     93 
     94     def __exit__(self, *exc):
     95         sys.stdin = self.real_stdin
     96 
     97 
     98 def write(x):
     99     print x
    100 
    101 def test_pdb_displayhook():
    102     """This tests the custom displayhook for pdb.
    103 
    104     >>> def test_function(foo, bar):
    105     ...     import pdb; pdb.Pdb().set_trace()
    106     ...     pass
    107 
    108     >>> with PdbTestInput([
    109     ...     'foo',
    110     ...     'bar',
    111     ...     'for i in range(5): write(i)',
    112     ...     'continue',
    113     ... ]):
    114     ...     test_function(1, None)
    115     > <doctest test.test_pdb.test_pdb_displayhook[0]>(3)test_function()
    116     -> pass
    117     (Pdb) foo
    118     1
    119     (Pdb) bar
    120     (Pdb) for i in range(5): write(i)
    121     0
    122     1
    123     2
    124     3
    125     4
    126     (Pdb) continue
    127     """
    128 
    129 def test_pdb_breakpoint_commands():
    130     """Test basic commands related to breakpoints.
    131 
    132     >>> def test_function():
    133     ...     import pdb; pdb.Pdb().set_trace()
    134     ...     print(1)
    135     ...     print(2)
    136     ...     print(3)
    137     ...     print(4)
    138 
    139     First, need to clear bdb state that might be left over from previous tests.
    140     Otherwise, the new breakpoints might get assigned different numbers.
    141 
    142     >>> from bdb import Breakpoint
    143     >>> Breakpoint.next = 1
    144     >>> Breakpoint.bplist = {}
    145     >>> Breakpoint.bpbynumber = [None]
    146 
    147     Now test the breakpoint commands.  NORMALIZE_WHITESPACE is needed because
    148     the breakpoint list outputs a tab for the "stop only" and "ignore next"
    149     lines, which we don't want to put in here.
    150 
    151     >>> with PdbTestInput([  # doctest: +NORMALIZE_WHITESPACE
    152     ...     'break 3',
    153     ...     'disable 1',
    154     ...     'ignore 1 10',
    155     ...     'condition 1 1 < 2',
    156     ...     'break 4',
    157     ...     'break 4',
    158     ...     'break',
    159     ...     'clear 3',
    160     ...     'break',
    161     ...     'condition 1',
    162     ...     'enable 1',
    163     ...     'clear 1',
    164     ...     'commands 2',
    165     ...     'print 42',
    166     ...     'end',
    167     ...     'continue',  # will stop at breakpoint 2 (line 4)
    168     ...     'clear',     # clear all!
    169     ...     'y',
    170     ...     'tbreak 5',
    171     ...     'continue',  # will stop at temporary breakpoint
    172     ...     'break',     # make sure breakpoint is gone
    173     ...     'continue',
    174     ... ]):
    175     ...    test_function()
    176     > <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>(3)test_function()
    177     -> print(1)
    178     (Pdb) break 3
    179     Breakpoint 1 at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:3
    180     (Pdb) disable 1
    181     (Pdb) ignore 1 10
    182     Will ignore next 10 crossings of breakpoint 1.
    183     (Pdb) condition 1 1 < 2
    184     (Pdb) break 4
    185     Breakpoint 2 at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:4
    186     (Pdb) break 4
    187     Breakpoint 3 at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:4
    188     (Pdb) break
    189     Num Type         Disp Enb   Where
    190     1   breakpoint   keep no    at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:3
    191             stop only if 1 < 2
    192             ignore next 10 hits
    193     2   breakpoint   keep yes   at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:4
    194     3   breakpoint   keep yes   at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:4
    195     (Pdb) clear 3
    196     Deleted breakpoint 3
    197     (Pdb) break
    198     Num Type         Disp Enb   Where
    199     1   breakpoint   keep no    at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:3
    200             stop only if 1 < 2
    201             ignore next 10 hits
    202     2   breakpoint   keep yes   at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:4
    203     (Pdb) condition 1
    204     Breakpoint 1 is now unconditional.
    205     (Pdb) enable 1
    206     (Pdb) clear 1
    207     Deleted breakpoint 1
    208     (Pdb) commands 2
    209     (com) print 42
    210     (com) end
    211     (Pdb) continue
    212     1
    213     42
    214     > <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>(4)test_function()
    215     -> print(2)
    216     (Pdb) clear
    217     Clear all breaks? y
    218     (Pdb) tbreak 5
    219     Breakpoint 4 at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:5
    220     (Pdb) continue
    221     2
    222     Deleted breakpoint 4
    223     > <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>(5)test_function()
    224     -> print(3)
    225     (Pdb) break
    226     (Pdb) continue
    227     3
    228     4
    229     """
    230 
    231 
    232 def test_pdb_skip_modules():
    233     """This illustrates the simple case of module skipping.
    234 
    235     >>> def skip_module():
    236     ...     import string
    237     ...     import pdb; pdb.Pdb(skip=['string*']).set_trace()
    238     ...     string.lower('FOO')
    239 
    240     >>> with PdbTestInput([
    241     ...     'step',
    242     ...     'continue',
    243     ... ]):
    244     ...     skip_module()
    245     > <doctest test.test_pdb.test_pdb_skip_modules[0]>(4)skip_module()
    246     -> string.lower('FOO')
    247     (Pdb) step
    248     --Return--
    249     > <doctest test.test_pdb.test_pdb_skip_modules[0]>(4)skip_module()->None
    250     -> string.lower('FOO')
    251     (Pdb) continue
    252     """
    253 
    254 
    255 # Module for testing skipping of module that makes a callback
    256 mod = imp.new_module('module_to_skip')
    257 exec 'def foo_pony(callback): x = 1; callback(); return None' in mod.__dict__
    258 
    259 
    260 def test_pdb_skip_modules_with_callback():
    261     """This illustrates skipping of modules that call into other code.
    262 
    263     >>> def skip_module():
    264     ...     def callback():
    265     ...         return None
    266     ...     import pdb; pdb.Pdb(skip=['module_to_skip*']).set_trace()
    267     ...     mod.foo_pony(callback)
    268 
    269     >>> with PdbTestInput([
    270     ...     'step',
    271     ...     'step',
    272     ...     'step',
    273     ...     'step',
    274     ...     'step',
    275     ...     'continue',
    276     ... ]):
    277     ...     skip_module()
    278     ...     pass  # provides something to "step" to
    279     > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(5)skip_module()
    280     -> mod.foo_pony(callback)
    281     (Pdb) step
    282     --Call--
    283     > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(2)callback()
    284     -> def callback():
    285     (Pdb) step
    286     > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(3)callback()
    287     -> return None
    288     (Pdb) step
    289     --Return--
    290     > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(3)callback()->None
    291     -> return None
    292     (Pdb) step
    293     --Return--
    294     > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[0]>(5)skip_module()->None
    295     -> mod.foo_pony(callback)
    296     (Pdb) step
    297     > <doctest test.test_pdb.test_pdb_skip_modules_with_callback[1]>(10)<module>()
    298     -> pass  # provides something to "step" to
    299     (Pdb) continue
    300     """
    301 
    302 
    303 def test_pdb_continue_in_bottomframe():
    304     """Test that "continue" and "next" work properly in bottom frame (issue #5294).
    305 
    306     >>> def test_function():
    307     ...     import pdb, sys; inst = pdb.Pdb()
    308     ...     inst.set_trace()
    309     ...     inst.botframe = sys._getframe()  # hackery to get the right botframe
    310     ...     print(1)
    311     ...     print(2)
    312     ...     print(3)
    313     ...     print(4)
    314 
    315     First, need to clear bdb state that might be left over from previous tests.
    316     Otherwise, the new breakpoints might get assigned different numbers.
    317 
    318     >>> from bdb import Breakpoint
    319     >>> Breakpoint.next = 1
    320     >>> Breakpoint.bplist = {}
    321     >>> Breakpoint.bpbynumber = [None]
    322 
    323     >>> with PdbTestInput([
    324     ...     'next',
    325     ...     'break 7',
    326     ...     'continue',
    327     ...     'next',
    328     ...     'continue',
    329     ...     'continue',
    330     ... ]):
    331     ...    test_function()
    332     > <doctest test.test_pdb.test_pdb_continue_in_bottomframe[0]>(4)test_function()
    333     -> inst.botframe = sys._getframe()  # hackery to get the right botframe
    334     (Pdb) next
    335     > <doctest test.test_pdb.test_pdb_continue_in_bottomframe[0]>(5)test_function()
    336     -> print(1)
    337     (Pdb) break 7
    338     Breakpoint 1 at <doctest test.test_pdb.test_pdb_continue_in_bottomframe[0]>:7
    339     (Pdb) continue
    340     1
    341     2
    342     > <doctest test.test_pdb.test_pdb_continue_in_bottomframe[0]>(7)test_function()
    343     -> print(3)
    344     (Pdb) next
    345     3
    346     > <doctest test.test_pdb.test_pdb_continue_in_bottomframe[0]>(8)test_function()
    347     -> print(4)
    348     (Pdb) continue
    349     4
    350     """
    351 
    352 class ModuleInitTester(unittest.TestCase):
    353 
    354     def test_filename_correct(self):
    355         """
    356         In issue 7750, it was found that if the filename has a sequence that
    357         resolves to an escape character in a Python string (such as \t), it
    358         will be treated as the escaped character.
    359         """
    360         # the test_fn must contain something like \t
    361         # on Windows, this will create 'test_mod.py' in the current directory.
    362         # on Unix, this will create '.\test_mod.py' in the current directory.
    363         test_fn = '.\\test_mod.py'
    364         code = 'print("testing pdb")'
    365         with open(test_fn, 'w') as f:
    366             f.write(code)
    367         self.addCleanup(os.remove, test_fn)
    368         cmd = [sys.executable, '-m', 'pdb', test_fn,]
    369         proc = subprocess.Popen(cmd,
    370             stdout=subprocess.PIPE,
    371             stdin=subprocess.PIPE,
    372             stderr=subprocess.STDOUT,
    373             )
    374         stdout, stderr = proc.communicate('quit\n')
    375         self.assertIn(code, stdout, "pdb munged the filename")
    376 
    377 
    378 def test_main():
    379     from test import test_pdb
    380     test_support.run_doctest(test_pdb, verbosity=True)
    381     test_support.run_unittest(
    382         PdbTestCase,
    383         ModuleInitTester)
    384 
    385 if __name__ == '__main__':
    386     test_main()
    387