test_browser.py 8.2 KB

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