[Python-checkins] bpo-31003: IDLE - Add more tests for General tab (#2859)

Terry Jan Reedy webhook-mailer at python.org
Wed Jul 26 20:54:42 EDT 2017


https://github.com/python/cpython/commit/2bc8f0e6867f59e5e8444b2bde99bb0fa3dbefc8
commit: 2bc8f0e6867f59e5e8444b2bde99bb0fa3dbefc8
branch: master
author: Terry Jan Reedy <tjreedy at udel.edu>
committer: GitHub <noreply at github.com>
date: 2017-07-26T20:54:40-04:00
summary:

bpo-31003: IDLE - Add more tests for General tab (#2859)

* In configdialog: Document causal pathways in create_page_general.
Move related functions to follow this. Simplify some attribute names.
* In test_configdialog: Add tests for load and helplist functions.
Coverage for the general tab is now complete, and 63% overall.

files:
A Misc/NEWS.d/next/IDLE/2017-07-25-01-28-35.bpo-31003.bYINVH.rst
M Lib/idlelib/configdialog.py
M Lib/idlelib/idle_test/mock_idle.py
M Lib/idlelib/idle_test/test_configdialog.py

diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py
index f98af4600ee..daaa34459e2 100644
--- a/Lib/idlelib/configdialog.py
+++ b/Lib/idlelib/configdialog.py
@@ -160,7 +160,7 @@ def create_page_font_tab(self):
         corresponding aspect of the font sample on this page and
         highlight sample on highlight page.
 
-        Load_font_cfg initializes font vars and widgets from
+        Funtion load_font_cfg initializes font vars and widgets from
         idleConf entries and tk.
 
         Fontlist: mouse button 1 click or up or down key invoke
@@ -470,7 +470,7 @@ def tem(event, elem=element):
                 event.widget.winfo_toplevel().highlight_target.set(elem)
             text.tag_bind(
                     self.theme_elements[element][0], '<ButtonPress-1>', tem)
-        text.config(state=DISABLED)
+        text['state'] = DISABLED
         self.frame_color_set = Frame(frame_custom, relief=SOLID, borderwidth=1)
         frame_fg_bg_toggle = Frame(frame_custom)
         button_set_color = Button(
@@ -650,59 +650,61 @@ def create_page_keys(self):
         frames[1].pack(side=TOP, fill=X, expand=True, pady=2)
         return frame
 
+
     def create_page_general(self):
         """Return frame of widgets for General tab.
 
-        Tk Variables:
-            win_width: Initial window width in characters.
-            win_height: Initial window height in characters.
-            startup_edit: Selector for opening in editor or shell mode.
-            autosave: Selector for save prompt popup when using Run.
-
-        Methods:
-            load_general_config:
-            help_source_selected: Bound to list_help button release.
-            set_helplist_button_states: Toggle based on list.
-            helplist_item_edit: Command for button_helplist_edit.
-            helplist_item_add: Command for button_helplist_add.
-            helplist_item_remove: Command for button_helplist_remove.
-            update_user_help_changed_items: Fill in changes.
+        Enable users to provisionally change general options. Function
+        load_general_cfg intializes tk variables and helplist using
+        idleConf.  Radiobuttons startup_shell_on and startup_editor_on
+        set var startup_edit. Radiobuttons save_ask_on and save_auto_on
+        set var autosave. Entry boxes win_width_int and win_height_int
+        set var win_width and win_height.  Setting var_name invokes the
+        var_changed_var_name callback that adds option to changes.
+
+        Helplist: load_general_cfg loads list user_helplist with
+        name, position pairs and copies names to listbox helplist.
+        Clicking a name invokes help_source selected. Clicking
+        button_helplist_name invokes helplist_item_name, which also
+        changes user_helplist.  These functions all call
+        set_add_delete_state. All but load call update_help_changes to
+        rewrite changes['main']['HelpFiles'].
 
         Widget Structure:  (*) widgets bound to self
             frame
                 frame_run: LabelFrame
                     startup_title: Label
-                    (*)radio_startup_edit: Radiobutton - startup_edit
-                    (*)radio_startup_shell: Radiobutton - startup_edit
+                    (*)startup_editor_on: Radiobutton - startup_edit
+                    (*)startup_shell_on: Radiobutton - startup_edit
                 frame_save: LabelFrame
                     run_save_title: Label
-                    (*)radio_save_ask: Radiobutton - autosave
-                    (*)radio_save_auto: Radiobutton - autosave
+                    (*)save_ask_on: Radiobutton - autosave
+                    (*)save_auto_on: Radiobutton - autosave
                 frame_win_size: LabelFrame
                     win_size_title: Label
                     win_width_title: Label
-                    (*)entry_win_width: Entry - win_width
+                    (*)win_width_int: Entry - win_width
                     win_height_title: Label
-                    (*)entry_win_height: Entry - win_height
+                    (*)win_height_int: Entry - win_height
                 frame_help: LabelFrame
                     frame_helplist: Frame
                         frame_helplist_buttons: Frame
                             (*)button_helplist_edit
                             (*)button_helplist_add
                             (*)button_helplist_remove
+                        (*)helplist: ListBox
                         scroll_helplist: Scrollbar
-                        (*)list_help: ListBox
         """
         parent = self.parent
-        self.win_width = StringVar(parent)
-        self.win_height = StringVar(parent)
         self.startup_edit = IntVar(parent)
         self.autosave = IntVar(parent)
+        self.win_width = StringVar(parent)
+        self.win_height = StringVar(parent)
 
-        #widget creation
-        #body
+        # Create widgets:
+        # body.
         frame = self.tab_pages.pages['General'].frame
-        #body section frames
+        # body section frames.
         frame_run = LabelFrame(frame, borderwidth=2, relief=GROOVE,
                               text=' Startup Preferences ')
         frame_save = LabelFrame(frame, borderwidth=2, relief=GROOVE,
@@ -710,41 +712,41 @@ def create_page_general(self):
         frame_win_size = Frame(frame, borderwidth=2, relief=GROOVE)
         frame_help = LabelFrame(frame, borderwidth=2, relief=GROOVE,
                                text=' Additional Help Sources ')
-        #frame_run
+        # frame_run.
         startup_title = Label(frame_run, text='At Startup')
-        self.radio_startup_edit = Radiobutton(
+        self.startup_editor_on = Radiobutton(
                 frame_run, variable=self.startup_edit, value=1,
                 text="Open Edit Window")
-        self.radio_startup_shell = Radiobutton(
+        self.startup_shell_on = Radiobutton(
                 frame_run, variable=self.startup_edit, value=0,
                 text='Open Shell Window')
-        #frame_save
+        # frame_save.
         run_save_title = Label(frame_save, text='At Start of Run (F5)  ')
-        self.radio_save_ask = Radiobutton(
+        self.save_ask_on = Radiobutton(
                 frame_save, variable=self.autosave, value=0,
                 text="Prompt to Save")
-        self.radio_save_auto = Radiobutton(
+        self.save_auto_on = Radiobutton(
                 frame_save, variable=self.autosave, value=1,
                 text='No Prompt')
-        #frame_win_size
+        # frame_win_size.
         win_size_title = Label(
                 frame_win_size, text='Initial Window Size  (in characters)')
         win_width_title = Label(frame_win_size, text='Width')
-        self.entry_win_width = Entry(
+        self.win_width_int = Entry(
                 frame_win_size, textvariable=self.win_width, width=3)
         win_height_title = Label(frame_win_size, text='Height')
-        self.entry_win_height = Entry(
+        self.win_height_int = Entry(
                 frame_win_size, textvariable=self.win_height, width=3)
-        #frame_help
+        # frame_help.
         frame_helplist = Frame(frame_help)
         frame_helplist_buttons = Frame(frame_helplist)
-        scroll_helplist = Scrollbar(frame_helplist)
-        self.list_help = Listbox(
+        self.helplist = Listbox(
                 frame_helplist, height=5, takefocus=FALSE,
                 exportselection=FALSE)
-        scroll_helplist.config(command=self.list_help.yview)
-        self.list_help.config(yscrollcommand=scroll_helplist.set)
-        self.list_help.bind('<ButtonRelease-1>', self.help_source_selected)
+        scroll_helplist = Scrollbar(frame_helplist)
+        scroll_helplist['command'] = self.helplist.yview
+        self.helplist['yscrollcommand'] = scroll_helplist.set
+        self.helplist.bind('<ButtonRelease-1>', self.help_source_selected)
         self.button_helplist_edit = Button(
                 frame_helplist_buttons, text='Edit', state=DISABLED,
                 width=8, command=self.helplist_item_edit)
@@ -755,36 +757,146 @@ def create_page_general(self):
                 frame_helplist_buttons, text='Remove', state=DISABLED,
                 width=8, command=self.helplist_item_remove)
 
-        #widget packing
-        #body
+        # Pack widgets:
+        # body.
         frame_run.pack(side=TOP, padx=5, pady=5, fill=X)
         frame_save.pack(side=TOP, padx=5, pady=5, fill=X)
         frame_win_size.pack(side=TOP, padx=5, pady=5, fill=X)
         frame_help.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
-        #frame_run
+        # frame_run.
         startup_title.pack(side=LEFT, anchor=W, padx=5, pady=5)
-        self.radio_startup_shell.pack(side=RIGHT, anchor=W, padx=5, pady=5)
-        self.radio_startup_edit.pack(side=RIGHT, anchor=W, padx=5, pady=5)
-        #frame_save
+        self.startup_shell_on.pack(side=RIGHT, anchor=W, padx=5, pady=5)
+        self.startup_editor_on.pack(side=RIGHT, anchor=W, padx=5, pady=5)
+        # frame_save.
         run_save_title.pack(side=LEFT, anchor=W, padx=5, pady=5)
-        self.radio_save_auto.pack(side=RIGHT, anchor=W, padx=5, pady=5)
-        self.radio_save_ask.pack(side=RIGHT, anchor=W, padx=5, pady=5)
-        #frame_win_size
+        self.save_auto_on.pack(side=RIGHT, anchor=W, padx=5, pady=5)
+        self.save_ask_on.pack(side=RIGHT, anchor=W, padx=5, pady=5)
+        # frame_win_size.
         win_size_title.pack(side=LEFT, anchor=W, padx=5, pady=5)
-        self.entry_win_height.pack(side=RIGHT, anchor=E, padx=10, pady=5)
+        self.win_height_int.pack(side=RIGHT, anchor=E, padx=10, pady=5)
         win_height_title.pack(side=RIGHT, anchor=E, pady=5)
-        self.entry_win_width.pack(side=RIGHT, anchor=E, padx=10, pady=5)
+        self.win_width_int.pack(side=RIGHT, anchor=E, padx=10, pady=5)
         win_width_title.pack(side=RIGHT, anchor=E, pady=5)
-        #frame_help
+        # frame_help.
         frame_helplist_buttons.pack(side=RIGHT, padx=5, pady=5, fill=Y)
         frame_helplist.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
         scroll_helplist.pack(side=RIGHT, anchor=W, fill=Y)
-        self.list_help.pack(side=LEFT, anchor=E, expand=TRUE, fill=BOTH)
+        self.helplist.pack(side=LEFT, anchor=E, expand=TRUE, fill=BOTH)
         self.button_helplist_edit.pack(side=TOP, anchor=W, pady=5)
         self.button_helplist_add.pack(side=TOP, anchor=W)
         self.button_helplist_remove.pack(side=TOP, anchor=W, pady=5)
+
         return frame
 
+    def load_general_cfg(self):
+        "Load current configuration settings for the general options."
+        # Set startup state.
+        self.startup_edit.set(idleConf.GetOption(
+                'main', 'General', 'editor-on-startup', default=0, type='bool'))
+        # Set autosave state.
+        self.autosave.set(idleConf.GetOption(
+                'main', 'General', 'autosave', default=0, type='bool'))
+        # Set initial window size.
+        self.win_width.set(idleConf.GetOption(
+                'main', 'EditorWindow', 'width', type='int'))
+        self.win_height.set(idleConf.GetOption(
+                'main', 'EditorWindow', 'height', type='int'))
+        # Set additional help sources.
+        self.user_helplist = idleConf.GetAllExtraHelpSourcesList()
+        self.helplist.delete(0, 'end')
+        for help_item in self.user_helplist:
+            self.helplist.insert(END, help_item[0])
+        self.set_add_delete_state()
+
+    def var_changed_startup_edit(self, *params):
+        "Store change to toggle for starting IDLE in the editor or shell."
+        value = self.startup_edit.get()
+        changes.add_option('main', 'General', 'editor-on-startup', value)
+
+    def var_changed_autosave(self, *params):
+        "Store change to autosave."
+        value = self.autosave.get()
+        changes.add_option('main', 'General', 'autosave', value)
+
+    def var_changed_win_width(self, *params):
+        "Store change to window width."
+        value = self.win_width.get()
+        changes.add_option('main', 'EditorWindow', 'width', value)
+
+    def var_changed_win_height(self, *params):
+        "Store change to window height."
+        value = self.win_height.get()
+        changes.add_option('main', 'EditorWindow', 'height', value)
+
+    def help_source_selected(self, event):
+        "Handle event for selecting additional help."
+        self.set_add_delete_state()
+
+    def set_add_delete_state(self):
+        "Toggle the state for the help list buttons based on list entries."
+        if self.helplist.size() < 1:  # No entries in list.
+            self.button_helplist_edit['state'] = DISABLED
+            self.button_helplist_remove['state'] = DISABLED
+        else:  # Some entries.
+            if self.helplist.curselection():  # There currently is a selection.
+                self.button_helplist_edit['state'] = NORMAL
+                self.button_helplist_remove['state'] = NORMAL
+            else:  # There currently is not a selection.
+                self.button_helplist_edit['state'] = DISABLED
+                self.button_helplist_remove['state'] = DISABLED
+
+    def helplist_item_add(self):
+        """Handle add button for the help list.
+
+        Query for name and location of new help sources and add
+        them to the list.
+        """
+        help_source = HelpSource(self, 'New Help Source').result
+        if help_source:
+            self.user_helplist.append(help_source)
+            self.helplist.insert(END, help_source[0])
+            self.update_help_changes()
+
+    def helplist_item_edit(self):
+        """Handle edit button for the help list.
+
+        Query with existing help source information and update
+        config if the values are changed.
+        """
+        item_index = self.helplist.index(ANCHOR)
+        help_source = self.user_helplist[item_index]
+        new_help_source = HelpSource(
+                self, 'Edit Help Source',
+                menuitem=help_source[0],
+                filepath=help_source[1],
+                ).result
+        if new_help_source and new_help_source != help_source:
+            self.user_helplist[item_index] = new_help_source
+            self.helplist.delete(item_index)
+            self.helplist.insert(item_index, new_help_source[0])
+            self.update_help_changes()
+            self.set_add_delete_state()  # Selected will be un-selected
+
+    def helplist_item_remove(self):
+        """Handle remove button for the help list.
+
+        Delete the help list item from config.
+        """
+        item_index = self.helplist.index(ANCHOR)
+        del(self.user_helplist[item_index])
+        self.helplist.delete(item_index)
+        self.update_help_changes()
+        self.set_add_delete_state()
+
+    def update_help_changes(self):
+        "Clear and rebuild the HelpFiles section in changes"
+        changes['main']['HelpFiles'] = {}
+        for num in range(1, len(self.user_helplist) + 1):
+            changes.add_option(
+                    'main', 'HelpFiles', str(num),
+                    ';'.join(self.user_helplist[num-1][:2]))
+
+
     def attach_var_callbacks(self):
         "Attach callbacks to variables that can be changed."
         self.font_size.trace_add('write', self.var_changed_font)
@@ -917,26 +1029,6 @@ def var_changed_are_keys_builtin(self, *params):
         else:
             self.var_changed_custom_keys()
 
-    def var_changed_win_width(self, *params):
-        "Store change to window width."
-        value = self.win_width.get()
-        changes.add_option('main', 'EditorWindow', 'width', value)
-
-    def var_changed_win_height(self, *params):
-        "Store change to window height."
-        value = self.win_height.get()
-        changes.add_option('main', 'EditorWindow', 'height', value)
-
-    def var_changed_startup_edit(self, *params):
-        "Store change to toggle for starting IDLE in the editor or shell."
-        value = self.startup_edit.get()
-        changes.add_option('main', 'General', 'editor-on-startup', value)
-
-    def var_changed_autosave(self, *params):
-        "Store change to autosave."
-        value = self.autosave.get()
-        changes.add_option('main', 'General', 'autosave', value)
-
     def set_theme_type(self):
         """Set available screen options based on builtin or custom theme.
 
@@ -956,26 +1048,26 @@ def set_theme_type(self):
             load_theme_cfg
         """
         if self.is_builtin_theme.get():
-            self.opt_menu_theme_builtin.config(state=NORMAL)
-            self.opt_menu_theme_custom.config(state=DISABLED)
-            self.button_delete_custom_theme.config(state=DISABLED)
+            self.opt_menu_theme_builtin['state'] = NORMAL
+            self.opt_menu_theme_custom['state'] = DISABLED
+            self.button_delete_custom_theme['state'] = DISABLED
         else:
-            self.opt_menu_theme_builtin.config(state=DISABLED)
-            self.radio_theme_custom.config(state=NORMAL)
-            self.opt_menu_theme_custom.config(state=NORMAL)
-            self.button_delete_custom_theme.config(state=NORMAL)
+            self.opt_menu_theme_builtin['state'] = DISABLED
+            self.radio_theme_custom['state'] = NORMAL
+            self.opt_menu_theme_custom['state'] = NORMAL
+            self.button_delete_custom_theme['state'] = NORMAL
 
     def set_keys_type(self):
         "Set available screen options based on builtin or custom key set."
         if self.are_keys_builtin.get():
-            self.opt_menu_keys_builtin.config(state=NORMAL)
-            self.opt_menu_keys_custom.config(state=DISABLED)
-            self.button_delete_custom_keys.config(state=DISABLED)
+            self.opt_menu_keys_builtin['state'] = NORMAL
+            self.opt_menu_keys_custom['state'] = DISABLED
+            self.button_delete_custom_keys['state'] = DISABLED
         else:
-            self.opt_menu_keys_builtin.config(state=DISABLED)
-            self.radio_keys_custom.config(state=NORMAL)
-            self.opt_menu_keys_custom.config(state=NORMAL)
-            self.button_delete_custom_keys.config(state=NORMAL)
+            self.opt_menu_keys_builtin['state'] = DISABLED
+            self.radio_keys_custom['state'] = NORMAL
+            self.opt_menu_keys_custom['state'] = NORMAL
+            self.button_delete_custom_keys['state'] = NORMAL
 
     def get_new_keys(self):
         """Handle event to change key binding for selected line.
@@ -1037,7 +1129,7 @@ def save_as_new_key_set(self):
 
     def keybinding_selected(self, event):
         "Activate button to assign new keys to selected action."
-        self.button_new_keys.config(state=NORMAL)
+        self.button_new_keys['state'] = NORMAL
 
     def create_new_key_set(self, new_key_set_name):
         """Create a new custom key set with the given name.
@@ -1115,7 +1207,7 @@ def delete_custom_keys(self):
         item_list = idleConf.GetSectionList('user', 'keys')
         item_list.sort()
         if not item_list:
-            self.radio_keys_custom.config(state=DISABLED)
+            self.radio_keys_custom['state'] = DISABLED
             self.opt_menu_keys_custom.SetMenu(item_list, '- no custom keys -')
         else:
             self.opt_menu_keys_custom.SetMenu(item_list, item_list[0])
@@ -1164,7 +1256,7 @@ def delete_custom_theme(self):
         item_list = idleConf.GetSectionList('user', 'highlight')
         item_list.sort()
         if not item_list:
-            self.radio_theme_custom.config(state=DISABLED)
+            self.radio_theme_custom['state'] = DISABLED
             self.opt_menu_theme_custom.SetMenu(item_list, '- no custom themes -')
         else:
             self.opt_menu_theme_custom.SetMenu(item_list, item_list[0])
@@ -1303,12 +1395,12 @@ def set_highlight_target(self):
             load_theme_cfg
         """
         if self.highlight_target.get() == 'Cursor':  # bg not possible
-            self.radio_fg.config(state=DISABLED)
-            self.radio_bg.config(state=DISABLED)
+            self.radio_fg['state'] = DISABLED
+            self.radio_bg['state'] = DISABLED
             self.fg_bg_toggle.set(1)
         else:  # Both fg and bg can be set.
-            self.radio_fg.config(state=NORMAL)
-            self.radio_bg.config(state=NORMAL)
+            self.radio_fg['state'] = NORMAL
+            self.radio_bg['state'] = NORMAL
             self.fg_bg_toggle.set(1)
         self.set_color_sample()
 
@@ -1378,76 +1470,6 @@ def paint_theme_sample(self):
             self.highlight_sample.tag_config(element, **colors)
         self.set_color_sample()
 
-    def help_source_selected(self, event):
-        "Handle event for selecting additional help."
-        self.set_helplist_button_states()
-
-    def set_helplist_button_states(self):
-        "Toggle the state for the help list buttons based on list entries."
-        if self.list_help.size() < 1:  # No entries in list.
-            self.button_helplist_edit.config(state=DISABLED)
-            self.button_helplist_remove.config(state=DISABLED)
-        else:  # Some entries.
-            if self.list_help.curselection():  # There currently is a selection.
-                self.button_helplist_edit.config(state=NORMAL)
-                self.button_helplist_remove.config(state=NORMAL)
-            else:  # There currently is not a selection.
-                self.button_helplist_edit.config(state=DISABLED)
-                self.button_helplist_remove.config(state=DISABLED)
-
-    def helplist_item_add(self):
-        """Handle add button for the help list.
-
-        Query for name and location of new help sources and add
-        them to the list.
-        """
-        help_source = HelpSource(self, 'New Help Source',
-                                ).result
-        if help_source:
-            self.user_helplist.append((help_source[0], help_source[1]))
-            self.list_help.insert(END, help_source[0])
-            self.update_user_help_changed_items()
-        self.set_helplist_button_states()
-
-    def helplist_item_edit(self):
-        """Handle edit button for the help list.
-
-        Query with existing help source information and update
-        config if the values are changed.
-        """
-        item_index = self.list_help.index(ANCHOR)
-        help_source = self.user_helplist[item_index]
-        new_help_source = HelpSource(
-                self, 'Edit Help Source',
-                menuitem=help_source[0],
-                filepath=help_source[1],
-                ).result
-        if new_help_source and new_help_source != help_source:
-            self.user_helplist[item_index] = new_help_source
-            self.list_help.delete(item_index)
-            self.list_help.insert(item_index, new_help_source[0])
-            self.update_user_help_changed_items()
-            self.set_helplist_button_states()
-
-    def helplist_item_remove(self):
-        """Handle remove button for the help list.
-
-        Delete the help list item from config.
-        """
-        item_index = self.list_help.index(ANCHOR)
-        del(self.user_helplist[item_index])
-        self.list_help.delete(item_index)
-        self.update_user_help_changed_items()
-        self.set_helplist_button_states()
-
-    def update_user_help_changed_items(self):
-        "Clear and rebuild the HelpFiles section in changes"
-        changes['main']['HelpFiles'] = {}
-        for num in range(1, len(self.user_helplist) + 1):
-            changes.add_option(
-                    'main', 'HelpFiles', str(num),
-                    ';'.join(self.user_helplist[num-1][:2]))
-
     def load_theme_cfg(self):
         """Load current configuration settings for the theme options.
 
@@ -1481,7 +1503,7 @@ def load_theme_cfg(self):
             item_list = idleConf.GetSectionList('user', 'highlight')
             item_list.sort()
             if not item_list:
-                self.radio_theme_custom.config(state=DISABLED)
+                self.radio_theme_custom['state'] = DISABLED
                 self.custom_theme.set('- no custom themes -')
             else:
                 self.opt_menu_theme_custom.SetMenu(item_list, item_list[0])
@@ -1515,7 +1537,7 @@ def load_key_cfg(self):
             item_list = idleConf.GetSectionList('user', 'keys')
             item_list.sort()
             if not item_list:
-                self.radio_keys_custom.config(state=DISABLED)
+                self.radio_keys_custom['state'] = DISABLED
                 self.custom_keys.set('- no custom keys -')
             else:
                 self.opt_menu_keys_custom.SetMenu(item_list, item_list[0])
@@ -1531,25 +1553,6 @@ def load_key_cfg(self):
         keyset_name = idleConf.CurrentKeys()
         self.load_keys_list(keyset_name)
 
-    def load_general_cfg(self):
-        "Load current configuration settings for the general options."
-        # Set startup state.
-        self.startup_edit.set(idleConf.GetOption(
-                'main', 'General', 'editor-on-startup', default=1, type='bool'))
-        # Set autosave state.
-        self.autosave.set(idleConf.GetOption(
-                'main', 'General', 'autosave', default=0, type='bool'))
-        # Set initial window size.
-        self.win_width.set(idleConf.GetOption(
-                'main', 'EditorWindow', 'width', type='int'))
-        self.win_height.set(idleConf.GetOption(
-                'main', 'EditorWindow', 'height', type='int'))
-        # Set additional help sources.
-        self.user_helplist = idleConf.GetAllExtraHelpSourcesList()
-        for help_item in self.user_helplist:
-            self.list_help.insert(END, help_item[0])
-        self.set_helplist_button_states()
-
     def load_configs(self):
         """Load configuration for each page.
 
diff --git a/Lib/idlelib/idle_test/mock_idle.py b/Lib/idlelib/idle_test/mock_idle.py
index 8f3147b1c5c..f279a52fd51 100644
--- a/Lib/idlelib/idle_test/mock_idle.py
+++ b/Lib/idlelib/idle_test/mock_idle.py
@@ -13,14 +13,16 @@ class Func:
     self.args - capture positional arguments.
     self.kwds - capture keyword arguments.
     self.result - return or raise value set in __init__.
+    self.return_self - return self instead, to mock query class return.
 
     Most common use will probably be to mock instance methods.
     Given class instance, can set and delete as instance attribute.
     Mock_tk.Var and Mbox_func are special variants of this.
     '''
-    def __init__(self, result=None):
+    def __init__(self, result=None, return_self=False):
         self.called = 0
         self.result = result
+        self.return_self = return_self
         self.args = None
         self.kwds = None
     def __call__(self, *args, **kwds):
@@ -29,6 +31,8 @@ def __call__(self, *args, **kwds):
         self.kwds = kwds
         if isinstance(self.result, BaseException):
             raise self.result
+        elif self.return_self:
+            return self
         else:
             return self.result
 
diff --git a/Lib/idlelib/idle_test/test_configdialog.py b/Lib/idlelib/idle_test/test_configdialog.py
index ce02ae4a8e6..7296075fbec 100644
--- a/Lib/idlelib/idle_test/test_configdialog.py
+++ b/Lib/idlelib/idle_test/test_configdialog.py
@@ -1,16 +1,17 @@
 """Test idlelib.configdialog.
 
 Half the class creates dialog, half works with user customizations.
-Coverage: 46% just by creating dialog, 60% with current tests.
+Coverage: 63%.
 """
-from idlelib.configdialog import ConfigDialog, idleConf, changes, VarTrace
+from idlelib import configdialog
 from test.support import requires
 requires('gui')
-from tkinter import Tk, IntVar, BooleanVar
 import unittest
 from unittest import mock
-import idlelib.config as config
 from idlelib.idle_test.mock_idle import Func
+from tkinter import Tk, IntVar, BooleanVar, DISABLED, NORMAL
+from idlelib import config
+from idlelib.configdialog import ConfigDialog, idleConf, changes, VarTrace
 
 # Tests should not depend on fortuitous user configurations.
 # They must not affect actual user .cfg files.
@@ -226,27 +227,200 @@ def setUp(self):
 
 
 class GeneralTest(unittest.TestCase):
+    """Test that general tab widgets enable users to make changes.
+
+    Test that widget actions set vars, that var changes add
+    options to changes and that helplist works correctly.
+    """
+    @classmethod
+    def setUpClass(cls):
+        # Mask instance methods used by help functions.
+        d = dialog
+        d.set = d.set_add_delete_state = Func()
+        d.upc = d.update_help_changes = Func()
+
+    @classmethod
+    def tearDownClass(cls):
+        d = dialog
+        del d.set, d.set_add_delete_state
+        del d.upc, d.update_help_changes
+        d.helplist.delete(0, 'end')
+        d.user_helplist.clear()
 
     def setUp(self):
         changes.clear()
 
+    def test_load_general_cfg(self):
+        # Set to wrong values, load, check right values.
+        eq = self.assertEqual
+        d = dialog
+        d.startup_edit.set(1)
+        d.autosave.set(1)
+        d.win_width.set(1)
+        d.win_height.set(1)
+        d.helplist.insert('end', 'bad')
+        d.user_helplist = ['bad', 'worse']
+        idleConf.SetOption('main', 'HelpFiles', '1', 'name;file')
+        d.load_general_cfg()
+        eq(d.startup_edit.get(), 0)
+        eq(d.autosave.get(), 0)
+        eq(d.win_width.get(), '80')
+        eq(d.win_height.get(), '40')
+        eq(d.helplist.get(0, 'end'), ('name',))
+        eq(d.user_helplist, [('name', 'file', '1')])
+
     def test_startup(self):
-        dialog.radio_startup_edit.invoke()
+        dialog.startup_editor_on.invoke()
         self.assertEqual(mainpage,
                          {'General': {'editor-on-startup': '1'}})
+        changes.clear()
+        dialog.startup_shell_on.invoke()
+        self.assertEqual(mainpage,
+                         {'General': {'editor-on-startup': '0'}})
 
     def test_autosave(self):
-        dialog.radio_save_auto.invoke()
+        dialog.save_auto_on.invoke()
         self.assertEqual(mainpage, {'General': {'autosave': '1'}})
+        dialog.save_ask_on.invoke()
+        self.assertEqual(mainpage, {'General': {'autosave': '0'}})
 
     def test_editor_size(self):
-        dialog.entry_win_height.insert(0, '1')
+        dialog.win_height_int.insert(0, '1')
         self.assertEqual(mainpage, {'EditorWindow': {'height': '140'}})
         changes.clear()
-        dialog.entry_win_width.insert(0, '1')
+        dialog.win_width_int.insert(0, '1')
         self.assertEqual(mainpage, {'EditorWindow': {'width': '180'}})
 
-    #def test_help_sources(self): pass  # TODO
+    def test_source_selected(self):
+        d = dialog
+        d.set = d.set_add_delete_state
+        d.upc = d.update_help_changes
+        helplist = d.helplist
+        helplist.insert(0, 'source')
+        helplist.activate(0)
+
+        helplist.focus_force()
+        helplist.see(0)
+        helplist.update()
+        x, y, dx, dy = helplist.bbox(0)
+        x += dx // 2
+        y += dy // 2
+        d.set.called = d.upc.called = 0
+        helplist.event_generate('<Button-1>', x=x, y=y)
+        helplist.event_generate('<ButtonRelease-1>', x=x, y=y)
+        self.assertEqual(helplist.get('anchor'), 'source')
+        self.assertTrue(d.set.called)
+        self.assertFalse(d.upc.called)
+
+    def test_set_add_delete_state(self):
+        # Call with 0 items, 1 unselected item, 1 selected item.
+        eq = self.assertEqual
+        d = dialog
+        del d.set_add_delete_state  # Unmask method.
+        sad = d.set_add_delete_state
+        h = d.helplist
+
+        h.delete(0, 'end')
+        sad()
+        eq(d.button_helplist_edit['state'], DISABLED)
+        eq(d.button_helplist_remove['state'], DISABLED)
+
+        h.insert(0, 'source')
+        sad()
+        eq(d.button_helplist_edit['state'], DISABLED)
+        eq(d.button_helplist_remove['state'], DISABLED)
+
+        h.selection_set(0)
+        sad()
+        eq(d.button_helplist_edit['state'], NORMAL)
+        eq(d.button_helplist_remove['state'], NORMAL)
+        d.set_add_delete_state = Func()  # Mask method.
+
+    def test_helplist_item_add(self):
+        # Call without and twice with HelpSource result.
+        # Double call enables check on order.
+        eq = self.assertEqual
+        orig_helpsource = configdialog.HelpSource
+        hs = configdialog.HelpSource = Func(return_self=True)
+        d = dialog
+        d.helplist.delete(0, 'end')
+        d.user_helplist.clear()
+        d.set.called = d.upc.called = 0
+
+        hs.result = ''
+        d.helplist_item_add()
+        self.assertTrue(list(d.helplist.get(0, 'end')) ==
+                        d.user_helplist == [])
+        self.assertFalse(d.upc.called)
+
+        hs.result = ('name1', 'file1')
+        d.helplist_item_add()
+        hs.result = ('name2', 'file2')
+        d.helplist_item_add()
+        eq(d.helplist.get(0, 'end'), ('name1', 'name2'))
+        eq(d.user_helplist, [('name1', 'file1'), ('name2', 'file2')])
+        eq(d.upc.called, 2)
+        self.assertFalse(d.set.called)
+
+        configdialog.HelpSource = orig_helpsource
+
+    def test_helplist_item_edit(self):
+        # Call without and with HelpSource change.
+        eq = self.assertEqual
+        orig_helpsource = configdialog.HelpSource
+        hs = configdialog.HelpSource = Func(return_self=True)
+        d = dialog
+        d.helplist.delete(0, 'end')
+        d.helplist.insert(0, 'name1')
+        d.helplist.selection_set(0)
+        d.helplist.selection_anchor(0)
+        d.user_helplist.clear()
+        d.user_helplist.append(('name1', 'file1'))
+        d.set.called = d.upc.called = 0
+
+        hs.result = ''
+        d.helplist_item_edit()
+        hs.result = ('name1', 'file1')
+        d.helplist_item_edit()
+        eq(d.helplist.get(0, 'end'), ('name1',))
+        eq(d.user_helplist, [('name1', 'file1')])
+        self.assertFalse(d.upc.called)
+
+        hs.result = ('name2', 'file2')
+        d.helplist_item_edit()
+        eq(d.helplist.get(0, 'end'), ('name2',))
+        eq(d.user_helplist, [('name2', 'file2')])
+        self.assertTrue(d.upc.called == d.set.called == 1)
+
+        configdialog.HelpSource = orig_helpsource
+
+    def test_helplist_item_remove(self):
+        eq = self.assertEqual
+        d = dialog
+        d.helplist.delete(0, 'end')
+        d.helplist.insert(0, 'name1')
+        d.helplist.selection_set(0)
+        d.helplist.selection_anchor(0)
+        d.user_helplist.clear()
+        d.user_helplist.append(('name1', 'file1'))
+        d.set.called = d.upc.called = 0
+
+        d.helplist_item_remove()
+        eq(d.helplist.get(0, 'end'), ())
+        eq(d.user_helplist, [])
+        self.assertTrue(d.upc.called == d.set.called == 1)
+
+    def test_update_help_changes(self):
+        d = dialog
+        del d.update_help_changes
+        d.user_helplist.clear()
+        d.user_helplist.append(('name1', 'file1'))
+        d.user_helplist.append(('name2', 'file2'))
+
+        d.update_help_changes()
+        self.assertEqual(mainpage['HelpFiles'],
+                        {'1': 'name1;file1', '2': 'name2;file2'})
+        d.update_help_changes = Func()
 
 
 class TestVarTrace(unittest.TestCase):
diff --git a/Misc/NEWS.d/next/IDLE/2017-07-25-01-28-35.bpo-31003.bYINVH.rst b/Misc/NEWS.d/next/IDLE/2017-07-25-01-28-35.bpo-31003.bYINVH.rst
new file mode 100644
index 00000000000..f3dab0fd9e6
--- /dev/null
+++ b/Misc/NEWS.d/next/IDLE/2017-07-25-01-28-35.bpo-31003.bYINVH.rst
@@ -0,0 +1 @@
+IDLE: Add more tests for General tab.



More information about the Python-checkins mailing list