test_editor.py 6.8 KB

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