17db96d56Sopenharmony_ci"""Test config_key, coverage 98%.
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ciCoverage is effectively 100%.  Tkinter dialog is mocked, Mac-only line
47db96d56Sopenharmony_cimay be skipped, and dummy function in bind test should not be called.
57db96d56Sopenharmony_ciNot tested: exit with 'self.advanced or self.keys_ok(keys) ...' False.
67db96d56Sopenharmony_ci"""
77db96d56Sopenharmony_ci
87db96d56Sopenharmony_cifrom idlelib import config_key
97db96d56Sopenharmony_cifrom test.support import requires
107db96d56Sopenharmony_ciimport unittest
117db96d56Sopenharmony_cifrom unittest import mock
127db96d56Sopenharmony_cifrom tkinter import Tk, TclError
137db96d56Sopenharmony_cifrom idlelib.idle_test.mock_idle import Func
147db96d56Sopenharmony_cifrom idlelib.idle_test.mock_tk import Mbox_func
157db96d56Sopenharmony_ci
167db96d56Sopenharmony_ci
177db96d56Sopenharmony_ciclass ValidationTest(unittest.TestCase):
187db96d56Sopenharmony_ci    "Test validation methods: ok, keys_ok, bind_ok."
197db96d56Sopenharmony_ci
207db96d56Sopenharmony_ci    class Validator(config_key.GetKeysFrame):
217db96d56Sopenharmony_ci        def __init__(self, *args, **kwargs):
227db96d56Sopenharmony_ci            super().__init__(*args, **kwargs)
237db96d56Sopenharmony_ci            class list_keys_final:
247db96d56Sopenharmony_ci                get = Func()
257db96d56Sopenharmony_ci            self.list_keys_final = list_keys_final
267db96d56Sopenharmony_ci        get_modifiers = Func()
277db96d56Sopenharmony_ci        showerror = Mbox_func()
287db96d56Sopenharmony_ci
297db96d56Sopenharmony_ci    @classmethod
307db96d56Sopenharmony_ci    def setUpClass(cls):
317db96d56Sopenharmony_ci        requires('gui')
327db96d56Sopenharmony_ci        cls.root = Tk()
337db96d56Sopenharmony_ci        cls.root.withdraw()
347db96d56Sopenharmony_ci        keylist = [['<Key-F12>'], ['<Control-Key-x>', '<Control-Key-X>']]
357db96d56Sopenharmony_ci        cls.dialog = cls.Validator(cls.root, '<<Test>>', keylist)
367db96d56Sopenharmony_ci
377db96d56Sopenharmony_ci    @classmethod
387db96d56Sopenharmony_ci    def tearDownClass(cls):
397db96d56Sopenharmony_ci        del cls.dialog
407db96d56Sopenharmony_ci        cls.root.update_idletasks()
417db96d56Sopenharmony_ci        cls.root.destroy()
427db96d56Sopenharmony_ci        del cls.root
437db96d56Sopenharmony_ci
447db96d56Sopenharmony_ci    def setUp(self):
457db96d56Sopenharmony_ci        self.dialog.showerror.message = ''
467db96d56Sopenharmony_ci    # A test that needs a particular final key value should set it.
477db96d56Sopenharmony_ci    # A test that sets a non-blank modifier list should reset it to [].
487db96d56Sopenharmony_ci
497db96d56Sopenharmony_ci    def test_ok_empty(self):
507db96d56Sopenharmony_ci        self.dialog.key_string.set(' ')
517db96d56Sopenharmony_ci        self.dialog.ok()
527db96d56Sopenharmony_ci        self.assertEqual(self.dialog.result, '')
537db96d56Sopenharmony_ci        self.assertEqual(self.dialog.showerror.message, 'No key specified.')
547db96d56Sopenharmony_ci
557db96d56Sopenharmony_ci    def test_ok_good(self):
567db96d56Sopenharmony_ci        self.dialog.key_string.set('<Key-F11>')
577db96d56Sopenharmony_ci        self.dialog.list_keys_final.get.result = 'F11'
587db96d56Sopenharmony_ci        self.dialog.ok()
597db96d56Sopenharmony_ci        self.assertEqual(self.dialog.result, '<Key-F11>')
607db96d56Sopenharmony_ci        self.assertEqual(self.dialog.showerror.message, '')
617db96d56Sopenharmony_ci
627db96d56Sopenharmony_ci    def test_keys_no_ending(self):
637db96d56Sopenharmony_ci        self.assertFalse(self.dialog.keys_ok('<Control-Shift'))
647db96d56Sopenharmony_ci        self.assertIn('Missing the final', self.dialog.showerror.message)
657db96d56Sopenharmony_ci
667db96d56Sopenharmony_ci    def test_keys_no_modifier_bad(self):
677db96d56Sopenharmony_ci        self.dialog.list_keys_final.get.result = 'A'
687db96d56Sopenharmony_ci        self.assertFalse(self.dialog.keys_ok('<Key-A>'))
697db96d56Sopenharmony_ci        self.assertIn('No modifier', self.dialog.showerror.message)
707db96d56Sopenharmony_ci
717db96d56Sopenharmony_ci    def test_keys_no_modifier_ok(self):
727db96d56Sopenharmony_ci        self.dialog.list_keys_final.get.result = 'F11'
737db96d56Sopenharmony_ci        self.assertTrue(self.dialog.keys_ok('<Key-F11>'))
747db96d56Sopenharmony_ci        self.assertEqual(self.dialog.showerror.message, '')
757db96d56Sopenharmony_ci
767db96d56Sopenharmony_ci    def test_keys_shift_bad(self):
777db96d56Sopenharmony_ci        self.dialog.list_keys_final.get.result = 'a'
787db96d56Sopenharmony_ci        self.dialog.get_modifiers.result = ['Shift']
797db96d56Sopenharmony_ci        self.assertFalse(self.dialog.keys_ok('<a>'))
807db96d56Sopenharmony_ci        self.assertIn('shift modifier', self.dialog.showerror.message)
817db96d56Sopenharmony_ci        self.dialog.get_modifiers.result = []
827db96d56Sopenharmony_ci
837db96d56Sopenharmony_ci    def test_keys_dup(self):
847db96d56Sopenharmony_ci        for mods, final, seq in (([], 'F12', '<Key-F12>'),
857db96d56Sopenharmony_ci                                 (['Control'], 'x', '<Control-Key-x>'),
867db96d56Sopenharmony_ci                                 (['Control'], 'X', '<Control-Key-X>')):
877db96d56Sopenharmony_ci            with self.subTest(m=mods, f=final, s=seq):
887db96d56Sopenharmony_ci                self.dialog.list_keys_final.get.result = final
897db96d56Sopenharmony_ci                self.dialog.get_modifiers.result = mods
907db96d56Sopenharmony_ci                self.assertFalse(self.dialog.keys_ok(seq))
917db96d56Sopenharmony_ci                self.assertIn('already in use', self.dialog.showerror.message)
927db96d56Sopenharmony_ci        self.dialog.get_modifiers.result = []
937db96d56Sopenharmony_ci
947db96d56Sopenharmony_ci    def test_bind_ok(self):
957db96d56Sopenharmony_ci        self.assertTrue(self.dialog.bind_ok('<Control-Shift-Key-a>'))
967db96d56Sopenharmony_ci        self.assertEqual(self.dialog.showerror.message, '')
977db96d56Sopenharmony_ci
987db96d56Sopenharmony_ci    def test_bind_not_ok(self):
997db96d56Sopenharmony_ci        self.assertFalse(self.dialog.bind_ok('<Control-Shift>'))
1007db96d56Sopenharmony_ci        self.assertIn('not accepted', self.dialog.showerror.message)
1017db96d56Sopenharmony_ci
1027db96d56Sopenharmony_ci
1037db96d56Sopenharmony_ciclass ToggleLevelTest(unittest.TestCase):
1047db96d56Sopenharmony_ci    "Test toggle between Basic and Advanced frames."
1057db96d56Sopenharmony_ci
1067db96d56Sopenharmony_ci    @classmethod
1077db96d56Sopenharmony_ci    def setUpClass(cls):
1087db96d56Sopenharmony_ci        requires('gui')
1097db96d56Sopenharmony_ci        cls.root = Tk()
1107db96d56Sopenharmony_ci        cls.root.withdraw()
1117db96d56Sopenharmony_ci        cls.dialog = config_key.GetKeysFrame(cls.root, '<<Test>>', [])
1127db96d56Sopenharmony_ci
1137db96d56Sopenharmony_ci    @classmethod
1147db96d56Sopenharmony_ci    def tearDownClass(cls):
1157db96d56Sopenharmony_ci        del cls.dialog
1167db96d56Sopenharmony_ci        cls.root.update_idletasks()
1177db96d56Sopenharmony_ci        cls.root.destroy()
1187db96d56Sopenharmony_ci        del cls.root
1197db96d56Sopenharmony_ci
1207db96d56Sopenharmony_ci    def test_toggle_level(self):
1217db96d56Sopenharmony_ci        dialog = self.dialog
1227db96d56Sopenharmony_ci
1237db96d56Sopenharmony_ci        def stackorder():
1247db96d56Sopenharmony_ci            """Get the stack order of the children of the frame.
1257db96d56Sopenharmony_ci
1267db96d56Sopenharmony_ci            winfo_children() stores the children in stack order, so
1277db96d56Sopenharmony_ci            this can be used to check whether a frame is above or
1287db96d56Sopenharmony_ci            below another one.
1297db96d56Sopenharmony_ci            """
1307db96d56Sopenharmony_ci            for index, child in enumerate(dialog.winfo_children()):
1317db96d56Sopenharmony_ci                if child._name == 'keyseq_basic':
1327db96d56Sopenharmony_ci                    basic = index
1337db96d56Sopenharmony_ci                if child._name == 'keyseq_advanced':
1347db96d56Sopenharmony_ci                    advanced = index
1357db96d56Sopenharmony_ci            return basic, advanced
1367db96d56Sopenharmony_ci
1377db96d56Sopenharmony_ci        # New window starts at basic level.
1387db96d56Sopenharmony_ci        self.assertFalse(dialog.advanced)
1397db96d56Sopenharmony_ci        self.assertIn('Advanced', dialog.button_level['text'])
1407db96d56Sopenharmony_ci        basic, advanced = stackorder()
1417db96d56Sopenharmony_ci        self.assertGreater(basic, advanced)
1427db96d56Sopenharmony_ci
1437db96d56Sopenharmony_ci        # Toggle to advanced.
1447db96d56Sopenharmony_ci        dialog.toggle_level()
1457db96d56Sopenharmony_ci        self.assertTrue(dialog.advanced)
1467db96d56Sopenharmony_ci        self.assertIn('Basic', dialog.button_level['text'])
1477db96d56Sopenharmony_ci        basic, advanced = stackorder()
1487db96d56Sopenharmony_ci        self.assertGreater(advanced, basic)
1497db96d56Sopenharmony_ci
1507db96d56Sopenharmony_ci        # Toggle to basic.
1517db96d56Sopenharmony_ci        dialog.button_level.invoke()
1527db96d56Sopenharmony_ci        self.assertFalse(dialog.advanced)
1537db96d56Sopenharmony_ci        self.assertIn('Advanced', dialog.button_level['text'])
1547db96d56Sopenharmony_ci        basic, advanced = stackorder()
1557db96d56Sopenharmony_ci        self.assertGreater(basic, advanced)
1567db96d56Sopenharmony_ci
1577db96d56Sopenharmony_ci
1587db96d56Sopenharmony_ciclass KeySelectionTest(unittest.TestCase):
1597db96d56Sopenharmony_ci    "Test selecting key on Basic frames."
1607db96d56Sopenharmony_ci
1617db96d56Sopenharmony_ci    class Basic(config_key.GetKeysFrame):
1627db96d56Sopenharmony_ci        def __init__(self, *args, **kwargs):
1637db96d56Sopenharmony_ci            super().__init__(*args, **kwargs)
1647db96d56Sopenharmony_ci            class list_keys_final:
1657db96d56Sopenharmony_ci                get = Func()
1667db96d56Sopenharmony_ci                select_clear = Func()
1677db96d56Sopenharmony_ci                yview = Func()
1687db96d56Sopenharmony_ci            self.list_keys_final = list_keys_final
1697db96d56Sopenharmony_ci        def set_modifiers_for_platform(self):
1707db96d56Sopenharmony_ci            self.modifiers = ['foo', 'bar', 'BAZ']
1717db96d56Sopenharmony_ci            self.modifier_label = {'BAZ': 'ZZZ'}
1727db96d56Sopenharmony_ci        showerror = Mbox_func()
1737db96d56Sopenharmony_ci
1747db96d56Sopenharmony_ci    @classmethod
1757db96d56Sopenharmony_ci    def setUpClass(cls):
1767db96d56Sopenharmony_ci        requires('gui')
1777db96d56Sopenharmony_ci        cls.root = Tk()
1787db96d56Sopenharmony_ci        cls.root.withdraw()
1797db96d56Sopenharmony_ci        cls.dialog = cls.Basic(cls.root, '<<Test>>', [])
1807db96d56Sopenharmony_ci
1817db96d56Sopenharmony_ci    @classmethod
1827db96d56Sopenharmony_ci    def tearDownClass(cls):
1837db96d56Sopenharmony_ci        del cls.dialog
1847db96d56Sopenharmony_ci        cls.root.update_idletasks()
1857db96d56Sopenharmony_ci        cls.root.destroy()
1867db96d56Sopenharmony_ci        del cls.root
1877db96d56Sopenharmony_ci
1887db96d56Sopenharmony_ci    def setUp(self):
1897db96d56Sopenharmony_ci        self.dialog.clear_key_seq()
1907db96d56Sopenharmony_ci
1917db96d56Sopenharmony_ci    def test_get_modifiers(self):
1927db96d56Sopenharmony_ci        dialog = self.dialog
1937db96d56Sopenharmony_ci        gm = dialog.get_modifiers
1947db96d56Sopenharmony_ci        eq = self.assertEqual
1957db96d56Sopenharmony_ci
1967db96d56Sopenharmony_ci        # Modifiers are set on/off by invoking the checkbutton.
1977db96d56Sopenharmony_ci        dialog.modifier_checkbuttons['foo'].invoke()
1987db96d56Sopenharmony_ci        eq(gm(), ['foo'])
1997db96d56Sopenharmony_ci
2007db96d56Sopenharmony_ci        dialog.modifier_checkbuttons['BAZ'].invoke()
2017db96d56Sopenharmony_ci        eq(gm(), ['foo', 'BAZ'])
2027db96d56Sopenharmony_ci
2037db96d56Sopenharmony_ci        dialog.modifier_checkbuttons['foo'].invoke()
2047db96d56Sopenharmony_ci        eq(gm(), ['BAZ'])
2057db96d56Sopenharmony_ci
2067db96d56Sopenharmony_ci    @mock.patch.object(config_key.GetKeysFrame, 'get_modifiers')
2077db96d56Sopenharmony_ci    def test_build_key_string(self, mock_modifiers):
2087db96d56Sopenharmony_ci        dialog = self.dialog
2097db96d56Sopenharmony_ci        key = dialog.list_keys_final
2107db96d56Sopenharmony_ci        string = dialog.key_string.get
2117db96d56Sopenharmony_ci        eq = self.assertEqual
2127db96d56Sopenharmony_ci
2137db96d56Sopenharmony_ci        key.get.result = 'a'
2147db96d56Sopenharmony_ci        mock_modifiers.return_value = []
2157db96d56Sopenharmony_ci        dialog.build_key_string()
2167db96d56Sopenharmony_ci        eq(string(), '<Key-a>')
2177db96d56Sopenharmony_ci
2187db96d56Sopenharmony_ci        mock_modifiers.return_value = ['mymod']
2197db96d56Sopenharmony_ci        dialog.build_key_string()
2207db96d56Sopenharmony_ci        eq(string(), '<mymod-Key-a>')
2217db96d56Sopenharmony_ci
2227db96d56Sopenharmony_ci        key.get.result = ''
2237db96d56Sopenharmony_ci        mock_modifiers.return_value = ['mymod', 'test']
2247db96d56Sopenharmony_ci        dialog.build_key_string()
2257db96d56Sopenharmony_ci        eq(string(), '<mymod-test>')
2267db96d56Sopenharmony_ci
2277db96d56Sopenharmony_ci    @mock.patch.object(config_key.GetKeysFrame, 'get_modifiers')
2287db96d56Sopenharmony_ci    def test_final_key_selected(self, mock_modifiers):
2297db96d56Sopenharmony_ci        dialog = self.dialog
2307db96d56Sopenharmony_ci        key = dialog.list_keys_final
2317db96d56Sopenharmony_ci        string = dialog.key_string.get
2327db96d56Sopenharmony_ci        eq = self.assertEqual
2337db96d56Sopenharmony_ci
2347db96d56Sopenharmony_ci        mock_modifiers.return_value = ['Shift']
2357db96d56Sopenharmony_ci        key.get.result = '{'
2367db96d56Sopenharmony_ci        dialog.final_key_selected()
2377db96d56Sopenharmony_ci        eq(string(), '<Shift-Key-braceleft>')
2387db96d56Sopenharmony_ci
2397db96d56Sopenharmony_ci
2407db96d56Sopenharmony_ciclass CancelWindowTest(unittest.TestCase):
2417db96d56Sopenharmony_ci    "Simulate user clicking [Cancel] button."
2427db96d56Sopenharmony_ci
2437db96d56Sopenharmony_ci    @classmethod
2447db96d56Sopenharmony_ci    def setUpClass(cls):
2457db96d56Sopenharmony_ci        requires('gui')
2467db96d56Sopenharmony_ci        cls.root = Tk()
2477db96d56Sopenharmony_ci        cls.root.withdraw()
2487db96d56Sopenharmony_ci        cls.dialog = config_key.GetKeysWindow(
2497db96d56Sopenharmony_ci            cls.root, 'Title', '<<Test>>', [], _utest=True)
2507db96d56Sopenharmony_ci
2517db96d56Sopenharmony_ci    @classmethod
2527db96d56Sopenharmony_ci    def tearDownClass(cls):
2537db96d56Sopenharmony_ci        cls.dialog.cancel()
2547db96d56Sopenharmony_ci        del cls.dialog
2557db96d56Sopenharmony_ci        cls.root.update_idletasks()
2567db96d56Sopenharmony_ci        cls.root.destroy()
2577db96d56Sopenharmony_ci        del cls.root
2587db96d56Sopenharmony_ci
2597db96d56Sopenharmony_ci    @mock.patch.object(config_key.GetKeysFrame, 'ok')
2607db96d56Sopenharmony_ci    def test_cancel(self, mock_frame_ok):
2617db96d56Sopenharmony_ci        self.assertEqual(self.dialog.winfo_class(), 'Toplevel')
2627db96d56Sopenharmony_ci        self.dialog.button_cancel.invoke()
2637db96d56Sopenharmony_ci        with self.assertRaises(TclError):
2647db96d56Sopenharmony_ci            self.dialog.winfo_class()
2657db96d56Sopenharmony_ci        self.assertEqual(self.dialog.result, '')
2667db96d56Sopenharmony_ci        mock_frame_ok.assert_not_called()
2677db96d56Sopenharmony_ci
2687db96d56Sopenharmony_ci
2697db96d56Sopenharmony_ciclass OKWindowTest(unittest.TestCase):
2707db96d56Sopenharmony_ci    "Simulate user clicking [OK] button."
2717db96d56Sopenharmony_ci
2727db96d56Sopenharmony_ci    @classmethod
2737db96d56Sopenharmony_ci    def setUpClass(cls):
2747db96d56Sopenharmony_ci        requires('gui')
2757db96d56Sopenharmony_ci        cls.root = Tk()
2767db96d56Sopenharmony_ci        cls.root.withdraw()
2777db96d56Sopenharmony_ci        cls.dialog = config_key.GetKeysWindow(
2787db96d56Sopenharmony_ci            cls.root, 'Title', '<<Test>>', [], _utest=True)
2797db96d56Sopenharmony_ci
2807db96d56Sopenharmony_ci    @classmethod
2817db96d56Sopenharmony_ci    def tearDownClass(cls):
2827db96d56Sopenharmony_ci        cls.dialog.cancel()
2837db96d56Sopenharmony_ci        del cls.dialog
2847db96d56Sopenharmony_ci        cls.root.update_idletasks()
2857db96d56Sopenharmony_ci        cls.root.destroy()
2867db96d56Sopenharmony_ci        del cls.root
2877db96d56Sopenharmony_ci
2887db96d56Sopenharmony_ci    @mock.patch.object(config_key.GetKeysFrame, 'ok')
2897db96d56Sopenharmony_ci    def test_ok(self, mock_frame_ok):
2907db96d56Sopenharmony_ci        self.assertEqual(self.dialog.winfo_class(), 'Toplevel')
2917db96d56Sopenharmony_ci        self.dialog.button_ok.invoke()
2927db96d56Sopenharmony_ci        with self.assertRaises(TclError):
2937db96d56Sopenharmony_ci            self.dialog.winfo_class()
2947db96d56Sopenharmony_ci        mock_frame_ok.assert_called()
2957db96d56Sopenharmony_ci
2967db96d56Sopenharmony_ci
2977db96d56Sopenharmony_ciclass WindowResultTest(unittest.TestCase):
2987db96d56Sopenharmony_ci    "Test window result get and set."
2997db96d56Sopenharmony_ci
3007db96d56Sopenharmony_ci    @classmethod
3017db96d56Sopenharmony_ci    def setUpClass(cls):
3027db96d56Sopenharmony_ci        requires('gui')
3037db96d56Sopenharmony_ci        cls.root = Tk()
3047db96d56Sopenharmony_ci        cls.root.withdraw()
3057db96d56Sopenharmony_ci        cls.dialog = config_key.GetKeysWindow(
3067db96d56Sopenharmony_ci            cls.root, 'Title', '<<Test>>', [], _utest=True)
3077db96d56Sopenharmony_ci
3087db96d56Sopenharmony_ci    @classmethod
3097db96d56Sopenharmony_ci    def tearDownClass(cls):
3107db96d56Sopenharmony_ci        cls.dialog.cancel()
3117db96d56Sopenharmony_ci        del cls.dialog
3127db96d56Sopenharmony_ci        cls.root.update_idletasks()
3137db96d56Sopenharmony_ci        cls.root.destroy()
3147db96d56Sopenharmony_ci        del cls.root
3157db96d56Sopenharmony_ci
3167db96d56Sopenharmony_ci    def test_result(self):
3177db96d56Sopenharmony_ci        dialog = self.dialog
3187db96d56Sopenharmony_ci        eq = self.assertEqual
3197db96d56Sopenharmony_ci
3207db96d56Sopenharmony_ci        dialog.result = ''
3217db96d56Sopenharmony_ci        eq(dialog.result, '')
3227db96d56Sopenharmony_ci        eq(dialog.frame.result,'')
3237db96d56Sopenharmony_ci
3247db96d56Sopenharmony_ci        dialog.result = 'bar'
3257db96d56Sopenharmony_ci        eq(dialog.result,'bar')
3267db96d56Sopenharmony_ci        eq(dialog.frame.result,'bar')
3277db96d56Sopenharmony_ci
3287db96d56Sopenharmony_ci        dialog.frame.result = 'foo'
3297db96d56Sopenharmony_ci        eq(dialog.result, 'foo')
3307db96d56Sopenharmony_ci        eq(dialog.frame.result,'foo')
3317db96d56Sopenharmony_ci
3327db96d56Sopenharmony_ci
3337db96d56Sopenharmony_ciclass HelperTest(unittest.TestCase):
3347db96d56Sopenharmony_ci    "Test module level helper functions."
3357db96d56Sopenharmony_ci
3367db96d56Sopenharmony_ci    def test_translate_key(self):
3377db96d56Sopenharmony_ci        tr = config_key.translate_key
3387db96d56Sopenharmony_ci        eq = self.assertEqual
3397db96d56Sopenharmony_ci
3407db96d56Sopenharmony_ci        # Letters return unchanged with no 'Shift'.
3417db96d56Sopenharmony_ci        eq(tr('q', []), 'Key-q')
3427db96d56Sopenharmony_ci        eq(tr('q', ['Control', 'Alt']), 'Key-q')
3437db96d56Sopenharmony_ci
3447db96d56Sopenharmony_ci        # 'Shift' uppercases single lowercase letters.
3457db96d56Sopenharmony_ci        eq(tr('q', ['Shift']), 'Key-Q')
3467db96d56Sopenharmony_ci        eq(tr('q', ['Control', 'Shift']), 'Key-Q')
3477db96d56Sopenharmony_ci        eq(tr('q', ['Control', 'Alt', 'Shift']), 'Key-Q')
3487db96d56Sopenharmony_ci
3497db96d56Sopenharmony_ci        # Convert key name to keysym.
3507db96d56Sopenharmony_ci        eq(tr('Page Up', []), 'Key-Prior')
3517db96d56Sopenharmony_ci        # 'Shift' doesn't change case when it's not a single char.
3527db96d56Sopenharmony_ci        eq(tr('*', ['Shift']), 'Key-asterisk')
3537db96d56Sopenharmony_ci
3547db96d56Sopenharmony_ci
3557db96d56Sopenharmony_ciif __name__ == '__main__':
3567db96d56Sopenharmony_ci    unittest.main(verbosity=2)
357