(root)/
Python-3.12.0/
Lib/
idlelib/
idle_test/
test_browser.py
       1  "Test browser, coverage 90%."
       2  
       3  from idlelib import browser
       4  from test.support import requires
       5  import unittest
       6  from unittest import mock
       7  from idlelib.idle_test.mock_idle import Func
       8  from idlelib.util import py_extensions
       9  
      10  from collections import deque
      11  import os.path
      12  import pyclbr
      13  from tkinter import Tk
      14  
      15  from idlelib.tree import TreeNode
      16  
      17  
      18  class ESC[4;38;5;81mModuleBrowserTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      19  
      20      @classmethod
      21      def setUpClass(cls):
      22          requires('gui')
      23          cls.root = Tk()
      24          cls.root.withdraw()
      25          cls.mb = browser.ModuleBrowser(cls.root, __file__, _utest=True)
      26  
      27      @classmethod
      28      def tearDownClass(cls):
      29          cls.mb.close()
      30          cls.root.update_idletasks()
      31          cls.root.destroy()
      32          del cls.root, cls.mb
      33  
      34      def test_init(self):
      35          mb = self.mb
      36          eq = self.assertEqual
      37          eq(mb.path, __file__)
      38          eq(pyclbr._modules, {})
      39          self.assertIsInstance(mb.node, TreeNode)
      40          self.assertIsNotNone(browser.file_open)
      41  
      42      def test_settitle(self):
      43          mb = self.mb
      44          self.assertIn(os.path.basename(__file__), mb.top.title())
      45          self.assertEqual(mb.top.iconname(), 'Module Browser')
      46  
      47      def test_rootnode(self):
      48          mb = self.mb
      49          rn = mb.rootnode()
      50          self.assertIsInstance(rn, browser.ModuleBrowserTreeItem)
      51  
      52      def test_close(self):
      53          mb = self.mb
      54          mb.top.destroy = Func()
      55          mb.node.destroy = Func()
      56          mb.close()
      57          self.assertTrue(mb.top.destroy.called)
      58          self.assertTrue(mb.node.destroy.called)
      59          del mb.top.destroy, mb.node.destroy
      60  
      61      def test_is_browseable_extension(self):
      62          path = "/path/to/file"
      63          for ext in py_extensions:
      64              with self.subTest(ext=ext):
      65                  filename = f'{path}{ext}'
      66                  actual = browser.is_browseable_extension(filename)
      67                  expected = ext not in browser.browseable_extension_blocklist
      68                  self.assertEqual(actual, expected)
      69  
      70  
      71  # Nested tree same as in test_pyclbr.py except for supers on C0. C1.
      72  mb = pyclbr
      73  module, fname = 'test', 'test.py'
      74  C0 = mb.Class(module, 'C0', ['base'], fname, 1, end_lineno=9)
      75  F1 = mb._nest_function(C0, 'F1', 3, 5)
      76  C1 = mb._nest_class(C0, 'C1', 6, 9, [''])
      77  C2 = mb._nest_class(C1, 'C2', 7, 9)
      78  F3 = mb._nest_function(C2, 'F3', 9, 9)
      79  f0 = mb.Function(module, 'f0', fname, 11, end_lineno=15)
      80  f1 = mb._nest_function(f0, 'f1', 12, 14)
      81  f2 = mb._nest_function(f1, 'f2', 13, 13)
      82  c1 = mb._nest_class(f0, 'c1', 15, 15)
      83  mock_pyclbr_tree = {'C0': C0, 'f0': f0}
      84  
      85  # Adjust C0.name, C1.name so tests do not depend on order.
      86  browser.transform_children(mock_pyclbr_tree, 'test')  # C0(base)
      87  browser.transform_children(C0.children)  # C1()
      88  
      89  # The class below checks that the calls above are correct
      90  # and that duplicate calls have no effect.
      91  
      92  
      93  class ESC[4;38;5;81mTransformChildrenTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      94  
      95      def test_transform_module_children(self):
      96          eq = self.assertEqual
      97          transform = browser.transform_children
      98          # Parameter matches tree module.
      99          tcl = list(transform(mock_pyclbr_tree, 'test'))
     100          eq(tcl, [C0, f0])
     101          eq(tcl[0].name, 'C0(base)')
     102          eq(tcl[1].name, 'f0')
     103          # Check that second call does not change suffix.
     104          tcl = list(transform(mock_pyclbr_tree, 'test'))
     105          eq(tcl[0].name, 'C0(base)')
     106          # Nothing to traverse if parameter name isn't same as tree module.
     107          tcl = list(transform(mock_pyclbr_tree, 'different name'))
     108          eq(tcl, [])
     109  
     110      def test_transform_node_children(self):
     111          eq = self.assertEqual
     112          transform = browser.transform_children
     113          # Class with two children, one name altered.
     114          tcl = list(transform(C0.children))
     115          eq(tcl, [F1, C1])
     116          eq(tcl[0].name, 'F1')
     117          eq(tcl[1].name, 'C1()')
     118          tcl = list(transform(C0.children))
     119          eq(tcl[1].name, 'C1()')
     120          # Function with two children.
     121          eq(list(transform(f0.children)), [f1, c1])
     122  
     123  
     124  class ESC[4;38;5;81mModuleBrowserTreeItemTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     125  
     126      @classmethod
     127      def setUpClass(cls):
     128          cls.mbt = browser.ModuleBrowserTreeItem(fname)
     129  
     130      def test_init(self):
     131          self.assertEqual(self.mbt.file, fname)
     132  
     133      def test_gettext(self):
     134          self.assertEqual(self.mbt.GetText(), fname)
     135  
     136      def test_geticonname(self):
     137          self.assertEqual(self.mbt.GetIconName(), 'python')
     138  
     139      def test_isexpandable(self):
     140          self.assertTrue(self.mbt.IsExpandable())
     141  
     142      def test_listchildren(self):
     143          save_rex = browser.pyclbr.readmodule_ex
     144          save_tc = browser.transform_children
     145          browser.pyclbr.readmodule_ex = Func(result=mock_pyclbr_tree)
     146          browser.transform_children = Func(result=[f0, C0])
     147          try:
     148              self.assertEqual(self.mbt.listchildren(), [f0, C0])
     149          finally:
     150              browser.pyclbr.readmodule_ex = save_rex
     151              browser.transform_children = save_tc
     152  
     153      def test_getsublist(self):
     154          mbt = self.mbt
     155          mbt.listchildren = Func(result=[f0, C0])
     156          sub0, sub1 = mbt.GetSubList()
     157          del mbt.listchildren
     158          self.assertIsInstance(sub0, browser.ChildBrowserTreeItem)
     159          self.assertIsInstance(sub1, browser.ChildBrowserTreeItem)
     160          self.assertEqual(sub0.name, 'f0')
     161          self.assertEqual(sub1.name, 'C0(base)')
     162  
     163      @mock.patch('idlelib.browser.file_open')
     164      def test_ondoubleclick(self, fopen):
     165          mbt = self.mbt
     166  
     167          with mock.patch('os.path.exists', return_value=False):
     168              mbt.OnDoubleClick()
     169              fopen.assert_not_called()
     170  
     171          with mock.patch('os.path.exists', return_value=True):
     172              mbt.OnDoubleClick()
     173              fopen.assert_called_once_with(fname)
     174  
     175  
     176  class ESC[4;38;5;81mChildBrowserTreeItemTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     177  
     178      @classmethod
     179      def setUpClass(cls):
     180          CBT = browser.ChildBrowserTreeItem
     181          cls.cbt_f1 = CBT(f1)
     182          cls.cbt_C1 = CBT(C1)
     183          cls.cbt_F1 = CBT(F1)
     184  
     185      @classmethod
     186      def tearDownClass(cls):
     187          del cls.cbt_C1, cls.cbt_f1, cls.cbt_F1
     188  
     189      def test_init(self):
     190          eq = self.assertEqual
     191          eq(self.cbt_C1.name, 'C1()')
     192          self.assertFalse(self.cbt_C1.isfunction)
     193          eq(self.cbt_f1.name, 'f1')
     194          self.assertTrue(self.cbt_f1.isfunction)
     195  
     196      def test_gettext(self):
     197          self.assertEqual(self.cbt_C1.GetText(), 'class C1()')
     198          self.assertEqual(self.cbt_f1.GetText(), 'def f1(...)')
     199  
     200      def test_geticonname(self):
     201          self.assertEqual(self.cbt_C1.GetIconName(), 'folder')
     202          self.assertEqual(self.cbt_f1.GetIconName(), 'python')
     203  
     204      def test_isexpandable(self):
     205          self.assertTrue(self.cbt_C1.IsExpandable())
     206          self.assertTrue(self.cbt_f1.IsExpandable())
     207          self.assertFalse(self.cbt_F1.IsExpandable())
     208  
     209      def test_getsublist(self):
     210          eq = self.assertEqual
     211          CBT = browser.ChildBrowserTreeItem
     212  
     213          f1sublist = self.cbt_f1.GetSubList()
     214          self.assertIsInstance(f1sublist[0], CBT)
     215          eq(len(f1sublist), 1)
     216          eq(f1sublist[0].name, 'f2')
     217  
     218          eq(self.cbt_F1.GetSubList(), [])
     219  
     220      @mock.patch('idlelib.browser.file_open')
     221      def test_ondoubleclick(self, fopen):
     222          goto = fopen.return_value.gotoline = mock.Mock()
     223          self.cbt_F1.OnDoubleClick()
     224          fopen.assert_called()
     225          goto.assert_called()
     226          goto.assert_called_with(self.cbt_F1.obj.lineno)
     227          # Failure test would have to raise OSError or AttributeError.
     228  
     229  
     230  class ESC[4;38;5;81mNestedChildrenTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     231      "Test that all the nodes in a nested tree are added to the BrowserTree."
     232  
     233      def test_nested(self):
     234          queue = deque()
     235          actual_names = []
     236          # The tree items are processed in breadth first order.
     237          # Verify that processing each sublist hits every node and
     238          # in the right order.
     239          expected_names = ['f0', 'C0(base)',
     240                            'f1', 'c1', 'F1', 'C1()',
     241                            'f2', 'C2',
     242                            'F3']
     243          CBT = browser.ChildBrowserTreeItem
     244          queue.extend((CBT(f0), CBT(C0)))
     245          while queue:
     246              cb = queue.popleft()
     247              sublist = cb.GetSubList()
     248              queue.extend(sublist)
     249              self.assertIn(cb.name, cb.GetText())
     250              self.assertIn(cb.GetIconName(), ('python', 'folder'))
     251              self.assertIs(cb.IsExpandable(), sublist != [])
     252              actual_names.append(cb.name)
     253          self.assertEqual(actual_names, expected_names)
     254  
     255  
     256  if __name__ == '__main__':
     257      unittest.main(verbosity=2)