[Python-checkins] bpo-35598: IDLE: Increase test coverage for config_key.py (#11360)

Terry Jan Reedy webhook-mailer at python.org
Sat Dec 29 23:25:13 EST 2018


https://github.com/python/cpython/commit/b0a6196ffd58ff91462191f426706897dc920eee
commit: b0a6196ffd58ff91462191f426706897dc920eee
branch: master
author: Cheryl Sabella <cheryl.sabella at gmail.com>
committer: Terry Jan Reedy <tjreedy at udel.edu>
date: 2018-12-29T23:25:09-05:00
summary:

bpo-35598: IDLE: Increase test coverage for config_key.py (#11360)

files:
M Lib/idlelib/config_key.py
M Lib/idlelib/idle_test/test_config_key.py
M Misc/NEWS.d/next/IDLE/2018-12-27-15-29-11.bpo-35598.FWOOm8.rst

diff --git a/Lib/idlelib/config_key.py b/Lib/idlelib/config_key.py
index 4b0232300f23..4e7b38b75a1d 100644
--- a/Lib/idlelib/config_key.py
+++ b/Lib/idlelib/config_key.py
@@ -67,7 +67,7 @@ def showerror(self, *args, **kwargs):
         messagebox.showerror(*args, **kwargs)
 
     def create_widgets(self):
-        frame = Frame(self, borderwidth=2, relief=SUNKEN)
+        self.frame = frame = Frame(self, borderwidth=2, relief=SUNKEN)
         frame.pack(side=TOP, expand=True, fill=BOTH)
 
         frame_buttons = Frame(self)
@@ -81,7 +81,7 @@ def create_widgets(self):
         self.button_cancel.grid(row=0, column=1, padx=5, pady=5)
 
         # Basic entry key sequence.
-        self.frame_keyseq_basic = Frame(frame)
+        self.frame_keyseq_basic = Frame(frame, name='keyseq_basic')
         self.frame_keyseq_basic.grid(row=0, column=0, sticky=NSEW,
                                       padx=5, pady=5)
         basic_title = Label(self.frame_keyseq_basic,
@@ -135,7 +135,7 @@ def create_widgets(self):
         self.button_clear.grid(row=2, column=0, columnspan=4)
 
         # Advanced entry key sequence.
-        self.frame_keyseq_advanced = Frame(frame)
+        self.frame_keyseq_advanced = Frame(frame, name='keyseq_advanced')
         self.frame_keyseq_advanced.grid(row=0, column=0, sticky=NSEW,
                                          padx=5, pady=5)
         advanced_title = Label(self.frame_keyseq_advanced, justify=LEFT,
@@ -197,7 +197,7 @@ def toggle_level(self):
             self.frame_controls_basic.lift()
             self.advanced = False
 
-    def final_key_selected(self, event):
+    def final_key_selected(self, event=None):
         "Handler for clicking on key in basic settings list."
         self.build_key_string()
 
diff --git a/Lib/idlelib/idle_test/test_config_key.py b/Lib/idlelib/idle_test/test_config_key.py
index adf02c98361c..9412b22c2c87 100644
--- a/Lib/idlelib/idle_test/test_config_key.py
+++ b/Lib/idlelib/idle_test/test_config_key.py
@@ -1,17 +1,25 @@
-"Test config_key, coverage 82%"
+"""Test config_key, coverage 98%.
+
+Coverage is effectively 100%.  Tkinter dialog is mocked, Mac-only line
+may be skipped, and dummy function in bind test should not be called.
+Not tested: exit with 'self.advanced or self.keys_ok(keys)) ...' False.
+"""
 
 from idlelib import config_key
 from test.support import requires
 import unittest
-from tkinter import Tk
+from unittest import mock
+from tkinter import Tk, TclError
 from idlelib.idle_test.mock_idle import Func
 from idlelib.idle_test.mock_tk import Mbox_func
 
+gkd = config_key.GetKeysDialog
+
 
 class ValidationTest(unittest.TestCase):
     "Test validation methods: ok, keys_ok, bind_ok."
 
-    class Validator(config_key.GetKeysDialog):
+    class Validator(gkd):
         def __init__(self, *args, **kwargs):
             config_key.GetKeysDialog.__init__(self, *args, **kwargs)
             class list_keys_final:
@@ -95,5 +103,186 @@ def test_bind_not_ok(self):
         self.assertIn('not accepted', self.dialog.showerror.message)
 
 
+class ToggleLevelTest(unittest.TestCase):
+    "Test toggle between Basic and Advanced frames."
+
+    @classmethod
+    def setUpClass(cls):
+        requires('gui')
+        cls.root = Tk()
+        cls.root.withdraw()
+        cls.dialog = gkd(cls.root, 'Title', '<<Test>>', [], _utest=True)
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.dialog.cancel()
+        cls.root.update_idletasks()
+        cls.root.destroy()
+        del cls.dialog, cls.root
+
+    def test_toggle_level(self):
+        dialog = self.dialog
+
+        def stackorder():
+            """Get the stack order of the children of the frame.
+
+            winfo_children() stores the children in stack order, so
+            this can be used to check whether a frame is above or
+            below another one.
+            """
+            for index, child in enumerate(dialog.frame.winfo_children()):
+                if child._name == 'keyseq_basic':
+                    basic = index
+                if child._name == 'keyseq_advanced':
+                    advanced = index
+            return basic, advanced
+
+        # New window starts at basic level.
+        self.assertFalse(dialog.advanced)
+        self.assertIn('Advanced', dialog.button_level['text'])
+        basic, advanced = stackorder()
+        self.assertGreater(basic, advanced)
+
+        # Toggle to advanced.
+        dialog.toggle_level()
+        self.assertTrue(dialog.advanced)
+        self.assertIn('Basic', dialog.button_level['text'])
+        basic, advanced = stackorder()
+        self.assertGreater(advanced, basic)
+
+        # Toggle to basic.
+        dialog.button_level.invoke()
+        self.assertFalse(dialog.advanced)
+        self.assertIn('Advanced', dialog.button_level['text'])
+        basic, advanced = stackorder()
+        self.assertGreater(basic, advanced)
+
+
+class KeySelectionTest(unittest.TestCase):
+    "Test selecting key on Basic frames."
+
+    class Basic(gkd):
+        def __init__(self, *args, **kwargs):
+            super().__init__(*args, **kwargs)
+            class list_keys_final:
+                get = Func()
+                select_clear = Func()
+                yview = Func()
+            self.list_keys_final = list_keys_final
+        def set_modifiers_for_platform(self):
+            self.modifiers = ['foo', 'bar', 'BAZ']
+            self.modifier_label = {'BAZ': 'ZZZ'}
+        showerror = Mbox_func()
+
+    @classmethod
+    def setUpClass(cls):
+        requires('gui')
+        cls.root = Tk()
+        cls.root.withdraw()
+        cls.dialog = cls.Basic(cls.root, 'Title', '<<Test>>', [], _utest=True)
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.dialog.cancel()
+        cls.root.update_idletasks()
+        cls.root.destroy()
+        del cls.dialog, cls.root
+
+    def setUp(self):
+        self.dialog.clear_key_seq()
+
+    def test_get_modifiers(self):
+        dialog = self.dialog
+        gm = dialog.get_modifiers
+        eq = self.assertEqual
+
+        # Modifiers are set by selecting/deselecting the checkbutton.
+        dialog.modifier_checkbuttons['foo'].select()
+        eq(gm(), ['foo'])
+
+        dialog.modifier_checkbuttons['BAZ'].select()
+        eq(gm(), ['foo', 'BAZ'])
+
+        dialog.modifier_checkbuttons['foo'].deselect()
+        eq(gm(), ['BAZ'])
+
+    def test_translate_key(self):
+        dialog = self.dialog
+        tr = dialog.translate_key
+        eq = self.assertEqual
+
+        # Letters return unchanged with no 'Shift'.
+        eq(tr('q', []), 'Key-q')
+        eq(tr('q', ['Control', 'Alt']), 'Key-q')
+
+        # 'Shift' uppercases single lowercase letters.
+        eq(tr('q', ['Shift']), 'Key-Q')
+        eq(tr('q', ['Control', 'Shift']), 'Key-Q')
+        eq(tr('q', ['Control', 'Alt', 'Shift']), 'Key-Q')
+
+        # Convert key name to keysym.
+        eq(tr('Page Up', []), 'Key-Prior')
+        # 'Shift' doesn't change case.
+        eq(tr('Page Down', ['Shift']), 'Key-Next')
+
+    @mock.patch.object(gkd, 'get_modifiers')
+    def test_build_key_string(self, mock_modifiers):
+        dialog = self.dialog
+        key = dialog.list_keys_final
+        string = dialog.key_string.get
+        eq = self.assertEqual
+
+        key.get.result = 'a'
+        mock_modifiers.return_value = []
+        dialog.build_key_string()
+        eq(string(), '<Key-a>')
+
+        mock_modifiers.return_value = ['mymod']
+        dialog.build_key_string()
+        eq(string(), '<mymod-Key-a>')
+
+        key.get.result = ''
+        mock_modifiers.return_value = ['mymod', 'test']
+        dialog.build_key_string()
+        eq(string(), '<mymod-test>')
+
+    @mock.patch.object(gkd, 'get_modifiers')
+    def test_final_key_selected(self, mock_modifiers):
+        dialog = self.dialog
+        key = dialog.list_keys_final
+        string = dialog.key_string.get
+        eq = self.assertEqual
+
+        mock_modifiers.return_value = ['Shift']
+        key.get.result = '{'
+        dialog.final_key_selected()
+        eq(string(), '<Shift-Key-braceleft>')
+
+
+class CancelTest(unittest.TestCase):
+    "Simulate user clicking [Cancel] button."
+
+    @classmethod
+    def setUpClass(cls):
+        requires('gui')
+        cls.root = Tk()
+        cls.root.withdraw()
+        cls.dialog = gkd(cls.root, 'Title', '<<Test>>', [], _utest=True)
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.dialog.cancel()
+        cls.root.update_idletasks()
+        cls.root.destroy()
+        del cls.dialog, cls.root
+
+    def test_cancel(self):
+        self.assertEqual(self.dialog.winfo_class(), 'Toplevel')
+        self.dialog.button_cancel.invoke()
+        with self.assertRaises(TclError):
+            self.dialog.winfo_class()
+        self.assertEqual(self.dialog.result, '')
+
+
 if __name__ == '__main__':
     unittest.main(verbosity=2)
diff --git a/Misc/NEWS.d/next/IDLE/2018-12-27-15-29-11.bpo-35598.FWOOm8.rst b/Misc/NEWS.d/next/IDLE/2018-12-27-15-29-11.bpo-35598.FWOOm8.rst
index 54347c58f93d..6cc3557b5190 100644
--- a/Misc/NEWS.d/next/IDLE/2018-12-27-15-29-11.bpo-35598.FWOOm8.rst
+++ b/Misc/NEWS.d/next/IDLE/2018-12-27-15-29-11.bpo-35598.FWOOm8.rst
@@ -1 +1 @@
-Apply PEP8 naming convention to config_key.py.
+Update config_key: use PEP 8 names and add tests.



More information about the Python-checkins mailing list