(root)/
Python-3.12.0/
Lib/
idlelib/
idle_test/
test_config_key.py
       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  """
       7  
       8  from idlelib import config_key
       9  from test.support import requires
      10  import unittest
      11  from unittest import mock
      12  from tkinter import Tk, TclError
      13  from idlelib.idle_test.mock_idle import Func
      14  from idlelib.idle_test.mock_tk import Mbox_func
      15  
      16  
      17  class ESC[4;38;5;81mValidationTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      18      "Test validation methods: ok, keys_ok, bind_ok."
      19  
      20      class ESC[4;38;5;81mValidator(ESC[4;38;5;149mconfig_keyESC[4;38;5;149m.ESC[4;38;5;149mGetKeysFrame):
      21          def __init__(self, *args, **kwargs):
      22              super().__init__(*args, **kwargs)
      23              class ESC[4;38;5;81mlist_keys_final:
      24                  get = Func()
      25              self.list_keys_final = list_keys_final
      26          get_modifiers = Func()
      27          showerror = Mbox_func()
      28  
      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)
      36  
      37      @classmethod
      38      def tearDownClass(cls):
      39          del cls.dialog
      40          cls.root.update_idletasks()
      41          cls.root.destroy()
      42          del cls.root
      43  
      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 [].
      48  
      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.')
      54  
      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, '')
      61  
      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)
      65  
      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)
      70  
      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, '')
      75  
      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 = []
      82  
      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 = []
      93  
      94      def test_bind_ok(self):
      95          self.assertTrue(self.dialog.bind_ok('<Control-Shift-Key-a>'))
      96          self.assertEqual(self.dialog.showerror.message, '')
      97  
      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)
     101  
     102  
     103  class ESC[4;38;5;81mToggleLevelTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     104      "Test toggle between Basic and Advanced frames."
     105  
     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>>', [])
     112  
     113      @classmethod
     114      def tearDownClass(cls):
     115          del cls.dialog
     116          cls.root.update_idletasks()
     117          cls.root.destroy()
     118          del cls.root
     119  
     120      def test_toggle_level(self):
     121          dialog = self.dialog
     122  
     123          def stackorder():
     124              """Get the stack order of the children of the frame.
     125  
     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
     136  
     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)
     142  
     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)
     149  
     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)
     156  
     157  
     158  class ESC[4;38;5;81mKeySelectionTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     159      "Test selecting key on Basic frames."
     160  
     161      class ESC[4;38;5;81mBasic(ESC[4;38;5;149mconfig_keyESC[4;38;5;149m.ESC[4;38;5;149mGetKeysFrame):
     162          def __init__(self, *args, **kwargs):
     163              super().__init__(*args, **kwargs)
     164              class ESC[4;38;5;81mlist_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()
     173  
     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>>', [])
     180  
     181      @classmethod
     182      def tearDownClass(cls):
     183          del cls.dialog
     184          cls.root.update_idletasks()
     185          cls.root.destroy()
     186          del cls.root
     187  
     188      def setUp(self):
     189          self.dialog.clear_key_seq()
     190  
     191      def test_get_modifiers(self):
     192          dialog = self.dialog
     193          gm = dialog.get_modifiers
     194          eq = self.assertEqual
     195  
     196          # Modifiers are set on/off by invoking the checkbutton.
     197          dialog.modifier_checkbuttons['foo'].invoke()
     198          eq(gm(), ['foo'])
     199  
     200          dialog.modifier_checkbuttons['BAZ'].invoke()
     201          eq(gm(), ['foo', 'BAZ'])
     202  
     203          dialog.modifier_checkbuttons['foo'].invoke()
     204          eq(gm(), ['BAZ'])
     205  
     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
     212  
     213          key.get.result = 'a'
     214          mock_modifiers.return_value = []
     215          dialog.build_key_string()
     216          eq(string(), '<Key-a>')
     217  
     218          mock_modifiers.return_value = ['mymod']
     219          dialog.build_key_string()
     220          eq(string(), '<mymod-Key-a>')
     221  
     222          key.get.result = ''
     223          mock_modifiers.return_value = ['mymod', 'test']
     224          dialog.build_key_string()
     225          eq(string(), '<mymod-test>')
     226  
     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
     233  
     234          mock_modifiers.return_value = ['Shift']
     235          key.get.result = '{'
     236          dialog.final_key_selected()
     237          eq(string(), '<Shift-Key-braceleft>')
     238  
     239  
     240  class ESC[4;38;5;81mCancelWindowTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     241      "Simulate user clicking [Cancel] button."
     242  
     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)
     250  
     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
     258  
     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()
     267  
     268  
     269  class ESC[4;38;5;81mOKWindowTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     270      "Simulate user clicking [OK] button."
     271  
     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)
     279  
     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
     287  
     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()
     295  
     296  
     297  class ESC[4;38;5;81mWindowResultTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     298      "Test window result get and set."
     299  
     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)
     307  
     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
     315  
     316      def test_result(self):
     317          dialog = self.dialog
     318          eq = self.assertEqual
     319  
     320          dialog.result = ''
     321          eq(dialog.result, '')
     322          eq(dialog.frame.result,'')
     323  
     324          dialog.result = 'bar'
     325          eq(dialog.result,'bar')
     326          eq(dialog.frame.result,'bar')
     327  
     328          dialog.frame.result = 'foo'
     329          eq(dialog.result, 'foo')
     330          eq(dialog.frame.result,'foo')
     331  
     332  
     333  class ESC[4;38;5;81mHelperTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     334      "Test module level helper functions."
     335  
     336      def test_translate_key(self):
     337          tr = config_key.translate_key
     338          eq = self.assertEqual
     339  
     340          # Letters return unchanged with no 'Shift'.
     341          eq(tr('q', []), 'Key-q')
     342          eq(tr('q', ['Control', 'Alt']), 'Key-q')
     343  
     344          # 'Shift' uppercases single lowercase letters.
     345          eq(tr('q', ['Shift']), 'Key-Q')
     346          eq(tr('q', ['Control', 'Shift']), 'Key-Q')
     347          eq(tr('q', ['Control', 'Alt', 'Shift']), 'Key-Q')
     348  
     349          # Convert key name to keysym.
     350          eq(tr('Page Up', []), 'Key-Prior')
     351          # 'Shift' doesn't change case when it's not a single char.
     352          eq(tr('*', ['Shift']), 'Key-asterisk')
     353  
     354  
     355  if __name__ == '__main__':
     356      unittest.main(verbosity=2)