bpo-30780: Add IDLE configdialog tests (GH-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>
(cherry picked from commit dd023ad161)

Co-authored-by: Cheryl Sabella <cheryl.sabella@gmail.com>
This commit is contained in:
Miss Islington (bot) 2020-01-27 14:31:33 -08:00 committed by GitHub
parent 414ab5de48
commit 5aefee6f98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 149 additions and 31 deletions

View File

@ -3,6 +3,9 @@ Released on 2019-12-16?
======================================
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 @@ 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)

View File

@ -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):
@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 @@ 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

View File

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