Coverage for idle_test/test_tooltip.py: 2%
114 statements
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-11 13:22 -0700
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-11 13:22 -0700
1"""Test tooltip, coverage 100%.
3Coverage is 100% after excluding 6 lines with "# pragma: no cover".
4They involve TclErrors that either should or should not happen in a
5particular situation, and which are 'pass'ed if they do.
6"""
8from idlelib.tooltip import TooltipBase, Hovertip
9from test.support import requires
10requires('gui')
12from functools import wraps
13import time
14from tkinter import Button, Tk, Toplevel
15import unittest
18def setUpModule():
19 global root
20 root = Tk()
22def tearDownModule():
23 global root
24 root.update_idletasks()
25 root.destroy()
26 del root
29def add_call_counting(func):
30 @wraps(func)
31 def wrapped_func(*args, **kwargs):
32 wrapped_func.call_args_list.append((args, kwargs))
33 return func(*args, **kwargs)
34 wrapped_func.call_args_list = []
35 return wrapped_func
38def _make_top_and_button(testobj):
39 global root
40 top = Toplevel(root)
41 testobj.addCleanup(top.destroy)
42 top.title("Test tooltip")
43 button = Button(top, text='ToolTip test button')
44 button.pack()
45 testobj.addCleanup(button.destroy)
46 top.lift()
47 return top, button
50class ToolTipBaseTest(unittest.TestCase):
51 def setUp(self):
52 self.top, self.button = _make_top_and_button(self)
54 def test_base_class_is_unusable(self):
55 global root
56 top = Toplevel(root)
57 self.addCleanup(top.destroy)
59 button = Button(top, text='ToolTip test button')
60 button.pack()
61 self.addCleanup(button.destroy)
63 with self.assertRaises(NotImplementedError):
64 tooltip = TooltipBase(button)
65 tooltip.showtip()
68class HovertipTest(unittest.TestCase):
69 def setUp(self):
70 self.top, self.button = _make_top_and_button(self)
72 def is_tipwindow_shown(self, tooltip):
73 return tooltip.tipwindow and tooltip.tipwindow.winfo_viewable()
75 def test_showtip(self):
76 tooltip = Hovertip(self.button, 'ToolTip text')
77 self.addCleanup(tooltip.hidetip)
78 self.assertFalse(self.is_tipwindow_shown(tooltip))
79 tooltip.showtip()
80 self.assertTrue(self.is_tipwindow_shown(tooltip))
82 def test_showtip_twice(self):
83 tooltip = Hovertip(self.button, 'ToolTip text')
84 self.addCleanup(tooltip.hidetip)
85 self.assertFalse(self.is_tipwindow_shown(tooltip))
86 tooltip.showtip()
87 self.assertTrue(self.is_tipwindow_shown(tooltip))
88 orig_tipwindow = tooltip.tipwindow
89 tooltip.showtip()
90 self.assertTrue(self.is_tipwindow_shown(tooltip))
91 self.assertIs(tooltip.tipwindow, orig_tipwindow)
93 def test_hidetip(self):
94 tooltip = Hovertip(self.button, 'ToolTip text')
95 self.addCleanup(tooltip.hidetip)
96 tooltip.showtip()
97 tooltip.hidetip()
98 self.assertFalse(self.is_tipwindow_shown(tooltip))
100 def test_showtip_on_mouse_enter_no_delay(self):
101 tooltip = Hovertip(self.button, 'ToolTip text', hover_delay=None)
102 self.addCleanup(tooltip.hidetip)
103 tooltip.showtip = add_call_counting(tooltip.showtip)
104 root.update()
105 self.assertFalse(self.is_tipwindow_shown(tooltip))
106 self.button.event_generate('<Enter>', x=0, y=0)
107 root.update()
108 self.assertTrue(self.is_tipwindow_shown(tooltip))
109 self.assertGreater(len(tooltip.showtip.call_args_list), 0)
111 def test_hover_with_delay(self):
112 # Run multiple tests requiring an actual delay simultaneously.
114 # Test #1: A hover tip with a non-zero delay appears after the delay.
115 tooltip1 = Hovertip(self.button, 'ToolTip text', hover_delay=100)
116 self.addCleanup(tooltip1.hidetip)
117 tooltip1.showtip = add_call_counting(tooltip1.showtip)
118 root.update()
119 self.assertFalse(self.is_tipwindow_shown(tooltip1))
120 self.button.event_generate('<Enter>', x=0, y=0)
121 root.update()
122 self.assertFalse(self.is_tipwindow_shown(tooltip1))
124 # Test #2: A hover tip with a non-zero delay doesn't appear when
125 # the mouse stops hovering over the base widget before the delay
126 # expires.
127 tooltip2 = Hovertip(self.button, 'ToolTip text', hover_delay=100)
128 self.addCleanup(tooltip2.hidetip)
129 tooltip2.showtip = add_call_counting(tooltip2.showtip)
130 root.update()
131 self.button.event_generate('<Enter>', x=0, y=0)
132 root.update()
133 self.button.event_generate('<Leave>', x=0, y=0)
134 root.update()
136 time.sleep(0.15)
137 root.update()
139 # Test #1 assertions.
140 self.assertTrue(self.is_tipwindow_shown(tooltip1))
141 self.assertGreater(len(tooltip1.showtip.call_args_list), 0)
143 # Test #2 assertions.
144 self.assertFalse(self.is_tipwindow_shown(tooltip2))
145 self.assertEqual(tooltip2.showtip.call_args_list, [])
147 def test_hidetip_on_mouse_leave(self):
148 tooltip = Hovertip(self.button, 'ToolTip text', hover_delay=None)
149 self.addCleanup(tooltip.hidetip)
150 tooltip.showtip = add_call_counting(tooltip.showtip)
151 root.update()
152 self.button.event_generate('<Enter>', x=0, y=0)
153 root.update()
154 self.button.event_generate('<Leave>', x=0, y=0)
155 root.update()
156 self.assertFalse(self.is_tipwindow_shown(tooltip))
157 self.assertGreater(len(tooltip.showtip.call_args_list), 0)
160if __name__ == '__main__':
161 unittest.main(verbosity=2)