Hide keyboard shortcuts

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

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

373 

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) 

386 

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

403 

404 c, x = self.c, self.x 

405 

406 class DummyTagController: 

407 def add_tag(self, p, tag): 

408 pass 

409 

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 

474 

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

494 

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

567 

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) 

657 

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

679 

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) 

702 

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

724 

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) 

747 

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 ) 

762 

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 

924 

925#@-leo