python (3.11.7)

(root)/
lib/
python3.11/
test/
test_bdb.py
       1  """ Test the bdb module.
       2  
       3      A test defines a list of tuples that may be seen as paired tuples, each
       4      pair being defined by 'expect_tuple, set_tuple' as follows:
       5  
       6          ([event, [lineno[, co_name[, eargs]]]]), (set_type, [sargs])
       7  
       8      * 'expect_tuple' describes the expected current state of the Bdb instance.
       9        It may be the empty tuple and no check is done in that case.
      10      * 'set_tuple' defines the set_*() method to be invoked when the Bdb
      11        instance reaches this state.
      12  
      13      Example of an 'expect_tuple, set_tuple' pair:
      14  
      15          ('line', 2, 'tfunc_main'), ('step', )
      16  
      17      Definitions of the members of the 'expect_tuple':
      18          event:
      19              Name of the trace event. The set methods that do not give back
      20              control to the tracer [1] do not trigger a tracer event and in
      21              that case the next 'event' may be 'None' by convention, its value
      22              is not checked.
      23              [1] Methods that trigger a trace event are set_step(), set_next(),
      24              set_return(), set_until() and set_continue().
      25          lineno:
      26              Line number. Line numbers are relative to the start of the
      27              function when tracing a function in the test_bdb module (i.e. this
      28              module).
      29          co_name:
      30              Name of the function being currently traced.
      31          eargs:
      32              A tuple:
      33              * On an 'exception' event the tuple holds a class object, the
      34                current exception must be an instance of this class.
      35              * On a 'line' event, the tuple holds a dictionary and a list. The
      36                dictionary maps each breakpoint number that has been hit on this
      37                line to its hits count. The list holds the list of breakpoint
      38                number temporaries that are being deleted.
      39  
      40      Definitions of the members of the 'set_tuple':
      41          set_type:
      42              The type of the set method to be invoked. This may
      43              be the type of one of the Bdb set methods: 'step', 'next',
      44              'until', 'return', 'continue', 'break', 'quit', or the type of one
      45              of the set methods added by test_bdb.Bdb: 'ignore', 'enable',
      46              'disable', 'clear', 'up', 'down'.
      47          sargs:
      48              The arguments of the set method if any, packed in a tuple.
      49  """
      50  
      51  import bdb as _bdb
      52  import sys
      53  import os
      54  import unittest
      55  import textwrap
      56  import importlib
      57  import linecache
      58  from contextlib import contextmanager
      59  from itertools import islice, repeat
      60  from test.support import import_helper
      61  from test.support import os_helper
      62  from test.support import patch_list
      63  
      64  
      65  class ESC[4;38;5;81mBdbException(ESC[4;38;5;149mException): pass
      66  class ESC[4;38;5;81mBdbError(ESC[4;38;5;149mBdbException): """Error raised by the Bdb instance."""
      67  class ESC[4;38;5;81mBdbSyntaxError(ESC[4;38;5;149mBdbException): """Syntax error in the test case."""
      68  class ESC[4;38;5;81mBdbNotExpectedError(ESC[4;38;5;149mBdbException): """Unexpected result."""
      69  
      70  # When 'dry_run' is set to true, expect tuples are ignored and the actual
      71  # state of the tracer is printed after running each set_*() method of the test
      72  # case. The full list of breakpoints and their attributes is also printed
      73  # after each 'line' event where a breakpoint has been hit.
      74  dry_run = 0
      75  
      76  def reset_Breakpoint():
      77      _bdb.Breakpoint.clearBreakpoints()
      78  
      79  def info_breakpoints():
      80      bp_list = [bp for  bp in _bdb.Breakpoint.bpbynumber if bp]
      81      if not bp_list:
      82          return ''
      83  
      84      header_added = False
      85      for bp in bp_list:
      86          if not header_added:
      87              info = 'BpNum Temp Enb Hits Ignore Where\n'
      88              header_added = True
      89  
      90          disp = 'yes ' if bp.temporary else 'no  '
      91          enab = 'yes' if bp.enabled else 'no '
      92          info += ('%-5d %s %s %-4d %-6d at %s:%d' %
      93                      (bp.number, disp, enab, bp.hits, bp.ignore,
      94                       os.path.basename(bp.file), bp.line))
      95          if bp.cond:
      96              info += '\n\tstop only if %s' % (bp.cond,)
      97          info += '\n'
      98      return info
      99  
     100  class ESC[4;38;5;81mBdb(ESC[4;38;5;149m_bdbESC[4;38;5;149m.ESC[4;38;5;149mBdb):
     101      """Extend Bdb to enhance test coverage."""
     102  
     103      def trace_dispatch(self, frame, event, arg):
     104          self.currentbp = None
     105          return super().trace_dispatch(frame, event, arg)
     106  
     107      def set_break(self, filename, lineno, temporary=False, cond=None,
     108                    funcname=None):
     109          if isinstance(funcname, str):
     110              if filename == __file__:
     111                  globals_ = globals()
     112              else:
     113                  module = importlib.import_module(filename[:-3])
     114                  globals_ = module.__dict__
     115              func = eval(funcname, globals_)
     116              code = func.__code__
     117              filename = code.co_filename
     118              lineno = code.co_firstlineno
     119              funcname = code.co_name
     120  
     121          res = super().set_break(filename, lineno, temporary=temporary,
     122                                   cond=cond, funcname=funcname)
     123          if isinstance(res, str):
     124              raise BdbError(res)
     125          return res
     126  
     127      def get_stack(self, f, t):
     128          self.stack, self.index = super().get_stack(f, t)
     129          self.frame = self.stack[self.index][0]
     130          return self.stack, self.index
     131  
     132      def set_ignore(self, bpnum):
     133          """Increment the ignore count of Breakpoint number 'bpnum'."""
     134          bp = self.get_bpbynumber(bpnum)
     135          bp.ignore += 1
     136  
     137      def set_enable(self, bpnum):
     138          bp = self.get_bpbynumber(bpnum)
     139          bp.enabled = True
     140  
     141      def set_disable(self, bpnum):
     142          bp = self.get_bpbynumber(bpnum)
     143          bp.enabled = False
     144  
     145      def set_clear(self, fname, lineno):
     146          err = self.clear_break(fname, lineno)
     147          if err:
     148              raise BdbError(err)
     149  
     150      def set_up(self):
     151          """Move up in the frame stack."""
     152          if not self.index:
     153              raise BdbError('Oldest frame')
     154          self.index -= 1
     155          self.frame = self.stack[self.index][0]
     156  
     157      def set_down(self):
     158          """Move down in the frame stack."""
     159          if self.index + 1 == len(self.stack):
     160              raise BdbError('Newest frame')
     161          self.index += 1
     162          self.frame = self.stack[self.index][0]
     163  
     164  class ESC[4;38;5;81mTracer(ESC[4;38;5;149mBdb):
     165      """A tracer for testing the bdb module."""
     166  
     167      def __init__(self, expect_set, skip=None, dry_run=False, test_case=None):
     168          super().__init__(skip=skip)
     169          self.expect_set = expect_set
     170          self.dry_run = dry_run
     171          self.header = ('Dry-run results for %s:' % test_case if
     172                         test_case is not None else None)
     173          self.init_test()
     174  
     175      def init_test(self):
     176          self.cur_except = None
     177          self.expect_set_no = 0
     178          self.breakpoint_hits = None
     179          self.expected_list = list(islice(self.expect_set, 0, None, 2))
     180          self.set_list = list(islice(self.expect_set, 1, None, 2))
     181  
     182      def trace_dispatch(self, frame, event, arg):
     183          # On an 'exception' event, call_exc_trace() in Python/ceval.c discards
     184          # a BdbException raised by the Tracer instance, so we raise it on the
     185          # next trace_dispatch() call that occurs unless the set_quit() or
     186          # set_continue() method has been invoked on the 'exception' event.
     187          if self.cur_except is not None:
     188              raise self.cur_except
     189  
     190          if event == 'exception':
     191              try:
     192                  res = super().trace_dispatch(frame, event, arg)
     193                  return res
     194              except BdbException as e:
     195                  self.cur_except = e
     196                  return self.trace_dispatch
     197          else:
     198              return super().trace_dispatch(frame, event, arg)
     199  
     200      def user_call(self, frame, argument_list):
     201          # Adopt the same behavior as pdb and, as a side effect, skip also the
     202          # first 'call' event when the Tracer is started with Tracer.runcall()
     203          # which may be possibly considered as a bug.
     204          if not self.stop_here(frame):
     205              return
     206          self.process_event('call', frame, argument_list)
     207          self.next_set_method()
     208  
     209      def user_line(self, frame):
     210          self.process_event('line', frame)
     211  
     212          if self.dry_run and self.breakpoint_hits:
     213              info = info_breakpoints().strip('\n')
     214              # Indent each line.
     215              for line in info.split('\n'):
     216                  print('  ' + line)
     217          self.delete_temporaries()
     218          self.breakpoint_hits = None
     219  
     220          self.next_set_method()
     221  
     222      def user_return(self, frame, return_value):
     223          self.process_event('return', frame, return_value)
     224          self.next_set_method()
     225  
     226      def user_exception(self, frame, exc_info):
     227          self.exc_info = exc_info
     228          self.process_event('exception', frame)
     229          self.next_set_method()
     230  
     231      def do_clear(self, arg):
     232          # The temporary breakpoints are deleted in user_line().
     233          bp_list = [self.currentbp]
     234          self.breakpoint_hits = (bp_list, bp_list)
     235  
     236      def delete_temporaries(self):
     237          if self.breakpoint_hits:
     238              for n in self.breakpoint_hits[1]:
     239                  self.clear_bpbynumber(n)
     240  
     241      def pop_next(self):
     242          self.expect_set_no += 1
     243          try:
     244              self.expect = self.expected_list.pop(0)
     245          except IndexError:
     246              raise BdbNotExpectedError(
     247                  'expect_set list exhausted, cannot pop item %d' %
     248                  self.expect_set_no)
     249          self.set_tuple = self.set_list.pop(0)
     250  
     251      def process_event(self, event, frame, *args):
     252          # Call get_stack() to enable walking the stack with set_up() and
     253          # set_down().
     254          tb = None
     255          if event == 'exception':
     256              tb = self.exc_info[2]
     257          self.get_stack(frame, tb)
     258  
     259          # A breakpoint has been hit and it is not a temporary.
     260          if self.currentbp is not None and not self.breakpoint_hits:
     261              bp_list = [self.currentbp]
     262              self.breakpoint_hits = (bp_list, [])
     263  
     264          # Pop next event.
     265          self.event= event
     266          self.pop_next()
     267          if self.dry_run:
     268              self.print_state(self.header)
     269              return
     270  
     271          # Validate the expected results.
     272          if self.expect:
     273              self.check_equal(self.expect[0], event, 'Wrong event type')
     274              self.check_lno_name()
     275  
     276          if event in ('call', 'return'):
     277              self.check_expect_max_size(3)
     278          elif len(self.expect) > 3:
     279              if event == 'line':
     280                  bps, temporaries = self.expect[3]
     281                  bpnums = sorted(bps.keys())
     282                  if not self.breakpoint_hits:
     283                      self.raise_not_expected(
     284                          'No breakpoints hit at expect_set item %d' %
     285                          self.expect_set_no)
     286                  self.check_equal(bpnums, self.breakpoint_hits[0],
     287                      'Breakpoint numbers do not match')
     288                  self.check_equal([bps[n] for n in bpnums],
     289                      [self.get_bpbynumber(n).hits for
     290                          n in self.breakpoint_hits[0]],
     291                      'Wrong breakpoint hit count')
     292                  self.check_equal(sorted(temporaries), self.breakpoint_hits[1],
     293                      'Wrong temporary breakpoints')
     294  
     295              elif event == 'exception':
     296                  if not isinstance(self.exc_info[1], self.expect[3]):
     297                      self.raise_not_expected(
     298                          "Wrong exception at expect_set item %d, got '%s'" %
     299                          (self.expect_set_no, self.exc_info))
     300  
     301      def check_equal(self, expected, result, msg):
     302          if expected == result:
     303              return
     304          self.raise_not_expected("%s at expect_set item %d, got '%s'" %
     305                                  (msg, self.expect_set_no, result))
     306  
     307      def check_lno_name(self):
     308          """Check the line number and function co_name."""
     309          s = len(self.expect)
     310          if s > 1:
     311              lineno = self.lno_abs2rel()
     312              self.check_equal(self.expect[1], lineno, 'Wrong line number')
     313          if s > 2:
     314              self.check_equal(self.expect[2], self.frame.f_code.co_name,
     315                                                  'Wrong function name')
     316  
     317      def check_expect_max_size(self, size):
     318          if len(self.expect) > size:
     319              raise BdbSyntaxError('Invalid size of the %s expect tuple: %s' %
     320                                   (self.event, self.expect))
     321  
     322      def lno_abs2rel(self):
     323          fname = self.canonic(self.frame.f_code.co_filename)
     324          lineno = self.frame.f_lineno
     325          return ((lineno - self.frame.f_code.co_firstlineno + 1)
     326              if fname == self.canonic(__file__) else lineno)
     327  
     328      def lno_rel2abs(self, fname, lineno):
     329          return (self.frame.f_code.co_firstlineno + lineno - 1
     330              if (lineno and self.canonic(fname) == self.canonic(__file__))
     331              else lineno)
     332  
     333      def get_state(self):
     334          lineno = self.lno_abs2rel()
     335          co_name = self.frame.f_code.co_name
     336          state = "('%s', %d, '%s'" % (self.event, lineno, co_name)
     337          if self.breakpoint_hits:
     338              bps = '{'
     339              for n in self.breakpoint_hits[0]:
     340                  if bps != '{':
     341                      bps += ', '
     342                  bps += '%s: %s' % (n, self.get_bpbynumber(n).hits)
     343              bps += '}'
     344              bps = '(' + bps + ', ' + str(self.breakpoint_hits[1]) + ')'
     345              state += ', ' + bps
     346          elif self.event == 'exception':
     347              state += ', ' + self.exc_info[0].__name__
     348          state += '), '
     349          return state.ljust(32) + str(self.set_tuple) + ','
     350  
     351      def print_state(self, header=None):
     352          if header is not None and self.expect_set_no == 1:
     353              print()
     354              print(header)
     355          print('%d: %s' % (self.expect_set_no, self.get_state()))
     356  
     357      def raise_not_expected(self, msg):
     358          msg += '\n'
     359          msg += '  Expected: %s\n' % str(self.expect)
     360          msg += '  Got:      ' + self.get_state()
     361          raise BdbNotExpectedError(msg)
     362  
     363      def next_set_method(self):
     364          set_type = self.set_tuple[0]
     365          args = self.set_tuple[1] if len(self.set_tuple) == 2 else None
     366          set_method = getattr(self, 'set_' + set_type)
     367  
     368          # The following set methods give back control to the tracer.
     369          if set_type in ('step', 'continue', 'quit'):
     370              set_method()
     371              return
     372          elif set_type in ('next', 'return'):
     373              set_method(self.frame)
     374              return
     375          elif set_type == 'until':
     376              lineno = None
     377              if args:
     378                  lineno = self.lno_rel2abs(self.frame.f_code.co_filename,
     379                                            args[0])
     380              set_method(self.frame, lineno)
     381              return
     382  
     383          # The following set methods do not give back control to the tracer and
     384          # next_set_method() is called recursively.
     385          if (args and set_type in ('break', 'clear', 'ignore', 'enable',
     386                                      'disable')) or set_type in ('up', 'down'):
     387              if set_type in ('break', 'clear'):
     388                  fname, lineno, *remain = args
     389                  lineno = self.lno_rel2abs(fname, lineno)
     390                  args = [fname, lineno]
     391                  args.extend(remain)
     392                  set_method(*args)
     393              elif set_type in ('ignore', 'enable', 'disable'):
     394                  set_method(*args)
     395              elif set_type in ('up', 'down'):
     396                  set_method()
     397  
     398              # Process the next expect_set item.
     399              # It is not expected that a test may reach the recursion limit.
     400              self.event= None
     401              self.pop_next()
     402              if self.dry_run:
     403                  self.print_state()
     404              else:
     405                  if self.expect:
     406                      self.check_lno_name()
     407                  self.check_expect_max_size(3)
     408              self.next_set_method()
     409          else:
     410              raise BdbSyntaxError('"%s" is an invalid set_tuple' %
     411                                   self.set_tuple)
     412  
     413  class ESC[4;38;5;81mTracerRun():
     414      """Provide a context for running a Tracer instance with a test case."""
     415  
     416      def __init__(self, test_case, skip=None):
     417          self.test_case = test_case
     418          self.dry_run = test_case.dry_run
     419          self.tracer = Tracer(test_case.expect_set, skip=skip,
     420                               dry_run=self.dry_run, test_case=test_case.id())
     421          self._original_tracer = None
     422  
     423      def __enter__(self):
     424          # test_pdb does not reset Breakpoint class attributes on exit :-(
     425          reset_Breakpoint()
     426          self._original_tracer = sys.gettrace()
     427          return self.tracer
     428  
     429      def __exit__(self, type_=None, value=None, traceback=None):
     430          reset_Breakpoint()
     431          sys.settrace(self._original_tracer)
     432  
     433          not_empty = ''
     434          if self.tracer.set_list:
     435              not_empty += 'All paired tuples have not been processed, '
     436              not_empty += ('the last one was number %d' %
     437                            self.tracer.expect_set_no)
     438  
     439          # Make a BdbNotExpectedError a unittest failure.
     440          if type_ is not None and issubclass(BdbNotExpectedError, type_):
     441              if isinstance(value, BaseException) and value.args:
     442                  err_msg = value.args[0]
     443                  if not_empty:
     444                      err_msg += '\n' + not_empty
     445                  if self.dry_run:
     446                      print(err_msg)
     447                      return True
     448                  else:
     449                      self.test_case.fail(err_msg)
     450              else:
     451                  assert False, 'BdbNotExpectedError with empty args'
     452  
     453          if not_empty:
     454              if self.dry_run:
     455                  print(not_empty)
     456              else:
     457                  self.test_case.fail(not_empty)
     458  
     459  def run_test(modules, set_list, skip=None):
     460      """Run a test and print the dry-run results.
     461  
     462      'modules':  A dictionary mapping module names to their source code as a
     463                  string. The dictionary MUST include one module named
     464                  'test_module' with a main() function.
     465      'set_list': A list of set_type tuples to be run on the module.
     466  
     467      For example, running the following script outputs the following results:
     468  
     469      *****************************   SCRIPT   ********************************
     470  
     471      from test.test_bdb import run_test, break_in_func
     472  
     473      code = '''
     474          def func():
     475              lno = 3
     476  
     477          def main():
     478              func()
     479              lno = 7
     480      '''
     481  
     482      set_list = [
     483                  break_in_func('func', 'test_module.py'),
     484                  ('continue', ),
     485                  ('step', ),
     486                  ('step', ),
     487                  ('step', ),
     488                  ('quit', ),
     489              ]
     490  
     491      modules = { 'test_module': code }
     492      run_test(modules, set_list)
     493  
     494      ****************************   results   ********************************
     495  
     496      1: ('line', 2, 'tfunc_import'),    ('next',),
     497      2: ('line', 3, 'tfunc_import'),    ('step',),
     498      3: ('call', 5, 'main'),            ('break', ('test_module.py', None, False, None, 'func')),
     499      4: ('None', 5, 'main'),            ('continue',),
     500      5: ('line', 3, 'func', ({1: 1}, [])), ('step',),
     501        BpNum Temp Enb Hits Ignore Where
     502        1     no   yes 1    0      at test_module.py:2
     503      6: ('return', 3, 'func'),          ('step',),
     504      7: ('line', 7, 'main'),            ('step',),
     505      8: ('return', 7, 'main'),          ('quit',),
     506  
     507      *************************************************************************
     508  
     509      """
     510      def gen(a, b):
     511          try:
     512              while 1:
     513                  x = next(a)
     514                  y = next(b)
     515                  yield x
     516                  yield y
     517          except StopIteration:
     518              return
     519  
     520      # Step over the import statement in tfunc_import using 'next' and step
     521      # into main() in test_module.
     522      sl = [('next', ), ('step', )]
     523      sl.extend(set_list)
     524  
     525      test = BaseTestCase()
     526      test.dry_run = True
     527      test.id = lambda : None
     528      test.expect_set = list(gen(repeat(()), iter(sl)))
     529      with create_modules(modules):
     530          with TracerRun(test, skip=skip) as tracer:
     531              tracer.runcall(tfunc_import)
     532  
     533  @contextmanager
     534  def create_modules(modules):
     535      with os_helper.temp_cwd():
     536          sys.path.append(os.getcwd())
     537          try:
     538              for m in modules:
     539                  fname = m + '.py'
     540                  with open(fname, 'w', encoding="utf-8") as f:
     541                      f.write(textwrap.dedent(modules[m]))
     542                  linecache.checkcache(fname)
     543              importlib.invalidate_caches()
     544              yield
     545          finally:
     546              for m in modules:
     547                  import_helper.forget(m)
     548              sys.path.pop()
     549  
     550  def break_in_func(funcname, fname=__file__, temporary=False, cond=None):
     551      return 'break', (fname, None, temporary, cond, funcname)
     552  
     553  TEST_MODULE = 'test_module_for_bdb'
     554  TEST_MODULE_FNAME = TEST_MODULE + '.py'
     555  def tfunc_import():
     556      import test_module_for_bdb
     557      test_module_for_bdb.main()
     558  
     559  def tfunc_main():
     560      lno = 2
     561      tfunc_first()
     562      tfunc_second()
     563      lno = 5
     564      lno = 6
     565      lno = 7
     566  
     567  def tfunc_first():
     568      lno = 2
     569      lno = 3
     570      lno = 4
     571  
     572  def tfunc_second():
     573      lno = 2
     574  
     575  class ESC[4;38;5;81mBaseTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     576      """Base class for all tests."""
     577  
     578      dry_run = dry_run
     579  
     580      def fail(self, msg=None):
     581          # Override fail() to use 'raise from None' to avoid repetition of the
     582          # error message and traceback.
     583          raise self.failureException(msg) from None
     584  
     585  class ESC[4;38;5;81mStateTestCase(ESC[4;38;5;149mBaseTestCase):
     586      """Test the step, next, return, until and quit 'set_' methods."""
     587  
     588      def test_step(self):
     589          self.expect_set = [
     590              ('line', 2, 'tfunc_main'),  ('step', ),
     591              ('line', 3, 'tfunc_main'),  ('step', ),
     592              ('call', 1, 'tfunc_first'), ('step', ),
     593              ('line', 2, 'tfunc_first'), ('quit', ),
     594          ]
     595          with TracerRun(self) as tracer:
     596              tracer.runcall(tfunc_main)
     597  
     598      def test_step_next_on_last_statement(self):
     599          for set_type in ('step', 'next'):
     600              with self.subTest(set_type=set_type):
     601                  self.expect_set = [
     602                      ('line', 2, 'tfunc_main'),               ('step', ),
     603                      ('line', 3, 'tfunc_main'),               ('step', ),
     604                      ('call', 1, 'tfunc_first'),              ('break', (__file__, 3)),
     605                      ('None', 1, 'tfunc_first'),              ('continue', ),
     606                      ('line', 3, 'tfunc_first', ({1:1}, [])), (set_type, ),
     607                      ('line', 4, 'tfunc_first'),              ('quit', ),
     608                  ]
     609                  with TracerRun(self) as tracer:
     610                      tracer.runcall(tfunc_main)
     611  
     612      def test_next(self):
     613          self.expect_set = [
     614              ('line', 2, 'tfunc_main'),   ('step', ),
     615              ('line', 3, 'tfunc_main'),   ('next', ),
     616              ('line', 4, 'tfunc_main'),   ('step', ),
     617              ('call', 1, 'tfunc_second'), ('step', ),
     618              ('line', 2, 'tfunc_second'), ('quit', ),
     619          ]
     620          with TracerRun(self) as tracer:
     621              tracer.runcall(tfunc_main)
     622  
     623      def test_next_over_import(self):
     624          code = """
     625              def main():
     626                  lno = 3
     627          """
     628          modules = { TEST_MODULE: code }
     629          with create_modules(modules):
     630              self.expect_set = [
     631                  ('line', 2, 'tfunc_import'), ('next', ),
     632                  ('line', 3, 'tfunc_import'), ('quit', ),
     633              ]
     634              with TracerRun(self) as tracer:
     635                  tracer.runcall(tfunc_import)
     636  
     637      def test_next_on_plain_statement(self):
     638          # Check that set_next() is equivalent to set_step() on a plain
     639          # statement.
     640          self.expect_set = [
     641              ('line', 2, 'tfunc_main'),  ('step', ),
     642              ('line', 3, 'tfunc_main'),  ('step', ),
     643              ('call', 1, 'tfunc_first'), ('next', ),
     644              ('line', 2, 'tfunc_first'), ('quit', ),
     645          ]
     646          with TracerRun(self) as tracer:
     647              tracer.runcall(tfunc_main)
     648  
     649      def test_next_in_caller_frame(self):
     650          # Check that set_next() in the caller frame causes the tracer
     651          # to stop next in the caller frame.
     652          self.expect_set = [
     653              ('line', 2, 'tfunc_main'),  ('step', ),
     654              ('line', 3, 'tfunc_main'),  ('step', ),
     655              ('call', 1, 'tfunc_first'), ('up', ),
     656              ('None', 3, 'tfunc_main'),  ('next', ),
     657              ('line', 4, 'tfunc_main'),  ('quit', ),
     658          ]
     659          with TracerRun(self) as tracer:
     660              tracer.runcall(tfunc_main)
     661  
     662      def test_return(self):
     663          self.expect_set = [
     664              ('line', 2, 'tfunc_main'),    ('step', ),
     665              ('line', 3, 'tfunc_main'),    ('step', ),
     666              ('call', 1, 'tfunc_first'),   ('step', ),
     667              ('line', 2, 'tfunc_first'),   ('return', ),
     668              ('return', 4, 'tfunc_first'), ('step', ),
     669              ('line', 4, 'tfunc_main'),    ('quit', ),
     670          ]
     671          with TracerRun(self) as tracer:
     672              tracer.runcall(tfunc_main)
     673  
     674      def test_return_in_caller_frame(self):
     675          self.expect_set = [
     676              ('line', 2, 'tfunc_main'),   ('step', ),
     677              ('line', 3, 'tfunc_main'),   ('step', ),
     678              ('call', 1, 'tfunc_first'),  ('up', ),
     679              ('None', 3, 'tfunc_main'),   ('return', ),
     680              ('return', 7, 'tfunc_main'), ('quit', ),
     681          ]
     682          with TracerRun(self) as tracer:
     683              tracer.runcall(tfunc_main)
     684  
     685      def test_until(self):
     686          self.expect_set = [
     687              ('line', 2, 'tfunc_main'),  ('step', ),
     688              ('line', 3, 'tfunc_main'),  ('step', ),
     689              ('call', 1, 'tfunc_first'), ('step', ),
     690              ('line', 2, 'tfunc_first'), ('until', (4, )),
     691              ('line', 4, 'tfunc_first'), ('quit', ),
     692          ]
     693          with TracerRun(self) as tracer:
     694              tracer.runcall(tfunc_main)
     695  
     696      def test_until_with_too_large_count(self):
     697          self.expect_set = [
     698              ('line', 2, 'tfunc_main'),               break_in_func('tfunc_first'),
     699              ('None', 2, 'tfunc_main'),               ('continue', ),
     700              ('line', 2, 'tfunc_first', ({1:1}, [])), ('until', (9999, )),
     701              ('return', 4, 'tfunc_first'),            ('quit', ),
     702          ]
     703          with TracerRun(self) as tracer:
     704              tracer.runcall(tfunc_main)
     705  
     706      def test_until_in_caller_frame(self):
     707          self.expect_set = [
     708              ('line', 2, 'tfunc_main'),  ('step', ),
     709              ('line', 3, 'tfunc_main'),  ('step', ),
     710              ('call', 1, 'tfunc_first'), ('up', ),
     711              ('None', 3, 'tfunc_main'),  ('until', (6, )),
     712              ('line', 6, 'tfunc_main'),  ('quit', ),
     713          ]
     714          with TracerRun(self) as tracer:
     715              tracer.runcall(tfunc_main)
     716  
     717      @patch_list(sys.meta_path)
     718      def test_skip(self):
     719          # Check that tracing is skipped over the import statement in
     720          # 'tfunc_import()'.
     721  
     722          # Remove all but the standard importers.
     723          sys.meta_path[:] = (
     724              item
     725              for item in sys.meta_path
     726              if item.__module__.startswith('_frozen_importlib')
     727          )
     728  
     729          code = """
     730              def main():
     731                  lno = 3
     732          """
     733          modules = { TEST_MODULE: code }
     734          with create_modules(modules):
     735              self.expect_set = [
     736                  ('line', 2, 'tfunc_import'), ('step', ),
     737                  ('line', 3, 'tfunc_import'), ('quit', ),
     738              ]
     739              skip = ('importlib*', 'zipimport', 'encodings.*', TEST_MODULE)
     740              with TracerRun(self, skip=skip) as tracer:
     741                  tracer.runcall(tfunc_import)
     742  
     743      def test_skip_with_no_name_module(self):
     744          # some frames have `globals` with no `__name__`
     745          # for instance the second frame in this traceback
     746          # exec(compile('raise ValueError()', '', 'exec'), {})
     747          bdb = Bdb(skip=['anything*'])
     748          self.assertIs(bdb.is_skipped_module(None), False)
     749  
     750      def test_down(self):
     751          # Check that set_down() raises BdbError at the newest frame.
     752          self.expect_set = [
     753              ('line', 2, 'tfunc_main'), ('down', ),
     754          ]
     755          with TracerRun(self) as tracer:
     756              self.assertRaises(BdbError, tracer.runcall, tfunc_main)
     757  
     758      def test_up(self):
     759          self.expect_set = [
     760              ('line', 2, 'tfunc_main'),  ('step', ),
     761              ('line', 3, 'tfunc_main'),  ('step', ),
     762              ('call', 1, 'tfunc_first'), ('up', ),
     763              ('None', 3, 'tfunc_main'),  ('quit', ),
     764          ]
     765          with TracerRun(self) as tracer:
     766              tracer.runcall(tfunc_main)
     767  
     768  class ESC[4;38;5;81mBreakpointTestCase(ESC[4;38;5;149mBaseTestCase):
     769      """Test the breakpoint set method."""
     770  
     771      def test_bp_on_non_existent_module(self):
     772          self.expect_set = [
     773              ('line', 2, 'tfunc_import'), ('break', ('/non/existent/module.py', 1))
     774          ]
     775          with TracerRun(self) as tracer:
     776              self.assertRaises(BdbError, tracer.runcall, tfunc_import)
     777  
     778      def test_bp_after_last_statement(self):
     779          code = """
     780              def main():
     781                  lno = 3
     782          """
     783          modules = { TEST_MODULE: code }
     784          with create_modules(modules):
     785              self.expect_set = [
     786                  ('line', 2, 'tfunc_import'), ('break', (TEST_MODULE_FNAME, 4))
     787              ]
     788              with TracerRun(self) as tracer:
     789                  self.assertRaises(BdbError, tracer.runcall, tfunc_import)
     790  
     791      def test_temporary_bp(self):
     792          code = """
     793              def func():
     794                  lno = 3
     795  
     796              def main():
     797                  for i in range(2):
     798                      func()
     799          """
     800          modules = { TEST_MODULE: code }
     801          with create_modules(modules):
     802              self.expect_set = [
     803                  ('line', 2, 'tfunc_import'),
     804                      break_in_func('func', TEST_MODULE_FNAME, True),
     805                  ('None', 2, 'tfunc_import'),
     806                      break_in_func('func', TEST_MODULE_FNAME, True),
     807                  ('None', 2, 'tfunc_import'),       ('continue', ),
     808                  ('line', 3, 'func', ({1:1}, [1])), ('continue', ),
     809                  ('line', 3, 'func', ({2:1}, [2])), ('quit', ),
     810              ]
     811              with TracerRun(self) as tracer:
     812                  tracer.runcall(tfunc_import)
     813  
     814      def test_disabled_temporary_bp(self):
     815          code = """
     816              def func():
     817                  lno = 3
     818  
     819              def main():
     820                  for i in range(3):
     821                      func()
     822          """
     823          modules = { TEST_MODULE: code }
     824          with create_modules(modules):
     825              self.expect_set = [
     826                  ('line', 2, 'tfunc_import'),
     827                      break_in_func('func', TEST_MODULE_FNAME),
     828                  ('None', 2, 'tfunc_import'),
     829                      break_in_func('func', TEST_MODULE_FNAME, True),
     830                  ('None', 2, 'tfunc_import'),       ('disable', (2, )),
     831                  ('None', 2, 'tfunc_import'),       ('continue', ),
     832                  ('line', 3, 'func', ({1:1}, [])),  ('enable', (2, )),
     833                  ('None', 3, 'func'),               ('disable', (1, )),
     834                  ('None', 3, 'func'),               ('continue', ),
     835                  ('line', 3, 'func', ({2:1}, [2])), ('enable', (1, )),
     836                  ('None', 3, 'func'),               ('continue', ),
     837                  ('line', 3, 'func', ({1:2}, [])),  ('quit', ),
     838              ]
     839              with TracerRun(self) as tracer:
     840                  tracer.runcall(tfunc_import)
     841  
     842      def test_bp_condition(self):
     843          code = """
     844              def func(a):
     845                  lno = 3
     846  
     847              def main():
     848                  for i in range(3):
     849                      func(i)
     850          """
     851          modules = { TEST_MODULE: code }
     852          with create_modules(modules):
     853              self.expect_set = [
     854                  ('line', 2, 'tfunc_import'),
     855                      break_in_func('func', TEST_MODULE_FNAME, False, 'a == 2'),
     856                  ('None', 2, 'tfunc_import'),       ('continue', ),
     857                  ('line', 3, 'func', ({1:3}, [])),  ('quit', ),
     858              ]
     859              with TracerRun(self) as tracer:
     860                  tracer.runcall(tfunc_import)
     861  
     862      def test_bp_exception_on_condition_evaluation(self):
     863          code = """
     864              def func(a):
     865                  lno = 3
     866  
     867              def main():
     868                  func(0)
     869          """
     870          modules = { TEST_MODULE: code }
     871          with create_modules(modules):
     872              self.expect_set = [
     873                  ('line', 2, 'tfunc_import'),
     874                      break_in_func('func', TEST_MODULE_FNAME, False, '1 / 0'),
     875                  ('None', 2, 'tfunc_import'),       ('continue', ),
     876                  ('line', 3, 'func', ({1:1}, [])),  ('quit', ),
     877              ]
     878              with TracerRun(self) as tracer:
     879                  tracer.runcall(tfunc_import)
     880  
     881      def test_bp_ignore_count(self):
     882          code = """
     883              def func():
     884                  lno = 3
     885  
     886              def main():
     887                  for i in range(2):
     888                      func()
     889          """
     890          modules = { TEST_MODULE: code }
     891          with create_modules(modules):
     892              self.expect_set = [
     893                  ('line', 2, 'tfunc_import'),
     894                      break_in_func('func', TEST_MODULE_FNAME),
     895                  ('None', 2, 'tfunc_import'),      ('ignore', (1, )),
     896                  ('None', 2, 'tfunc_import'),      ('continue', ),
     897                  ('line', 3, 'func', ({1:2}, [])), ('quit', ),
     898              ]
     899              with TracerRun(self) as tracer:
     900                  tracer.runcall(tfunc_import)
     901  
     902      def test_ignore_count_on_disabled_bp(self):
     903          code = """
     904              def func():
     905                  lno = 3
     906  
     907              def main():
     908                  for i in range(3):
     909                      func()
     910          """
     911          modules = { TEST_MODULE: code }
     912          with create_modules(modules):
     913              self.expect_set = [
     914                  ('line', 2, 'tfunc_import'),
     915                      break_in_func('func', TEST_MODULE_FNAME),
     916                  ('None', 2, 'tfunc_import'),
     917                      break_in_func('func', TEST_MODULE_FNAME),
     918                  ('None', 2, 'tfunc_import'),      ('ignore', (1, )),
     919                  ('None', 2, 'tfunc_import'),      ('disable', (1, )),
     920                  ('None', 2, 'tfunc_import'),      ('continue', ),
     921                  ('line', 3, 'func', ({2:1}, [])), ('enable', (1, )),
     922                  ('None', 3, 'func'),              ('continue', ),
     923                  ('line', 3, 'func', ({2:2}, [])), ('continue', ),
     924                  ('line', 3, 'func', ({1:2}, [])), ('quit', ),
     925              ]
     926              with TracerRun(self) as tracer:
     927                  tracer.runcall(tfunc_import)
     928  
     929      def test_clear_two_bp_on_same_line(self):
     930          code = """
     931              def func():
     932                  lno = 3
     933                  lno = 4
     934  
     935              def main():
     936                  for i in range(3):
     937                      func()
     938          """
     939          modules = { TEST_MODULE: code }
     940          with create_modules(modules):
     941              self.expect_set = [
     942                  ('line', 2, 'tfunc_import'),      ('break', (TEST_MODULE_FNAME, 3)),
     943                  ('None', 2, 'tfunc_import'),      ('break', (TEST_MODULE_FNAME, 3)),
     944                  ('None', 2, 'tfunc_import'),      ('break', (TEST_MODULE_FNAME, 4)),
     945                  ('None', 2, 'tfunc_import'),      ('continue', ),
     946                  ('line', 3, 'func', ({1:1}, [])), ('continue', ),
     947                  ('line', 4, 'func', ({3:1}, [])), ('clear', (TEST_MODULE_FNAME, 3)),
     948                  ('None', 4, 'func'),              ('continue', ),
     949                  ('line', 4, 'func', ({3:2}, [])), ('quit', ),
     950              ]
     951              with TracerRun(self) as tracer:
     952                  tracer.runcall(tfunc_import)
     953  
     954      def test_clear_at_no_bp(self):
     955          self.expect_set = [
     956              ('line', 2, 'tfunc_import'), ('clear', (__file__, 1))
     957          ]
     958          with TracerRun(self) as tracer:
     959              self.assertRaises(BdbError, tracer.runcall, tfunc_import)
     960  
     961      def test_load_bps_from_previous_Bdb_instance(self):
     962          reset_Breakpoint()
     963          db1 = Bdb()
     964          fname = db1.canonic(__file__)
     965          db1.set_break(__file__, 1)
     966          self.assertEqual(db1.get_all_breaks(), {fname: [1]})
     967  
     968          db2 = Bdb()
     969          db2.set_break(__file__, 2)
     970          db2.set_break(__file__, 3)
     971          db2.set_break(__file__, 4)
     972          self.assertEqual(db1.get_all_breaks(), {fname: [1]})
     973          self.assertEqual(db2.get_all_breaks(), {fname: [1, 2, 3, 4]})
     974          db2.clear_break(__file__, 1)
     975          self.assertEqual(db1.get_all_breaks(), {fname: [1]})
     976          self.assertEqual(db2.get_all_breaks(), {fname: [2, 3, 4]})
     977  
     978          db3 = Bdb()
     979          self.assertEqual(db1.get_all_breaks(), {fname: [1]})
     980          self.assertEqual(db2.get_all_breaks(), {fname: [2, 3, 4]})
     981          self.assertEqual(db3.get_all_breaks(), {fname: [2, 3, 4]})
     982          db2.clear_break(__file__, 2)
     983          self.assertEqual(db1.get_all_breaks(), {fname: [1]})
     984          self.assertEqual(db2.get_all_breaks(), {fname: [3, 4]})
     985          self.assertEqual(db3.get_all_breaks(), {fname: [2, 3, 4]})
     986  
     987          db4 = Bdb()
     988          db4.set_break(__file__, 5)
     989          self.assertEqual(db1.get_all_breaks(), {fname: [1]})
     990          self.assertEqual(db2.get_all_breaks(), {fname: [3, 4]})
     991          self.assertEqual(db3.get_all_breaks(), {fname: [2, 3, 4]})
     992          self.assertEqual(db4.get_all_breaks(), {fname: [3, 4, 5]})
     993          reset_Breakpoint()
     994  
     995          db5 = Bdb()
     996          db5.set_break(__file__, 6)
     997          self.assertEqual(db1.get_all_breaks(), {fname: [1]})
     998          self.assertEqual(db2.get_all_breaks(), {fname: [3, 4]})
     999          self.assertEqual(db3.get_all_breaks(), {fname: [2, 3, 4]})
    1000          self.assertEqual(db4.get_all_breaks(), {fname: [3, 4, 5]})
    1001          self.assertEqual(db5.get_all_breaks(), {fname: [6]})
    1002  
    1003  
    1004  class ESC[4;38;5;81mRunTestCase(ESC[4;38;5;149mBaseTestCase):
    1005      """Test run, runeval and set_trace."""
    1006  
    1007      def test_run_step(self):
    1008          # Check that the bdb 'run' method stops at the first line event.
    1009          code = """
    1010              lno = 2
    1011          """
    1012          self.expect_set = [
    1013              ('line', 2, '<module>'),   ('step', ),
    1014              ('return', 2, '<module>'), ('quit', ),
    1015          ]
    1016          with TracerRun(self) as tracer:
    1017              tracer.run(compile(textwrap.dedent(code), '<string>', 'exec'))
    1018  
    1019      def test_runeval_step(self):
    1020          # Test bdb 'runeval'.
    1021          code = """
    1022              def main():
    1023                  lno = 3
    1024          """
    1025          modules = { TEST_MODULE: code }
    1026          with create_modules(modules):
    1027              self.expect_set = [
    1028                  ('line', 1, '<module>'),   ('step', ),
    1029                  ('call', 2, 'main'),       ('step', ),
    1030                  ('line', 3, 'main'),       ('step', ),
    1031                  ('return', 3, 'main'),     ('step', ),
    1032                  ('return', 1, '<module>'), ('quit', ),
    1033              ]
    1034              import test_module_for_bdb
    1035              with TracerRun(self) as tracer:
    1036                  tracer.runeval('test_module_for_bdb.main()', globals(), locals())
    1037  
    1038  class ESC[4;38;5;81mIssuesTestCase(ESC[4;38;5;149mBaseTestCase):
    1039      """Test fixed bdb issues."""
    1040  
    1041      def test_step_at_return_with_no_trace_in_caller(self):
    1042          # Issue #13183.
    1043          # Check that the tracer does step into the caller frame when the
    1044          # trace function is not set in that frame.
    1045          code_1 = """
    1046              from test_module_for_bdb_2 import func
    1047              def main():
    1048                  func()
    1049                  lno = 5
    1050          """
    1051          code_2 = """
    1052              def func():
    1053                  lno = 3
    1054          """
    1055          modules = {
    1056              TEST_MODULE: code_1,
    1057              'test_module_for_bdb_2': code_2,
    1058          }
    1059          with create_modules(modules):
    1060              self.expect_set = [
    1061                  ('line', 2, 'tfunc_import'),
    1062                      break_in_func('func', 'test_module_for_bdb_2.py'),
    1063                  ('None', 2, 'tfunc_import'),      ('continue', ),
    1064                  ('line', 3, 'func', ({1:1}, [])), ('step', ),
    1065                  ('return', 3, 'func'),            ('step', ),
    1066                  ('line', 5, 'main'),              ('quit', ),
    1067              ]
    1068              with TracerRun(self) as tracer:
    1069                  tracer.runcall(tfunc_import)
    1070  
    1071      def test_next_until_return_in_generator(self):
    1072          # Issue #16596.
    1073          # Check that set_next(), set_until() and set_return() do not treat the
    1074          # `yield` and `yield from` statements as if they were returns and stop
    1075          # instead in the current frame.
    1076          code = """
    1077              def test_gen():
    1078                  yield 0
    1079                  lno = 4
    1080                  return 123
    1081  
    1082              def main():
    1083                  it = test_gen()
    1084                  next(it)
    1085                  next(it)
    1086                  lno = 11
    1087          """
    1088          modules = { TEST_MODULE: code }
    1089          for set_type in ('next', 'until', 'return'):
    1090              with self.subTest(set_type=set_type):
    1091                  with create_modules(modules):
    1092                      self.expect_set = [
    1093                          ('line', 2, 'tfunc_import'),
    1094                              break_in_func('test_gen', TEST_MODULE_FNAME),
    1095                          ('None', 2, 'tfunc_import'),          ('continue', ),
    1096                          ('line', 3, 'test_gen', ({1:1}, [])), (set_type, ),
    1097                      ]
    1098  
    1099                      if set_type == 'return':
    1100                          self.expect_set.extend(
    1101                              [('exception', 10, 'main', StopIteration), ('step',),
    1102                               ('return', 10, 'main'),                   ('quit', ),
    1103                              ]
    1104                          )
    1105                      else:
    1106                          self.expect_set.extend(
    1107                              [('line', 4, 'test_gen'), ('quit', ),]
    1108                          )
    1109                      with TracerRun(self) as tracer:
    1110                          tracer.runcall(tfunc_import)
    1111  
    1112      def test_next_command_in_generator_for_loop(self):
    1113          # Issue #16596.
    1114          code = """
    1115              def test_gen():
    1116                  yield 0
    1117                  lno = 4
    1118                  yield 1
    1119                  return 123
    1120  
    1121              def main():
    1122                  for i in test_gen():
    1123                      lno = 10
    1124                  lno = 11
    1125          """
    1126          modules = { TEST_MODULE: code }
    1127          with create_modules(modules):
    1128              self.expect_set = [
    1129                  ('line', 2, 'tfunc_import'),
    1130                      break_in_func('test_gen', TEST_MODULE_FNAME),
    1131                  ('None', 2, 'tfunc_import'),             ('continue', ),
    1132                  ('line', 3, 'test_gen', ({1:1}, [])),    ('next', ),
    1133                  ('line', 4, 'test_gen'),                 ('next', ),
    1134                  ('line', 5, 'test_gen'),                 ('next', ),
    1135                  ('line', 6, 'test_gen'),                 ('next', ),
    1136                  ('exception', 9, 'main', StopIteration), ('step', ),
    1137                  ('line', 11, 'main'),                    ('quit', ),
    1138  
    1139              ]
    1140              with TracerRun(self) as tracer:
    1141                  tracer.runcall(tfunc_import)
    1142  
    1143      def test_next_command_in_generator_with_subiterator(self):
    1144          # Issue #16596.
    1145          code = """
    1146              def test_subgen():
    1147                  yield 0
    1148                  return 123
    1149  
    1150              def test_gen():
    1151                  x = yield from test_subgen()
    1152                  return 456
    1153  
    1154              def main():
    1155                  for i in test_gen():
    1156                      lno = 12
    1157                  lno = 13
    1158          """
    1159          modules = { TEST_MODULE: code }
    1160          with create_modules(modules):
    1161              self.expect_set = [
    1162                  ('line', 2, 'tfunc_import'),
    1163                      break_in_func('test_gen', TEST_MODULE_FNAME),
    1164                  ('None', 2, 'tfunc_import'),              ('continue', ),
    1165                  ('line', 7, 'test_gen', ({1:1}, [])),     ('next', ),
    1166                  ('line', 8, 'test_gen'),                  ('next', ),
    1167                  ('exception', 11, 'main', StopIteration), ('step', ),
    1168                  ('line', 13, 'main'),                     ('quit', ),
    1169  
    1170              ]
    1171              with TracerRun(self) as tracer:
    1172                  tracer.runcall(tfunc_import)
    1173  
    1174      def test_return_command_in_generator_with_subiterator(self):
    1175          # Issue #16596.
    1176          code = """
    1177              def test_subgen():
    1178                  yield 0
    1179                  return 123
    1180  
    1181              def test_gen():
    1182                  x = yield from test_subgen()
    1183                  return 456
    1184  
    1185              def main():
    1186                  for i in test_gen():
    1187                      lno = 12
    1188                  lno = 13
    1189          """
    1190          modules = { TEST_MODULE: code }
    1191          with create_modules(modules):
    1192              self.expect_set = [
    1193                  ('line', 2, 'tfunc_import'),
    1194                      break_in_func('test_subgen', TEST_MODULE_FNAME),
    1195                  ('None', 2, 'tfunc_import'),                  ('continue', ),
    1196                  ('line', 3, 'test_subgen', ({1:1}, [])),      ('return', ),
    1197                  ('exception', 7, 'test_gen', StopIteration),  ('return', ),
    1198                  ('exception', 11, 'main', StopIteration),     ('step', ),
    1199                  ('line', 13, 'main'),                         ('quit', ),
    1200  
    1201              ]
    1202              with TracerRun(self) as tracer:
    1203                  tracer.runcall(tfunc_import)
    1204  
    1205  
    1206  class ESC[4;38;5;81mTestRegressions(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
    1207      def test_format_stack_entry_no_lineno(self):
    1208          # See gh-101517
    1209          self.assertIn('Warning: lineno is None',
    1210                        Bdb().format_stack_entry((sys._getframe(), None)))
    1211  
    1212  
    1213  if __name__ == "__main__":
    1214      unittest.main()