Commit 9b622fb9 authored by Louie Lu's avatar Louie Lu Committed by terryjreedy

bpo-30870: IDLE: Add configdialog fontlist selection unittest (#2666)

Initial patch by Louie Lu.
parent c40ad03b
...@@ -47,7 +47,8 @@ class ConfigDialog(Toplevel): ...@@ -47,7 +47,8 @@ class ConfigDialog(Toplevel):
self.parent = parent self.parent = parent
if _htest: if _htest:
parent.instance_dict = {} parent.instance_dict = {}
self.withdraw() if not _utest:
self.withdraw()
self.configure(borderwidth=5) self.configure(borderwidth=5)
self.title(title or 'IDLE Preferences') self.title(title or 'IDLE Preferences')
...@@ -76,7 +77,6 @@ class ConfigDialog(Toplevel): ...@@ -76,7 +77,6 @@ class ConfigDialog(Toplevel):
self.create_widgets() self.create_widgets()
self.resizable(height=FALSE, width=FALSE) self.resizable(height=FALSE, width=FALSE)
self.transient(parent) self.transient(parent)
self.grab_set()
self.protocol("WM_DELETE_WINDOW", self.cancel) self.protocol("WM_DELETE_WINDOW", self.cancel)
self.fontlist.focus_set() self.fontlist.focus_set()
# XXX Decide whether to keep or delete these key bindings. # XXX Decide whether to keep or delete these key bindings.
...@@ -88,6 +88,7 @@ class ConfigDialog(Toplevel): ...@@ -88,6 +88,7 @@ class ConfigDialog(Toplevel):
self.attach_var_callbacks() # Avoid callbacks during load_configs. self.attach_var_callbacks() # Avoid callbacks during load_configs.
if not _utest: if not _utest:
self.grab_set()
self.wm_deiconify() self.wm_deiconify()
self.wait_window() self.wait_window()
......
...@@ -6,24 +6,25 @@ Attributes and methods will be added as needed for tests. ...@@ -6,24 +6,25 @@ Attributes and methods will be added as needed for tests.
from idlelib.idle_test.mock_tk import Text from idlelib.idle_test.mock_tk import Text
class Func: class Func:
'''Mock function captures args and returns result set by test. '''Record call, capture args, return/raise result set by test.
Attributes: When mock function is called, set or use attributes:
self.called - records call even if no args, kwds passed. self.called - increment call number even if no args, kwds passed.
self.result - set by init, returned by call. self.args - capture positional arguments.
self.args - captures positional arguments. self.kwds - capture keyword arguments.
self.kwds - captures 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. Mock_tk.Var and Mbox_func are special variants of this.
''' '''
def __init__(self, result=None): def __init__(self, result=None):
self.called = False self.called = 0
self.result = result self.result = result
self.args = None self.args = None
self.kwds = None self.kwds = None
def __call__(self, *args, **kwds): def __call__(self, *args, **kwds):
self.called = True self.called += 1
self.args = args self.args = args
self.kwds = kwds self.kwds = kwds
if isinstance(self.result, BaseException): if isinstance(self.result, BaseException):
......
"""Test idlelib.configdialog. """Test idlelib.configdialog.
Half the class creates dialog, half works with user customizations. 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 idlelib.configdialog import ConfigDialog, idleConf, changes
from test.support import requires from test.support import requires
...@@ -9,6 +9,7 @@ requires('gui') ...@@ -9,6 +9,7 @@ requires('gui')
from tkinter import Tk from tkinter import Tk
import unittest import unittest
import idlelib.config as config import idlelib.config as config
from idlelib.idle_test.mock_idle import Func
# Tests should not depend on fortuitous user configurations. # Tests should not depend on fortuitous user configurations.
# They must not affect actual user .cfg files. # They must not affect actual user .cfg files.
...@@ -22,27 +23,29 @@ testcfg = { ...@@ -22,27 +23,29 @@ testcfg = {
} }
root = None root = None
configure = None dialog = None
mainpage = changes['main'] mainpage = changes['main']
highpage = changes['highlight'] highpage = changes['highlight']
keyspage = changes['keys'] keyspage = changes['keys']
class TestDialog(ConfigDialog): pass # Delete?
class TestDialog(ConfigDialog):
pass # Delete?
def setUpModule(): def setUpModule():
global root, configure global root, dialog
idleConf.userCfg = testcfg idleConf.userCfg = testcfg
root = Tk() root = Tk()
root.withdraw() # root.withdraw() # Comment out, see issue 30870
configure = TestDialog(root, 'Test', _utest=True) dialog = TestDialog(root, 'Test', _utest=True)
def tearDownModule(): def tearDownModule():
global root, configure global root, dialog
idleConf.userCfg = usercfg idleConf.userCfg = usercfg
configure.remove_var_callbacks() dialog.remove_var_callbacks()
del configure del dialog
root.update_idletasks() root.update_idletasks()
root.destroy() root.destroy()
del root del root
...@@ -58,31 +61,105 @@ class FontTabTest(unittest.TestCase): ...@@ -58,31 +61,105 @@ class FontTabTest(unittest.TestCase):
default_font = idleConf.GetFont(root, 'main', 'EditorWindow') default_font = idleConf.GetFont(root, 'main', 'EditorWindow')
default_size = str(default_font[1]) default_size = str(default_font[1])
default_bold = default_font[2] == 'bold' default_bold = default_font[2] == 'bold'
configure.font_name.set('Test Font') dialog.font_name.set('Test Font')
expected = {'EditorWindow': {'font': 'Test Font', expected = {'EditorWindow': {'font': 'Test Font',
'font-size': default_size, 'font-size': default_size,
'font-bold': str(default_bold)}} 'font-bold': str(default_bold)}}
self.assertEqual(mainpage, expected) self.assertEqual(mainpage, expected)
changes.clear() changes.clear()
configure.font_size.set(20) dialog.font_size.set(20)
expected = {'EditorWindow': {'font': 'Test Font', expected = {'EditorWindow': {'font': 'Test Font',
'font-size': '20', 'font-size': '20',
'font-bold': str(default_bold)}} 'font-bold': str(default_bold)}}
self.assertEqual(mainpage, expected) self.assertEqual(mainpage, expected)
changes.clear() changes.clear()
configure.font_bold.set(not default_bold) dialog.font_bold.set(not default_bold)
expected = {'EditorWindow': {'font': 'Test Font', expected = {'EditorWindow': {'font': 'Test Font',
'font-size': '20', 'font-size': '20',
'font-bold': str(not default_bold)}} 'font-bold': str(not default_bold)}}
self.assertEqual(mainpage, expected) 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): def test_tabspace(self):
configure.space_num.set(6) dialog.space_num.set(6)
self.assertEqual(mainpage, {'Indent': {'num-spaces': '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): class HighlightTest(unittest.TestCase):
def setUp(self): def setUp(self):
...@@ -103,19 +180,19 @@ class GeneralTest(unittest.TestCase): ...@@ -103,19 +180,19 @@ class GeneralTest(unittest.TestCase):
changes.clear() changes.clear()
def test_startup(self): def test_startup(self):
configure.radio_startup_edit.invoke() dialog.radio_startup_edit.invoke()
self.assertEqual(mainpage, self.assertEqual(mainpage,
{'General': {'editor-on-startup': '1'}}) {'General': {'editor-on-startup': '1'}})
def test_autosave(self): def test_autosave(self):
configure.radio_save_auto.invoke() dialog.radio_save_auto.invoke()
self.assertEqual(mainpage, {'General': {'autosave': '1'}}) self.assertEqual(mainpage, {'General': {'autosave': '1'}})
def test_editor_size(self): 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'}}) self.assertEqual(mainpage, {'EditorWindow': {'height': '140'}})
changes.clear() changes.clear()
configure.entry_win_width.insert(0, '1') dialog.entry_win_width.insert(0, '1')
self.assertEqual(mainpage, {'EditorWindow': {'width': '180'}}) self.assertEqual(mainpage, {'EditorWindow': {'width': '180'}})
#def test_help_sources(self): pass # TODO #def test_help_sources(self): pass # TODO
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment