summaryrefslogtreecommitdiffstats
path: root/Lib/idlelib
diff options
context:
space:
mode:
authorLouie Lu <git@louie.lu>2017-07-14 00:35:48 (GMT)
committerterryjreedy <tjreedy@udel.edu>2017-07-14 00:35:48 (GMT)
commit9b622fb90331f259894e6edb29b5c64b9366491a (patch)
tree8be2cdae73c63fb902e4a20863b0a86b8d8c87d9 /Lib/idlelib
parentc40ad03bf2693b4af539978f1274e57b85367547 (diff)
downloadcpython-9b622fb90331f259894e6edb29b5c64b9366491a.zip
cpython-9b622fb90331f259894e6edb29b5c64b9366491a.tar.gz
cpython-9b622fb90331f259894e6edb29b5c64b9366491a.tar.bz2
bpo-30870: IDLE: Add configdialog fontlist selection unittest (#2666)
Initial patch by Louie Lu.
Diffstat (limited to 'Lib/idlelib')
-rw-r--r--Lib/idlelib/configdialog.py5
-rw-r--r--Lib/idlelib/idle_test/mock_idle.py19
-rw-r--r--Lib/idlelib/idle_test/test_configdialog.py113
3 files changed, 108 insertions, 29 deletions
diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py
index a2cfaab..0d68b80 100644
--- a/Lib/idlelib/configdialog.py
+++ b/Lib/idlelib/configdialog.py
@@ -47,7 +47,8 @@ class ConfigDialog(Toplevel):
self.parent = parent
if _htest:
parent.instance_dict = {}
- self.withdraw()
+ if not _utest:
+ self.withdraw()
self.configure(borderwidth=5)
self.title(title or 'IDLE Preferences')
@@ -76,7 +77,6 @@ class ConfigDialog(Toplevel):
self.create_widgets()
self.resizable(height=FALSE, width=FALSE)
self.transient(parent)
- self.grab_set()
self.protocol("WM_DELETE_WINDOW", self.cancel)
self.fontlist.focus_set()
# XXX Decide whether to keep or delete these key bindings.
@@ -88,6 +88,7 @@ class ConfigDialog(Toplevel):
self.attach_var_callbacks() # Avoid callbacks during load_configs.
if not _utest:
+ self.grab_set()
self.wm_deiconify()
self.wait_window()
diff --git a/Lib/idlelib/idle_test/mock_idle.py b/Lib/idlelib/idle_test/mock_idle.py
index c7b49ef..8f3147b 100644
--- a/Lib/idlelib/idle_test/mock_idle.py
+++ b/Lib/idlelib/idle_test/mock_idle.py
@@ -6,24 +6,25 @@ Attributes and methods will be added as needed for tests.
from idlelib.idle_test.mock_tk import Text
class Func:
- '''Mock function captures args and returns result set by test.
+ '''Record call, capture args, return/raise result set by test.
- Attributes:
- self.called - records call even if no args, kwds passed.
- self.result - set by init, returned by call.
- self.args - captures positional arguments.
- self.kwds - captures keyword arguments.
+ When mock function is called, set or use attributes:
+ self.called - increment call number even if no args, kwds passed.
+ self.args - capture positional arguments.
+ self.kwds - capture keyword arguments.
+ self.result - return or raise value set in __init__.
- Most common use will probably be to mock methods.
+ 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):
- self.called = False
+ self.called = 0
self.result = result
self.args = None
self.kwds = None
def __call__(self, *args, **kwds):
- self.called = True
+ self.called += 1
self.args = args
self.kwds = kwds
if isinstance(self.result, BaseException):
diff --git a/Lib/idlelib/idle_test/test_configdialog.py b/Lib/idlelib/idle_test/test_configdialog.py
index 26b045d..4f1f9af 100644
--- a/Lib/idlelib/idle_test/test_configdialog.py
+++ b/Lib/idlelib/idle_test/test_configdialog.py
@@ -1,7 +1,7 @@
"""Test idlelib.configdialog.
Half the class creates dialog, half works with user customizations.
-Coverage: 46% just by creating dialog, 56% with current tests.
+Coverage: 46% just by creating dialog, 60% with current tests.
"""
from idlelib.configdialog import ConfigDialog, idleConf, changes
from test.support import requires
@@ -9,6 +9,7 @@ requires('gui')
from tkinter import Tk
import unittest
import idlelib.config as config
+from idlelib.idle_test.mock_idle import Func
# Tests should not depend on fortuitous user configurations.
# They must not affect actual user .cfg files.
@@ -22,27 +23,29 @@ testcfg = {
}
root = None
-configure = None
+dialog = None
mainpage = changes['main']
highpage = changes['highlight']
keyspage = changes['keys']
-class TestDialog(ConfigDialog): pass # Delete?
+
+class TestDialog(ConfigDialog):
+ pass # Delete?
def setUpModule():
- global root, configure
+ global root, dialog
idleConf.userCfg = testcfg
root = Tk()
- root.withdraw()
- configure = TestDialog(root, 'Test', _utest=True)
+ # root.withdraw() # Comment out, see issue 30870
+ dialog = TestDialog(root, 'Test', _utest=True)
def tearDownModule():
- global root, configure
+ global root, dialog
idleConf.userCfg = usercfg
- configure.remove_var_callbacks()
- del configure
+ dialog.remove_var_callbacks()
+ del dialog
root.update_idletasks()
root.destroy()
del root
@@ -58,31 +61,105 @@ class FontTabTest(unittest.TestCase):
default_font = idleConf.GetFont(root, 'main', 'EditorWindow')
default_size = str(default_font[1])
default_bold = default_font[2] == 'bold'
- configure.font_name.set('Test Font')
+ dialog.font_name.set('Test Font')
expected = {'EditorWindow': {'font': 'Test Font',
'font-size': default_size,
'font-bold': str(default_bold)}}
self.assertEqual(mainpage, expected)
changes.clear()
- configure.font_size.set(20)
+ dialog.font_size.set(20)
expected = {'EditorWindow': {'font': 'Test Font',
'font-size': '20',
'font-bold': str(default_bold)}}
self.assertEqual(mainpage, expected)
changes.clear()
- configure.font_bold.set(not default_bold)
+ dialog.font_bold.set(not default_bold)
expected = {'EditorWindow': {'font': 'Test Font',
'font-size': '20',
'font-bold': str(not default_bold)}}
self.assertEqual(mainpage, expected)
- #def test_sample(self): pass # TODO
+ def test_set_sample(self):
+ # Set_font_sample also sets highlight_sample.
+ pass
def test_tabspace(self):
- configure.space_num.set(6)
+ dialog.space_num.set(6)
self.assertEqual(mainpage, {'Indent': {'num-spaces': '6'}})
+class FontSelectTest(unittest.TestCase):
+ # These two functions test that selecting a new font in the
+ # list of fonts changes font_name and calls set_font_sample.
+ # The fontlist widget and on_fontlist_select event handler
+ # are tested here together.
+
+ @classmethod
+ def setUpClass(cls):
+ if dialog.fontlist.size() < 2:
+ cls.skipTest('need at least 2 fonts')
+ dialog.set_font_sample = Func() # Mask instance method.
+
+ @classmethod
+ def tearDownClass(cls):
+ del dialog.set_font_sample # Unmask instance method.
+
+ def setUp(self):
+ dialog.set_font_sample.called = 0
+ changes.clear()
+
+ def test_select_font_key(self):
+ # Up and Down keys should select a new font.
+
+ fontlist = dialog.fontlist
+ fontlist.activate(0)
+ font = dialog.fontlist.get('active')
+
+ # Test Down key.
+ fontlist.focus_force()
+ fontlist.update()
+ fontlist.event_generate('<Key-Down>')
+ fontlist.event_generate('<KeyRelease-Down>')
+
+ down_font = fontlist.get('active')
+ self.assertNotEqual(down_font, font)
+ self.assertIn(dialog.font_name.get(), down_font.lower())
+ self.assertEqual(dialog.set_font_sample.called, 1)
+
+ # Test Up key.
+ fontlist.focus_force()
+ fontlist.update()
+ fontlist.event_generate('<Key-Up>')
+ fontlist.event_generate('<KeyRelease-Up>')
+
+ up_font = fontlist.get('active')
+ self.assertEqual(up_font, font)
+ self.assertIn(dialog.font_name.get(), up_font.lower())
+ self.assertEqual(dialog.set_font_sample.called, 2)
+
+ def test_select_font_mouse(self):
+ # Click on item should select that item.
+
+ fontlist = dialog.fontlist
+ fontlist.activate(0)
+
+ # Select next item in listbox
+ fontlist.focus_force()
+ fontlist.see(1)
+ fontlist.update()
+ x, y, dx, dy = fontlist.bbox(1)
+ x += dx // 2
+ y += dy // 2
+ fontlist.event_generate('<Button-1>', x=x, y=y)
+ fontlist.event_generate('<ButtonRelease-1>', x=x, y=y)
+
+ font1 = fontlist.get(1)
+ select_font = fontlist.get('anchor')
+ self.assertEqual(select_font, font1)
+ self.assertIn(dialog.font_name.get(), font1.lower())
+ self.assertEqual(dialog.set_font_sample.called, 1)
+
+
class HighlightTest(unittest.TestCase):
def setUp(self):
@@ -103,19 +180,19 @@ class GeneralTest(unittest.TestCase):
changes.clear()
def test_startup(self):
- configure.radio_startup_edit.invoke()
+ dialog.radio_startup_edit.invoke()
self.assertEqual(mainpage,
{'General': {'editor-on-startup': '1'}})
def test_autosave(self):
- configure.radio_save_auto.invoke()
+ dialog.radio_save_auto.invoke()
self.assertEqual(mainpage, {'General': {'autosave': '1'}})
def test_editor_size(self):
- configure.entry_win_height.insert(0, '1')
+ dialog.entry_win_height.insert(0, '1')
self.assertEqual(mainpage, {'EditorWindow': {'height': '140'}})
changes.clear()
- configure.entry_win_width.insert(0, '1')
+ dialog.entry_win_width.insert(0, '1')
self.assertEqual(mainpage, {'EditorWindow': {'width': '180'}})
#def test_help_sources(self): pass # TODO