bpo-30780: Add IDLE configdialog tests (#3592)

Expose dialog buttons to test code and complete their test coverage.
Complete test coverage for highlights and keys tabs.

Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu>
This commit is contained in:
Cheryl Sabella 2020-01-27 17:15:56 -05:00 committed by Terry Jan Reedy
parent 2528a6c3d0
commit dd023ad161
4 changed files with 149 additions and 31 deletions

View file

@ -3,6 +3,9 @@ Released on 2020-10-05?
======================================
bpo-30780: Add remaining configdialog tests for buttons and
highlights and keys tabs.
bpo-39388: Settings dialog Cancel button cancels pending changes.
bpo-39050: Settings dialog Help button again displays help text.

View file

@ -149,17 +149,19 @@ def create_action_buttons(self):
else:
padding_args = {'padding': (6, 3)}
outer = Frame(self, padding=2)
buttons = Frame(outer, padding=2)
buttons_frame = Frame(outer, padding=2)
self.buttons = {}
for txt, cmd in (
('Ok', self.ok),
('Apply', self.apply),
('Cancel', self.cancel),
('Help', self.help)):
Button(buttons, text=txt, command=cmd, takefocus=FALSE,
**padding_args).pack(side=LEFT, padx=5)
self.buttons[txt] = Button(buttons_frame, text=txt, command=cmd,
takefocus=FALSE, **padding_args)
self.buttons[txt].pack(side=LEFT, padx=5)
# Add space above buttons.
Frame(outer, height=2, borderwidth=0).pack(side=TOP)
buttons.pack(side=BOTTOM)
buttons_frame.pack(side=BOTTOM)
return outer
def ok(self):
@ -205,7 +207,6 @@ def help(self):
Attributes accessed:
note
Methods:
view_text: Method from textview module.
"""
@ -852,6 +853,7 @@ def create_page_highlight(self):
text.configure(
font=('courier', 12, ''), cursor='hand2', width=1, height=1,
takefocus=FALSE, highlightthickness=0, wrap=NONE)
# Prevent perhaps invisible selection of word or slice.
text.bind('<Double-Button-1>', lambda e: 'break')
text.bind('<B1-Motion>', lambda e: 'break')
string_tags=(
@ -1284,8 +1286,7 @@ def save_new(self, theme_name, theme):
theme_name - string, the name of the new theme
theme - dictionary containing the new theme
"""
if not idleConf.userCfg['highlight'].has_section(theme_name):
idleConf.userCfg['highlight'].add_section(theme_name)
idleConf.userCfg['highlight'].AddSection(theme_name)
for element in theme:
value = theme[element]
idleConf.userCfg['highlight'].SetOption(theme_name, element, value)
@ -1730,8 +1731,7 @@ def save_new_key_set(keyset_name, keyset):
keyset_name - string, the name of the new key set
keyset - dictionary containing the new keybindings
"""
if not idleConf.userCfg['keys'].has_section(keyset_name):
idleConf.userCfg['keys'].add_section(keyset_name)
idleConf.userCfg['keys'].AddSection(keyset_name)
for event in keyset:
value = keyset[event]
idleConf.userCfg['keys'].SetOption(keyset_name, event, value)

View file

@ -8,7 +8,7 @@
import unittest
from unittest import mock
from idlelib.idle_test.mock_idle import Func
from tkinter import Tk, StringVar, IntVar, BooleanVar, DISABLED, NORMAL
from tkinter import (Tk, StringVar, IntVar, BooleanVar, DISABLED, NORMAL)
from idlelib import config
from idlelib.configdialog import idleConf, changes, tracers
@ -30,6 +30,7 @@
keyspage = changes['keys']
extpage = changes['extensions']
def setUpModule():
global root, dialog
idleConf.userCfg = testcfg
@ -37,6 +38,7 @@ def setUpModule():
# root.withdraw() # Comment out, see issue 30870
dialog = configdialog.ConfigDialog(root, 'Test', _utest=True)
def tearDownModule():
global root, dialog
idleConf.userCfg = usercfg
@ -48,22 +50,56 @@ def tearDownModule():
root = dialog = None
class DialogTest(unittest.TestCase):
class ConfigDialogTest(unittest.TestCase):
@mock.patch(__name__+'.dialog.destroy', new_callable=Func)
def test_cancel(self, destroy):
def test_deactivate_current_config(self):
pass
def activate_config_changes(self):
pass
class ButtonTest(unittest.TestCase):
def test_click_ok(self):
d = dialog
apply = d.apply = mock.Mock()
destroy = d.destroy = mock.Mock()
d.buttons['Ok'].invoke()
apply.assert_called_once()
destroy.assert_called_once()
del d.destroy, d.apply
def test_click_apply(self):
d = dialog
deactivate = d.deactivate_current_config = mock.Mock()
save_ext = d.save_all_changed_extensions = mock.Mock()
activate = d.activate_config_changes = mock.Mock()
d.buttons['Apply'].invoke()
deactivate.assert_called_once()
save_ext.assert_called_once()
activate.assert_called_once()
del d.save_all_changed_extensions
del d.activate_config_changes, d.deactivate_current_config
def test_click_cancel(self):
d = dialog
d.destroy = Func()
changes['main']['something'] = 1
dialog.cancel()
d.buttons['Cancel'].invoke()
self.assertEqual(changes['main'], {})
self.assertEqual(destroy.called, 1)
self.assertEqual(d.destroy.called, 1)
del d.destroy
@mock.patch('idlelib.configdialog.view_text', new_callable=Func)
def test_help(self, view):
def test_click_help(self):
dialog.note.select(dialog.keyspage)
dialog.help()
s = view.kwds['contents']
self.assertTrue(s.startswith('When you click') and
s.endswith('a different name.\n'))
with mock.patch.object(configdialog, 'view_text',
new_callable=Func) as view:
dialog.buttons['Help'].invoke()
title, contents = view.kwds['title'], view.kwds['contents']
self.assertEqual(title, 'Help for IDLE preferences')
self.assertTrue(contents.startswith('When you click') and
contents.endswith('a different name.\n'))
class FontPageTest(unittest.TestCase):
@ -438,6 +474,48 @@ def click_it(start):
eq(d.highlight_target.get(), elem[tag])
eq(d.set_highlight_target.called, count)
def test_highlight_sample_double_click(self):
# Test double click on highlight_sample.
eq = self.assertEqual
d = self.page
hs = d.highlight_sample
hs.focus_force()
hs.see(1.0)
hs.update_idletasks()
# Test binding from configdialog.
hs.event_generate('<Enter>', x=0, y=0)
hs.event_generate('<Motion>', x=0, y=0)
# Double click is a sequence of two clicks in a row.
for _ in range(2):
hs.event_generate('<ButtonPress-1>', x=0, y=0)
hs.event_generate('<ButtonRelease-1>', x=0, y=0)
eq(hs.tag_ranges('sel'), ())
def test_highlight_sample_b1_motion(self):
# Test button motion on highlight_sample.
eq = self.assertEqual
d = self.page
hs = d.highlight_sample
hs.focus_force()
hs.see(1.0)
hs.update_idletasks()
x, y, dx, dy, offset = hs.dlineinfo('1.0')
# Test binding from configdialog.
hs.event_generate('<Leave>')
hs.event_generate('<Enter>')
hs.event_generate('<Motion>', x=x, y=y)
hs.event_generate('<ButtonPress-1>', x=x, y=y)
hs.event_generate('<B1-Motion>', x=dx, y=dy)
hs.event_generate('<ButtonRelease-1>', x=dx, y=dy)
eq(hs.tag_ranges('sel'), ())
def test_set_theme_type(self):
eq = self.assertEqual
d = self.page
@ -666,8 +744,13 @@ def test_delete_custom(self):
idleConf.userCfg['highlight'].SetOption(theme_name, 'name', 'value')
highpage[theme_name] = {'option': 'True'}
theme_name2 = 'other theme'
idleConf.userCfg['highlight'].SetOption(theme_name2, 'name', 'value')
highpage[theme_name2] = {'option': 'False'}
# Force custom theme.
d.theme_source.set(False)
d.custom_theme_on.state(('!disabled',))
d.custom_theme_on.invoke()
d.custom_name.set(theme_name)
# Cancel deletion.
@ -675,7 +758,7 @@ def test_delete_custom(self):
d.button_delete_custom.invoke()
eq(yesno.called, 1)
eq(highpage[theme_name], {'option': 'True'})
eq(idleConf.GetSectionList('user', 'highlight'), ['spam theme'])
eq(idleConf.GetSectionList('user', 'highlight'), [theme_name, theme_name2])
eq(dialog.deactivate_current_config.called, 0)
eq(dialog.activate_config_changes.called, 0)
eq(d.set_theme_type.called, 0)
@ -685,13 +768,26 @@ def test_delete_custom(self):
d.button_delete_custom.invoke()
eq(yesno.called, 2)
self.assertNotIn(theme_name, highpage)
eq(idleConf.GetSectionList('user', 'highlight'), [])
eq(d.custom_theme_on.state(), ('disabled',))
eq(d.custom_name.get(), '- no custom themes -')
eq(idleConf.GetSectionList('user', 'highlight'), [theme_name2])
eq(d.custom_theme_on.state(), ())
eq(d.custom_name.get(), theme_name2)
eq(dialog.deactivate_current_config.called, 1)
eq(dialog.activate_config_changes.called, 1)
eq(d.set_theme_type.called, 1)
# Confirm deletion of second theme - empties list.
d.custom_name.set(theme_name2)
yesno.result = True
d.button_delete_custom.invoke()
eq(yesno.called, 3)
self.assertNotIn(theme_name, highpage)
eq(idleConf.GetSectionList('user', 'highlight'), [])
eq(d.custom_theme_on.state(), ('disabled',))
eq(d.custom_name.get(), '- no custom themes -')
eq(dialog.deactivate_current_config.called, 2)
eq(dialog.activate_config_changes.called, 2)
eq(d.set_theme_type.called, 2)
del dialog.activate_config_changes, dialog.deactivate_current_config
del d.askyesno
@ -1059,8 +1155,13 @@ def test_delete_custom_keys(self):
idleConf.userCfg['keys'].SetOption(keyset_name, 'name', 'value')
keyspage[keyset_name] = {'option': 'True'}
keyset_name2 = 'other key set'
idleConf.userCfg['keys'].SetOption(keyset_name2, 'name', 'value')
keyspage[keyset_name2] = {'option': 'False'}
# Force custom keyset.
d.keyset_source.set(False)
d.custom_keyset_on.state(('!disabled',))
d.custom_keyset_on.invoke()
d.custom_name.set(keyset_name)
# Cancel deletion.
@ -1068,7 +1169,7 @@ def test_delete_custom_keys(self):
d.button_delete_custom_keys.invoke()
eq(yesno.called, 1)
eq(keyspage[keyset_name], {'option': 'True'})
eq(idleConf.GetSectionList('user', 'keys'), ['spam key set'])
eq(idleConf.GetSectionList('user', 'keys'), [keyset_name, keyset_name2])
eq(dialog.deactivate_current_config.called, 0)
eq(dialog.activate_config_changes.called, 0)
eq(d.set_keys_type.called, 0)
@ -1078,13 +1179,26 @@ def test_delete_custom_keys(self):
d.button_delete_custom_keys.invoke()
eq(yesno.called, 2)
self.assertNotIn(keyset_name, keyspage)
eq(idleConf.GetSectionList('user', 'keys'), [])
eq(d.custom_keyset_on.state(), ('disabled',))
eq(d.custom_name.get(), '- no custom keys -')
eq(idleConf.GetSectionList('user', 'keys'), [keyset_name2])
eq(d.custom_keyset_on.state(), ())
eq(d.custom_name.get(), keyset_name2)
eq(dialog.deactivate_current_config.called, 1)
eq(dialog.activate_config_changes.called, 1)
eq(d.set_keys_type.called, 1)
# Confirm deletion of second keyset - empties list.
d.custom_name.set(keyset_name2)
yesno.result = True
d.button_delete_custom_keys.invoke()
eq(yesno.called, 3)
self.assertNotIn(keyset_name, keyspage)
eq(idleConf.GetSectionList('user', 'keys'), [])
eq(d.custom_keyset_on.state(), ('disabled',))
eq(d.custom_name.get(), '- no custom keys -')
eq(dialog.deactivate_current_config.called, 2)
eq(dialog.activate_config_changes.called, 2)
eq(d.set_keys_type.called, 2)
del dialog.activate_config_changes, dialog.deactivate_current_config
del d.askyesno

View file

@ -0,0 +1 @@
Add remaining configdialog tests for buttons and highlights and keys tabs.