summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTerry Jan Reedy <tjreedy@udel.edu>2017-07-27 00:54:40 (GMT)
committerGitHub <noreply@github.com>2017-07-27 00:54:40 (GMT)
commit2bc8f0e6867f59e5e8444b2bde99bb0fa3dbefc8 (patch)
tree78946072316d95a5d036cdff438a298b8bd4f2cb
parent45bf723c6c591ec56a18dad8150ae89797450d8b (diff)
downloadcpython-2bc8f0e6867f59e5e8444b2bde99bb0fa3dbefc8.zip
cpython-2bc8f0e6867f59e5e8444b2bde99bb0fa3dbefc8.tar.gz
cpython-2bc8f0e6867f59e5e8444b2bde99bb0fa3dbefc8.tar.bz2
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.
-rw-r--r--Lib/idlelib/configdialog.py379
-rw-r--r--Lib/idlelib/idle_test/mock_idle.py6
-rw-r--r--Lib/idlelib/idle_test/test_configdialog.py192
-rw-r--r--Misc/NEWS.d/next/IDLE/2017-07-25-01-28-35.bpo-31003.bYINVH.rst1
4 files changed, 380 insertions, 198 deletions
diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py
index f98af46..daaa344 100644
--- a/Lib/idlelib/configdialog.py
+++ b/Lib/idlelib/configdialog.py
@@ -160,7 +160,7 @@ class ConfigDialog(Toplevel):
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 @@ class ConfigDialog(Toplevel):
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 @@ class ConfigDialog(Toplevel):
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 @@ class ConfigDialog(Toplevel):
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 @@ class ConfigDialog(Toplevel):
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 @@ class ConfigDialog(Toplevel):
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 @@ class ConfigDialog(Toplevel):
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 @@ class ConfigDialog(Toplevel):
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 @@ class ConfigDialog(Toplevel):
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 @@ class ConfigDialog(Toplevel):
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 @@ class ConfigDialog(Toplevel):
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 @@ class ConfigDialog(Toplevel):
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 @@ class ConfigDialog(Toplevel):
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 @@ class ConfigDialog(Toplevel):
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 @@ class ConfigDialog(Toplevel):
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 8f3147b..f279a52 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 @@ class Func:
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 ce02ae4..7296075 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 @@ class KeysTest(unittest.TestCase):
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 0000000..f3dab0f
--- /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.