Coverage for core\test_leoFind.py: 100%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

615 statements  

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""" 

6 

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 

12 

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 

35 

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 

41 

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 

47 

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) 

52 

53 for p in c.all_positions(): 

54 p.v.clearDirty() 

55 p.v.clearVisited() 

56 

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() 

64 

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 

74 

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 

142 

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): 

195 

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() 

202 

203 #@+node:ekr.20210110073117.62: *4* TestFind.clone-find-tag 

204 def test_clone_find_tag(self): 

205 c, x = self.c, self.x 

206 

207 class DummyTagController: 

208 

209 def __init__(self, clones): 

210 self.clones = clones 

211 

212 def get_tagged_nodes(self, tag): 

213 return self.clones 

214 

215 def show_all_tags(self): 

216 pass 

217 

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 

227 

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 

239 

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) 

264 

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 for bool_val in (True, False): 

276 x.reverse_find_defs = bool_val 

277 p, pos, newpos = x.do_find_def(settings, word='child5', strict=True) 

278 assert p 

279 self.assertEqual(p.h, 'child 5') 

280 s = p.b[pos:newpos] 

281 self.assertEqual(s, 'def child5') 

282 # Test 2: switch style. 

283 p, pos, newpos = x.do_find_def(settings, word='child_5', strict=False) 

284 assert p 

285 self.assertEqual(p.h, 'child 5') 

286 # Test 3: not found after switching style. 

287 p, pos, newpos = x.do_find_def(settings, word='xyzzy', strict=False) 

288 assert p is None, repr(p) 

289 #@+node:ekr.20210110073117.64: *4* TestFind.find-next 

290 def test_find_next(self): 

291 settings, x = self.settings, self.x 

292 settings.find_text = 'def top1' 

293 p, pos, newpos = x.do_find_next(settings) 

294 assert p 

295 self.assertEqual(p.h, 'Node 1') 

296 s = p.b[pos:newpos] 

297 self.assertEqual(s, settings.find_text) 

298 #@+node:ekr.20210220072631.1: *4* TestFind.find-next (suboutline-only) 

299 def test_find_next_suboutline_only(self): 

300 settings, x = self.settings, self.x 

301 settings.find_text = 'def root()' 

302 settings.suboutline_only = True # init_ivars_from_settings will set the ivar. 

303 p, pos, newpos = x.do_find_next(settings) 

304 assert p 

305 self.assertEqual(p.h, 'Root') 

306 s = p.b[pos:newpos] 

307 self.assertEqual(s, settings.find_text) 

308 #@+node:ekr.20210924032146.1: *4* TestFind.change-then-find (headline) 

309 def test_change_then_find_in_headline(self): 

310 # Test #2220: 

311 # https://github.com/leo-editor/leo-editor/issues/2220 

312 # Let block. 

313 settings, c, x = self.settings, self.c, self.x 

314 # Set up the search. 

315 settings.find_text = 'Test' 

316 settings.change_text = 'XX' 

317 # Create the tree. 

318 test_p = self.c.rootPosition().insertAfter() 

319 test_p.h = 'Test1 Test2 Test3' 

320 after_p = test_p.insertAfter() 

321 after_p.h = 'After' 

322 # Find test_p. 

323 p, pos, newpos = x.do_find_next(settings) 

324 self.assertEqual(p, test_p) 

325 w = c.edit_widget(p) 

326 self.assertEqual(test_p.h, w.getAllText()) 

327 self.assertEqual(w.getSelectionRange(), (pos, newpos)) 

328 # Do change-then-find. 

329 ok = x.do_change_then_find(settings) 

330 self.assertTrue(ok) 

331 p = c.p 

332 self.assertEqual(p, test_p) 

333 self.assertEqual(p.h, 'XX1 Test2 Test3') 

334 #@+node:ekr.20210216094444.1: *4* TestFind.find-prev 

335 def test_find_prev(self): 

336 c, settings, x = self.c, self.settings, self.x 

337 settings.find_text = 'def top1' 

338 # Start at end, so we stay in the node. 

339 grand_child = g.findNodeAnywhere(c, 'child 6') 

340 settings.p = grand_child 

341 assert settings.p 

342 settings.find_text = 'def child2' 

343 # Set c.p in the command. 

344 x.c.selectPosition(grand_child) 

345 p, pos, newpos = x.do_find_prev(settings) 

346 assert p 

347 self.assertEqual(p.h, 'child 2') 

348 s = p.b[pos:newpos] 

349 self.assertEqual(s, settings.find_text) 

350 #@+node:ekr.20210110073117.66: *4* TestFind.find-var 

351 def test_find_var(self): 

352 settings, x = self.settings, self.x 

353 p, pos, newpos = x.do_find_var(settings, word='v5') 

354 assert p 

355 self.assertEqual(p.h, 'child 5') 

356 s = p.b[pos:newpos] 

357 self.assertEqual(s, 'v5 =') 

358 #@+node:ekr.20210110073117.68: *4* TestFind.replace-then-find 

359 def test_replace_then_find(self): 

360 settings, w, x = self.settings, self.c.frame.body.wrapper, self.x 

361 settings.find_text = 'def top1' 

362 settings.change_text = 'def top' 

363 # find-next 

364 p, pos, newpos = x.do_find_next(settings) 

365 assert p 

366 self.assertEqual(p.h, 'Node 1') 

367 s = p.b[pos:newpos] 

368 self.assertEqual(s, settings.find_text) 

369 # replace-then-find 

370 w.setSelectionRange(pos, newpos, insert=pos) 

371 x.do_change_then_find(settings) 

372 # Failure exit. 

373 w.setSelectionRange(0, 0) 

374 x.do_change_then_find(settings) 

375 

376 def test_replace_then_find_regex(self): 

377 settings, w, x = self.settings, self.c.frame.body.wrapper, self.x 

378 settings.find_text = r'(def) top1' 

379 settings.change_text = r'\1\1' 

380 settings.pattern_match = True 

381 # find-next 

382 p, pos, newpos = x.do_find_next(settings) 

383 s = p.b[pos:newpos] 

384 self.assertEqual(s, 'def top1') 

385 # replace-then-find 

386 w.setSelectionRange(pos, newpos, insert=pos) 

387 x.do_change_then_find(settings) 

388 

389 def test_replace_then_find_in_headline(self): 

390 settings, x = self.settings, self.x 

391 p = settings.p 

392 settings.find_text = 'Node 1' 

393 settings.change_text = 'Node 1a' 

394 settings.in_headline = True 

395 # find-next 

396 p, pos, newpos = x.do_find_next(settings) 

397 assert p 

398 self.assertEqual(p.h, settings.find_text) 

399 w = self.c.edit_widget(p) 

400 assert w 

401 s = p.h[pos:newpos] 

402 self.assertEqual(s, settings.find_text) 

403 #@+node:ekr.20210110073117.69: *4* TestFind.tag-children 

404 def test_tag_children(self): 

405 

406 c, x = self.c, self.x 

407 

408 class DummyTagController: 

409 def add_tag(self, p, tag): 

410 pass 

411 

412 p = c.rootPosition().next() 

413 c.theTagController = None 

414 x.do_tag_children(p, 'test') 

415 c.theTagController = DummyTagController() 

416 x.do_tag_children(p, 'test') 

417 #@+node:ekr.20210219181001.1: *4* testFind.test_batch_change_regex 

418 def test_batch_change_regex(self): 

419 c, x = self.c, self.x 

420 # self.dump_tree() 

421 # Test 1: Match in body. 

422 settings = dict( 

423 ignore_case=False, 

424 node_only=False, 

425 pattern_match=True, 

426 search_body=True, 

427 search_headline=True, 

428 suboutline_only=False, 

429 whole_word=False, 

430 ) 

431 # Test 1: Match in body. 

432 n = x.batch_change( 

433 root=c.rootPosition(), 

434 replacements=((r'^def\b', 'DEF'),), 

435 settings=settings) 

436 assert n > 3, n # Test 1. 

437 # Test 2: Match in headline. 

438 n = x.batch_change( 

439 root=c.rootPosition(), 

440 replacements=((r'^Node\b', 'DEF'),), 

441 settings=settings) 

442 self.assertEqual(n, 2) 

443 # Test 3: node-only. 

444 settings['node_only'] = True 

445 n = x.batch_change( 

446 root=c.rootPosition(), 

447 replacements=((r'^DEF\b', 'def'),), 

448 settings=settings) 

449 self.assertEqual(n, 1) 

450 # Test 4: suboutline-only. 

451 settings['node_only'] = False 

452 settings['suboutline_only'] = True 

453 n = x.batch_change( 

454 root=c.rootPosition(), 

455 replacements=((r'^def\b', 'DEF'),), 

456 settings=settings) 

457 self.assertEqual(n, 1) 

458 #@+node:ekr.20210219175850.1: *4* testFind.test_batch_change_word 

459 def test_batch_change_word(self): 

460 # settings, x = self.settings, self.x 

461 c, x = self.c, self.x 

462 settings = dict( 

463 ignore_case=False, 

464 node_only=False, 

465 pattern_match=False, 

466 search_body=True, 

467 search_headline=True, 

468 suboutline_only=False, 

469 whole_word=True, 

470 ) 

471 n = x.batch_change( 

472 root=c.rootPosition(), 

473 replacements=(('def', 'DEF'),), 

474 settings=settings) 

475 assert n > 0 

476 

477 #@+node:ekr.20210110073117.58: *4* TestFind.test_tree 

478 def test_tree(self): 

479 c = self.c 

480 table = ( 

481 (0, 'Root'), 

482 (0, 'Node 1'), 

483 (1, 'child 2'), 

484 (2, 'child 3'), 

485 (0, 'Node 4'), 

486 (1, 'child 5'), 

487 (2, 'child 6'), 

488 ) 

489 for level, h in table: 

490 p = g.findNodeAnywhere(c, h) 

491 self.assertEqual(p.h, h) 

492 self.assertEqual(p.level(), level) 

493 #@+node:ekr.20210110073117.70: *3* Tests of Helpers... 

494 #@+node:ekr.20210110073117.72: *4* TestFind.test_argument_errors 

495 def test_argument_errors(self): 

496 

497 settings, x = self.settings, self.x 

498 # Bad search pattern. 

499 settings.find_text = r'^def\b((' 

500 settings.pattern_match = True 

501 x.do_clone_find_all(settings) 

502 x.find_next_match(p=None) 

503 x.do_change_all(settings) 

504 #@+node:ekr.20210110073117.74: *4* TestFind.test_batch_plain_replace 

505 def test_batch_plain_replace(self): 

506 settings, x = self.settings, self.x 

507 settings.find_text = 'b' 

508 settings.change_text = 'B' 

509 for ignore in (True, False): 

510 settings.ignore_case = ignore 

511 x.init_ivars_from_settings(settings) 

512 s = 'abc b z' 

513 count, s2 = x.batch_plain_replace(s) 

514 self.assertEqual(count, 2, msg=f"ignore: {ignore}") 

515 self.assertEqual(s2, 'aBc B z', msg=f"ignore: {ignore}") 

516 #@+node:ekr.20210110073117.75: *4* TestFind.test_batch_regex_replace 

517 def test_batch_regex_replace(self): 

518 settings, x = self.settings, self.x 

519 s = 'abc b z' 

520 table = ( 

521 (1, 2, 'B', 'B', 'aBc B z'), 

522 (0, 2, 'b', 'B', 'aBc B z'), 

523 (1, 2, r'([BX])', 'B', 'aBc B z'), 

524 ) 

525 for ignore, count, find, change, expected_s in table: 

526 settings.ignore_case = bool(ignore) 

527 settings.find_text = find 

528 settings.change_text = change 

529 x.init_ivars_from_settings(settings) 

530 actual_count, actual_s = x.batch_regex_replace(s) 

531 self.assertEqual(actual_count, count, msg=find) 

532 self.assertEqual(actual_s, expected_s, msg=find) 

533 #@+node:ekr.20210110073117.73: *4* TestFind.test_batch_word_replace 

534 def test_batch_word_replace(self): 

535 settings, x = self.settings, self.x 

536 settings.find_text = 'b' 

537 settings.change_text = 'B' 

538 for ignore in (True, False): 

539 settings.ignore_case = ignore 

540 x.init_ivars_from_settings(settings) 

541 s = 'abc b z' 

542 count, s2 = x.batch_word_replace(s) 

543 self.assertEqual(count, 1) 

544 self.assertEqual(s2, 'abc B z') 

545 #@+node:ekr.20210110073117.71: *4* TestFind.test_cfa_backwards_search 

546 def test_cfa_backwards_search(self): 

547 settings, x = self.settings, self.x 

548 pattern = 'def' 

549 for nocase in (True, False): 

550 settings.ignore_case = nocase 

551 for word in (True, False): 

552 for s in ('def spam():\n', 'define spam'): 

553 settings.whole_word = word 

554 x.init_ivars_from_settings(settings) 

555 x._inner_search_backward(s, 0, len(s), pattern, nocase, word) 

556 x._inner_search_backward(s, 0, 0, pattern, nocase, word) 

557 #@+node:ekr.20210110073117.80: *4* TestFind.test_cfa_find_next_match 

558 def test_cfa_find_next_match(self): 

559 c, settings, x = self.c, self.settings, self.x 

560 p = c.rootPosition() 

561 for find in ('xxx', 'def'): 

562 settings.find_text = find 

563 x._cfa_find_next_match(p) 

564 #@+node:ekr.20210110073117.83: *4* TestFind.test_cfa_match_word 

565 def test_cfa_match_word(self): 

566 x = self.x 

567 x._inner_search_match_word("def spam():", 0, "spam") 

568 x._inner_search_match_word("def spam():", 0, "xxx") 

569 

570 #@+node:ekr.20210110073117.85: *4* TestFind.test_cfa_plain_search 

571 def test_cfa_plain_search(self): 

572 settings, x = self.settings, self.x 

573 pattern = 'def' 

574 for nocase in (True, False): 

575 settings.ignore_case = nocase 

576 for word in (True, False): 

577 for s in ('def spam():\n', 'define'): 

578 settings.whole_word = word 

579 x.init_ivars_from_settings(settings) 

580 x._inner_search_plain(s, 0, len(s), pattern, nocase, word) 

581 x._inner_search_plain(s, 0, 0, pattern, nocase, word) 

582 #@+node:ekr.20210110073117.88: *4* TestFind.test_cfa_regex_search 

583 def test_cfa_regex_search(self): 

584 x = self.x 

585 pattern = r'(.*)pattern' 

586 x.re_obj = re.compile(pattern) 

587 table = ( 

588 'test pattern', # Match. 

589 'xxx', # No match. 

590 ) 

591 for backwards in (True, False): 

592 for nocase in (True, False): 

593 for s in table: 

594 if backwards: 

595 i = j = len(s) 

596 else: 

597 i = j = 0 

598 x._inner_search_regex(s, i, j, pattern, backwards, nocase) 

599 # Error test. 

600 x.re_obj = None 

601 backwards = pattern = nocase = None 

602 x._inner_search_regex("", 0, 0, pattern, backwards, nocase) 

603 #@+node:ekr.20210110073117.76: *4* TestFind.test_check_args 

604 def test_check_args(self): 

605 # Bad search patterns.. 

606 x = self.x 

607 settings = self.settings 

608 # Not searching headline or body. 

609 settings.search_body = False 

610 settings.search_headline = False 

611 x.do_clone_find_all(settings) 

612 # Empty find pattern. 

613 settings.search_body = True 

614 settings.find_text = '' 

615 x.do_clone_find_all(settings) 

616 x.do_clone_find_all_flattened(settings) 

617 x.do_find_all(settings) 

618 x.do_find_next(settings) 

619 x.do_find_next(settings) 

620 x.do_find_prev(settings) 

621 x.do_change_all(settings) 

622 x.do_change_then_find(settings) 

623 #@+node:ekr.20210829203927.10: *4* TestFind.test_clean_init 

624 def test_clean_init(self): 

625 c = self.c 

626 x = leoFind.LeoFind(c) 

627 table = ( 

628 'ignore_case', 'node_only', 'pattern_match', 

629 'search_headline', 'search_body', 'suboutline_only', 

630 'mark_changes', 'mark_finds', 'whole_word', 

631 ) 

632 for ivar in table: 

633 assert getattr(x, ivar) is None, ivar 

634 assert x.reverse is False 

635 #@+node:ekr.20210110073117.77: *4* TestFind.test_compute_result_status 

636 def test_compute_result_status(self): 

637 x = self.x 

638 # find_all_flag is True 

639 all_settings = x.default_settings() 

640 all_settings.ignore_case = True 

641 all_settings.pattern_match = True 

642 all_settings.whole_word = True 

643 all_settings.wrapping = True 

644 x.init_ivars_from_settings(all_settings) 

645 x.compute_result_status(find_all_flag=True) 

646 # find_all_flag is False 

647 partial_settings = x.default_settings() 

648 partial_settings.search_body = True 

649 partial_settings.search_headline = True 

650 partial_settings.node_only = True 

651 partial_settings.suboutline_only = True 

652 partial_settings.wrapping = True 

653 x.init_ivars_from_settings(partial_settings) 

654 x.compute_result_status(find_all_flag=False) 

655 #@+node:ekr.20210829203927.12: *4* TestFind.test_inner_search_backward 

656 def test_inner_search_backward(self): 

657 c = self.c 

658 x = leoFind.LeoFind(c) 

659 

660 def test(table, table_name, nocase, word): 

661 test_n = 0 

662 for pattern, s, i, j, expected, expected_i, expected_j in table: 

663 test_n += 1 

664 if j == -1: 

665 j = len(s) 

666 got_i, got_j = x._inner_search_backward(s, i, j, 

667 pattern, nocase=nocase, word=word) 

668 got = s[got_i:got_j] 

669 assert expected == got and got_i == expected_i and got_j == expected_j, ( 

670 '\n table: %s' 

671 '\n i test: %s' 

672 '\n pattern: %r' 

673 '\n s: %r' 

674 '\n expected: %r' 

675 '\n got: %r' 

676 '\nexpected i: %s' 

677 '\n got i: %s' 

678 '\nexpected j: %s' 

679 '\n got j: %s' 

680 % (table_name, test_n, pattern, s, expected, got, expected_i, got_i, expected_j, got_j)) 

681 

682 plain_table = ( 

683 # pattern s i, j expected, expected_i, expected_j 

684 ('a', 'abaca', 0, -1, 'a', 4, 5), 

685 ('A', 'Abcde', 0, -1, 'A', 0, 1), 

686 ) 

687 nocase_table = ( 

688 # pattern s i, j expected, expected_i, expected_j 

689 ('a', 'abaAca', 0, -1, 'a', 5, 6), 

690 ('A', 'Abcdca', 0, -1, 'a', 5, 6), 

691 ) 

692 word_table = ( 

693 # pattern s i, j expected, expected_i, expected_j 

694 ('a', 'abaAca', 0, -1, '', -1, -1), 

695 ('A', 'AA A AB', 0, -1, 'A', 3, 4), 

696 ) 

697 test(plain_table, 'plain_table', nocase=False, word=False) 

698 test(nocase_table, 'nocase_table', nocase=True, word=False) 

699 test(word_table, 'word_table', nocase=False, word=True) 

700 #@+node:ekr.20210829203927.13: *4* TestFind.test_inner_search_plain 

701 def test_inner_search_plain(self): 

702 c = self.c 

703 x = leoFind.LeoFind(c) 

704 

705 def test(table, table_name, nocase, word): 

706 test_n = 0 

707 for pattern, s, i, j, expected, expected_i, expected_j in table: 

708 test_n += 1 

709 if j == -1: 

710 j = len(s) 

711 got_i, got_j = x._inner_search_plain(s, i, j, pattern, 

712 nocase=nocase, word=word) 

713 got = s[got_i:got_j] 

714 assert expected == got and got_i == expected_i and got_j == expected_j, ( 

715 '\n table: %s' 

716 '\n i test: %s' 

717 '\n pattern: %r' 

718 '\n s: %r' 

719 '\n expected: %r' 

720 '\n got: %r' 

721 '\nexpected i: %s' 

722 '\n got i: %s' 

723 '\nexpected j: %s' 

724 '\n got j: %s' 

725 % (table_name, test_n, pattern, s, expected, got, expected_i, got_i, expected_j, got_j)) 

726 

727 plain_table = ( 

728 # pattern s i, j expected, expected_i, expected_j 

729 ('a', 'baca', 0, -1, 'a', 1, 2), 

730 ('A', 'bAcde', 0, -1, 'A', 1, 2), 

731 ) 

732 nocase_table = ( 

733 # pattern s i, j expected, expected_i, expected_j 

734 ('a', 'abaAca', 0, -1, 'a', 0, 1), 

735 ('A', 'abcdca', 0, -1, 'a', 0, 1), 

736 ) 

737 word_table = ( 

738 # pattern s i, j expected, expected_i, expected_j 

739 ('a', 'abaAca', 0, -1, '', -1, -1), 

740 ('A', 'AA A AAB', 0, -1, 'A', 3, 4), 

741 ) 

742 test(plain_table, 'plain_table', nocase=False, word=False) 

743 test(nocase_table, 'nocase_table', nocase=True, word=False) 

744 test(word_table, 'word_table', nocase=False, word=True) 

745 #@+node:ekr.20210829203927.11: *4* TestFind.test_inner_search_regex 

746 def test_inner_search_regex(self): 

747 c = self.c 

748 x = leoFind.LeoFind(c) 

749 

750 def test(table, table_name, back, nocase): 

751 for pattern, s, expected in table: 

752 flags = re.IGNORECASE if nocase else 0 

753 x.re_obj = re.compile(pattern, flags) 

754 pos, new_pos = x._inner_search_regex(s, 0, len(s), 

755 pattern, backwards=back, nocase=nocase) 

756 got = s[pos:new_pos] 

757 assert expected == got, ( 

758 '\n table: %s' 

759 '\n pattern: %r' 

760 '\n s: %r' 

761 '\nexpected: %r' 

762 '\n got: %r' % (table_name, pattern, s, expected, got) 

763 ) 

764 

765 plain_table = ( 

766 # pattern s expected 

767 (r'.', 'A', 'A'), 

768 (r'A', 'xAy', 'A'), 

769 ) 

770 nocase_table = ( 

771 # pattern s expected 

772 (r'.', 'A', 'A'), 

773 (r'.', 'a', 'a'), 

774 (r'A', 'xay', 'a'), 

775 (r'a', 'xAy', 'A'), 

776 ) 

777 back_table = ( 

778 # pattern s expected 

779 (r'a.b', 'a1b a2b', 'a2b'), 

780 ) 

781 test(plain_table, 'plain_table', back=False, nocase=False) 

782 test(nocase_table, 'nocase_table', back=False, nocase=True) 

783 test(back_table, 'back_table', back=True, nocase=False) 

784 #@+node:ekr.20210110073117.82: *4* TestFind.test_make_regex_subs 

785 def test_make_regex_subs(self): 

786 x = self.x 

787 x.re_obj = re.compile(r'(.*)pattern') # The search pattern. 

788 m = x.re_obj.search('test pattern') # The find pattern. 

789 change_text = r'\1Pattern\2' # \2 is non-matching group. 

790 x.make_regex_subs(change_text, m.groups()) 

791 #@+node:ekr.20210110073117.84: *4* TestFind.test_next_node_after_fail 

792 def test_fnm_next_after_fail(self): 

793 settings, x = self.settings, self.x 

794 for reverse in (True, False): 

795 settings.reverse = reverse 

796 for wrapping in (True, False): 

797 settings.wrapping = wrapping 

798 x.init_ivars_from_settings(settings) 

799 x._fnm_next_after_fail(settings.p) 

800 #@+node:ekr.20210110073117.86: *4* TestFind.test_replace_all_helper 

801 def test_replace_all_helper(self): 

802 settings, x = self.settings, self.x 

803 settings.find_text = 'xyzzy' 

804 settings.change_text = 'xYzzy' 

805 s = 'abc xyzzy done' 

806 x.replace_all_helper('') # Error test. 

807 for regex in (True, False): 

808 settings.pattern_match = regex 

809 for word in (True, False): 

810 settings.whole_word = word 

811 x.init_ivars_from_settings(settings) 

812 x.replace_all_helper(s) 

813 #@+node:ekr.20210829203927.2: *4* TestFind.test_replace_all_plain_search 

814 def test_replace_all_plain_search(self): 

815 c = self.c 

816 fc = c.findCommands 

817 plain_table = ( 

818 # s find change count result 

819 ('aA', 'a', 'C', 1, 'CA'), 

820 ('Aa', 'A', 'C', 1, 'Ca'), 

821 ('Aba', 'b', 'C', 1, 'ACa'), 

822 ) 

823 for s, find, change, count, result in plain_table: 

824 fc.ignore_case = False 

825 fc.find_text = find 

826 fc.change_text = change 

827 count2, result2 = fc._change_all_plain(s) 

828 self.assertEqual(result, result2) 

829 self.assertEqual(count, count2) 

830 #@+node:ekr.20210829203927.3: *4* TestFind.test_replace_all_plain_search_ignore_case 

831 def test_replace_all_plain_search_ignore_case(self): 

832 c = self.c 

833 fc = c.findCommands 

834 plain_table = ( 

835 # s find change count result 

836 ('aA', 'a', 'C', 2, 'CC'), 

837 ('AbBa', 'b', 'C', 2, 'ACCa'), 

838 ) 

839 for s, find, change, count, result in plain_table: 

840 fc.ignore_case = True 

841 fc.find_text = find 

842 fc.change_text = change 

843 count2, result2 = fc._change_all_plain(s) 

844 self.assertEqual(result, result2) 

845 self.assertEqual(count, count2) 

846 #@+node:ekr.20210829203927.4: *4* TestFind.test_replace_all_regex_search 

847 def test_replace_all_regex_search(self): 

848 c = self.c 

849 fc = c.findCommands 

850 regex_table = ( 

851 # s find change count result 

852 ('a ba aa a ab a', r'\b\w+\b', 'C', 6, 'C C C C C C'), 

853 ('a AA aa aab ab a', r'\baa\b', 'C', 1, 'a AA C aab ab a'), 

854 # Multi-line 

855 ('aaa AA\naa aab', r'\baa\b', 'C', 1, 'aaa AA\nC aab'), 

856 ) 

857 for s, find, change, count, result in regex_table: 

858 fc.ignore_case = False 

859 fc.find_text = find 

860 fc.change_text = change 

861 count2, result2 = fc._change_all_regex(s) 

862 self.assertEqual(result, result2) 

863 self.assertEqual(count, count2) 

864 #@+node:ekr.20210829203927.5: *4* TestFind.test_replace_all_word_search 

865 def test_replace_all_word_search(self): 

866 c = self.c 

867 fc = c.findCommands 

868 word_table = ( 

869 # s find change count result 

870 ('a ba aa a ab a', 'a', 'C', 3, 'C ba aa C ab C'), 

871 ('a ba aa a ab a', 'aa', 'C', 1, 'a ba C a ab a'), 

872 ) 

873 for s, find, change, count, result in word_table: 

874 fc.ignore_case = False 

875 fc.find_text = find 

876 fc.change_text = change 

877 count2, result2 = fc._change_all_word(s) 

878 self.assertEqual(result, result2) 

879 self.assertEqual(count, count2) 

880 #@+node:ekr.20210829203927.6: *4* TestFind.test_replace_all_word_search_ignore_case 

881 def test_replace_all_word_search_ignore_case(self): 

882 c = self.c 

883 fc = c.findCommands 

884 word_table = ( 

885 # s find change count result 

886 ('a ba aa A ab a', 'a', 'C', 3, 'C ba aa C ab C'), 

887 ('a ba aa AA ab a', 'aa', 'C', 2, 'a ba C C ab a'), 

888 ) 

889 for s, find, change, count, result in word_table: 

890 fc.ignore_case = True 

891 fc.find_text = find 

892 fc.change_text = change 

893 count2, result2 = fc._change_all_word(s) 

894 self.assertEqual(result, result2) 

895 self.assertEqual(count, count2) 

896 #@+node:ekr.20210829203927.14: *4* TestFind.test_replace_back_slashes 

897 def test_replace_back_slashes(self): 

898 c = self.c 

899 x = leoFind.LeoFind(c) 

900 table = ( 

901 ('\\\\', '\\'), 

902 ('\\n', '\n'), 

903 ('\\t', '\t'), 

904 (r'a\bc', r'a\bc'), 

905 (r'a\\bc', r'a\bc'), 

906 (r'a\tc', 'a\tc'), # Replace \t by a tab. 

907 (r'a\nc', 'a\nc'), # Replace \n by a newline. 

908 ) 

909 for s, expected in table: 

910 got = x.replace_back_slashes(s) 

911 self.assertEqual(expected, got, msg=s) 

912 #@+node:ekr.20210110073117.89: *4* TestFind.test_switch_style 

913 def test_switch_style(self): 

914 x = self.x 

915 table = ( 

916 ('', None), 

917 ('TestClass', None), 

918 ('camelCase', 'camel_case'), 

919 ('under_score', 'underScore'), 

920 ) 

921 for s, expected in table: 

922 result = x._switch_style(s) 

923 self.assertEqual(result, expected, msg=repr(s)) 

924 #@-others 

925#@-others 

926 

927#@-leo