summaryrefslogtreecommitdiffstats
path: root/Lib/idlelib
diff options
context:
space:
mode:
authorCheryl Sabella <cheryl.sabella@gmail.com>2020-01-27 22:15:56 (GMT)
committerTerry Jan Reedy <tjreedy@udel.edu>2020-01-27 22:15:56 (GMT)
commitdd023ad1619b6f1ab313986e8953eea32c18f50c (patch)
tree36889888b43e651314f5480d93a28653628eec03 /Lib/idlelib
parent2528a6c3d0660c03ae43d796628462ccf8e58190 (diff)
downloadcpython-dd023ad1619b6f1ab313986e8953eea32c18f50c.zip
cpython-dd023ad1619b6f1ab313986e8953eea32c18f50c.tar.gz
cpython-dd023ad1619b6f1ab313986e8953eea32c18f50c.tar.bz2
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>
Diffstat (limited to 'Lib/idlelib')
-rw-r--r--Lib/idlelib/NEWS.txt3
-rw-r--r--Lib/idlelib/configdialog.py18
-rw-r--r--Lib/idlelib/idle_test/test_configdialog.py158
3 files changed, 148 insertions, 31 deletions
diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt
index eda7c27..2b54398 100644
--- a/Lib/idlelib/NEWS.txt
+++ b/Lib/idlelib/NEWS.txt
@@ -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.
diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py
index 2f95c9c..2235973 100644
--- a/Lib/idlelib/configdialog.py
+++ b/Lib/idlelib/configdialog.py
@@ -149,17 +149,19 @@ class ConfigDialog(Toplevel):
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 @@ class ConfigDialog(Toplevel):
Attributes accessed:
note
-
Methods:
view_text: Method from textview module.
"""
@@ -852,6 +853,7 @@ class HighPage(Frame):
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 @@ class HighPage(Frame):
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 @@ class KeysPage(Frame):
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)
diff --git a/Lib/idlelib/idle_test/test_configdialog.py b/Lib/idlelib/idle_test/test_configdialog.py
index 817a3521..1fea6d4 100644
--- a/Lib/idlelib/idle_test/test_configdialog.py
+++ b/Lib/idlelib/idle_test/test_configdialog.py
@@ -8,7 +8,7 @@ requires('gui')
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 @@ highpage = changes['highlight']
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):
+
+ def test_deactivate_current_config(self):
+ pass
+
+ def activate_config_changes(self):
+ pass
+
- @mock.patch(__name__+'.dialog.destroy', new_callable=Func)
- def test_cancel(self, destroy):
+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 @@ class HighPageTest(unittest.TestCase):
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 @@ class HighPageTest(unittest.TestCase):
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 @@ class HighPageTest(unittest.TestCase):
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 @@ class HighPageTest(unittest.TestCase):
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 @@ class KeysPageTest(unittest.TestCase):
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 @@ class KeysPageTest(unittest.TestCase):
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 @@ class KeysPageTest(unittest.TestCase):
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