summaryrefslogtreecommitdiffstats
path: root/Lib/idlelib/idle_test
diff options
context:
space:
mode:
authorTal Einat <taleinat+github@gmail.com>2018-08-05 06:21:08 (GMT)
committerGitHub <noreply@github.com>2018-08-05 06:21:08 (GMT)
commit87e59ac11ee074b0dc1bc864c74fac0660b27f6e (patch)
tree997de582df11483d05e0d70c3e38a7ec6cf8d0fe /Lib/idlelib/idle_test
parent2e5566d9e774dcde81e8139b486730917816e045 (diff)
downloadcpython-87e59ac11ee074b0dc1bc864c74fac0660b27f6e.zip
cpython-87e59ac11ee074b0dc1bc864c74fac0660b27f6e.tar.gz
cpython-87e59ac11ee074b0dc1bc864c74fac0660b27f6e.tar.bz2
bpo-33839: refactor IDLE's tooltips & calltips, add docstrings and tests (GH-7683)
* make CallTip and ToolTip sub-classes of a common abstract base class * remove ListboxToolTip (unused and ugly) * greatly increase test coverage * tested on Windows, Linux and macOS
Diffstat (limited to 'Lib/idlelib/idle_test')
-rw-r--r--Lib/idlelib/idle_test/htest.py3
-rw-r--r--Lib/idlelib/idle_test/test_calltip_w.py2
-rw-r--r--Lib/idlelib/idle_test/test_tooltip.py146
3 files changed, 150 insertions, 1 deletions
diff --git a/Lib/idlelib/idle_test/htest.py b/Lib/idlelib/idle_test/htest.py
index 95f6274..03bee51 100644
--- a/Lib/idlelib/idle_test/htest.py
+++ b/Lib/idlelib/idle_test/htest.py
@@ -80,11 +80,14 @@ AboutDialog_spec = {
"are correctly displayed.\n [Close] to exit.",
}
+# TODO implement ^\; adding '<Control-Key-\\>' to function does not work.
_calltip_window_spec = {
'file': 'calltip_w',
'kwds': {},
'msg': "Typing '(' should display a calltip.\n"
"Typing ') should hide the calltip.\n"
+ "So should moving cursor out of argument area.\n"
+ "Force-open-calltip does not work here.\n"
}
_module_browser_spec = {
diff --git a/Lib/idlelib/idle_test/test_calltip_w.py b/Lib/idlelib/idle_test/test_calltip_w.py
index 59e6967..a5ec76e 100644
--- a/Lib/idlelib/idle_test/test_calltip_w.py
+++ b/Lib/idlelib/idle_test/test_calltip_w.py
@@ -23,7 +23,7 @@ class CallTipWindowTest(unittest.TestCase):
del cls.text, cls.root
def test_init(self):
- self.assertEqual(self.calltip.widget, self.text)
+ self.assertEqual(self.calltip.anchor_widget, self.text)
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/Lib/idlelib/idle_test/test_tooltip.py b/Lib/idlelib/idle_test/test_tooltip.py
new file mode 100644
index 0000000..44ea111
--- /dev/null
+++ b/Lib/idlelib/idle_test/test_tooltip.py
@@ -0,0 +1,146 @@
+from idlelib.tooltip import TooltipBase, Hovertip
+from test.support import requires
+requires('gui')
+
+from functools import wraps
+import time
+from tkinter import Button, Tk, Toplevel
+import unittest
+
+
+def setUpModule():
+ global root
+ root = Tk()
+
+def root_update():
+ global root
+ root.update()
+
+def tearDownModule():
+ global root
+ root.update_idletasks()
+ root.destroy()
+ del root
+
+def add_call_counting(func):
+ @wraps(func)
+ def wrapped_func(*args, **kwargs):
+ wrapped_func.call_args_list.append((args, kwargs))
+ return func(*args, **kwargs)
+ wrapped_func.call_args_list = []
+ return wrapped_func
+
+
+def _make_top_and_button(testobj):
+ global root
+ top = Toplevel(root)
+ testobj.addCleanup(top.destroy)
+ top.title("Test tooltip")
+ button = Button(top, text='ToolTip test button')
+ button.pack()
+ testobj.addCleanup(button.destroy)
+ top.lift()
+ return top, button
+
+
+class ToolTipBaseTest(unittest.TestCase):
+ def setUp(self):
+ self.top, self.button = _make_top_and_button(self)
+
+ def test_base_class_is_unusable(self):
+ global root
+ top = Toplevel(root)
+ self.addCleanup(top.destroy)
+
+ button = Button(top, text='ToolTip test button')
+ button.pack()
+ self.addCleanup(button.destroy)
+
+ with self.assertRaises(NotImplementedError):
+ tooltip = TooltipBase(button)
+ tooltip.showtip()
+
+
+class HovertipTest(unittest.TestCase):
+ def setUp(self):
+ self.top, self.button = _make_top_and_button(self)
+
+ def test_showtip(self):
+ tooltip = Hovertip(self.button, 'ToolTip text')
+ self.addCleanup(tooltip.hidetip)
+ self.assertFalse(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ tooltip.showtip()
+ self.assertTrue(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+
+ def test_showtip_twice(self):
+ tooltip = Hovertip(self.button, 'ToolTip text')
+ self.addCleanup(tooltip.hidetip)
+ self.assertFalse(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ tooltip.showtip()
+ self.assertTrue(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ orig_tipwindow = tooltip.tipwindow
+ tooltip.showtip()
+ self.assertTrue(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ self.assertIs(tooltip.tipwindow, orig_tipwindow)
+
+ def test_hidetip(self):
+ tooltip = Hovertip(self.button, 'ToolTip text')
+ self.addCleanup(tooltip.hidetip)
+ tooltip.showtip()
+ tooltip.hidetip()
+ self.assertFalse(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+
+ def test_showtip_on_mouse_enter_no_delay(self):
+ tooltip = Hovertip(self.button, 'ToolTip text', hover_delay=None)
+ self.addCleanup(tooltip.hidetip)
+ tooltip.showtip = add_call_counting(tooltip.showtip)
+ root_update()
+ self.assertFalse(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ self.button.event_generate('<Enter>', x=0, y=0)
+ root_update()
+ self.assertTrue(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ self.assertGreater(len(tooltip.showtip.call_args_list), 0)
+
+ def test_showtip_on_mouse_enter_hover_delay(self):
+ tooltip = Hovertip(self.button, 'ToolTip text', hover_delay=50)
+ self.addCleanup(tooltip.hidetip)
+ tooltip.showtip = add_call_counting(tooltip.showtip)
+ root_update()
+ self.assertFalse(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ self.button.event_generate('<Enter>', x=0, y=0)
+ root_update()
+ self.assertFalse(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ time.sleep(0.1)
+ root_update()
+ self.assertTrue(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ self.assertGreater(len(tooltip.showtip.call_args_list), 0)
+
+ def test_hidetip_on_mouse_leave(self):
+ tooltip = Hovertip(self.button, 'ToolTip text', hover_delay=None)
+ self.addCleanup(tooltip.hidetip)
+ tooltip.showtip = add_call_counting(tooltip.showtip)
+ root_update()
+ self.button.event_generate('<Enter>', x=0, y=0)
+ root_update()
+ self.button.event_generate('<Leave>', x=0, y=0)
+ root_update()
+ self.assertFalse(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ self.assertGreater(len(tooltip.showtip.call_args_list), 0)
+
+ def test_dont_show_on_mouse_leave_before_delay(self):
+ tooltip = Hovertip(self.button, 'ToolTip text', hover_delay=50)
+ self.addCleanup(tooltip.hidetip)
+ tooltip.showtip = add_call_counting(tooltip.showtip)
+ root_update()
+ self.button.event_generate('<Enter>', x=0, y=0)
+ root_update()
+ self.button.event_generate('<Leave>', x=0, y=0)
+ root_update()
+ time.sleep(0.1)
+ root_update()
+ self.assertFalse(tooltip.tipwindow and tooltip.tipwindow.winfo_viewable())
+ self.assertEqual(tooltip.showtip.call_args_list, [])
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)