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