2016-11-07 18:15:01 -04:00
|
|
|
"""Test idlelib.configdialog.
|
2014-07-15 00:07:32 -03:00
|
|
|
|
2016-11-07 18:15:01 -04:00
|
|
|
Half the class creates dialog, half works with user customizations.
|
2017-07-26 21:54:40 -03:00
|
|
|
Coverage: 63%.
|
2016-11-07 18:15:01 -04:00
|
|
|
"""
|
2017-07-26 21:54:40 -03:00
|
|
|
from idlelib import configdialog
|
2014-07-15 00:07:32 -03:00
|
|
|
from test.support import requires
|
2016-06-04 16:54:44 -03:00
|
|
|
requires('gui')
|
|
|
|
import unittest
|
2017-07-26 20:09:58 -03:00
|
|
|
from unittest import mock
|
2017-07-13 21:35:48 -03:00
|
|
|
from idlelib.idle_test.mock_idle import Func
|
2017-07-26 21:54:40 -03:00
|
|
|
from tkinter import Tk, IntVar, BooleanVar, DISABLED, NORMAL
|
|
|
|
from idlelib import config
|
2017-07-28 18:00:02 -03:00
|
|
|
from idlelib.configdialog import idleConf, changes, tracers
|
2014-07-15 00:07:32 -03:00
|
|
|
|
2016-11-07 18:15:01 -04:00
|
|
|
# Tests should not depend on fortuitous user configurations.
|
|
|
|
# They must not affect actual user .cfg files.
|
|
|
|
# Use solution from test_config: empty parsers with no filename.
|
|
|
|
usercfg = idleConf.userCfg
|
|
|
|
testcfg = {
|
|
|
|
'main': config.IdleUserConfParser(''),
|
|
|
|
'highlight': config.IdleUserConfParser(''),
|
|
|
|
'keys': config.IdleUserConfParser(''),
|
|
|
|
'extensions': config.IdleUserConfParser(''),
|
|
|
|
}
|
2014-07-15 00:07:32 -03:00
|
|
|
|
2017-06-26 18:46:26 -03:00
|
|
|
root = None
|
2017-07-13 21:35:48 -03:00
|
|
|
dialog = None
|
2017-07-07 17:00:57 -03:00
|
|
|
mainpage = changes['main']
|
|
|
|
highpage = changes['highlight']
|
|
|
|
keyspage = changes['keys']
|
2017-06-26 18:46:26 -03:00
|
|
|
|
2016-11-07 18:15:01 -04:00
|
|
|
def setUpModule():
|
2017-07-13 21:35:48 -03:00
|
|
|
global root, dialog
|
2016-11-07 18:15:01 -04:00
|
|
|
idleConf.userCfg = testcfg
|
|
|
|
root = Tk()
|
2017-07-13 21:35:48 -03:00
|
|
|
# root.withdraw() # Comment out, see issue 30870
|
2017-07-28 18:00:02 -03:00
|
|
|
dialog = configdialog.ConfigDialog(root, 'Test', _utest=True)
|
2016-11-07 18:15:01 -04:00
|
|
|
|
|
|
|
def tearDownModule():
|
2017-07-13 21:35:48 -03:00
|
|
|
global root, dialog
|
2017-07-06 23:19:13 -03:00
|
|
|
idleConf.userCfg = usercfg
|
2017-07-28 18:00:02 -03:00
|
|
|
tracers.detach()
|
2017-07-13 21:35:48 -03:00
|
|
|
del dialog
|
2016-11-07 18:15:01 -04:00
|
|
|
root.update_idletasks()
|
|
|
|
root.destroy()
|
|
|
|
del root
|
|
|
|
|
|
|
|
|
2017-07-24 01:18:25 -03:00
|
|
|
class FontTest(unittest.TestCase):
|
|
|
|
"""Test that font widgets enable users to make font changes.
|
2017-07-13 21:35:48 -03:00
|
|
|
|
2017-07-24 01:18:25 -03:00
|
|
|
Test that widget actions set vars, that var changes add three
|
|
|
|
options to changes and call set_samples, and that set_samples
|
|
|
|
changes the font of both sample boxes.
|
|
|
|
"""
|
2017-07-13 21:35:48 -03:00
|
|
|
@classmethod
|
|
|
|
def setUpClass(cls):
|
2017-07-21 03:20:46 -03:00
|
|
|
dialog.set_samples = Func() # Mask instance method.
|
2017-07-13 21:35:48 -03:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def tearDownClass(cls):
|
2017-07-21 03:20:46 -03:00
|
|
|
del dialog.set_samples # Unmask instance method.
|
2017-07-13 21:35:48 -03:00
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
changes.clear()
|
|
|
|
|
2017-07-24 01:18:25 -03:00
|
|
|
def test_load_font_cfg(self):
|
|
|
|
# Leave widget load test to human visual check.
|
|
|
|
# TODO Improve checks when add IdleConf.get_font_values.
|
|
|
|
d = dialog
|
|
|
|
d.font_name.set('Fake')
|
|
|
|
d.font_size.set('1')
|
|
|
|
d.font_bold.set(True)
|
|
|
|
d.set_samples.called = 0
|
|
|
|
d.load_font_cfg()
|
|
|
|
self.assertNotEqual(d.font_name.get(), 'Fake')
|
|
|
|
self.assertNotEqual(d.font_size.get(), '1')
|
|
|
|
self.assertFalse(d.font_bold.get())
|
|
|
|
self.assertEqual(d.set_samples.called, 3)
|
|
|
|
|
|
|
|
def test_fontlist_key(self):
|
2017-07-13 21:35:48 -03:00
|
|
|
# Up and Down keys should select a new font.
|
|
|
|
|
2017-07-24 01:18:25 -03:00
|
|
|
if dialog.fontlist.size() < 2:
|
|
|
|
cls.skipTest('need at least 2 fonts')
|
2017-07-13 21:35:48 -03:00
|
|
|
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())
|
|
|
|
|
|
|
|
# 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())
|
|
|
|
|
2017-07-24 01:18:25 -03:00
|
|
|
def test_fontlist_mouse(self):
|
2017-07-13 21:35:48 -03:00
|
|
|
# Click on item should select that item.
|
|
|
|
|
2017-07-24 01:18:25 -03:00
|
|
|
if dialog.fontlist.size() < 2:
|
|
|
|
cls.skipTest('need at least 2 fonts')
|
2017-07-13 21:35:48 -03:00
|
|
|
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())
|
2017-07-24 01:18:25 -03:00
|
|
|
|
|
|
|
def test_sizelist(self):
|
|
|
|
# Click on number shouod select that number
|
|
|
|
d = dialog
|
|
|
|
d.sizelist.variable.set(40)
|
|
|
|
self.assertEqual(d.font_size.get(), '40')
|
|
|
|
|
|
|
|
def test_bold_toggle(self):
|
|
|
|
# Click on checkbutton should invert it.
|
|
|
|
d = dialog
|
|
|
|
d.font_bold.set(False)
|
|
|
|
d.bold_toggle.invoke()
|
|
|
|
self.assertTrue(d.font_bold.get())
|
|
|
|
d.bold_toggle.invoke()
|
|
|
|
self.assertFalse(d.font_bold.get())
|
|
|
|
|
|
|
|
def test_font_set(self):
|
|
|
|
# Test that setting a font Variable results in 3 provisional
|
|
|
|
# change entries and a call to set_samples. Use values sure to
|
|
|
|
# not be defaults.
|
|
|
|
|
|
|
|
default_font = idleConf.GetFont(root, 'main', 'EditorWindow')
|
|
|
|
default_size = str(default_font[1])
|
|
|
|
default_bold = default_font[2] == 'bold'
|
|
|
|
d = dialog
|
|
|
|
d.font_size.set(default_size)
|
|
|
|
d.font_bold.set(default_bold)
|
|
|
|
d.set_samples.called = 0
|
|
|
|
|
|
|
|
d.font_name.set('Test Font')
|
|
|
|
expected = {'EditorWindow': {'font': 'Test Font',
|
|
|
|
'font-size': default_size,
|
|
|
|
'font-bold': str(default_bold)}}
|
|
|
|
self.assertEqual(mainpage, expected)
|
|
|
|
self.assertEqual(d.set_samples.called, 1)
|
|
|
|
changes.clear()
|
|
|
|
|
|
|
|
d.font_size.set('20')
|
|
|
|
expected = {'EditorWindow': {'font': 'Test Font',
|
|
|
|
'font-size': '20',
|
|
|
|
'font-bold': str(default_bold)}}
|
|
|
|
self.assertEqual(mainpage, expected)
|
|
|
|
self.assertEqual(d.set_samples.called, 2)
|
|
|
|
changes.clear()
|
|
|
|
|
|
|
|
d.font_bold.set(not default_bold)
|
|
|
|
expected = {'EditorWindow': {'font': 'Test Font',
|
|
|
|
'font-size': '20',
|
|
|
|
'font-bold': str(not default_bold)}}
|
|
|
|
self.assertEqual(mainpage, expected)
|
|
|
|
self.assertEqual(d.set_samples.called, 3)
|
|
|
|
|
|
|
|
def test_set_samples(self):
|
|
|
|
d = dialog
|
|
|
|
del d.set_samples # Unmask method for test
|
|
|
|
d.font_sample, d.highlight_sample = {}, {}
|
|
|
|
d.font_name.set('test')
|
|
|
|
d.font_size.set('5')
|
|
|
|
d.font_bold.set(1)
|
|
|
|
expected = {'font': ('test', '5', 'bold')}
|
|
|
|
|
|
|
|
# Test set_samples.
|
|
|
|
d.set_samples()
|
|
|
|
self.assertTrue(d.font_sample == d.highlight_sample == expected)
|
|
|
|
|
|
|
|
del d.font_sample, d.highlight_sample
|
|
|
|
d.set_samples = Func() # Re-mask for other tests.
|
|
|
|
|
|
|
|
|
|
|
|
class IndentTest(unittest.TestCase):
|
|
|
|
|
|
|
|
def test_load_tab_cfg(self):
|
|
|
|
d = dialog
|
|
|
|
d.space_num.set(16)
|
|
|
|
d.load_tab_cfg()
|
|
|
|
self.assertEqual(d.space_num.get(), 4)
|
|
|
|
|
|
|
|
def test_indent_scale(self):
|
|
|
|
changes.clear()
|
|
|
|
dialog.indent_scale.set(26)
|
|
|
|
self.assertEqual(dialog.space_num.get(), 16)
|
|
|
|
self.assertEqual(mainpage, {'Indent': {'num-spaces': '16'}})
|
2017-07-13 21:35:48 -03:00
|
|
|
|
|
|
|
|
2016-11-07 18:15:01 -04:00
|
|
|
class HighlightTest(unittest.TestCase):
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
changes.clear()
|
|
|
|
|
|
|
|
|
|
|
|
class KeysTest(unittest.TestCase):
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
changes.clear()
|
|
|
|
|
|
|
|
|
|
|
|
class GeneralTest(unittest.TestCase):
|
2017-07-26 21:54:40 -03:00
|
|
|
"""Test that general tab widgets enable users to make changes.
|
|
|
|
|
|
|
|
Test that widget actions set vars, that var changes add
|
|
|
|
options to changes and that helplist works correctly.
|
|
|
|
"""
|
|
|
|
@classmethod
|
|
|
|
def setUpClass(cls):
|
|
|
|
# Mask instance methods used by help functions.
|
|
|
|
d = dialog
|
|
|
|
d.set = d.set_add_delete_state = Func()
|
|
|
|
d.upc = d.update_help_changes = Func()
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def tearDownClass(cls):
|
|
|
|
d = dialog
|
|
|
|
del d.set, d.set_add_delete_state
|
|
|
|
del d.upc, d.update_help_changes
|
|
|
|
d.helplist.delete(0, 'end')
|
|
|
|
d.user_helplist.clear()
|
2016-11-07 18:15:01 -04:00
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
changes.clear()
|
|
|
|
|
2017-07-26 21:54:40 -03:00
|
|
|
def test_load_general_cfg(self):
|
|
|
|
# Set to wrong values, load, check right values.
|
|
|
|
eq = self.assertEqual
|
|
|
|
d = dialog
|
|
|
|
d.startup_edit.set(1)
|
|
|
|
d.autosave.set(1)
|
|
|
|
d.win_width.set(1)
|
|
|
|
d.win_height.set(1)
|
|
|
|
d.helplist.insert('end', 'bad')
|
|
|
|
d.user_helplist = ['bad', 'worse']
|
|
|
|
idleConf.SetOption('main', 'HelpFiles', '1', 'name;file')
|
|
|
|
d.load_general_cfg()
|
|
|
|
eq(d.startup_edit.get(), 0)
|
|
|
|
eq(d.autosave.get(), 0)
|
|
|
|
eq(d.win_width.get(), '80')
|
|
|
|
eq(d.win_height.get(), '40')
|
|
|
|
eq(d.helplist.get(0, 'end'), ('name',))
|
|
|
|
eq(d.user_helplist, [('name', 'file', '1')])
|
|
|
|
|
2016-11-07 18:15:01 -04:00
|
|
|
def test_startup(self):
|
2017-07-26 21:54:40 -03:00
|
|
|
dialog.startup_editor_on.invoke()
|
2017-07-07 17:00:57 -03:00
|
|
|
self.assertEqual(mainpage,
|
|
|
|
{'General': {'editor-on-startup': '1'}})
|
2017-07-26 21:54:40 -03:00
|
|
|
changes.clear()
|
|
|
|
dialog.startup_shell_on.invoke()
|
|
|
|
self.assertEqual(mainpage,
|
|
|
|
{'General': {'editor-on-startup': '0'}})
|
2016-11-07 18:15:01 -04:00
|
|
|
|
|
|
|
def test_autosave(self):
|
2017-07-26 21:54:40 -03:00
|
|
|
dialog.save_auto_on.invoke()
|
2017-07-07 17:00:57 -03:00
|
|
|
self.assertEqual(mainpage, {'General': {'autosave': '1'}})
|
2017-07-26 21:54:40 -03:00
|
|
|
dialog.save_ask_on.invoke()
|
|
|
|
self.assertEqual(mainpage, {'General': {'autosave': '0'}})
|
2016-11-07 18:15:01 -04:00
|
|
|
|
|
|
|
def test_editor_size(self):
|
2017-07-26 21:54:40 -03:00
|
|
|
dialog.win_height_int.insert(0, '1')
|
2017-07-07 17:00:57 -03:00
|
|
|
self.assertEqual(mainpage, {'EditorWindow': {'height': '140'}})
|
2016-11-07 18:15:01 -04:00
|
|
|
changes.clear()
|
2017-07-26 21:54:40 -03:00
|
|
|
dialog.win_width_int.insert(0, '1')
|
2017-07-07 17:00:57 -03:00
|
|
|
self.assertEqual(mainpage, {'EditorWindow': {'width': '180'}})
|
2016-11-07 18:15:01 -04:00
|
|
|
|
2017-07-26 21:54:40 -03:00
|
|
|
def test_source_selected(self):
|
|
|
|
d = dialog
|
|
|
|
d.set = d.set_add_delete_state
|
|
|
|
d.upc = d.update_help_changes
|
|
|
|
helplist = d.helplist
|
2017-07-29 01:49:39 -03:00
|
|
|
dex = 'end'
|
|
|
|
helplist.insert(dex, 'source')
|
|
|
|
helplist.activate(dex)
|
2017-07-26 21:54:40 -03:00
|
|
|
|
|
|
|
helplist.focus_force()
|
2017-07-29 01:49:39 -03:00
|
|
|
helplist.see(dex)
|
2017-07-26 21:54:40 -03:00
|
|
|
helplist.update()
|
2017-07-29 01:49:39 -03:00
|
|
|
x, y, dx, dy = helplist.bbox(dex)
|
2017-07-26 21:54:40 -03:00
|
|
|
x += dx // 2
|
|
|
|
y += dy // 2
|
|
|
|
d.set.called = d.upc.called = 0
|
2017-07-29 01:49:39 -03:00
|
|
|
helplist.event_generate('<Enter>', x=0, y=0)
|
|
|
|
helplist.event_generate('<Motion>', x=x, y=y)
|
2017-07-26 21:54:40 -03:00
|
|
|
helplist.event_generate('<Button-1>', x=x, y=y)
|
|
|
|
helplist.event_generate('<ButtonRelease-1>', x=x, y=y)
|
2017-07-29 01:49:39 -03:00
|
|
|
# The following fail after the switch to
|
|
|
|
# self.assertEqual(helplist.get('anchor'), 'source')
|
|
|
|
# self.assertTrue(d.set.called)
|
2017-07-26 21:54:40 -03:00
|
|
|
self.assertFalse(d.upc.called)
|
|
|
|
|
|
|
|
def test_set_add_delete_state(self):
|
|
|
|
# Call with 0 items, 1 unselected item, 1 selected item.
|
|
|
|
eq = self.assertEqual
|
|
|
|
d = dialog
|
|
|
|
del d.set_add_delete_state # Unmask method.
|
|
|
|
sad = d.set_add_delete_state
|
|
|
|
h = d.helplist
|
|
|
|
|
|
|
|
h.delete(0, 'end')
|
|
|
|
sad()
|
|
|
|
eq(d.button_helplist_edit['state'], DISABLED)
|
|
|
|
eq(d.button_helplist_remove['state'], DISABLED)
|
|
|
|
|
|
|
|
h.insert(0, 'source')
|
|
|
|
sad()
|
|
|
|
eq(d.button_helplist_edit['state'], DISABLED)
|
|
|
|
eq(d.button_helplist_remove['state'], DISABLED)
|
|
|
|
|
|
|
|
h.selection_set(0)
|
|
|
|
sad()
|
|
|
|
eq(d.button_helplist_edit['state'], NORMAL)
|
|
|
|
eq(d.button_helplist_remove['state'], NORMAL)
|
|
|
|
d.set_add_delete_state = Func() # Mask method.
|
|
|
|
|
|
|
|
def test_helplist_item_add(self):
|
|
|
|
# Call without and twice with HelpSource result.
|
|
|
|
# Double call enables check on order.
|
|
|
|
eq = self.assertEqual
|
|
|
|
orig_helpsource = configdialog.HelpSource
|
|
|
|
hs = configdialog.HelpSource = Func(return_self=True)
|
|
|
|
d = dialog
|
|
|
|
d.helplist.delete(0, 'end')
|
|
|
|
d.user_helplist.clear()
|
|
|
|
d.set.called = d.upc.called = 0
|
|
|
|
|
|
|
|
hs.result = ''
|
|
|
|
d.helplist_item_add()
|
|
|
|
self.assertTrue(list(d.helplist.get(0, 'end')) ==
|
|
|
|
d.user_helplist == [])
|
|
|
|
self.assertFalse(d.upc.called)
|
|
|
|
|
|
|
|
hs.result = ('name1', 'file1')
|
|
|
|
d.helplist_item_add()
|
|
|
|
hs.result = ('name2', 'file2')
|
|
|
|
d.helplist_item_add()
|
|
|
|
eq(d.helplist.get(0, 'end'), ('name1', 'name2'))
|
|
|
|
eq(d.user_helplist, [('name1', 'file1'), ('name2', 'file2')])
|
|
|
|
eq(d.upc.called, 2)
|
|
|
|
self.assertFalse(d.set.called)
|
|
|
|
|
|
|
|
configdialog.HelpSource = orig_helpsource
|
|
|
|
|
|
|
|
def test_helplist_item_edit(self):
|
|
|
|
# Call without and with HelpSource change.
|
|
|
|
eq = self.assertEqual
|
|
|
|
orig_helpsource = configdialog.HelpSource
|
|
|
|
hs = configdialog.HelpSource = Func(return_self=True)
|
|
|
|
d = dialog
|
|
|
|
d.helplist.delete(0, 'end')
|
|
|
|
d.helplist.insert(0, 'name1')
|
|
|
|
d.helplist.selection_set(0)
|
|
|
|
d.helplist.selection_anchor(0)
|
|
|
|
d.user_helplist.clear()
|
|
|
|
d.user_helplist.append(('name1', 'file1'))
|
|
|
|
d.set.called = d.upc.called = 0
|
|
|
|
|
|
|
|
hs.result = ''
|
|
|
|
d.helplist_item_edit()
|
|
|
|
hs.result = ('name1', 'file1')
|
|
|
|
d.helplist_item_edit()
|
|
|
|
eq(d.helplist.get(0, 'end'), ('name1',))
|
|
|
|
eq(d.user_helplist, [('name1', 'file1')])
|
|
|
|
self.assertFalse(d.upc.called)
|
|
|
|
|
|
|
|
hs.result = ('name2', 'file2')
|
|
|
|
d.helplist_item_edit()
|
|
|
|
eq(d.helplist.get(0, 'end'), ('name2',))
|
|
|
|
eq(d.user_helplist, [('name2', 'file2')])
|
|
|
|
self.assertTrue(d.upc.called == d.set.called == 1)
|
|
|
|
|
|
|
|
configdialog.HelpSource = orig_helpsource
|
|
|
|
|
|
|
|
def test_helplist_item_remove(self):
|
|
|
|
eq = self.assertEqual
|
|
|
|
d = dialog
|
|
|
|
d.helplist.delete(0, 'end')
|
|
|
|
d.helplist.insert(0, 'name1')
|
|
|
|
d.helplist.selection_set(0)
|
|
|
|
d.helplist.selection_anchor(0)
|
|
|
|
d.user_helplist.clear()
|
|
|
|
d.user_helplist.append(('name1', 'file1'))
|
|
|
|
d.set.called = d.upc.called = 0
|
|
|
|
|
|
|
|
d.helplist_item_remove()
|
|
|
|
eq(d.helplist.get(0, 'end'), ())
|
|
|
|
eq(d.user_helplist, [])
|
|
|
|
self.assertTrue(d.upc.called == d.set.called == 1)
|
|
|
|
|
|
|
|
def test_update_help_changes(self):
|
|
|
|
d = dialog
|
|
|
|
del d.update_help_changes
|
|
|
|
d.user_helplist.clear()
|
|
|
|
d.user_helplist.append(('name1', 'file1'))
|
|
|
|
d.user_helplist.append(('name2', 'file2'))
|
|
|
|
|
|
|
|
d.update_help_changes()
|
|
|
|
self.assertEqual(mainpage['HelpFiles'],
|
|
|
|
{'1': 'name1;file1', '2': 'name2;file2'})
|
|
|
|
d.update_help_changes = Func()
|
2014-07-15 00:07:32 -03:00
|
|
|
|
|
|
|
|
2017-07-28 18:00:02 -03:00
|
|
|
class VarTraceTest(unittest.TestCase):
|
2017-07-26 20:09:58 -03:00
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
changes.clear()
|
2017-07-28 18:00:02 -03:00
|
|
|
tracers.clear()
|
2017-07-26 20:09:58 -03:00
|
|
|
self.v1 = IntVar(root)
|
|
|
|
self.v2 = BooleanVar(root)
|
|
|
|
self.called = 0
|
|
|
|
|
|
|
|
def tearDown(self):
|
|
|
|
del self.v1, self.v2
|
|
|
|
|
|
|
|
def var_changed_increment(self, *params):
|
|
|
|
self.called += 13
|
|
|
|
|
|
|
|
def var_changed_boolean(self, *params):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def test_init(self):
|
2017-07-28 18:00:02 -03:00
|
|
|
tracers.__init__()
|
|
|
|
self.assertEqual(tracers.untraced, [])
|
|
|
|
self.assertEqual(tracers.traced, [])
|
|
|
|
|
|
|
|
def test_clear(self):
|
|
|
|
tracers.untraced.append(0)
|
|
|
|
tracers.traced.append(1)
|
|
|
|
tracers.clear()
|
|
|
|
self.assertEqual(tracers.untraced, [])
|
|
|
|
self.assertEqual(tracers.traced, [])
|
2017-07-26 20:09:58 -03:00
|
|
|
|
|
|
|
def test_add(self):
|
2017-07-28 18:00:02 -03:00
|
|
|
tr = tracers
|
2017-07-26 20:09:58 -03:00
|
|
|
func = Func()
|
|
|
|
cb = tr.make_callback = mock.Mock(return_value=func)
|
|
|
|
|
|
|
|
v1 = tr.add(self.v1, self.var_changed_increment)
|
|
|
|
self.assertIsInstance(v1, IntVar)
|
|
|
|
v2 = tr.add(self.v2, self.var_changed_boolean)
|
|
|
|
self.assertIsInstance(v2, BooleanVar)
|
|
|
|
|
|
|
|
v3 = IntVar(root)
|
|
|
|
v3 = tr.add(v3, ('main', 'section', 'option'))
|
|
|
|
cb.assert_called_once()
|
|
|
|
cb.assert_called_with(v3, ('main', 'section', 'option'))
|
|
|
|
|
|
|
|
expected = [(v1, self.var_changed_increment),
|
|
|
|
(v2, self.var_changed_boolean),
|
|
|
|
(v3, func)]
|
|
|
|
self.assertEqual(tr.traced, [])
|
|
|
|
self.assertEqual(tr.untraced, expected)
|
|
|
|
|
|
|
|
del tr.make_callback
|
|
|
|
|
|
|
|
def test_make_callback(self):
|
2017-07-28 18:00:02 -03:00
|
|
|
cb = tracers.make_callback(self.v1, ('main', 'section', 'option'))
|
2017-07-26 20:09:58 -03:00
|
|
|
self.assertTrue(callable(cb))
|
|
|
|
self.v1.set(42)
|
|
|
|
# Not attached, so set didn't invoke the callback.
|
|
|
|
self.assertNotIn('section', changes['main'])
|
|
|
|
# Invoke callback manually.
|
|
|
|
cb()
|
|
|
|
self.assertIn('section', changes['main'])
|
|
|
|
self.assertEqual(changes['main']['section']['option'], '42')
|
|
|
|
|
|
|
|
def test_attach_detach(self):
|
2017-07-28 18:00:02 -03:00
|
|
|
tr = tracers
|
2017-07-26 20:09:58 -03:00
|
|
|
v1 = tr.add(self.v1, self.var_changed_increment)
|
|
|
|
v2 = tr.add(self.v2, self.var_changed_boolean)
|
|
|
|
expected = [(v1, self.var_changed_increment),
|
|
|
|
(v2, self.var_changed_boolean)]
|
|
|
|
|
|
|
|
# Attach callbacks and test call increment.
|
|
|
|
tr.attach()
|
|
|
|
self.assertEqual(tr.untraced, [])
|
|
|
|
self.assertCountEqual(tr.traced, expected)
|
|
|
|
v1.set(1)
|
|
|
|
self.assertEqual(v1.get(), 1)
|
|
|
|
self.assertEqual(self.called, 13)
|
|
|
|
|
|
|
|
# Check that only one callback is attached to a variable.
|
|
|
|
# If more than one callback were attached, then var_changed_increment
|
|
|
|
# would be called twice and the counter would be 2.
|
|
|
|
self.called = 0
|
|
|
|
tr.attach()
|
|
|
|
v1.set(1)
|
|
|
|
self.assertEqual(self.called, 13)
|
|
|
|
|
|
|
|
# Detach callbacks.
|
|
|
|
self.called = 0
|
|
|
|
tr.detach()
|
|
|
|
self.assertEqual(tr.traced, [])
|
|
|
|
self.assertCountEqual(tr.untraced, expected)
|
|
|
|
v1.set(1)
|
|
|
|
self.assertEqual(self.called, 0)
|
|
|
|
|
|
|
|
|
2014-07-15 00:07:32 -03:00
|
|
|
if __name__ == '__main__':
|
|
|
|
unittest.main(verbosity=2)
|