summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/idlelib/SearchDialogBase.py25
-rw-r--r--Lib/idlelib/idle_test/test_searchdialogbase.py198
2 files changed, 213 insertions, 10 deletions
diff --git a/Lib/idlelib/SearchDialogBase.py b/Lib/idlelib/SearchDialogBase.py
index d258973..f0d7d51 100644
--- a/Lib/idlelib/SearchDialogBase.py
+++ b/Lib/idlelib/SearchDialogBase.py
@@ -16,10 +16,12 @@ class SearchDialogBase:
(make_button, create_command_buttons).
These are bound to functions that execute the command.
- Except for command buttons, this base class is not limited to
- items common to all three subclasses. Rather, it is the Find dialog
- minus the "Find Next" command and its execution function.
- The other dialogs override methods to replace and add widgets.
+ Except for command buttons, this base class is not limited to items
+ common to all three subclasses. Rather, it is the Find dialog minus
+ the "Find Next" command, its execution function, and the
+ default_command attribute needed in create_widgets. The other
+ dialogs override attributes and methods, the latter to replace and
+ add widgets.
'''
title = "Search Dialog" # replace in subclasses
@@ -30,9 +32,10 @@ class SearchDialogBase:
'''Initialize root, engine, and top attributes.
top (level widget): set in create_widgets() called from open().
- text (Text being searched): set in open(), only used in subclasses().
+ text (Text searched): set in open(), only used in subclasses().
ent (ry): created in make_entry() called from create_entry().
row (of grid): 0 in create_widgets(), +1 in make_entry/frame().
+ default_command: set in subclasses, used in create_widgers().
title (of dialog): class attribute, override in subclasses.
icon (of dialog): ditto, use unclear if cannot minimize dialog.
@@ -93,25 +96,27 @@ class SearchDialogBase:
e = Entry(self.top, textvariable=var, exportselection=0)
e.grid(row=self.row, column=1, sticky="nwe")
self.row = self.row + 1
- return e
+ return l, e # return label for testing
def create_entries(self):
"Create one or more entry lines with make_entry."
- self.ent = self.make_entry("Find:", self.engine.patvar)
+ self.ent = self.make_entry("Find:", self.engine.patvar)[1]
def make_frame(self,labeltext=None):
"Return gridded labeled Frame for option or other buttons."
if labeltext:
l = Label(self.top, text=labeltext)
l.grid(row=self.row, column=0, sticky="nw")
+ else:
+ l = ''
f = Frame(self.top)
f.grid(row=self.row, column=1, columnspan=1, sticky="nwe")
self.row = self.row + 1
- return f
+ return l, f
def create_option_buttons(self):
"Fill frame with Checkbuttons bound to SearchEngine booleanvars."
- f = self.make_frame("Options")
+ f = self.make_frame("Options")[1]
btn = Checkbutton(f, anchor="w",
variable=self.engine.revar,
@@ -144,7 +149,7 @@ class SearchDialogBase:
def create_other_buttons(self):
"Fill frame with buttons tied to other options."
- f = self.make_frame("Direction")
+ f = self.make_frame("Direction")[1]
btn = Radiobutton(f, anchor="w",
variable=self.engine.backvar, value=1,
diff --git a/Lib/idlelib/idle_test/test_searchdialogbase.py b/Lib/idlelib/idle_test/test_searchdialogbase.py
new file mode 100644
index 0000000..df71ba3
--- /dev/null
+++ b/Lib/idlelib/idle_test/test_searchdialogbase.py
@@ -0,0 +1,198 @@
+'''Unittests for idlelib/SearchDialogBase.py
+
+Coverage: 99%. The only thing not covered is inconsequential --
+testing skipping of suite when self.needwrapbutton is false.
+
+'''
+import unittest
+from test.support import requires
+from tkinter import Tk, Toplevel, Frame, Label, BooleanVar, StringVar
+from idlelib import SearchEngine as se
+from idlelib import SearchDialogBase as sdb
+from idlelib.idle_test.mock_idle import Func
+from idlelib.idle_test.mock_tk import Var, Mbox
+
+# The following could help make some tests gui-free.
+# However, they currently make radiobutton tests fail.
+##def setUpModule():
+## # Replace tk objects used to initialize se.SearchEngine.
+## se.BooleanVar = Var
+## se.StringVar = Var
+##
+##def tearDownModule():
+## se.BooleanVar = BooleanVar
+## se.StringVar = StringVar
+
+class SearchDialogBaseTest(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ requires('gui')
+ cls.root = Tk()
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.root.destroy()
+ del cls.root
+
+ def setUp(self):
+ self.engine = se.SearchEngine(self.root) # None also seems to work
+ self.dialog = sdb.SearchDialogBase(root=self.root, engine=self.engine)
+
+ def tearDown(self):
+ self.dialog.close()
+
+ def test_open_and_close(self):
+ # open calls create_widgets, which needs default_command
+ self.dialog.default_command = None
+
+ # Since text parameter of .open is not used in base class,
+ # pass dummy 'text' instead of tk.Text().
+ self.dialog.open('text')
+ self.assertEqual(self.dialog.top.state(), 'normal')
+ self.dialog.close()
+ self.assertEqual(self.dialog.top.state(), 'withdrawn')
+
+ self.dialog.open('text', searchphrase="hello")
+ self.assertEqual(self.dialog.ent.get(), 'hello')
+ self.dialog.close()
+
+ def test_create_widgets(self):
+ self.dialog.create_entries = Func()
+ self.dialog.create_option_buttons = Func()
+ self.dialog.create_other_buttons = Func()
+ self.dialog.create_command_buttons = Func()
+
+ self.dialog.default_command = None
+ self.dialog.create_widgets()
+
+ self.assertTrue(self.dialog.create_entries.called)
+ self.assertTrue(self.dialog.create_option_buttons.called)
+ self.assertTrue(self.dialog.create_other_buttons.called)
+ self.assertTrue(self.dialog.create_command_buttons.called)
+
+ def test_make_entry(self):
+ equal = self.assertEqual
+ self.dialog.row = 0
+ self.dialog.top = Toplevel(self.root)
+ label, entry = self.dialog.make_entry("Test:", 'hello')
+ equal(label.cget('text'), 'Test:')
+
+ self.assertIn(entry.get(), 'hello')
+ egi = entry.grid_info()
+ equal(egi['row'], 0)
+ equal(egi['column'], 1)
+ equal(egi['rowspan'], 1)
+ equal(egi['columnspan'], 1)
+ equal(self.dialog.row, 1)
+
+ def test_create_entries(self):
+ self.dialog.row = 0
+ self.engine.setpat('hello')
+ self.dialog.create_entries()
+ self.assertIn(self.dialog.ent.get(), 'hello')
+
+ def test_make_frame(self):
+ self.dialog.row = 0
+ self.dialog.top = Toplevel(self.root)
+ label, frame = self.dialog.make_frame()
+ self.assertEqual(label, '')
+ self.assertIsInstance(frame, Frame)
+
+ label, labelledframe = self.dialog.make_frame('testlabel')
+ self.assertEqual(label.cget('text'), 'testlabel')
+ self.assertIsInstance(labelledframe, Frame)
+
+ def btn_test_setup(self, which):
+ self.dialog.row = 0
+ self.dialog.top = Toplevel(self.root)
+ if which == 'option':
+ self.dialog.create_option_buttons()
+ elif which == 'other':
+ self.dialog.create_other_buttons()
+ else:
+ raise ValueError('bad which arg %s' % which)
+
+ def test_create_option_buttons(self):
+ self.btn_test_setup('option')
+ self.checkboxtests()
+
+ def test_create_option_buttons_flipped(self):
+ for var in ('revar', 'casevar', 'wordvar', 'wrapvar'):
+ Var = getattr(self.engine, var)
+ Var.set(not Var.get())
+ self.btn_test_setup('option')
+ self.checkboxtests(flip=1)
+
+ def checkboxtests(self, flip=0):
+ """Tests the four checkboxes in the search dialog window."""
+ engine = self.engine
+ for child in self.dialog.top.winfo_children():
+ for grandchild in child.winfo_children():
+ text = grandchild.config()['text'][-1]
+ if text == ('Regular', 'expression'):
+ self.btnstatetest(grandchild, engine.revar, flip)
+ elif text == ('Match', 'case'):
+ self.btnstatetest(grandchild, engine.casevar, flip)
+ elif text == ('Whole', 'word'):
+ self.btnstatetest(grandchild, engine.wordvar, flip)
+ elif text == ('Wrap', 'around'):
+ self.btnstatetest(grandchild, engine.wrapvar, not flip)
+
+ def btnstatetest(self, button, var, defaultstate):
+ self.assertEqual(var.get(), defaultstate)
+ if defaultstate == 1:
+ button.deselect()
+ else:
+ button.select()
+ self.assertEqual(var.get(), 1 - defaultstate)
+
+ def test_create_other_buttons(self):
+ self.btn_test_setup('other')
+ self.radiobuttontests()
+
+ def test_create_other_buttons_flipped(self):
+ self.engine.backvar.set(1)
+ self.btn_test_setup('other')
+ self.radiobuttontests(back=1)
+
+ def radiobuttontests(self, back=0):
+ searchupbtn = None
+ searchdownbtn = None
+
+ for child in self.dialog.top.winfo_children():
+ for grandchild in child.children.values():
+ text = grandchild.config()['text'][-1]
+ if text == 'Up':
+ searchupbtn = grandchild
+ elif text == 'Down':
+ searchdownbtn = grandchild
+
+ # Defaults to searching downward
+ self.assertEqual(self.engine.backvar.get(), back)
+ if back:
+ searchdownbtn.select()
+ else:
+ searchupbtn.select()
+ self.assertEqual(self.engine.backvar.get(), not back)
+ searchdownbtn.select()
+
+ def test_make_button(self):
+ self.dialog.top = Toplevel(self.root)
+ self.dialog.buttonframe = Frame(self.dialog.top)
+ btn = self.dialog.make_button('Test', self.dialog.close)
+ self.assertEqual(btn.cget('text'), 'Test')
+
+ def test_create_command_buttons(self):
+ self.dialog.create_command_buttons()
+ # Look for close button command in buttonframe
+ closebuttoncommand = ''
+ for child in self.dialog.buttonframe.winfo_children():
+ if child.config()['text'][-1] == 'close':
+ closebuttoncommand = child.config()['command'][-1]
+ self.assertIn('close', closebuttoncommand)
+
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2, exit=2)