test_editor.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. "Test editor, coverage 35%."
  2. from idlelib import editor
  3. import unittest
  4. from collections import namedtuple
  5. from test.support import requires
  6. from tkinter import Tk
  7. from idlelib.idle_test.mock_idle import Func
  8. Editor = editor.EditorWindow
  9. class EditorWindowTest(unittest.TestCase):
  10. @classmethod
  11. def setUpClass(cls):
  12. requires('gui')
  13. cls.root = Tk()
  14. cls.root.withdraw()
  15. @classmethod
  16. def tearDownClass(cls):
  17. cls.root.update_idletasks()
  18. for id in cls.root.tk.call('after', 'info'):
  19. cls.root.after_cancel(id)
  20. cls.root.destroy()
  21. del cls.root
  22. def test_init(self):
  23. e = Editor(root=self.root)
  24. self.assertEqual(e.root, self.root)
  25. e._close()
  26. class TestGetLineIndent(unittest.TestCase):
  27. def test_empty_lines(self):
  28. for tabwidth in [1, 2, 4, 6, 8]:
  29. for line in ['', '\n']:
  30. with self.subTest(line=line, tabwidth=tabwidth):
  31. self.assertEqual(
  32. editor.get_line_indent(line, tabwidth=tabwidth),
  33. (0, 0),
  34. )
  35. def test_tabwidth_4(self):
  36. # (line, (raw, effective))
  37. tests = (('no spaces', (0, 0)),
  38. # Internal space isn't counted.
  39. (' space test', (4, 4)),
  40. ('\ttab test', (1, 4)),
  41. ('\t\tdouble tabs test', (2, 8)),
  42. # Different results when mixing tabs and spaces.
  43. (' \tmixed test', (5, 8)),
  44. (' \t mixed test', (5, 6)),
  45. ('\t mixed test', (5, 8)),
  46. # Spaces not divisible by tabwidth.
  47. (' \tmixed test', (3, 4)),
  48. (' \t mixed test', (3, 5)),
  49. ('\t mixed test', (3, 6)),
  50. # Only checks spaces and tabs.
  51. ('\nnewline test', (0, 0)))
  52. for line, expected in tests:
  53. with self.subTest(line=line):
  54. self.assertEqual(
  55. editor.get_line_indent(line, tabwidth=4),
  56. expected,
  57. )
  58. def test_tabwidth_8(self):
  59. # (line, (raw, effective))
  60. tests = (('no spaces', (0, 0)),
  61. # Internal space isn't counted.
  62. (' space test', (8, 8)),
  63. ('\ttab test', (1, 8)),
  64. ('\t\tdouble tabs test', (2, 16)),
  65. # Different results when mixing tabs and spaces.
  66. (' \tmixed test', (9, 16)),
  67. (' \t mixed test', (9, 10)),
  68. ('\t mixed test', (9, 16)),
  69. # Spaces not divisible by tabwidth.
  70. (' \tmixed test', (3, 8)),
  71. (' \t mixed test', (3, 9)),
  72. ('\t mixed test', (3, 10)),
  73. # Only checks spaces and tabs.
  74. ('\nnewline test', (0, 0)))
  75. for line, expected in tests:
  76. with self.subTest(line=line):
  77. self.assertEqual(
  78. editor.get_line_indent(line, tabwidth=8),
  79. expected,
  80. )
  81. def insert(text, string):
  82. text.delete('1.0', 'end')
  83. text.insert('end', string)
  84. text.update() # Force update for colorizer to finish.
  85. class IndentAndNewlineTest(unittest.TestCase):
  86. @classmethod
  87. def setUpClass(cls):
  88. requires('gui')
  89. cls.root = Tk()
  90. cls.root.withdraw()
  91. cls.window = Editor(root=cls.root)
  92. cls.window.indentwidth = 2
  93. cls.window.tabwidth = 2
  94. @classmethod
  95. def tearDownClass(cls):
  96. cls.window._close()
  97. del cls.window
  98. cls.root.update_idletasks()
  99. for id in cls.root.tk.call('after', 'info'):
  100. cls.root.after_cancel(id)
  101. cls.root.destroy()
  102. del cls.root
  103. def test_indent_and_newline_event(self):
  104. eq = self.assertEqual
  105. w = self.window
  106. text = w.text
  107. get = text.get
  108. nl = w.newline_and_indent_event
  109. TestInfo = namedtuple('Tests', ['label', 'text', 'expected', 'mark'])
  110. tests = (TestInfo('Empty line inserts with no indent.',
  111. ' \n def __init__(self):',
  112. '\n \n def __init__(self):\n',
  113. '1.end'),
  114. TestInfo('Inside bracket before space, deletes space.',
  115. ' def f1(self, a, b):',
  116. ' def f1(self,\n a, b):\n',
  117. '1.14'),
  118. TestInfo('Inside bracket after space, deletes space.',
  119. ' def f1(self, a, b):',
  120. ' def f1(self,\n a, b):\n',
  121. '1.15'),
  122. TestInfo('Inside string with one line - no indent.',
  123. ' """Docstring."""',
  124. ' """Docstring.\n"""\n',
  125. '1.15'),
  126. TestInfo('Inside string with more than one line.',
  127. ' """Docstring.\n Docstring Line 2"""',
  128. ' """Docstring.\n Docstring Line 2\n """\n',
  129. '2.18'),
  130. TestInfo('Backslash with one line.',
  131. 'a =\\',
  132. 'a =\\\n \n',
  133. '1.end'),
  134. TestInfo('Backslash with more than one line.',
  135. 'a =\\\n multiline\\',
  136. 'a =\\\n multiline\\\n \n',
  137. '2.end'),
  138. TestInfo('Block opener - indents +1 level.',
  139. ' def f1(self):\n pass',
  140. ' def f1(self):\n \n pass\n',
  141. '1.end'),
  142. TestInfo('Block closer - dedents -1 level.',
  143. ' def f1(self):\n pass',
  144. ' def f1(self):\n pass\n \n',
  145. '2.end'),
  146. )
  147. w.prompt_last_line = ''
  148. for test in tests:
  149. with self.subTest(label=test.label):
  150. insert(text, test.text)
  151. text.mark_set('insert', test.mark)
  152. nl(event=None)
  153. eq(get('1.0', 'end'), test.expected)
  154. # Selected text.
  155. insert(text, ' def f1(self, a, b):\n return a + b')
  156. text.tag_add('sel', '1.17', '1.end')
  157. nl(None)
  158. # Deletes selected text before adding new line.
  159. eq(get('1.0', 'end'), ' def f1(self, a,\n \n return a + b\n')
  160. # Preserves the whitespace in shell prompt.
  161. w.prompt_last_line = '>>> '
  162. insert(text, '>>> \t\ta =')
  163. text.mark_set('insert', '1.5')
  164. nl(None)
  165. eq(get('1.0', 'end'), '>>> \na =\n')
  166. class RMenuTest(unittest.TestCase):
  167. @classmethod
  168. def setUpClass(cls):
  169. requires('gui')
  170. cls.root = Tk()
  171. cls.root.withdraw()
  172. cls.window = Editor(root=cls.root)
  173. @classmethod
  174. def tearDownClass(cls):
  175. cls.window._close()
  176. del cls.window
  177. cls.root.update_idletasks()
  178. for id in cls.root.tk.call('after', 'info'):
  179. cls.root.after_cancel(id)
  180. cls.root.destroy()
  181. del cls.root
  182. class DummyRMenu:
  183. def tk_popup(x, y): pass
  184. def test_rclick(self):
  185. pass
  186. if __name__ == '__main__':
  187. unittest.main(verbosity=2)