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