Coverage for idle_test/test_config_key.py: 39%
255 statements
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-11 13:22 -0700
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-11 13:22 -0700
1"""Test config_key, coverage 98%.
3Coverage is effectively 100%. Tkinter dialog is mocked, Mac-only line
4may be skipped, and dummy function in bind test should not be called.
5Not tested: exit with 'self.advanced or self.keys_ok(keys) ...' False.
6"""
8from idlelib import config_key
9from test.support import requires
10import unittest
11from unittest import mock
12from tkinter import Tk, TclError
13from idlelib.idle_test.mock_idle import Func
14from idlelib.idle_test.mock_tk import Mbox_func
17class ValidationTest(unittest.TestCase):
18 "Test validation methods: ok, keys_ok, bind_ok."
20 class Validator(config_key.GetKeysFrame):
21 def __init__(self, *args, **kwargs):
22 super().__init__(*args, **kwargs)
23 class list_keys_final:
24 get = Func()
25 self.list_keys_final = list_keys_final
26 get_modifiers = Func()
27 showerror = Mbox_func()
29 @classmethod
30 def setUpClass(cls):
31 requires('gui')
32 cls.root = Tk()
33 cls.root.withdraw()
34 keylist = [['<Key-F12>'], ['<Control-Key-x>', '<Control-Key-X>']]
35 cls.dialog = cls.Validator(cls.root, '<<Test>>', keylist)
37 @classmethod
38 def tearDownClass(cls):
39 del cls.dialog
40 cls.root.update_idletasks()
41 cls.root.destroy()
42 del cls.root
44 def setUp(self):
45 self.dialog.showerror.message = ''
46 # A test that needs a particular final key value should set it.
47 # A test that sets a non-blank modifier list should reset it to [].
49 def test_ok_empty(self):
50 self.dialog.key_string.set(' ')
51 self.dialog.ok()
52 self.assertEqual(self.dialog.result, '')
53 self.assertEqual(self.dialog.showerror.message, 'No key specified.')
55 def test_ok_good(self):
56 self.dialog.key_string.set('<Key-F11>')
57 self.dialog.list_keys_final.get.result = 'F11'
58 self.dialog.ok()
59 self.assertEqual(self.dialog.result, '<Key-F11>')
60 self.assertEqual(self.dialog.showerror.message, '')
62 def test_keys_no_ending(self):
63 self.assertFalse(self.dialog.keys_ok('<Control-Shift'))
64 self.assertIn('Missing the final', self.dialog.showerror.message)
66 def test_keys_no_modifier_bad(self):
67 self.dialog.list_keys_final.get.result = 'A'
68 self.assertFalse(self.dialog.keys_ok('<Key-A>'))
69 self.assertIn('No modifier', self.dialog.showerror.message)
71 def test_keys_no_modifier_ok(self):
72 self.dialog.list_keys_final.get.result = 'F11'
73 self.assertTrue(self.dialog.keys_ok('<Key-F11>'))
74 self.assertEqual(self.dialog.showerror.message, '')
76 def test_keys_shift_bad(self):
77 self.dialog.list_keys_final.get.result = 'a'
78 self.dialog.get_modifiers.result = ['Shift']
79 self.assertFalse(self.dialog.keys_ok('<a>'))
80 self.assertIn('shift modifier', self.dialog.showerror.message)
81 self.dialog.get_modifiers.result = []
83 def test_keys_dup(self):
84 for mods, final, seq in (([], 'F12', '<Key-F12>'),
85 (['Control'], 'x', '<Control-Key-x>'),
86 (['Control'], 'X', '<Control-Key-X>')):
87 with self.subTest(m=mods, f=final, s=seq):
88 self.dialog.list_keys_final.get.result = final
89 self.dialog.get_modifiers.result = mods
90 self.assertFalse(self.dialog.keys_ok(seq))
91 self.assertIn('already in use', self.dialog.showerror.message)
92 self.dialog.get_modifiers.result = []
94 def test_bind_ok(self):
95 self.assertTrue(self.dialog.bind_ok('<Control-Shift-Key-a>'))
96 self.assertEqual(self.dialog.showerror.message, '')
98 def test_bind_not_ok(self):
99 self.assertFalse(self.dialog.bind_ok('<Control-Shift>'))
100 self.assertIn('not accepted', self.dialog.showerror.message)
103class ToggleLevelTest(unittest.TestCase):
104 "Test toggle between Basic and Advanced frames."
106 @classmethod
107 def setUpClass(cls):
108 requires('gui')
109 cls.root = Tk()
110 cls.root.withdraw()
111 cls.dialog = config_key.GetKeysFrame(cls.root, '<<Test>>', [])
113 @classmethod
114 def tearDownClass(cls):
115 del cls.dialog
116 cls.root.update_idletasks()
117 cls.root.destroy()
118 del cls.root
120 def test_toggle_level(self):
121 dialog = self.dialog
123 def stackorder():
124 """Get the stack order of the children of the frame.
126 winfo_children() stores the children in stack order, so
127 this can be used to check whether a frame is above or
128 below another one.
129 """
130 for index, child in enumerate(dialog.winfo_children()):
131 if child._name == 'keyseq_basic':
132 basic = index
133 if child._name == 'keyseq_advanced':
134 advanced = index
135 return basic, advanced
137 # New window starts at basic level.
138 self.assertFalse(dialog.advanced)
139 self.assertIn('Advanced', dialog.button_level['text'])
140 basic, advanced = stackorder()
141 self.assertGreater(basic, advanced)
143 # Toggle to advanced.
144 dialog.toggle_level()
145 self.assertTrue(dialog.advanced)
146 self.assertIn('Basic', dialog.button_level['text'])
147 basic, advanced = stackorder()
148 self.assertGreater(advanced, basic)
150 # Toggle to basic.
151 dialog.button_level.invoke()
152 self.assertFalse(dialog.advanced)
153 self.assertIn('Advanced', dialog.button_level['text'])
154 basic, advanced = stackorder()
155 self.assertGreater(basic, advanced)
158class KeySelectionTest(unittest.TestCase):
159 "Test selecting key on Basic frames."
161 class Basic(config_key.GetKeysFrame):
162 def __init__(self, *args, **kwargs):
163 super().__init__(*args, **kwargs)
164 class list_keys_final:
165 get = Func()
166 select_clear = Func()
167 yview = Func()
168 self.list_keys_final = list_keys_final
169 def set_modifiers_for_platform(self):
170 self.modifiers = ['foo', 'bar', 'BAZ']
171 self.modifier_label = {'BAZ': 'ZZZ'}
172 showerror = Mbox_func()
174 @classmethod
175 def setUpClass(cls):
176 requires('gui')
177 cls.root = Tk()
178 cls.root.withdraw()
179 cls.dialog = cls.Basic(cls.root, '<<Test>>', [])
181 @classmethod
182 def tearDownClass(cls):
183 del cls.dialog
184 cls.root.update_idletasks()
185 cls.root.destroy()
186 del cls.root
188 def setUp(self):
189 self.dialog.clear_key_seq()
191 def test_get_modifiers(self):
192 dialog = self.dialog
193 gm = dialog.get_modifiers
194 eq = self.assertEqual
196 # Modifiers are set on/off by invoking the checkbutton.
197 dialog.modifier_checkbuttons['foo'].invoke()
198 eq(gm(), ['foo'])
200 dialog.modifier_checkbuttons['BAZ'].invoke()
201 eq(gm(), ['foo', 'BAZ'])
203 dialog.modifier_checkbuttons['foo'].invoke()
204 eq(gm(), ['BAZ'])
206 @mock.patch.object(config_key.GetKeysFrame, 'get_modifiers')
207 def test_build_key_string(self, mock_modifiers):
208 dialog = self.dialog
209 key = dialog.list_keys_final
210 string = dialog.key_string.get
211 eq = self.assertEqual
213 key.get.result = 'a'
214 mock_modifiers.return_value = []
215 dialog.build_key_string()
216 eq(string(), '<Key-a>')
218 mock_modifiers.return_value = ['mymod']
219 dialog.build_key_string()
220 eq(string(), '<mymod-Key-a>')
222 key.get.result = ''
223 mock_modifiers.return_value = ['mymod', 'test']
224 dialog.build_key_string()
225 eq(string(), '<mymod-test>')
227 @mock.patch.object(config_key.GetKeysFrame, 'get_modifiers')
228 def test_final_key_selected(self, mock_modifiers):
229 dialog = self.dialog
230 key = dialog.list_keys_final
231 string = dialog.key_string.get
232 eq = self.assertEqual
234 mock_modifiers.return_value = ['Shift']
235 key.get.result = '{'
236 dialog.final_key_selected()
237 eq(string(), '<Shift-Key-braceleft>')
240class CancelWindowTest(unittest.TestCase):
241 "Simulate user clicking [Cancel] button."
243 @classmethod
244 def setUpClass(cls):
245 requires('gui')
246 cls.root = Tk()
247 cls.root.withdraw()
248 cls.dialog = config_key.GetKeysWindow(
249 cls.root, 'Title', '<<Test>>', [], _utest=True)
251 @classmethod
252 def tearDownClass(cls):
253 cls.dialog.cancel()
254 del cls.dialog
255 cls.root.update_idletasks()
256 cls.root.destroy()
257 del cls.root
259 @mock.patch.object(config_key.GetKeysFrame, 'ok')
260 def test_cancel(self, mock_frame_ok):
261 self.assertEqual(self.dialog.winfo_class(), 'Toplevel')
262 self.dialog.button_cancel.invoke()
263 with self.assertRaises(TclError):
264 self.dialog.winfo_class()
265 self.assertEqual(self.dialog.result, '')
266 mock_frame_ok.assert_not_called()
269class OKWindowTest(unittest.TestCase):
270 "Simulate user clicking [OK] button."
272 @classmethod
273 def setUpClass(cls):
274 requires('gui')
275 cls.root = Tk()
276 cls.root.withdraw()
277 cls.dialog = config_key.GetKeysWindow(
278 cls.root, 'Title', '<<Test>>', [], _utest=True)
280 @classmethod
281 def tearDownClass(cls):
282 cls.dialog.cancel()
283 del cls.dialog
284 cls.root.update_idletasks()
285 cls.root.destroy()
286 del cls.root
288 @mock.patch.object(config_key.GetKeysFrame, 'ok')
289 def test_ok(self, mock_frame_ok):
290 self.assertEqual(self.dialog.winfo_class(), 'Toplevel')
291 self.dialog.button_ok.invoke()
292 with self.assertRaises(TclError):
293 self.dialog.winfo_class()
294 mock_frame_ok.assert_called()
297class WindowResultTest(unittest.TestCase):
298 "Test window result get and set."
300 @classmethod
301 def setUpClass(cls):
302 requires('gui')
303 cls.root = Tk()
304 cls.root.withdraw()
305 cls.dialog = config_key.GetKeysWindow(
306 cls.root, 'Title', '<<Test>>', [], _utest=True)
308 @classmethod
309 def tearDownClass(cls):
310 cls.dialog.cancel()
311 del cls.dialog
312 cls.root.update_idletasks()
313 cls.root.destroy()
314 del cls.root
316 def test_result(self):
317 dialog = self.dialog
318 eq = self.assertEqual
320 dialog.result = ''
321 eq(dialog.result, '')
322 eq(dialog.frame.result,'')
324 dialog.result = 'bar'
325 eq(dialog.result,'bar')
326 eq(dialog.frame.result,'bar')
328 dialog.frame.result = 'foo'
329 eq(dialog.result, 'foo')
330 eq(dialog.frame.result,'foo')
333class HelperTest(unittest.TestCase):
334 "Test module level helper functions."
336 def test_translate_key(self):
337 tr = config_key.translate_key 1b
338 eq = self.assertEqual 1b
340 # Letters return unchanged with no 'Shift'.
341 eq(tr('q', []), 'Key-q') 1b
342 eq(tr('q', ['Control', 'Alt']), 'Key-q') 1b
344 # 'Shift' uppercases single lowercase letters.
345 eq(tr('q', ['Shift']), 'Key-Q') 1b
346 eq(tr('q', ['Control', 'Shift']), 'Key-Q') 1b
347 eq(tr('q', ['Control', 'Alt', 'Shift']), 'Key-Q') 1b
349 # Convert key name to keysym.
350 eq(tr('Page Up', []), 'Key-Prior') 1b
351 # 'Shift' doesn't change case when it's not a single char.
352 eq(tr('*', ['Shift']), 'Key-asterisk') 1b
355if __name__ == '__main__': 355 ↛ 356line 355 didn't jump to line 356, because the condition on line 355 was never true
356 unittest.main(verbosity=2)