Coverage for core\test_leoFind.py : 100%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
2#@+leo-ver=5-thin
3#@+node:ekr.20210829124658.1: * @file ../unittests/core/test_leoFind.py
4#@@first
5"""Tests for leo.core.leoFind"""
7import re
8from leo.core import leoGlobals as g
9import leo.core.leoFind as leoFind
10from leo.core.leoGui import StringFindTabManager
11from leo.core.leoTest2 import LeoUnitTest
13#@+others
14#@+node:ekr.20200216063538.1: ** class TestFind(LeoUnitTest)
15class TestFind(LeoUnitTest):
16 """Test cases for leoFind.py"""
17 #@+others
18 #@+node:ekr.20210110073117.57: *3* TestFind.setUp
19 def setUp(self):
20 """setUp for TestFind class"""
21 super().setUp()
22 c = self.c
23 c.findCommands = self.x = x = leoFind.LeoFind(c)
24 x.ftm = StringFindTabManager(c)
25 self.settings = x.default_settings()
26 self.make_test_tree()
27 #@+node:ekr.20210110073117.56: *3* TestFind.make_test_tree
28 def make_test_tree(self):
29 """Make a test tree for other tests"""
30 c = self.c
31 root = c.rootPosition()
32 root.h = 'Root'
33 root.b = "def root():\n pass\n"
34 last = root
36 def make_child(n, p):
37 p2 = p.insertAsLastChild()
38 p2.h = f"child {n}"
39 p2.b = f"def child{n}():\n v{n} = 2\n"
40 return p2
42 def make_top(n, sib):
43 p = sib.insertAfter()
44 p.h = f"Node {n}"
45 p.b = f"def top{n}():\n v{n} = 3\n"
46 return p
48 for n in range(0, 4, 3):
49 last = make_top(n + 1, last)
50 child = make_child(n + 2, last)
51 make_child(n + 3, child)
53 for p in c.all_positions():
54 p.v.clearDirty()
55 p.v.clearVisited()
57 # Always start with the root selected.
58 c.selectPosition(c.rootPosition())
59 #@+node:ekr.20210110073117.59: *3* Tests of Commands...
60 #@+node:ekr.20210110073117.67: *4* TestFind.change-all
61 def test_change_all(self):
62 c, settings, x = self.c, self.settings, self.x
63 root = c.rootPosition()
65 def init():
66 self.make_test_tree() # Reinit the whole tree.
67 settings.change_text = '_DEF_'
68 settings.find_text = 'def'
69 settings.ignore_case = False
70 settings.node_only = False
71 settings.pattern_match = False
72 settings.suboutline_only = False
73 settings.whole_word = True
75 # Default settings.
76 init()
77 x.do_change_all(settings)
78 # Plain search, ignore case.
79 init()
80 settings.whole_word = False
81 settings.ignore_case = True
82 x.do_change_all(settings)
83 # Node only.
84 init()
85 settings.node_only = True
86 x.do_change_all(settings)
87 # Suboutline only.
88 init()
89 settings.suboutline_only = True
90 x.do_change_all(settings)
91 # Pattern match.
92 init()
93 settings.pattern_match = True
94 x.do_change_all(settings)
95 # Pattern match, ignore case.
96 init()
97 settings.pattern_match = True
98 settings.ignore_case = True
99 x.do_change_all(settings)
100 # Pattern match, with groups.
101 init()
102 settings.pattern_match = True
103 settings.find_text = r'^(def)'
104 settings.change_text = '*\1*'
105 x.do_change_all(settings)
106 # Ignore case
107 init()
108 settings.ignore_case = True
109 x.do_change_all(settings)
110 # Word, ignore case.
111 init()
112 settings.ignore_case = True
113 settings.whole_word = True
114 x.do_change_all(settings)
115 # Multiple matches
116 init()
117 root.h = 'abc'
118 root.b = 'abc\nxyz abc\n'
119 settings.find_text = settings.change_text = 'abc'
120 x.do_change_all(settings)
121 # Set ancestor @file node dirty.
122 root.h = '@file xyzzy'
123 settings.find_text = settings.change_text = 'child1'
124 x.do_change_all(settings)
125 #@+node:ekr.20210220091434.1: *4* TestFind.change-all (@file node)
126 def test_change_all_with_at_file_node(self):
127 c, settings, x = self.c, self.settings, self.x
128 root = c.rootPosition().next() # Must have children.
129 settings.find_text = 'def'
130 settings.change_text = '_DEF_'
131 settings.ignore_case = False
132 settings.match_word = True
133 settings.pattern_match = False
134 settings.suboutline_only = False
135 # Ensure that the @file node is marked dirty.
136 root.h = '@file xyzzy.py'
137 root.b = ''
138 root.v.clearDirty()
139 assert root.anyAtFileNodeName()
140 x.do_change_all(settings)
141 assert root.v.isDirty(), root.h
143 #@+node:ekr.20210220091434.2: *4* TestFind.change-all (headline)
144 def test_change_all_headline(self):
145 settings, x = self.settings, self.x
146 settings.find_text = 'child'
147 settings.change_text = '_CHILD_'
148 settings.ignore_case = False
149 settings.in_headline = True
150 settings.match_word = True
151 settings.pattern_match = False
152 settings.suboutline_only = False
153 x.do_change_all(settings)
154 #@+node:ekr.20210110073117.60: *4* TestFind.clone-find-all
155 def test_clone_find_all(self):
156 settings, x = self.settings, self.x
157 # Regex find.
158 settings.find_text = r'^def\b'
159 settings.change_text = 'def' # Don't actually change anything!
160 settings.pattern_match = True
161 x.do_clone_find_all(settings)
162 # Word find.
163 settings.find_text = 'def'
164 settings.match_word = True
165 settings.pattern_match = False
166 x.do_clone_find_all(settings)
167 # Suboutline only.
168 settings.suboutline_only = True
169 x.do_clone_find_all(settings)
170 #@+node:ekr.20210110073117.61: *4* TestFind.clone-find-all-flattened
171 def test_clone_find_all_flattened(self):
172 settings, x = self.settings, self.x
173 # regex find.
174 settings.find_text = r'^def\b'
175 settings.pattern_match = True
176 x.do_clone_find_all_flattened(settings)
177 # word find.
178 settings.find_text = 'def'
179 settings.match_word = True
180 settings.pattern_match = False
181 x.do_clone_find_all_flattened(settings)
182 # Suboutline only.
183 settings.suboutline_only = True
184 x.do_clone_find_all_flattened(settings)
185 #@+node:ekr.20210617072622.1: *4* TestFind.clone-find-marked
186 def test_clone_find_marked(self):
187 c, x = self.c, self.x
188 root = c.rootPosition()
189 root.setMarked()
190 x.cloneFindAllMarked()
191 x.cloneFindAllFlattenedMarked()
192 root.setMarked()
193 #@+node:ekr.20210615084049.1: *4* TestFind.clone-find-parents
194 def test_clone_find_parents(self):
196 c, x = self.c, self.x
197 root = c.rootPosition()
198 p = root.next().firstChild()
199 p.clone() # c.p must be a clone.
200 c.selectPosition(p)
201 x.cloneFindParents()
203 #@+node:ekr.20210110073117.62: *4* TestFind.clone-find-tag
204 def test_clone_find_tag(self):
205 c, x = self.c, self.x
207 class DummyTagController:
209 def __init__(self, clones):
210 self.clones = clones
212 def get_tagged_nodes(self, tag):
213 return self.clones
215 def show_all_tags(self):
216 pass
218 c.theTagController = DummyTagController([c.rootPosition()])
219 x.do_clone_find_tag('test')
220 c.theTagController = DummyTagController([])
221 x.do_clone_find_tag('test')
222 c.theTagController = None
223 x.do_clone_find_tag('test')
224 #@+node:ekr.20210110073117.63: *4* TestFind.find-all
225 def test_find_all(self):
226 settings, x = self.settings, self.x
228 def init():
229 self.make_test_tree() # Reinit the whole tree.
230 x.findAllUniqueFlag = False
231 x.unique_matches = set()
232 settings.change_text = '_DEF_'
233 settings.find_text = 'def'
234 settings.ignore_case = False
235 settings.node_only = False
236 settings.pattern_match = False
237 settings.suboutline_only = False
238 settings.whole_word = True
240 # Test 1.
241 init()
242 settings.pattern_match = True
243 x.do_find_all(settings)
244 # Test 2.
245 init()
246 settings.suboutline_only = True
247 x.do_find_all(settings)
248 # Test 3.
249 init()
250 settings.search_headline = False
251 settings.p.setVisited()
252 x.do_find_all(settings)
253 # Test 4.
254 init()
255 x.findAllUniqueFlag = True
256 settings.pattern_match = True
257 settings.find_text = r'^(def)'
258 settings.change_text = '*\1*'
259 x.do_find_all(settings)
260 # Test 5: no match.
261 init()
262 settings.find_text = 'not-found-xyzzy'
263 x.do_find_all(settings)
265 #@+node:ekr.20210110073117.65: *4* TestFind.find-def
266 def test_find_def(self):
267 settings, x = self.settings, self.x
268 # Test methods called by x.find_def.
269 # It would be wrong to call these methods from x.do_find_def.
270 x._save_before_find_def(x.c.rootPosition()) # Also tests _restore_after_find_def.
271 x._compute_find_def_settings('my-find-pattern')
272 #
273 # Now the main tests...
274 # Test 1.
275 p, pos, newpos = x.do_find_def(settings, word='child5', strict=True)
276 assert p
277 self.assertEqual(p.h, 'child 5')
278 s = p.b[pos:newpos]
279 self.assertEqual(s, 'def child5')
280 # Test 2: switch style.
281 p, pos, newpos = x.do_find_def(settings, word='child_5', strict=False)
282 assert p
283 self.assertEqual(p.h, 'child 5')
284 # Test 3: not found after switching style.
285 p, pos, newpos = x.do_find_def(settings, word='xyzzy', strict=False)
286 assert p is None, repr(p)
287 #@+node:ekr.20210110073117.64: *4* TestFind.find-next
288 def test_find_next(self):
289 settings, x = self.settings, self.x
290 settings.find_text = 'def top1'
291 p, pos, newpos = x.do_find_next(settings)
292 assert p
293 self.assertEqual(p.h, 'Node 1')
294 s = p.b[pos:newpos]
295 self.assertEqual(s, settings.find_text)
296 #@+node:ekr.20210220072631.1: *4* TestFind.find-next (suboutline-only)
297 def test_find_next_suboutline_only(self):
298 settings, x = self.settings, self.x
299 settings.find_text = 'def root()'
300 settings.suboutline_only = True # init_ivars_from_settings will set the ivar.
301 p, pos, newpos = x.do_find_next(settings)
302 assert p
303 self.assertEqual(p.h, 'Root')
304 s = p.b[pos:newpos]
305 self.assertEqual(s, settings.find_text)
306 #@+node:ekr.20210924032146.1: *4* TestFind.change-then-find (headline)
307 def test_change_then_find_in_headline(self):
308 # Test #2220:
309 # https://github.com/leo-editor/leo-editor/issues/2220
310 # Let block.
311 settings, c, x = self.settings, self.c, self.x
312 # Set up the search.
313 settings.find_text = 'Test'
314 settings.change_text = 'XX'
315 # Create the tree.
316 test_p = self.c.rootPosition().insertAfter()
317 test_p.h = 'Test1 Test2 Test3'
318 after_p = test_p.insertAfter()
319 after_p.h = 'After'
320 # Find test_p.
321 p, pos, newpos = x.do_find_next(settings)
322 self.assertEqual(p, test_p)
323 w = c.edit_widget(p)
324 self.assertEqual(test_p.h, w.getAllText())
325 self.assertEqual(w.getSelectionRange(), (pos, newpos))
326 # Do change-then-find.
327 ok = x.do_change_then_find(settings)
328 self.assertTrue(ok)
329 p = c.p
330 self.assertEqual(p, test_p)
331 self.assertEqual(p.h, 'XX1 Test2 Test3')
332 #@+node:ekr.20210216094444.1: *4* TestFind.find-prev
333 def test_find_prev(self):
334 c, settings, x = self.c, self.settings, self.x
335 settings.find_text = 'def top1'
336 # Start at end, so we stay in the node.
337 grand_child = g.findNodeAnywhere(c, 'child 6')
338 settings.p = grand_child
339 assert settings.p
340 settings.find_text = 'def child2'
341 # Set c.p in the command.
342 x.c.selectPosition(grand_child)
343 p, pos, newpos = x.do_find_prev(settings)
344 assert p
345 self.assertEqual(p.h, 'child 2')
346 s = p.b[pos:newpos]
347 self.assertEqual(s, settings.find_text)
348 #@+node:ekr.20210110073117.66: *4* TestFind.find-var
349 def test_find_var(self):
350 settings, x = self.settings, self.x
351 p, pos, newpos = x.do_find_var(settings, word='v5')
352 assert p
353 self.assertEqual(p.h, 'child 5')
354 s = p.b[pos:newpos]
355 self.assertEqual(s, 'v5 =')
356 #@+node:ekr.20210110073117.68: *4* TestFind.replace-then-find
357 def test_replace_then_find(self):
358 settings, w, x = self.settings, self.c.frame.body.wrapper, self.x
359 settings.find_text = 'def top1'
360 settings.change_text = 'def top'
361 # find-next
362 p, pos, newpos = x.do_find_next(settings)
363 assert p
364 self.assertEqual(p.h, 'Node 1')
365 s = p.b[pos:newpos]
366 self.assertEqual(s, settings.find_text)
367 # replace-then-find
368 w.setSelectionRange(pos, newpos, insert=pos)
369 x.do_change_then_find(settings)
370 # Failure exit.
371 w.setSelectionRange(0, 0)
372 x.do_change_then_find(settings)
374 def test_replace_then_find_regex(self):
375 settings, w, x = self.settings, self.c.frame.body.wrapper, self.x
376 settings.find_text = r'(def) top1'
377 settings.change_text = r'\1\1'
378 settings.pattern_match = True
379 # find-next
380 p, pos, newpos = x.do_find_next(settings)
381 s = p.b[pos:newpos]
382 self.assertEqual(s, 'def top1')
383 # replace-then-find
384 w.setSelectionRange(pos, newpos, insert=pos)
385 x.do_change_then_find(settings)
387 def test_replace_then_find_in_headline(self):
388 settings, x = self.settings, self.x
389 p = settings.p
390 settings.find_text = 'Node 1'
391 settings.change_text = 'Node 1a'
392 settings.in_headline = True
393 # find-next
394 p, pos, newpos = x.do_find_next(settings)
395 assert p
396 self.assertEqual(p.h, settings.find_text)
397 w = self.c.edit_widget(p)
398 assert w
399 s = p.h[pos:newpos]
400 self.assertEqual(s, settings.find_text)
401 #@+node:ekr.20210110073117.69: *4* TestFind.tag-children
402 def test_tag_children(self):
404 c, x = self.c, self.x
406 class DummyTagController:
407 def add_tag(self, p, tag):
408 pass
410 p = c.rootPosition().next()
411 c.theTagController = None
412 x.do_tag_children(p, 'test')
413 c.theTagController = DummyTagController()
414 x.do_tag_children(p, 'test')
415 #@+node:ekr.20210219181001.1: *4* testFind.test_batch_change_regex
416 def test_batch_change_regex(self):
417 c, x = self.c, self.x
418 # self.dump_tree()
419 # Test 1: Match in body.
420 settings = dict(
421 ignore_case=False,
422 node_only=False,
423 pattern_match=True,
424 search_body=True,
425 search_headline=True,
426 suboutline_only=False,
427 whole_word=False,
428 )
429 # Test 1: Match in body.
430 n = x.batch_change(
431 root=c.rootPosition(),
432 replacements=((r'^def\b', 'DEF'),),
433 settings=settings)
434 assert n > 3, n # Test 1.
435 # Test 2: Match in headline.
436 n = x.batch_change(
437 root=c.rootPosition(),
438 replacements=((r'^Node\b', 'DEF'),),
439 settings=settings)
440 self.assertEqual(n, 2)
441 # Test 3: node-only.
442 settings['node_only'] = True
443 n = x.batch_change(
444 root=c.rootPosition(),
445 replacements=((r'^DEF\b', 'def'),),
446 settings=settings)
447 self.assertEqual(n, 1)
448 # Test 4: suboutline-only.
449 settings['node_only'] = False
450 settings['suboutline_only'] = True
451 n = x.batch_change(
452 root=c.rootPosition(),
453 replacements=((r'^def\b', 'DEF'),),
454 settings=settings)
455 self.assertEqual(n, 1)
456 #@+node:ekr.20210219175850.1: *4* testFind.test_batch_change_word
457 def test_batch_change_word(self):
458 # settings, x = self.settings, self.x
459 c, x = self.c, self.x
460 settings = dict(
461 ignore_case=False,
462 node_only=False,
463 pattern_match=False,
464 search_body=True,
465 search_headline=True,
466 suboutline_only=False,
467 whole_word=True,
468 )
469 n = x.batch_change(
470 root=c.rootPosition(),
471 replacements=(('def', 'DEF'),),
472 settings=settings)
473 assert n > 0
475 #@+node:ekr.20210110073117.58: *4* TestFind.test_tree
476 def test_tree(self):
477 c = self.c
478 table = (
479 (0, 'Root'),
480 (0, 'Node 1'),
481 (1, 'child 2'),
482 (2, 'child 3'),
483 (0, 'Node 4'),
484 (1, 'child 5'),
485 (2, 'child 6'),
486 )
487 for level, h in table:
488 p = g.findNodeAnywhere(c, h)
489 self.assertEqual(p.h, h)
490 self.assertEqual(p.level(), level)
491 #@+node:ekr.20210110073117.70: *3* Tests of Helpers...
492 #@+node:ekr.20210110073117.72: *4* TestFind.test_argument_errors
493 def test_argument_errors(self):
495 settings, x = self.settings, self.x
496 # Bad search pattern.
497 settings.find_text = r'^def\b(('
498 settings.pattern_match = True
499 x.do_clone_find_all(settings)
500 x.find_next_match(p=None)
501 x.do_change_all(settings)
502 #@+node:ekr.20210110073117.74: *4* TestFind.test_batch_plain_replace
503 def test_batch_plain_replace(self):
504 settings, x = self.settings, self.x
505 settings.find_text = 'b'
506 settings.change_text = 'B'
507 for ignore in (True, False):
508 settings.ignore_case = ignore
509 x.init_ivars_from_settings(settings)
510 s = 'abc b z'
511 count, s2 = x.batch_plain_replace(s)
512 self.assertEqual(count, 2, msg=f"ignore: {ignore}")
513 self.assertEqual(s2, 'aBc B z', msg=f"ignore: {ignore}")
514 #@+node:ekr.20210110073117.75: *4* TestFind.test_batch_regex_replace
515 def test_batch_regex_replace(self):
516 settings, x = self.settings, self.x
517 s = 'abc b z'
518 table = (
519 (1, 2, 'B', 'B', 'aBc B z'),
520 (0, 2, 'b', 'B', 'aBc B z'),
521 (1, 2, r'([BX])', 'B', 'aBc B z'),
522 )
523 for ignore, count, find, change, expected_s in table:
524 settings.ignore_case = bool(ignore)
525 settings.find_text = find
526 settings.change_text = change
527 x.init_ivars_from_settings(settings)
528 actual_count, actual_s = x.batch_regex_replace(s)
529 self.assertEqual(actual_count, count, msg=find)
530 self.assertEqual(actual_s, expected_s, msg=find)
531 #@+node:ekr.20210110073117.73: *4* TestFind.test_batch_word_replace
532 def test_batch_word_replace(self):
533 settings, x = self.settings, self.x
534 settings.find_text = 'b'
535 settings.change_text = 'B'
536 for ignore in (True, False):
537 settings.ignore_case = ignore
538 x.init_ivars_from_settings(settings)
539 s = 'abc b z'
540 count, s2 = x.batch_word_replace(s)
541 self.assertEqual(count, 1)
542 self.assertEqual(s2, 'abc B z')
543 #@+node:ekr.20210110073117.71: *4* TestFind.test_cfa_backwards_search
544 def test_cfa_backwards_search(self):
545 settings, x = self.settings, self.x
546 pattern = 'def'
547 for nocase in (True, False):
548 settings.ignore_case = nocase
549 for word in (True, False):
550 for s in ('def spam():\n', 'define spam'):
551 settings.whole_word = word
552 x.init_ivars_from_settings(settings)
553 x._inner_search_backward(s, 0, len(s), pattern, nocase, word)
554 x._inner_search_backward(s, 0, 0, pattern, nocase, word)
555 #@+node:ekr.20210110073117.80: *4* TestFind.test_cfa_find_next_match
556 def test_cfa_find_next_match(self):
557 c, settings, x = self.c, self.settings, self.x
558 p = c.rootPosition()
559 for find in ('xxx', 'def'):
560 settings.find_text = find
561 x._cfa_find_next_match(p)
562 #@+node:ekr.20210110073117.83: *4* TestFind.test_cfa_match_word
563 def test_cfa_match_word(self):
564 x = self.x
565 x._inner_search_match_word("def spam():", 0, "spam")
566 x._inner_search_match_word("def spam():", 0, "xxx")
568 #@+node:ekr.20210110073117.85: *4* TestFind.test_cfa_plain_search
569 def test_cfa_plain_search(self):
570 settings, x = self.settings, self.x
571 pattern = 'def'
572 for nocase in (True, False):
573 settings.ignore_case = nocase
574 for word in (True, False):
575 for s in ('def spam():\n', 'define'):
576 settings.whole_word = word
577 x.init_ivars_from_settings(settings)
578 x._inner_search_plain(s, 0, len(s), pattern, nocase, word)
579 x._inner_search_plain(s, 0, 0, pattern, nocase, word)
580 #@+node:ekr.20210110073117.88: *4* TestFind.test_cfa_regex_search
581 def test_cfa_regex_search(self):
582 x = self.x
583 pattern = r'(.*)pattern'
584 x.re_obj = re.compile(pattern)
585 table = (
586 'test pattern', # Match.
587 'xxx', # No match.
588 )
589 for backwards in (True, False):
590 for nocase in (True, False):
591 for s in table:
592 if backwards:
593 i = j = len(s)
594 else:
595 i = j = 0
596 x._inner_search_regex(s, i, j, pattern, backwards, nocase)
597 # Error test.
598 x.re_obj = None
599 backwards = pattern = nocase = None
600 x._inner_search_regex("", 0, 0, pattern, backwards, nocase)
601 #@+node:ekr.20210110073117.76: *4* TestFind.test_check_args
602 def test_check_args(self):
603 # Bad search patterns..
604 x = self.x
605 settings = self.settings
606 # Not searching headline or body.
607 settings.search_body = False
608 settings.search_headline = False
609 x.do_clone_find_all(settings)
610 # Empty find pattern.
611 settings.search_body = True
612 settings.find_text = ''
613 x.do_clone_find_all(settings)
614 x.do_clone_find_all_flattened(settings)
615 x.do_find_all(settings)
616 x.do_find_next(settings)
617 x.do_find_next(settings)
618 x.do_find_prev(settings)
619 x.do_change_all(settings)
620 x.do_change_then_find(settings)
621 #@+node:ekr.20210829203927.10: *4* TestFind.test_clean_init
622 def test_clean_init(self):
623 c = self.c
624 x = leoFind.LeoFind(c)
625 table = (
626 'ignore_case', 'node_only', 'pattern_match',
627 'search_headline', 'search_body', 'suboutline_only',
628 'mark_changes', 'mark_finds', 'whole_word',
629 )
630 for ivar in table:
631 assert getattr(x, ivar) is None, ivar
632 assert x.reverse is False
633 #@+node:ekr.20210110073117.77: *4* TestFind.test_compute_result_status
634 def test_compute_result_status(self):
635 x = self.x
636 # find_all_flag is True
637 all_settings = x.default_settings()
638 all_settings.ignore_case = True
639 all_settings.pattern_match = True
640 all_settings.whole_word = True
641 all_settings.wrapping = True
642 x.init_ivars_from_settings(all_settings)
643 x.compute_result_status(find_all_flag=True)
644 # find_all_flag is False
645 partial_settings = x.default_settings()
646 partial_settings.search_body = True
647 partial_settings.search_headline = True
648 partial_settings.node_only = True
649 partial_settings.suboutline_only = True
650 partial_settings.wrapping = True
651 x.init_ivars_from_settings(partial_settings)
652 x.compute_result_status(find_all_flag=False)
653 #@+node:ekr.20210829203927.12: *4* TestFind.test_inner_search_backward
654 def test_inner_search_backward(self):
655 c = self.c
656 x = leoFind.LeoFind(c)
658 def test(table, table_name, nocase, word):
659 test_n = 0
660 for pattern, s, i, j, expected, expected_i, expected_j in table:
661 test_n += 1
662 if j == -1:
663 j = len(s)
664 got_i, got_j = x._inner_search_backward(s, i, j,
665 pattern, nocase=nocase, word=word)
666 got = s[got_i:got_j]
667 assert expected == got and got_i == expected_i and got_j == expected_j, (
668 '\n table: %s'
669 '\n i test: %s'
670 '\n pattern: %r'
671 '\n s: %r'
672 '\n expected: %r'
673 '\n got: %r'
674 '\nexpected i: %s'
675 '\n got i: %s'
676 '\nexpected j: %s'
677 '\n got j: %s'
678 % (table_name, test_n, pattern, s, expected, got, expected_i, got_i, expected_j, got_j))
680 plain_table = (
681 # pattern s i, j expected, expected_i, expected_j
682 ('a', 'abaca', 0, -1, 'a', 4, 5),
683 ('A', 'Abcde', 0, -1, 'A', 0, 1),
684 )
685 nocase_table = (
686 # pattern s i, j expected, expected_i, expected_j
687 ('a', 'abaAca', 0, -1, 'a', 5, 6),
688 ('A', 'Abcdca', 0, -1, 'a', 5, 6),
689 )
690 word_table = (
691 # pattern s i, j expected, expected_i, expected_j
692 ('a', 'abaAca', 0, -1, '', -1, -1),
693 ('A', 'AA A AB', 0, -1, 'A', 3, 4),
694 )
695 test(plain_table, 'plain_table', nocase=False, word=False)
696 test(nocase_table, 'nocase_table', nocase=True, word=False)
697 test(word_table, 'word_table', nocase=False, word=True)
698 #@+node:ekr.20210829203927.13: *4* TestFind.test_inner_search_plain
699 def test_inner_search_plain(self):
700 c = self.c
701 x = leoFind.LeoFind(c)
703 def test(table, table_name, nocase, word):
704 test_n = 0
705 for pattern, s, i, j, expected, expected_i, expected_j in table:
706 test_n += 1
707 if j == -1:
708 j = len(s)
709 got_i, got_j = x._inner_search_plain(s, i, j, pattern,
710 nocase=nocase, word=word)
711 got = s[got_i:got_j]
712 assert expected == got and got_i == expected_i and got_j == expected_j, (
713 '\n table: %s'
714 '\n i test: %s'
715 '\n pattern: %r'
716 '\n s: %r'
717 '\n expected: %r'
718 '\n got: %r'
719 '\nexpected i: %s'
720 '\n got i: %s'
721 '\nexpected j: %s'
722 '\n got j: %s'
723 % (table_name, test_n, pattern, s, expected, got, expected_i, got_i, expected_j, got_j))
725 plain_table = (
726 # pattern s i, j expected, expected_i, expected_j
727 ('a', 'baca', 0, -1, 'a', 1, 2),
728 ('A', 'bAcde', 0, -1, 'A', 1, 2),
729 )
730 nocase_table = (
731 # pattern s i, j expected, expected_i, expected_j
732 ('a', 'abaAca', 0, -1, 'a', 0, 1),
733 ('A', 'abcdca', 0, -1, 'a', 0, 1),
734 )
735 word_table = (
736 # pattern s i, j expected, expected_i, expected_j
737 ('a', 'abaAca', 0, -1, '', -1, -1),
738 ('A', 'AA A AAB', 0, -1, 'A', 3, 4),
739 )
740 test(plain_table, 'plain_table', nocase=False, word=False)
741 test(nocase_table, 'nocase_table', nocase=True, word=False)
742 test(word_table, 'word_table', nocase=False, word=True)
743 #@+node:ekr.20210829203927.11: *4* TestFind.test_inner_search_regex
744 def test_inner_search_regex(self):
745 c = self.c
746 x = leoFind.LeoFind(c)
748 def test(table, table_name, back, nocase):
749 for pattern, s, expected in table:
750 flags = re.IGNORECASE if nocase else 0
751 x.re_obj = re.compile(pattern, flags)
752 pos, new_pos = x._inner_search_regex(s, 0, len(s),
753 pattern, backwards=back, nocase=nocase)
754 got = s[pos:new_pos]
755 assert expected == got, (
756 '\n table: %s'
757 '\n pattern: %r'
758 '\n s: %r'
759 '\nexpected: %r'
760 '\n got: %r' % (table_name, pattern, s, expected, got)
761 )
763 plain_table = (
764 # pattern s expected
765 (r'.', 'A', 'A'),
766 (r'A', 'xAy', 'A'),
767 )
768 nocase_table = (
769 # pattern s expected
770 (r'.', 'A', 'A'),
771 (r'.', 'a', 'a'),
772 (r'A', 'xay', 'a'),
773 (r'a', 'xAy', 'A'),
774 )
775 back_table = (
776 # pattern s expected
777 (r'a.b', 'a1b a2b', 'a2b'),
778 )
779 test(plain_table, 'plain_table', back=False, nocase=False)
780 test(nocase_table, 'nocase_table', back=False, nocase=True)
781 test(back_table, 'back_table', back=True, nocase=False)
782 #@+node:ekr.20210110073117.82: *4* TestFind.test_make_regex_subs (to do)
783 def test_make_regex_subs(self):
784 x = self.x
785 x.re_obj = re.compile(r'(.*)pattern') # The search pattern.
786 m = x.re_obj.search('test pattern') # The find pattern.
787 change_text = r'\1Pattern\2' # \2 is non-matching group.
788 x.make_regex_subs(change_text, m.groups())
789 #@+node:ekr.20210110073117.84: *4* TestFind.test_next_node_after_fail
790 def test_fnm_next_after_fail(self):
791 settings, x = self.settings, self.x
792 for reverse in (True, False):
793 settings.reverse = reverse
794 for wrapping in (True, False):
795 settings.wrapping = wrapping
796 x.init_ivars_from_settings(settings)
797 x._fnm_next_after_fail(settings.p)
798 #@+node:ekr.20210110073117.86: *4* TestFind.test_replace_all_helper
799 def test_replace_all_helper(self):
800 settings, x = self.settings, self.x
801 settings.find_text = 'xyzzy'
802 settings.change_text = 'xYzzy'
803 s = 'abc xyzzy done'
804 x.replace_all_helper('') # Error test.
805 for regex in (True, False):
806 settings.pattern_match = regex
807 for word in (True, False):
808 settings.whole_word = word
809 x.init_ivars_from_settings(settings)
810 x.replace_all_helper(s)
811 #@+node:ekr.20210829203927.2: *4* TestFind.test_replace_all_plain_search
812 def test_replace_all_plain_search(self):
813 c = self.c
814 fc = c.findCommands
815 plain_table = (
816 # s find change count result
817 ('aA', 'a', 'C', 1, 'CA'),
818 ('Aa', 'A', 'C', 1, 'Ca'),
819 ('Aba', 'b', 'C', 1, 'ACa'),
820 )
821 for s, find, change, count, result in plain_table:
822 fc.ignore_case = False
823 fc.find_text = find
824 fc.change_text = change
825 count2, result2 = fc._change_all_plain(s)
826 self.assertEqual(result, result2)
827 self.assertEqual(count, count2)
828 #@+node:ekr.20210829203927.3: *4* TestFind.test_replace_all_plain_search_ignore_case
829 def test_replace_all_plain_search_ignore_case(self):
830 c = self.c
831 fc = c.findCommands
832 plain_table = (
833 # s find change count result
834 ('aA', 'a', 'C', 2, 'CC'),
835 ('AbBa', 'b', 'C', 2, 'ACCa'),
836 )
837 for s, find, change, count, result in plain_table:
838 fc.ignore_case = True
839 fc.find_text = find
840 fc.change_text = change
841 count2, result2 = fc._change_all_plain(s)
842 self.assertEqual(result, result2)
843 self.assertEqual(count, count2)
844 #@+node:ekr.20210829203927.4: *4* TestFind.test_replace_all_regex_search
845 def test_replace_all_regex_search(self):
846 c = self.c
847 fc = c.findCommands
848 regex_table = (
849 # s find change count result
850 ('a ba aa a ab a', r'\b\w+\b', 'C', 6, 'C C C C C C'),
851 ('a AA aa aab ab a', r'\baa\b', 'C', 1, 'a AA C aab ab a'),
852 # Multi-line
853 ('aaa AA\naa aab', r'\baa\b', 'C', 1, 'aaa AA\nC aab'),
854 )
855 for s, find, change, count, result in regex_table:
856 fc.ignore_case = False
857 fc.find_text = find
858 fc.change_text = change
859 count2, result2 = fc._change_all_regex(s)
860 self.assertEqual(result, result2)
861 self.assertEqual(count, count2)
862 #@+node:ekr.20210829203927.5: *4* TestFind.test_replace_all_word_search
863 def test_replace_all_word_search(self):
864 c = self.c
865 fc = c.findCommands
866 word_table = (
867 # s find change count result
868 ('a ba aa a ab a', 'a', 'C', 3, 'C ba aa C ab C'),
869 ('a ba aa a ab a', 'aa', 'C', 1, 'a ba C a ab a'),
870 )
871 for s, find, change, count, result in word_table:
872 fc.ignore_case = False
873 fc.find_text = find
874 fc.change_text = change
875 count2, result2 = fc._change_all_word(s)
876 self.assertEqual(result, result2)
877 self.assertEqual(count, count2)
878 #@+node:ekr.20210829203927.6: *4* TestFind.test_replace_all_word_search_ignore_case
879 def test_replace_all_word_search_ignore_case(self):
880 c = self.c
881 fc = c.findCommands
882 word_table = (
883 # s find change count result
884 ('a ba aa A ab a', 'a', 'C', 3, 'C ba aa C ab C'),
885 ('a ba aa AA ab a', 'aa', 'C', 2, 'a ba C C ab a'),
886 )
887 for s, find, change, count, result in word_table:
888 fc.ignore_case = True
889 fc.find_text = find
890 fc.change_text = change
891 count2, result2 = fc._change_all_word(s)
892 self.assertEqual(result, result2)
893 self.assertEqual(count, count2)
894 #@+node:ekr.20210829203927.14: *4* TestFind.test_replace_back_slashes
895 def test_replace_back_slashes(self):
896 c = self.c
897 x = leoFind.LeoFind(c)
898 table = (
899 ('\\\\', '\\'),
900 ('\\n', '\n'),
901 ('\\t', '\t'),
902 (r'a\bc', r'a\bc'),
903 (r'a\\bc', r'a\bc'),
904 (r'a\tc', 'a\tc'), # Replace \t by a tab.
905 (r'a\nc', 'a\nc'), # Replace \n by a newline.
906 )
907 for s, expected in table:
908 got = x.replace_back_slashes(s)
909 self.assertEqual(expected, got, msg=s)
910 #@+node:ekr.20210110073117.89: *4* TestFind.test_switch_style
911 def test_switch_style(self):
912 x = self.x
913 table = (
914 ('', None),
915 ('TestClass', None),
916 ('camelCase', 'camel_case'),
917 ('under_score', 'underScore'),
918 )
919 for s, expected in table:
920 result = x._switch_style(s)
921 self.assertEqual(result, expected, msg=repr(s))
922 #@-others
923#@-others
925#@-leo