(root)/
Python-3.12.0/
Lib/
idlelib/
idle_test/
test_hyperparser.py
       1  "Test hyperparser, coverage 98%."
       2  
       3  from idlelib.hyperparser import HyperParser
       4  import unittest
       5  from test.support import requires
       6  from tkinter import Tk, Text
       7  from idlelib.editor import EditorWindow
       8  
       9  class ESC[4;38;5;81mDummyEditwin:
      10      def __init__(self, text):
      11          self.text = text
      12          self.indentwidth = 8
      13          self.tabwidth = 8
      14          self.prompt_last_line = '>>>'
      15          self.num_context_lines = 50, 500, 1000
      16  
      17      _build_char_in_string_func = EditorWindow._build_char_in_string_func
      18      is_char_in_string = EditorWindow.is_char_in_string
      19  
      20  
      21  class ESC[4;38;5;81mHyperParserTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      22      code = (
      23              '"""This is a module docstring"""\n'
      24              '# this line is a comment\n'
      25              'x = "this is a string"\n'
      26              "y = 'this is also a string'\n"
      27              'l = [i for i in range(10)]\n'
      28              'm = [py*py for # comment\n'
      29              '       py in l]\n'
      30              'x.__len__\n'
      31              "z = ((r'asdf')+('a')))\n"
      32              '[x for x in\n'
      33              'for = False\n'
      34              'cliché = "this is a string with unicode, what a cliché"'
      35              )
      36  
      37      @classmethod
      38      def setUpClass(cls):
      39          requires('gui')
      40          cls.root = Tk()
      41          cls.root.withdraw()
      42          cls.text = Text(cls.root)
      43          cls.editwin = DummyEditwin(cls.text)
      44  
      45      @classmethod
      46      def tearDownClass(cls):
      47          del cls.text, cls.editwin
      48          cls.root.destroy()
      49          del cls.root
      50  
      51      def setUp(self):
      52          self.text.insert('insert', self.code)
      53  
      54      def tearDown(self):
      55          self.text.delete('1.0', 'end')
      56          self.editwin.prompt_last_line = '>>>'
      57  
      58      def get_parser(self, index):
      59          """
      60          Return a parser object with index at 'index'
      61          """
      62          return HyperParser(self.editwin, index)
      63  
      64      def test_init(self):
      65          """
      66          test corner cases in the init method
      67          """
      68          with self.assertRaises(ValueError) as ve:
      69              self.text.tag_add('console', '1.0', '1.end')
      70              p = self.get_parser('1.5')
      71          self.assertIn('precedes', str(ve.exception))
      72  
      73          # test without ps1
      74          self.editwin.prompt_last_line = ''
      75  
      76          # number of lines lesser than 50
      77          p = self.get_parser('end')
      78          self.assertEqual(p.rawtext, self.text.get('1.0', 'end'))
      79  
      80          # number of lines greater than 50
      81          self.text.insert('end', self.text.get('1.0', 'end')*4)
      82          p = self.get_parser('54.5')
      83  
      84      def test_is_in_string(self):
      85          get = self.get_parser
      86  
      87          p = get('1.0')
      88          self.assertFalse(p.is_in_string())
      89          p = get('1.4')
      90          self.assertTrue(p.is_in_string())
      91          p = get('2.3')
      92          self.assertFalse(p.is_in_string())
      93          p = get('3.3')
      94          self.assertFalse(p.is_in_string())
      95          p = get('3.7')
      96          self.assertTrue(p.is_in_string())
      97          p = get('4.6')
      98          self.assertTrue(p.is_in_string())
      99          p = get('12.54')
     100          self.assertTrue(p.is_in_string())
     101  
     102      def test_is_in_code(self):
     103          get = self.get_parser
     104  
     105          p = get('1.0')
     106          self.assertTrue(p.is_in_code())
     107          p = get('1.1')
     108          self.assertFalse(p.is_in_code())
     109          p = get('2.5')
     110          self.assertFalse(p.is_in_code())
     111          p = get('3.4')
     112          self.assertTrue(p.is_in_code())
     113          p = get('3.6')
     114          self.assertFalse(p.is_in_code())
     115          p = get('4.14')
     116          self.assertFalse(p.is_in_code())
     117  
     118      def test_get_surrounding_bracket(self):
     119          get = self.get_parser
     120  
     121          def without_mustclose(parser):
     122              # a utility function to get surrounding bracket
     123              # with mustclose=False
     124              return parser.get_surrounding_brackets(mustclose=False)
     125  
     126          def with_mustclose(parser):
     127              # a utility function to get surrounding bracket
     128              # with mustclose=True
     129              return parser.get_surrounding_brackets(mustclose=True)
     130  
     131          p = get('3.2')
     132          self.assertIsNone(with_mustclose(p))
     133          self.assertIsNone(without_mustclose(p))
     134  
     135          p = get('5.6')
     136          self.assertTupleEqual(without_mustclose(p), ('5.4', '5.25'))
     137          self.assertTupleEqual(without_mustclose(p), with_mustclose(p))
     138  
     139          p = get('5.23')
     140          self.assertTupleEqual(without_mustclose(p), ('5.21', '5.24'))
     141          self.assertTupleEqual(without_mustclose(p), with_mustclose(p))
     142  
     143          p = get('6.15')
     144          self.assertTupleEqual(without_mustclose(p), ('6.4', '6.end'))
     145          self.assertIsNone(with_mustclose(p))
     146  
     147          p = get('9.end')
     148          self.assertIsNone(with_mustclose(p))
     149          self.assertIsNone(without_mustclose(p))
     150  
     151      def test_get_expression(self):
     152          get = self.get_parser
     153  
     154          p = get('4.2')
     155          self.assertEqual(p.get_expression(), 'y ')
     156  
     157          p = get('4.7')
     158          with self.assertRaises(ValueError) as ve:
     159              p.get_expression()
     160          self.assertIn('is inside a code', str(ve.exception))
     161  
     162          p = get('5.25')
     163          self.assertEqual(p.get_expression(), 'range(10)')
     164  
     165          p = get('6.7')
     166          self.assertEqual(p.get_expression(), 'py')
     167  
     168          p = get('6.8')
     169          self.assertEqual(p.get_expression(), '')
     170  
     171          p = get('7.9')
     172          self.assertEqual(p.get_expression(), 'py')
     173  
     174          p = get('8.end')
     175          self.assertEqual(p.get_expression(), 'x.__len__')
     176  
     177          p = get('9.13')
     178          self.assertEqual(p.get_expression(), "r'asdf'")
     179  
     180          p = get('9.17')
     181          with self.assertRaises(ValueError) as ve:
     182              p.get_expression()
     183          self.assertIn('is inside a code', str(ve.exception))
     184  
     185          p = get('10.0')
     186          self.assertEqual(p.get_expression(), '')
     187  
     188          p = get('10.6')
     189          self.assertEqual(p.get_expression(), '')
     190  
     191          p = get('10.11')
     192          self.assertEqual(p.get_expression(), '')
     193  
     194          p = get('11.3')
     195          self.assertEqual(p.get_expression(), '')
     196  
     197          p = get('11.11')
     198          self.assertEqual(p.get_expression(), 'False')
     199  
     200          p = get('12.6')
     201          self.assertEqual(p.get_expression(), 'cliché')
     202  
     203      def test_eat_identifier(self):
     204          def is_valid_id(candidate):
     205              result = HyperParser._eat_identifier(candidate, 0, len(candidate))
     206              if result == len(candidate):
     207                  return True
     208              elif result == 0:
     209                  return False
     210              else:
     211                  err_msg = "Unexpected result: {} (expected 0 or {}".format(
     212                      result, len(candidate)
     213                  )
     214                  raise Exception(err_msg)
     215  
     216          # invalid first character which is valid elsewhere in an identifier
     217          self.assertFalse(is_valid_id('2notid'))
     218  
     219          # ASCII-only valid identifiers
     220          self.assertTrue(is_valid_id('valid_id'))
     221          self.assertTrue(is_valid_id('_valid_id'))
     222          self.assertTrue(is_valid_id('valid_id_'))
     223          self.assertTrue(is_valid_id('_2valid_id'))
     224  
     225          # keywords which should be "eaten"
     226          self.assertTrue(is_valid_id('True'))
     227          self.assertTrue(is_valid_id('False'))
     228          self.assertTrue(is_valid_id('None'))
     229  
     230          # keywords which should not be "eaten"
     231          self.assertFalse(is_valid_id('for'))
     232          self.assertFalse(is_valid_id('import'))
     233          self.assertFalse(is_valid_id('return'))
     234  
     235          # valid unicode identifiers
     236          self.assertTrue(is_valid_id('cliche'))
     237          self.assertTrue(is_valid_id('cliché'))
     238          self.assertTrue(is_valid_id(''))
     239  
     240          # invalid unicode identifiers
     241          self.assertFalse(is_valid_id('2a'))
     242          self.assertFalse(is_valid_id('٢a'))
     243          self.assertFalse(is_valid_id(''))
     244  
     245          # valid identifier after "punctuation"
     246          self.assertEqual(HyperParser._eat_identifier('+ var', 0, 5), len('var'))
     247          self.assertEqual(HyperParser._eat_identifier('+var', 0, 4), len('var'))
     248          self.assertEqual(HyperParser._eat_identifier('.var', 0, 4), len('var'))
     249  
     250          # invalid identifiers
     251          self.assertFalse(is_valid_id('+'))
     252          self.assertFalse(is_valid_id(' '))
     253          self.assertFalse(is_valid_id(':'))
     254          self.assertFalse(is_valid_id('?'))
     255          self.assertFalse(is_valid_id('^'))
     256          self.assertFalse(is_valid_id('\\'))
     257          self.assertFalse(is_valid_id('"'))
     258          self.assertFalse(is_valid_id('"a string"'))
     259  
     260      def test_eat_identifier_various_lengths(self):
     261          eat_id = HyperParser._eat_identifier
     262  
     263          for length in range(1, 21):
     264              self.assertEqual(eat_id('a' * length, 0, length), length)
     265              self.assertEqual(eat_id('é' * length, 0, length), length)
     266              self.assertEqual(eat_id('a' + '2' * (length - 1), 0, length), length)
     267              self.assertEqual(eat_id('é' + '2' * (length - 1), 0, length), length)
     268              self.assertEqual(eat_id('é' + 'a' * (length - 1), 0, length), length)
     269              self.assertEqual(eat_id('é' * (length - 1) + 'a', 0, length), length)
     270              self.assertEqual(eat_id('+' * length, 0, length), 0)
     271              self.assertEqual(eat_id('2' + 'a' * (length - 1), 0, length), 0)
     272              self.assertEqual(eat_id('2' + 'é' * (length - 1), 0, length), 0)
     273  
     274  
     275  if __name__ == '__main__':
     276      unittest.main(verbosity=2)