PageRenderTime 41ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/Lib/idlelib/idle_test/test_hyperparser.py

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