python (3.11.7)
       1  "Test run, coverage 54%."
       2  
       3  from idlelib import run
       4  import io
       5  import sys
       6  from test.support import captured_output, captured_stderr
       7  import unittest
       8  from unittest import mock
       9  import idlelib
      10  from idlelib.idle_test.mock_idle import Func
      11  
      12  idlelib.testing = True  # Use {} for executing test user code.
      13  
      14  
      15  class ESC[4;38;5;81mExceptionTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      16  
      17      def test_print_exception_unhashable(self):
      18          class ESC[4;38;5;81mUnhashableException(ESC[4;38;5;149mException):
      19              def __eq__(self, other):
      20                  return True
      21  
      22          ex1 = UnhashableException('ex1')
      23          ex2 = UnhashableException('ex2')
      24          try:
      25              raise ex2 from ex1
      26          except UnhashableException:
      27              try:
      28                  raise ex1
      29              except UnhashableException:
      30                  with captured_stderr() as output:
      31                      with mock.patch.object(run, 'cleanup_traceback') as ct:
      32                          ct.side_effect = lambda t, e: t
      33                          run.print_exception()
      34  
      35          tb = output.getvalue().strip().splitlines()
      36          self.assertEqual(11, len(tb))
      37          self.assertIn('UnhashableException: ex2', tb[3])
      38          self.assertIn('UnhashableException: ex1', tb[10])
      39  
      40      data = (('1/0', ZeroDivisionError, "division by zero\n"),
      41              ('abc', NameError, "name 'abc' is not defined. "
      42                                 "Did you mean: 'abs'?\n"),
      43              ('int.reel', AttributeError,
      44                   "type object 'int' has no attribute 'reel'. "
      45                   "Did you mean: 'real'?\n"),
      46              )
      47  
      48      def test_get_message(self):
      49          for code, exc, msg in self.data:
      50              with self.subTest(code=code):
      51                  try:
      52                      eval(compile(code, '', 'eval'))
      53                  except exc:
      54                      typ, val, tb = sys.exc_info()
      55                      actual = run.get_message_lines(typ, val, tb)[0]
      56                      expect = f'{exc.__name__}: {msg}'
      57                      self.assertEqual(actual, expect)
      58  
      59      @mock.patch.object(run, 'cleanup_traceback',
      60                         new_callable=lambda: (lambda t, e: None))
      61      def test_get_multiple_message(self, mock):
      62          d = self.data
      63          data2 = ((d[0], d[1]), (d[1], d[2]), (d[2], d[0]))
      64          subtests = 0
      65          for (code1, exc1, msg1), (code2, exc2, msg2) in data2:
      66              with self.subTest(codes=(code1,code2)):
      67                  try:
      68                      eval(compile(code1, '', 'eval'))
      69                  except exc1:
      70                      try:
      71                          eval(compile(code2, '', 'eval'))
      72                      except exc2:
      73                          with captured_stderr() as output:
      74                              run.print_exception()
      75                          actual = output.getvalue()
      76                          self.assertIn(msg1, actual)
      77                          self.assertIn(msg2, actual)
      78                          subtests += 1
      79          self.assertEqual(subtests, len(data2))  # All subtests ran?
      80  
      81  # StdioFile tests.
      82  
      83  class ESC[4;38;5;81mS(ESC[4;38;5;149mstr):
      84      def __str__(self):
      85          return '%s:str' % type(self).__name__
      86      def __unicode__(self):
      87          return '%s:unicode' % type(self).__name__
      88      def __len__(self):
      89          return 3
      90      def __iter__(self):
      91          return iter('abc')
      92      def __getitem__(self, *args):
      93          return '%s:item' % type(self).__name__
      94      def __getslice__(self, *args):
      95          return '%s:slice' % type(self).__name__
      96  
      97  
      98  class ESC[4;38;5;81mMockShell:
      99      def __init__(self):
     100          self.reset()
     101      def write(self, *args):
     102          self.written.append(args)
     103      def readline(self):
     104          return self.lines.pop()
     105      def close(self):
     106          pass
     107      def reset(self):
     108          self.written = []
     109      def push(self, lines):
     110          self.lines = list(lines)[::-1]
     111  
     112  
     113  class ESC[4;38;5;81mStdInputFilesTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     114  
     115      def test_misc(self):
     116          shell = MockShell()
     117          f = run.StdInputFile(shell, 'stdin')
     118          self.assertIsInstance(f, io.TextIOBase)
     119          self.assertEqual(f.encoding, 'utf-8')
     120          self.assertEqual(f.errors, 'strict')
     121          self.assertIsNone(f.newlines)
     122          self.assertEqual(f.name, '<stdin>')
     123          self.assertFalse(f.closed)
     124          self.assertTrue(f.isatty())
     125          self.assertTrue(f.readable())
     126          self.assertFalse(f.writable())
     127          self.assertFalse(f.seekable())
     128  
     129      def test_unsupported(self):
     130          shell = MockShell()
     131          f = run.StdInputFile(shell, 'stdin')
     132          self.assertRaises(OSError, f.fileno)
     133          self.assertRaises(OSError, f.tell)
     134          self.assertRaises(OSError, f.seek, 0)
     135          self.assertRaises(OSError, f.write, 'x')
     136          self.assertRaises(OSError, f.writelines, ['x'])
     137  
     138      def test_read(self):
     139          shell = MockShell()
     140          f = run.StdInputFile(shell, 'stdin')
     141          shell.push(['one\n', 'two\n', ''])
     142          self.assertEqual(f.read(), 'one\ntwo\n')
     143          shell.push(['one\n', 'two\n', ''])
     144          self.assertEqual(f.read(-1), 'one\ntwo\n')
     145          shell.push(['one\n', 'two\n', ''])
     146          self.assertEqual(f.read(None), 'one\ntwo\n')
     147          shell.push(['one\n', 'two\n', 'three\n', ''])
     148          self.assertEqual(f.read(2), 'on')
     149          self.assertEqual(f.read(3), 'e\nt')
     150          self.assertEqual(f.read(10), 'wo\nthree\n')
     151  
     152          shell.push(['one\n', 'two\n'])
     153          self.assertEqual(f.read(0), '')
     154          self.assertRaises(TypeError, f.read, 1.5)
     155          self.assertRaises(TypeError, f.read, '1')
     156          self.assertRaises(TypeError, f.read, 1, 1)
     157  
     158      def test_readline(self):
     159          shell = MockShell()
     160          f = run.StdInputFile(shell, 'stdin')
     161          shell.push(['one\n', 'two\n', 'three\n', 'four\n'])
     162          self.assertEqual(f.readline(), 'one\n')
     163          self.assertEqual(f.readline(-1), 'two\n')
     164          self.assertEqual(f.readline(None), 'three\n')
     165          shell.push(['one\ntwo\n'])
     166          self.assertEqual(f.readline(), 'one\n')
     167          self.assertEqual(f.readline(), 'two\n')
     168          shell.push(['one', 'two', 'three'])
     169          self.assertEqual(f.readline(), 'one')
     170          self.assertEqual(f.readline(), 'two')
     171          shell.push(['one\n', 'two\n', 'three\n'])
     172          self.assertEqual(f.readline(2), 'on')
     173          self.assertEqual(f.readline(1), 'e')
     174          self.assertEqual(f.readline(1), '\n')
     175          self.assertEqual(f.readline(10), 'two\n')
     176  
     177          shell.push(['one\n', 'two\n'])
     178          self.assertEqual(f.readline(0), '')
     179          self.assertRaises(TypeError, f.readlines, 1.5)
     180          self.assertRaises(TypeError, f.readlines, '1')
     181          self.assertRaises(TypeError, f.readlines, 1, 1)
     182  
     183      def test_readlines(self):
     184          shell = MockShell()
     185          f = run.StdInputFile(shell, 'stdin')
     186          shell.push(['one\n', 'two\n', ''])
     187          self.assertEqual(f.readlines(), ['one\n', 'two\n'])
     188          shell.push(['one\n', 'two\n', ''])
     189          self.assertEqual(f.readlines(-1), ['one\n', 'two\n'])
     190          shell.push(['one\n', 'two\n', ''])
     191          self.assertEqual(f.readlines(None), ['one\n', 'two\n'])
     192          shell.push(['one\n', 'two\n', ''])
     193          self.assertEqual(f.readlines(0), ['one\n', 'two\n'])
     194          shell.push(['one\n', 'two\n', ''])
     195          self.assertEqual(f.readlines(3), ['one\n'])
     196          shell.push(['one\n', 'two\n', ''])
     197          self.assertEqual(f.readlines(4), ['one\n', 'two\n'])
     198  
     199          shell.push(['one\n', 'two\n', ''])
     200          self.assertRaises(TypeError, f.readlines, 1.5)
     201          self.assertRaises(TypeError, f.readlines, '1')
     202          self.assertRaises(TypeError, f.readlines, 1, 1)
     203  
     204      def test_close(self):
     205          shell = MockShell()
     206          f = run.StdInputFile(shell, 'stdin')
     207          shell.push(['one\n', 'two\n', ''])
     208          self.assertFalse(f.closed)
     209          self.assertEqual(f.readline(), 'one\n')
     210          f.close()
     211          self.assertFalse(f.closed)
     212          self.assertEqual(f.readline(), 'two\n')
     213          self.assertRaises(TypeError, f.close, 1)
     214  
     215  
     216  class ESC[4;38;5;81mStdOutputFilesTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     217  
     218      def test_misc(self):
     219          shell = MockShell()
     220          f = run.StdOutputFile(shell, 'stdout')
     221          self.assertIsInstance(f, io.TextIOBase)
     222          self.assertEqual(f.encoding, 'utf-8')
     223          self.assertEqual(f.errors, 'strict')
     224          self.assertIsNone(f.newlines)
     225          self.assertEqual(f.name, '<stdout>')
     226          self.assertFalse(f.closed)
     227          self.assertTrue(f.isatty())
     228          self.assertFalse(f.readable())
     229          self.assertTrue(f.writable())
     230          self.assertFalse(f.seekable())
     231  
     232      def test_unsupported(self):
     233          shell = MockShell()
     234          f = run.StdOutputFile(shell, 'stdout')
     235          self.assertRaises(OSError, f.fileno)
     236          self.assertRaises(OSError, f.tell)
     237          self.assertRaises(OSError, f.seek, 0)
     238          self.assertRaises(OSError, f.read, 0)
     239          self.assertRaises(OSError, f.readline, 0)
     240  
     241      def test_write(self):
     242          shell = MockShell()
     243          f = run.StdOutputFile(shell, 'stdout')
     244          f.write('test')
     245          self.assertEqual(shell.written, [('test', 'stdout')])
     246          shell.reset()
     247          f.write('t\xe8\u015b\U0001d599')
     248          self.assertEqual(shell.written, [('t\xe8\u015b\U0001d599', 'stdout')])
     249          shell.reset()
     250  
     251          f.write(S('t\xe8\u015b\U0001d599'))
     252          self.assertEqual(shell.written, [('t\xe8\u015b\U0001d599', 'stdout')])
     253          self.assertEqual(type(shell.written[0][0]), str)
     254          shell.reset()
     255  
     256          self.assertRaises(TypeError, f.write)
     257          self.assertEqual(shell.written, [])
     258          self.assertRaises(TypeError, f.write, b'test')
     259          self.assertRaises(TypeError, f.write, 123)
     260          self.assertEqual(shell.written, [])
     261          self.assertRaises(TypeError, f.write, 'test', 'spam')
     262          self.assertEqual(shell.written, [])
     263  
     264      def test_write_stderr_nonencodable(self):
     265          shell = MockShell()
     266          f = run.StdOutputFile(shell, 'stderr', 'iso-8859-15', 'backslashreplace')
     267          f.write('t\xe8\u015b\U0001d599\xa4')
     268          self.assertEqual(shell.written, [('t\xe8\\u015b\\U0001d599\\xa4', 'stderr')])
     269          shell.reset()
     270  
     271          f.write(S('t\xe8\u015b\U0001d599\xa4'))
     272          self.assertEqual(shell.written, [('t\xe8\\u015b\\U0001d599\\xa4', 'stderr')])
     273          self.assertEqual(type(shell.written[0][0]), str)
     274          shell.reset()
     275  
     276          self.assertRaises(TypeError, f.write)
     277          self.assertEqual(shell.written, [])
     278          self.assertRaises(TypeError, f.write, b'test')
     279          self.assertRaises(TypeError, f.write, 123)
     280          self.assertEqual(shell.written, [])
     281          self.assertRaises(TypeError, f.write, 'test', 'spam')
     282          self.assertEqual(shell.written, [])
     283  
     284      def test_writelines(self):
     285          shell = MockShell()
     286          f = run.StdOutputFile(shell, 'stdout')
     287          f.writelines([])
     288          self.assertEqual(shell.written, [])
     289          shell.reset()
     290          f.writelines(['one\n', 'two'])
     291          self.assertEqual(shell.written,
     292                           [('one\n', 'stdout'), ('two', 'stdout')])
     293          shell.reset()
     294          f.writelines(['on\xe8\n', 'tw\xf2'])
     295          self.assertEqual(shell.written,
     296                           [('on\xe8\n', 'stdout'), ('tw\xf2', 'stdout')])
     297          shell.reset()
     298  
     299          f.writelines([S('t\xe8st')])
     300          self.assertEqual(shell.written, [('t\xe8st', 'stdout')])
     301          self.assertEqual(type(shell.written[0][0]), str)
     302          shell.reset()
     303  
     304          self.assertRaises(TypeError, f.writelines)
     305          self.assertEqual(shell.written, [])
     306          self.assertRaises(TypeError, f.writelines, 123)
     307          self.assertEqual(shell.written, [])
     308          self.assertRaises(TypeError, f.writelines, [b'test'])
     309          self.assertRaises(TypeError, f.writelines, [123])
     310          self.assertEqual(shell.written, [])
     311          self.assertRaises(TypeError, f.writelines, [], [])
     312          self.assertEqual(shell.written, [])
     313  
     314      def test_close(self):
     315          shell = MockShell()
     316          f = run.StdOutputFile(shell, 'stdout')
     317          self.assertFalse(f.closed)
     318          f.write('test')
     319          f.close()
     320          self.assertTrue(f.closed)
     321          self.assertRaises(ValueError, f.write, 'x')
     322          self.assertEqual(shell.written, [('test', 'stdout')])
     323          f.close()
     324          self.assertRaises(TypeError, f.close, 1)
     325  
     326  
     327  class ESC[4;38;5;81mRecursionLimitTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     328      # Test (un)install_recursionlimit_wrappers and fixdoc.
     329  
     330      def test_bad_setrecursionlimit_calls(self):
     331          run.install_recursionlimit_wrappers()
     332          self.addCleanup(run.uninstall_recursionlimit_wrappers)
     333          f = sys.setrecursionlimit
     334          self.assertRaises(TypeError, f, limit=100)
     335          self.assertRaises(TypeError, f, 100, 1000)
     336          self.assertRaises(ValueError, f, 0)
     337  
     338      def test_roundtrip(self):
     339          run.install_recursionlimit_wrappers()
     340          self.addCleanup(run.uninstall_recursionlimit_wrappers)
     341  
     342          # Check that setting the recursion limit works.
     343          orig_reclimit = sys.getrecursionlimit()
     344          self.addCleanup(sys.setrecursionlimit, orig_reclimit)
     345          sys.setrecursionlimit(orig_reclimit + 3)
     346  
     347          # Check that the new limit is returned by sys.getrecursionlimit().
     348          new_reclimit = sys.getrecursionlimit()
     349          self.assertEqual(new_reclimit, orig_reclimit + 3)
     350  
     351      def test_default_recursion_limit_preserved(self):
     352          orig_reclimit = sys.getrecursionlimit()
     353          run.install_recursionlimit_wrappers()
     354          self.addCleanup(run.uninstall_recursionlimit_wrappers)
     355          new_reclimit = sys.getrecursionlimit()
     356          self.assertEqual(new_reclimit, orig_reclimit)
     357  
     358      def test_fixdoc(self):
     359          # Put here until better place for miscellaneous test.
     360          def func(): "docstring"
     361          run.fixdoc(func, "more")
     362          self.assertEqual(func.__doc__, "docstring\n\nmore")
     363          func.__doc__ = None
     364          run.fixdoc(func, "more")
     365          self.assertEqual(func.__doc__, "more")
     366  
     367  
     368  class ESC[4;38;5;81mHandleErrorTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     369      # Method of MyRPCServer
     370      def test_fatal_error(self):
     371          eq = self.assertEqual
     372          with captured_output('__stderr__') as err,\
     373               mock.patch('idlelib.run.thread.interrupt_main',
     374                          new_callable=Func) as func:
     375              try:
     376                  raise EOFError
     377              except EOFError:
     378                  run.MyRPCServer.handle_error(None, 'abc', '123')
     379              eq(run.exit_now, True)
     380              run.exit_now = False
     381              eq(err.getvalue(), '')
     382  
     383              try:
     384                  raise IndexError
     385              except IndexError:
     386                  run.MyRPCServer.handle_error(None, 'abc', '123')
     387              eq(run.quitting, True)
     388              run.quitting = False
     389              msg = err.getvalue()
     390              self.assertIn('abc', msg)
     391              self.assertIn('123', msg)
     392              self.assertIn('IndexError', msg)
     393              eq(func.called, 2)
     394  
     395  
     396  class ESC[4;38;5;81mExecRuncodeTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     397  
     398      @classmethod
     399      def setUpClass(cls):
     400          cls.addClassCleanup(setattr,run,'print_exception',run.print_exception)
     401          cls.prt = Func()  # Need reference.
     402          run.print_exception = cls.prt
     403          mockrpc = mock.Mock()
     404          mockrpc.console.getvar = Func(result=False)
     405          cls.ex = run.Executive(mockrpc)
     406  
     407      @classmethod
     408      def tearDownClass(cls):
     409          assert sys.excepthook == sys.__excepthook__
     410  
     411      def test_exceptions(self):
     412          ex = self.ex
     413          ex.runcode('1/0')
     414          self.assertIs(ex.user_exc_info[0], ZeroDivisionError)
     415  
     416          self.addCleanup(setattr, sys, 'excepthook', sys.__excepthook__)
     417          sys.excepthook = lambda t, e, tb: run.print_exception(t)
     418          ex.runcode('1/0')
     419          self.assertIs(self.prt.args[0], ZeroDivisionError)
     420  
     421          sys.excepthook = lambda: None
     422          ex.runcode('1/0')
     423          t, e, tb = ex.user_exc_info
     424          self.assertIs(t, TypeError)
     425          self.assertTrue(isinstance(e.__context__, ZeroDivisionError))
     426  
     427  
     428  if __name__ == '__main__':
     429      unittest.main(verbosity=2)