bpo-35598: IDLE: Increase test coverage for config_key.py (#11360) · python/cpython@b0a6196
1-"Test config_key, coverage 82%"
1+"""Test config_key, coverage 98%.
2+3+Coverage is effectively 100%. Tkinter dialog is mocked, Mac-only line
4+may be skipped, and dummy function in bind test should not be called.
5+Not tested: exit with 'self.advanced or self.keys_ok(keys)) ...' False.
6+"""
2738from idlelib import config_key
49from test.support import requires
510import unittest
6-from tkinter import Tk
11+from unittest import mock
12+from tkinter import Tk, TclError
713from idlelib.idle_test.mock_idle import Func
814from idlelib.idle_test.mock_tk import Mbox_func
91516+gkd = config_key.GetKeysDialog
17+10181119class ValidationTest(unittest.TestCase):
1220"Test validation methods: ok, keys_ok, bind_ok."
132114-class Validator(config_key.GetKeysDialog):
22+class Validator(gkd):
1523def __init__(self, *args, **kwargs):
1624config_key.GetKeysDialog.__init__(self, *args, **kwargs)
1725class list_keys_final:
@@ -95,5 +103,186 @@ def test_bind_not_ok(self):
95103self.assertIn('not accepted', self.dialog.showerror.message)
9610497105106+class ToggleLevelTest(unittest.TestCase):
107+"Test toggle between Basic and Advanced frames."
108+109+@classmethod
110+def setUpClass(cls):
111+requires('gui')
112+cls.root = Tk()
113+cls.root.withdraw()
114+cls.dialog = gkd(cls.root, 'Title', '<<Test>>', [], _utest=True)
115+116+@classmethod
117+def tearDownClass(cls):
118+cls.dialog.cancel()
119+cls.root.update_idletasks()
120+cls.root.destroy()
121+del cls.dialog, cls.root
122+123+def test_toggle_level(self):
124+dialog = self.dialog
125+126+def stackorder():
127+"""Get the stack order of the children of the frame.
128+129+ winfo_children() stores the children in stack order, so
130+ this can be used to check whether a frame is above or
131+ below another one.
132+ """
133+for index, child in enumerate(dialog.frame.winfo_children()):
134+if child._name == 'keyseq_basic':
135+basic = index
136+if child._name == 'keyseq_advanced':
137+advanced = index
138+return basic, advanced
139+140+# New window starts at basic level.
141+self.assertFalse(dialog.advanced)
142+self.assertIn('Advanced', dialog.button_level['text'])
143+basic, advanced = stackorder()
144+self.assertGreater(basic, advanced)
145+146+# Toggle to advanced.
147+dialog.toggle_level()
148+self.assertTrue(dialog.advanced)
149+self.assertIn('Basic', dialog.button_level['text'])
150+basic, advanced = stackorder()
151+self.assertGreater(advanced, basic)
152+153+# Toggle to basic.
154+dialog.button_level.invoke()
155+self.assertFalse(dialog.advanced)
156+self.assertIn('Advanced', dialog.button_level['text'])
157+basic, advanced = stackorder()
158+self.assertGreater(basic, advanced)
159+160+161+class KeySelectionTest(unittest.TestCase):
162+"Test selecting key on Basic frames."
163+164+class Basic(gkd):
165+def __init__(self, *args, **kwargs):
166+super().__init__(*args, **kwargs)
167+class list_keys_final:
168+get = Func()
169+select_clear = Func()
170+yview = Func()
171+self.list_keys_final = list_keys_final
172+def set_modifiers_for_platform(self):
173+self.modifiers = ['foo', 'bar', 'BAZ']
174+self.modifier_label = {'BAZ': 'ZZZ'}
175+showerror = Mbox_func()
176+177+@classmethod
178+def setUpClass(cls):
179+requires('gui')
180+cls.root = Tk()
181+cls.root.withdraw()
182+cls.dialog = cls.Basic(cls.root, 'Title', '<<Test>>', [], _utest=True)
183+184+@classmethod
185+def tearDownClass(cls):
186+cls.dialog.cancel()
187+cls.root.update_idletasks()
188+cls.root.destroy()
189+del cls.dialog, cls.root
190+191+def setUp(self):
192+self.dialog.clear_key_seq()
193+194+def test_get_modifiers(self):
195+dialog = self.dialog
196+gm = dialog.get_modifiers
197+eq = self.assertEqual
198+199+# Modifiers are set by selecting/deselecting the checkbutton.
200+dialog.modifier_checkbuttons['foo'].select()
201+eq(gm(), ['foo'])
202+203+dialog.modifier_checkbuttons['BAZ'].select()
204+eq(gm(), ['foo', 'BAZ'])
205+206+dialog.modifier_checkbuttons['foo'].deselect()
207+eq(gm(), ['BAZ'])
208+209+def test_translate_key(self):
210+dialog = self.dialog
211+tr = dialog.translate_key
212+eq = self.assertEqual
213+214+# Letters return unchanged with no 'Shift'.
215+eq(tr('q', []), 'Key-q')
216+eq(tr('q', ['Control', 'Alt']), 'Key-q')
217+218+# 'Shift' uppercases single lowercase letters.
219+eq(tr('q', ['Shift']), 'Key-Q')
220+eq(tr('q', ['Control', 'Shift']), 'Key-Q')
221+eq(tr('q', ['Control', 'Alt', 'Shift']), 'Key-Q')
222+223+# Convert key name to keysym.
224+eq(tr('Page Up', []), 'Key-Prior')
225+# 'Shift' doesn't change case.
226+eq(tr('Page Down', ['Shift']), 'Key-Next')
227+228+@mock.patch.object(gkd, 'get_modifiers')
229+def test_build_key_string(self, mock_modifiers):
230+dialog = self.dialog
231+key = dialog.list_keys_final
232+string = dialog.key_string.get
233+eq = self.assertEqual
234+235+key.get.result = 'a'
236+mock_modifiers.return_value = []
237+dialog.build_key_string()
238+eq(string(), '<Key-a>')
239+240+mock_modifiers.return_value = ['mymod']
241+dialog.build_key_string()
242+eq(string(), '<mymod-Key-a>')
243+244+key.get.result = ''
245+mock_modifiers.return_value = ['mymod', 'test']
246+dialog.build_key_string()
247+eq(string(), '<mymod-test>')
248+249+@mock.patch.object(gkd, 'get_modifiers')
250+def test_final_key_selected(self, mock_modifiers):
251+dialog = self.dialog
252+key = dialog.list_keys_final
253+string = dialog.key_string.get
254+eq = self.assertEqual
255+256+mock_modifiers.return_value = ['Shift']
257+key.get.result = '{'
258+dialog.final_key_selected()
259+eq(string(), '<Shift-Key-braceleft>')
260+261+262+class CancelTest(unittest.TestCase):
263+"Simulate user clicking [Cancel] button."
264+265+@classmethod
266+def setUpClass(cls):
267+requires('gui')
268+cls.root = Tk()
269+cls.root.withdraw()
270+cls.dialog = gkd(cls.root, 'Title', '<<Test>>', [], _utest=True)
271+272+@classmethod
273+def tearDownClass(cls):
274+cls.dialog.cancel()
275+cls.root.update_idletasks()
276+cls.root.destroy()
277+del cls.dialog, cls.root
278+279+def test_cancel(self):
280+self.assertEqual(self.dialog.winfo_class(), 'Toplevel')
281+self.dialog.button_cancel.invoke()
282+with self.assertRaises(TclError):
283+self.dialog.winfo_class()
284+self.assertEqual(self.dialog.result, '')
285+286+98287if __name__ == '__main__':
99288unittest.main(verbosity=2)