PageRenderTime 55ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/Windows/Python3.8/WPy64-3830/WPy64-3830/python-3.8.3.amd64/Lib/idlelib/idle_test/test_searchengine.py

https://gitlab.com/abhi1tb/build
Python | 330 lines | 281 code | 20 blank | 29 comment | 7 complexity | 69d03ed40304ac49ad41c4119f279c46 MD5 | raw file
  1. "Test searchengine, coverage 99%."
  2. from idlelib import searchengine as se
  3. import unittest
  4. # from test.support import requires
  5. from tkinter import BooleanVar, StringVar, TclError # ,Tk, Text
  6. import tkinter.messagebox as tkMessageBox
  7. from idlelib.idle_test.mock_tk import Var, Mbox
  8. from idlelib.idle_test.mock_tk import Text as mockText
  9. import re
  10. # With mock replacements, the module does not use any gui widgets.
  11. # The use of tk.Text is avoided (for now, until mock Text is improved)
  12. # by patching instances with an index function returning what is needed.
  13. # This works because mock Text.get does not use .index.
  14. # The tkinter imports are used to restore searchengine.
  15. def setUpModule():
  16. # Replace s-e module tkinter imports other than non-gui TclError.
  17. se.BooleanVar = Var
  18. se.StringVar = Var
  19. se.tkMessageBox = Mbox
  20. def tearDownModule():
  21. # Restore 'just in case', though other tests should also replace.
  22. se.BooleanVar = BooleanVar
  23. se.StringVar = StringVar
  24. se.tkMessageBox = tkMessageBox
  25. class Mock:
  26. def __init__(self, *args, **kwargs): pass
  27. class GetTest(unittest.TestCase):
  28. # SearchEngine.get returns singleton created & saved on first call.
  29. def test_get(self):
  30. saved_Engine = se.SearchEngine
  31. se.SearchEngine = Mock # monkey-patch class
  32. try:
  33. root = Mock()
  34. engine = se.get(root)
  35. self.assertIsInstance(engine, se.SearchEngine)
  36. self.assertIs(root._searchengine, engine)
  37. self.assertIs(se.get(root), engine)
  38. finally:
  39. se.SearchEngine = saved_Engine # restore class to module
  40. class GetLineColTest(unittest.TestCase):
  41. # Test simple text-independent helper function
  42. def test_get_line_col(self):
  43. self.assertEqual(se.get_line_col('1.0'), (1, 0))
  44. self.assertEqual(se.get_line_col('1.11'), (1, 11))
  45. self.assertRaises(ValueError, se.get_line_col, ('1.0 lineend'))
  46. self.assertRaises(ValueError, se.get_line_col, ('end'))
  47. class GetSelectionTest(unittest.TestCase):
  48. # Test text-dependent helper function.
  49. ## # Need gui for text.index('sel.first/sel.last/insert').
  50. ## @classmethod
  51. ## def setUpClass(cls):
  52. ## requires('gui')
  53. ## cls.root = Tk()
  54. ##
  55. ## @classmethod
  56. ## def tearDownClass(cls):
  57. ## cls.root.destroy()
  58. ## del cls.root
  59. def test_get_selection(self):
  60. # text = Text(master=self.root)
  61. text = mockText()
  62. text.insert('1.0', 'Hello World!')
  63. # fix text.index result when called in get_selection
  64. def sel(s):
  65. # select entire text, cursor irrelevant
  66. if s == 'sel.first': return '1.0'
  67. if s == 'sel.last': return '1.12'
  68. raise TclError
  69. text.index = sel # replaces .tag_add('sel', '1.0, '1.12')
  70. self.assertEqual(se.get_selection(text), ('1.0', '1.12'))
  71. def mark(s):
  72. # no selection, cursor after 'Hello'
  73. if s == 'insert': return '1.5'
  74. raise TclError
  75. text.index = mark # replaces .mark_set('insert', '1.5')
  76. self.assertEqual(se.get_selection(text), ('1.5', '1.5'))
  77. class ReverseSearchTest(unittest.TestCase):
  78. # Test helper function that searches backwards within a line.
  79. def test_search_reverse(self):
  80. Equal = self.assertEqual
  81. line = "Here is an 'is' test text."
  82. prog = re.compile('is')
  83. Equal(se.search_reverse(prog, line, len(line)).span(), (12, 14))
  84. Equal(se.search_reverse(prog, line, 14).span(), (12, 14))
  85. Equal(se.search_reverse(prog, line, 13).span(), (5, 7))
  86. Equal(se.search_reverse(prog, line, 7).span(), (5, 7))
  87. Equal(se.search_reverse(prog, line, 6), None)
  88. class SearchEngineTest(unittest.TestCase):
  89. # Test class methods that do not use Text widget.
  90. def setUp(self):
  91. self.engine = se.SearchEngine(root=None)
  92. # Engine.root is only used to create error message boxes.
  93. # The mock replacement ignores the root argument.
  94. def test_is_get(self):
  95. engine = self.engine
  96. Equal = self.assertEqual
  97. Equal(engine.getpat(), '')
  98. engine.setpat('hello')
  99. Equal(engine.getpat(), 'hello')
  100. Equal(engine.isre(), False)
  101. engine.revar.set(1)
  102. Equal(engine.isre(), True)
  103. Equal(engine.iscase(), False)
  104. engine.casevar.set(1)
  105. Equal(engine.iscase(), True)
  106. Equal(engine.isword(), False)
  107. engine.wordvar.set(1)
  108. Equal(engine.isword(), True)
  109. Equal(engine.iswrap(), True)
  110. engine.wrapvar.set(0)
  111. Equal(engine.iswrap(), False)
  112. Equal(engine.isback(), False)
  113. engine.backvar.set(1)
  114. Equal(engine.isback(), True)
  115. def test_setcookedpat(self):
  116. engine = self.engine
  117. engine.setcookedpat(r'\s')
  118. self.assertEqual(engine.getpat(), r'\s')
  119. engine.revar.set(1)
  120. engine.setcookedpat(r'\s')
  121. self.assertEqual(engine.getpat(), r'\\s')
  122. def test_getcookedpat(self):
  123. engine = self.engine
  124. Equal = self.assertEqual
  125. Equal(engine.getcookedpat(), '')
  126. engine.setpat('hello')
  127. Equal(engine.getcookedpat(), 'hello')
  128. engine.wordvar.set(True)
  129. Equal(engine.getcookedpat(), r'\bhello\b')
  130. engine.wordvar.set(False)
  131. engine.setpat(r'\s')
  132. Equal(engine.getcookedpat(), r'\\s')
  133. engine.revar.set(True)
  134. Equal(engine.getcookedpat(), r'\s')
  135. def test_getprog(self):
  136. engine = self.engine
  137. Equal = self.assertEqual
  138. engine.setpat('Hello')
  139. temppat = engine.getprog()
  140. Equal(temppat.pattern, re.compile('Hello', re.IGNORECASE).pattern)
  141. engine.casevar.set(1)
  142. temppat = engine.getprog()
  143. Equal(temppat.pattern, re.compile('Hello').pattern, 0)
  144. engine.setpat('')
  145. Equal(engine.getprog(), None)
  146. engine.setpat('+')
  147. engine.revar.set(1)
  148. Equal(engine.getprog(), None)
  149. self.assertEqual(Mbox.showerror.message,
  150. 'Error: nothing to repeat at position 0\nPattern: +')
  151. def test_report_error(self):
  152. showerror = Mbox.showerror
  153. Equal = self.assertEqual
  154. pat = '[a-z'
  155. msg = 'unexpected end of regular expression'
  156. Equal(self.engine.report_error(pat, msg), None)
  157. Equal(showerror.title, 'Regular expression error')
  158. expected_message = ("Error: " + msg + "\nPattern: [a-z")
  159. Equal(showerror.message, expected_message)
  160. Equal(self.engine.report_error(pat, msg, 5), None)
  161. Equal(showerror.title, 'Regular expression error')
  162. expected_message += "\nOffset: 5"
  163. Equal(showerror.message, expected_message)
  164. class SearchTest(unittest.TestCase):
  165. # Test that search_text makes right call to right method.
  166. @classmethod
  167. def setUpClass(cls):
  168. ## requires('gui')
  169. ## cls.root = Tk()
  170. ## cls.text = Text(master=cls.root)
  171. cls.text = mockText()
  172. test_text = (
  173. 'First line\n'
  174. 'Line with target\n'
  175. 'Last line\n')
  176. cls.text.insert('1.0', test_text)
  177. cls.pat = re.compile('target')
  178. cls.engine = se.SearchEngine(None)
  179. cls.engine.search_forward = lambda *args: ('f', args)
  180. cls.engine.search_backward = lambda *args: ('b', args)
  181. ## @classmethod
  182. ## def tearDownClass(cls):
  183. ## cls.root.destroy()
  184. ## del cls.root
  185. def test_search(self):
  186. Equal = self.assertEqual
  187. engine = self.engine
  188. search = engine.search_text
  189. text = self.text
  190. pat = self.pat
  191. engine.patvar.set(None)
  192. #engine.revar.set(pat)
  193. Equal(search(text), None)
  194. def mark(s):
  195. # no selection, cursor after 'Hello'
  196. if s == 'insert': return '1.5'
  197. raise TclError
  198. text.index = mark
  199. Equal(search(text, pat), ('f', (text, pat, 1, 5, True, False)))
  200. engine.wrapvar.set(False)
  201. Equal(search(text, pat), ('f', (text, pat, 1, 5, False, False)))
  202. engine.wrapvar.set(True)
  203. engine.backvar.set(True)
  204. Equal(search(text, pat), ('b', (text, pat, 1, 5, True, False)))
  205. engine.backvar.set(False)
  206. def sel(s):
  207. if s == 'sel.first': return '2.10'
  208. if s == 'sel.last': return '2.16'
  209. raise TclError
  210. text.index = sel
  211. Equal(search(text, pat), ('f', (text, pat, 2, 16, True, False)))
  212. Equal(search(text, pat, True), ('f', (text, pat, 2, 10, True, True)))
  213. engine.backvar.set(True)
  214. Equal(search(text, pat), ('b', (text, pat, 2, 10, True, False)))
  215. Equal(search(text, pat, True), ('b', (text, pat, 2, 16, True, True)))
  216. class ForwardBackwardTest(unittest.TestCase):
  217. # Test that search_forward method finds the target.
  218. ## @classmethod
  219. ## def tearDownClass(cls):
  220. ## cls.root.destroy()
  221. ## del cls.root
  222. @classmethod
  223. def setUpClass(cls):
  224. cls.engine = se.SearchEngine(None)
  225. ## requires('gui')
  226. ## cls.root = Tk()
  227. ## cls.text = Text(master=cls.root)
  228. cls.text = mockText()
  229. # search_backward calls index('end-1c')
  230. cls.text.index = lambda index: '4.0'
  231. test_text = (
  232. 'First line\n'
  233. 'Line with target\n'
  234. 'Last line\n')
  235. cls.text.insert('1.0', test_text)
  236. cls.pat = re.compile('target')
  237. cls.res = (2, (10, 16)) # line, slice indexes of 'target'
  238. cls.failpat = re.compile('xyz') # not in text
  239. cls.emptypat = re.compile(r'\w*') # empty match possible
  240. def make_search(self, func):
  241. def search(pat, line, col, wrap, ok=0):
  242. res = func(self.text, pat, line, col, wrap, ok)
  243. # res is (line, matchobject) or None
  244. return (res[0], res[1].span()) if res else res
  245. return search
  246. def test_search_forward(self):
  247. # search for non-empty match
  248. Equal = self.assertEqual
  249. forward = self.make_search(self.engine.search_forward)
  250. pat = self.pat
  251. Equal(forward(pat, 1, 0, True), self.res)
  252. Equal(forward(pat, 3, 0, True), self.res) # wrap
  253. Equal(forward(pat, 3, 0, False), None) # no wrap
  254. Equal(forward(pat, 2, 10, False), self.res)
  255. Equal(forward(self.failpat, 1, 0, True), None)
  256. Equal(forward(self.emptypat, 2, 9, True, ok=True), (2, (9, 9)))
  257. #Equal(forward(self.emptypat, 2, 9, True), self.res)
  258. # While the initial empty match is correctly ignored, skipping
  259. # the rest of the line and returning (3, (0,4)) seems buggy - tjr.
  260. Equal(forward(self.emptypat, 2, 10, True), self.res)
  261. def test_search_backward(self):
  262. # search for non-empty match
  263. Equal = self.assertEqual
  264. backward = self.make_search(self.engine.search_backward)
  265. pat = self.pat
  266. Equal(backward(pat, 3, 5, True), self.res)
  267. Equal(backward(pat, 2, 0, True), self.res) # wrap
  268. Equal(backward(pat, 2, 0, False), None) # no wrap
  269. Equal(backward(pat, 2, 16, False), self.res)
  270. Equal(backward(self.failpat, 3, 9, True), None)
  271. Equal(backward(self.emptypat, 2, 10, True, ok=True), (2, (9,9)))
  272. # Accepted because 9 < 10, not because ok=True.
  273. # It is not clear that ok=True is useful going back - tjr
  274. Equal(backward(self.emptypat, 2, 9, True), (2, (5, 9)))
  275. if __name__ == '__main__':
  276. unittest.main(verbosity=2)