(root)/
Python-3.12.0/
Lib/
idlelib/
idle_test/
test_tooltip.py
       1  """Test tooltip, coverage 100%.
       2  
       3  Coverage is 100% after excluding 6 lines with "# pragma: no cover".
       4  They involve TclErrors that either should or should not happen in a
       5  particular situation, and which are 'pass'ed if they do.
       6  """
       7  
       8  from idlelib.tooltip import TooltipBase, Hovertip
       9  from test.support import requires
      10  requires('gui')
      11  
      12  from functools import wraps
      13  import time
      14  from tkinter import Button, Tk, Toplevel
      15  import unittest
      16  
      17  
      18  def setUpModule():
      19      global root
      20      root = Tk()
      21  
      22  def tearDownModule():
      23      global root
      24      root.update_idletasks()
      25      root.destroy()
      26      del root
      27  
      28  
      29  def 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
      36  
      37  
      38  def _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
      48  
      49  
      50  class ESC[4;38;5;81mToolTipBaseTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      51      def setUp(self):
      52          self.top, self.button = _make_top_and_button(self)
      53  
      54      def test_base_class_is_unusable(self):
      55          global root
      56          top = Toplevel(root)
      57          self.addCleanup(top.destroy)
      58  
      59          button = Button(top, text='ToolTip test button')
      60          button.pack()
      61          self.addCleanup(button.destroy)
      62  
      63          with self.assertRaises(NotImplementedError):
      64              tooltip = TooltipBase(button)
      65              tooltip.showtip()
      66  
      67  
      68  class ESC[4;38;5;81mHovertipTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      69      def setUp(self):
      70          self.top, self.button = _make_top_and_button(self)
      71  
      72      def is_tipwindow_shown(self, tooltip):
      73          return tooltip.tipwindow and tooltip.tipwindow.winfo_viewable()
      74  
      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))
      81  
      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)
      92  
      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))
      99  
     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)
     110  
     111      def test_hover_with_delay(self):
     112          # Run multiple tests requiring an actual delay simultaneously.
     113  
     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))
     123  
     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()
     135  
     136          time.sleep(0.15)
     137          root.update()
     138  
     139          # Test #1 assertions.
     140          self.assertTrue(self.is_tipwindow_shown(tooltip1))
     141          self.assertGreater(len(tooltip1.showtip.call_args_list), 0)
     142  
     143          # Test #2 assertions.
     144          self.assertFalse(self.is_tipwindow_shown(tooltip2))
     145          self.assertEqual(tooltip2.showtip.call_args_list, [])
     146  
     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)
     158  
     159  
     160  if __name__ == '__main__':
     161      unittest.main(verbosity=2)