Coverage for core\test_leoNodes.py : 99%

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.20201203042030.1: * @file ../unittests/core/test_leoNodes.py
4#@@first
5"""Tests for leo.core.leoNodes"""
7# pylint has troubles finding Commands methods.
8# pylint: disable=no-member
9import textwrap
10from leo.core import leoGlobals as g
11from leo.core.leoTest2 import LeoUnitTest
13#@+others
14#@+node:ekr.20210828112210.1: ** class TestNodes(LeoUnitTest)
15class TestNodes(LeoUnitTest):
16 """Unit tests for leo/core/leoNodes.py."""
18 test_outline = None # Set by create_test_outline.
20 #@+others
21 #@+node:ekr.20201203042409.3: *3* TestNodes.setUp
22 def setUp(self):
23 """Create the nodes in the commander."""
24 super().setUp()
25 c = self.c
26 self.create_test_outline()
27 c.selectPosition(c.rootPosition())
28 #@+node:ekr.20210902022909.1: *3* TestNodes.tests...
29 #@+node:ekr.20210830095545.3: *4* TestNodes.test_all_generators_return_unique_positions
30 def test_all_generators_return_unique_positions(self):
31 # This tests a major bug in *all* generators returning positions.
32 c, p = self.c, self.c.p
33 root = p.next()
34 table = (
35 ('all_positions', c.all_positions),
36 ('all_unique_positions', c.all_unique_positions),
37 ('children', root.children),
38 ('self_and_siblings', root.self_and_siblings),
39 ('self_and_parents', root.firstChild().self_and_parents),
40 ('self_and_subtree', root.self_and_subtree),
41 ('following_siblings', root.following_siblings),
42 ('parents', root.firstChild().firstChild().parents),
43 ('unique_subtree', root.unique_subtree),
44 )
45 for kind, generator in table:
46 aList = []
47 for p in generator():
48 self.assertFalse(p in aList, msg=f"{kind} {p.gnx} {p.h}")
49 aList.append(p)
50 #@+node:ekr.20210828075915.1: *4* TestNodes.test_all_nodes_coverage
51 def test_all_nodes_coverage(self):
52 # @test c iters: <coverage tests>
53 c = self.c
54 v1 = [p.v for p in c.all_positions()]
55 v2 = [v for v in c.all_nodes()]
56 for v in v2:
57 self.assertTrue(v in v1)
58 for v in v1:
59 self.assertTrue(v in v2)
60 #@+node:ekr.20210830095545.41: *4* TestNodes.test_at_most_one_VNode_has_str_leo_pos_attribute
61 def test_at_most_one_VNode_has_str_leo_pos_attribute(self):
62 c = self.c
63 n = 0
64 for v in c.all_unique_vnodes_iter():
65 if hasattr(v, 'unknownAttributes'):
66 d = v.unknownAttributes
67 if d.get('str_leo_pos'):
68 n += 1
69 self.assertTrue(n == 0)
70 #@+node:ekr.20210830095545.58: *4* TestNodes.test_at_others_directive
71 def test_at_others_directive(self):
72 p = self.c.p
73 p1 = p.insertAsLastChild()
74 p1.setHeadString('@file zzz')
75 body = ''' %s
76 ''' % (chr(64) + 'others') # ugly hack
77 p1.setBodyString(body)
78 p2 = p1.insertAsLastChild()
79 self.assertEqual(p1.textOffset(), 0)
80 self.assertEqual(p2.textOffset(), 5)
81 #@+node:ekr.20210830095545.6: *4* TestNodes.test_c_positionExists
82 def test_c_positionExists(self):
83 c, p = self.c, self.c.p
84 child = p.insertAsLastChild()
85 self.assertTrue(c.positionExists(child))
86 child.doDelete()
87 self.assertFalse(c.positionExists(child))
88 # also check the same on root level
89 child = c.rootPosition().insertAfter()
90 self.assertTrue(c.positionExists(child))
91 child.doDelete()
92 self.assertFalse(c.positionExists(child))
93 #@+node:ekr.20210830095545.7: *4* TestNodes.test_c_positionExists_for_all_nodes
94 def test_c_positionExists_for_all_nodes(self):
95 c, p = self.c, self.c.p
96 for p in c.all_positions():
97 self.assertTrue(c.positionExists(p))
98 # 2012/03/08: If a root is given, the search is confined to that root only.
99 #@+node:ekr.20210830095545.8: *4* TestNodes.test_c_safe_all_positions
100 def test_c_safe_all_positions(self):
101 c = self.c
102 aList1 = list(c.all_positions())
103 aList2 = list(c.safe_all_positions())
104 self.assertEqual(len(aList1), len(aList2))
105 #@+node:ekr.20210830095545.9: *4* TestNodes.test_check_all_gnx_s_exist_and_are_unique
106 def test_check_all_gnx_s_exist_and_are_unique(self):
107 c, p = self.c, self.c.p
108 d = {} # Keys are gnx's, values are lists of vnodes with that gnx.
109 for p in c.all_positions():
110 gnx = p.v.fileIndex
111 self.assertTrue(gnx)
112 aSet = d.get(gnx, set())
113 aSet.add(p.v)
114 d[gnx] = aSet
115 for gnx in sorted(d.keys()):
116 aList = sorted(d.get(gnx))
117 self.assertTrue(len(aList) == 1)
118 #@+node:ekr.20210830095545.42: *4* TestNodes.test_clone_and_move_the_clone_to_the_root
119 def test_clone_and_move_the_clone_to_the_root(self):
120 c, p = self.c, self.c.p
121 child = p.insertAsNthChild(0)
122 c.setHeadString(child, 'child') # Force the headline to update.
123 self.assertTrue(child)
124 c.selectPosition(child)
125 clone = c.clone()
126 self.assertEqual(clone, c.p)
127 self.assertEqual(clone.h, 'child')
128 assert child.isCloned(), 'fail 1'
129 assert clone.isCloned(), 'fail 2'
130 assert child.isCloned(), 'fail 3'
131 assert clone.isCloned(), 'fail 4'
132 c.undoer.undo()
133 assert not child.isCloned(), 'fail 1-a'
134 c.undoer.redo()
135 assert child.isCloned(), 'fail 1-b'
136 c.undoer.undo()
137 assert not child.isCloned(), 'fail 1-c'
138 c.undoer.redo()
139 assert child.isCloned(), 'fail 1-d'
140 clone.moveToRoot() # Does not change child position.
141 assert child.isCloned(), 'fail 3-2'
142 assert clone.isCloned(), 'fail 4-2'
143 assert not clone.parent(), 'fail 5'
144 assert not clone.back(), 'fail 6'
145 clone.doDelete()
146 assert not child.isCloned(), 'fail 7'
147 #@+node:ekr.20210830095545.2: *4* TestNodes.test_consistency_between_parents_iter_and_v_parents
148 def test_consistency_between_parents_iter_and_v_parents(self):
149 c, p = self.c, self.c.p
150 for p in c.all_positions():
151 parents1 = p.v.parents
152 parents2 = p.v.directParents()
153 self.assertEqual(len(parents1), len(parents2), msg=p.h)
154 for parent in parents1:
155 self.assertTrue(parent in parents2)
156 for parent in parents2:
157 self.assertTrue(parent in parents1)
158 #@+node:ekr.20210830095545.10: *4* TestNodes.test_consistency_of_back_next_links
159 def test_consistency_of_back_next_links(self):
160 c, p = self.c, self.c.p
161 for p in c.all_positions():
162 back = p.back()
163 next = p.next()
164 if back:
165 self.assertEqual(back.getNext(), p)
166 if next:
167 self.assertEqual(next.getBack(), p)
168 #@+node:ekr.20210830095545.11: *4* TestNodes.test_consistency_of_c_all_positions__and_p_ThreadNext_
169 def test_consistency_of_c_all_positions__and_p_ThreadNext_(self):
170 c, p = self.c, self.c.p
171 p2 = c.rootPosition()
172 for p in c.all_positions():
173 self.assertEqual(p, p2)
174 p2.moveToThreadNext()
175 self.assertFalse(p2)
176 #@+node:ekr.20210830095545.12: *4* TestNodes.test_consistency_of_firstChild__children_iter_
177 def test_consistency_of_firstChild__children_iter_(self):
178 c, p = self.c, self.c.p
179 for p in c.all_positions():
180 p2 = p.firstChild()
181 for p3 in p.children_iter():
182 self.assertEqual(p3, p2)
183 p2.moveToNext()
184 self.assertFalse(p2)
185 #@+node:ekr.20210830095545.13: *4* TestNodes.test_consistency_of_level
186 def test_consistency_of_level(self):
187 c, p = self.c, self.c.p
188 for p in c.all_positions():
189 if p.hasParent():
190 self.assertEqual(p.parent().level(), p.level() - 1)
191 if p.hasChildren():
192 self.assertEqual(p.firstChild().level(), p.level() + 1)
193 if p.hasNext():
194 self.assertEqual(p.next().level(), p.level())
195 if p.hasBack():
196 self.assertEqual(p.back().level(), p.level())
197 #@+node:ekr.20210830095545.14: *4* TestNodes.test_consistency_of_parent__parents_iter_
198 def test_consistency_of_parent__parents_iter_(self):
199 c, p = self.c, self.c.p
200 for p in c.all_positions():
201 p2 = p.parent()
202 for p3 in p.parents_iter():
203 self.assertEqual(p3, p2)
204 p2.moveToParent()
205 self.assertFalse(p2)
206 #@+node:ekr.20210830095545.15: *4* TestNodes.test_consistency_of_parent_child_links
207 def test_consistency_of_parent_child_links(self):
208 # Test consistency of p.parent, p.next, p.back and p.firstChild.
209 c, p = self.c, self.c.p
210 for p in c.all_positions():
211 if p.hasParent():
212 n = p.childIndex()
213 self.assertEqual(p, p.parent().moveToNthChild(n))
214 for child in p.children_iter():
215 self.assertEqual(p, child.parent())
216 if p.hasNext():
217 self.assertEqual(p.next().parent(), p.parent())
218 if p.hasBack():
219 self.assertEqual(p.back().parent(), p.parent())
220 #@+node:ekr.20210830095545.16: *4* TestNodes.test_consistency_of_threadBack_Next_links
221 def test_consistency_of_threadBack_Next_links(self):
222 c, p = self.c, self.c.p
223 for p in c.all_positions():
224 threadBack = p.threadBack()
225 threadNext = p.threadNext()
226 if threadBack:
227 self.assertEqual(p, threadBack.getThreadNext())
228 if threadNext:
229 self.assertEqual(p, threadNext.getThreadBack())
230 #@+node:ekr.20210830095545.17: *4* TestNodes.test_convertTreeToString_and_allies
231 def test_convertTreeToString_and_allies(self):
232 p = self.c.p
233 sib = p.next()
234 self.assertTrue(sib)
235 s = sib.convertTreeToString()
236 for p2 in sib.self_and_subtree():
237 self.assertTrue(p2.h in s)
238 #@+node:ekr.20210830095545.43: *4* TestNodes.test_delete_node
239 def test_delete_node(self):
240 # This test requires @bool select-next-after-delete = False
241 c, p = self.c, self.c.p
242 p2 = p.insertAsNthChild(0)
243 p2.setHeadString('A')
244 p3 = p.insertAsNthChild(1)
245 p3.setHeadString('B')
246 p4 = p.insertAsNthChild(2)
247 p4.setHeadString('C')
248 p.expand()
249 c.selectPosition(p3)
250 c.deleteOutline()
251 c.redraw_now()
252 p = c.p
253 self.assertEqual(p.h, 'A')
254 self.assertEqual(p.next().h, 'C')
255 c.undoer.undo()
256 c.outerUpdate()
257 p = c.p
258 self.assertEqual(p.back(), p2)
259 self.assertEqual(p.next(), p4)
260 c.undoer.redo()
261 c.outerUpdate()
262 p = c.p
263 self.assertEqual(p.h, 'A')
264 self.assertEqual(p.next().h, 'C')
265 c.undoer.undo()
266 c.outerUpdate()
267 p = c.p
268 self.assertEqual(p.back(), p2)
269 self.assertEqual(p.next(), p4)
270 c.undoer.redo()
271 c.outerUpdate()
272 p = c.p
273 self.assertEqual(p.h, 'A')
274 self.assertEqual(p.next().h, 'C')
275 #@+node:ekr.20210830095545.44: *4* TestNodes.test_deleting_the_root_should_select_another_node
276 def test_deleting_the_root_should_select_another_node(self):
277 c, p = self.c, self.c.p
278 root_h = p.h
279 child = p.next()
280 child.moveToRoot() # Does not change child position.
281 c.setRootPosition(child)
282 self.assertTrue(c.positionExists(child))
283 self.assertEqual(c.rootPosition().h, child.h)
284 next = c.rootPosition().next()
285 self.assertEqual(next.h, root_h)
286 c.rootPosition().doDelete(newNode=next)
287 c.setRootPosition(next)
288 #@+node:ekr.20210830095545.45: *4* TestNodes.test_demote
289 def test_demote(self):
290 c, p = self.c, self.c.p
291 p2 = p.insertAsNthChild(0)
292 p2.setHeadString('A')
293 p3 = p.insertAsNthChild(1)
294 p3.setHeadString('B')
295 p4 = p.insertAsNthChild(2)
296 p4.setHeadString('C')
297 p5 = p.insertAsNthChild(3)
298 p5.setHeadString('D')
299 p.expand()
300 c.setCurrentPosition(p3)
301 c.demote()
302 p = c.p
303 self.assertEqual(p, p3)
304 self.assertEqual(p.h, 'B')
305 assert not p.next()
306 self.assertEqual(p.firstChild().h, 'C')
307 self.assertEqual(p.firstChild().next().h, 'D')
308 c.undoer.undo()
309 p = c.p
310 self.assertEqual(p, p3)
311 self.assertEqual(p.back(), p2)
312 self.assertEqual(p.next(), p4)
313 c.undoer.redo()
314 self.assertEqual(p, p3)
315 self.assertEqual(p.h, 'B')
316 assert not p.next()
317 self.assertEqual(p.firstChild().h, 'C')
318 self.assertEqual(p.firstChild().next().h, 'D')
319 c.undoer.undo()
320 p = c.p
321 self.assertEqual(p.back(), p2)
322 self.assertEqual(p.next(), p4)
323 c.undoer.redo()
324 self.assertEqual(p, p3)
325 self.assertEqual(p.h, 'B')
326 assert not p.next()
327 self.assertEqual(p.firstChild().h, 'C')
328 self.assertEqual(p.firstChild().next().h, 'D')
329 #@+node:ekr.20210830095545.46: *4* TestNodes.test_insert_node
330 def test_insert_node(self):
331 c, p = self.c, self.c.p
332 self.assertEqual(p.h, 'root')
333 p2 = p.insertAsNthChild(0)
334 p2.setHeadString('A')
335 p3 = p.insertAsNthChild(1)
336 p3.setHeadString('B')
337 p.expand()
338 c.setCurrentPosition(p2)
339 p4 = c.insertHeadline()
340 self.assertEqual(p4, c.p)
341 p = c.p
342 self.assertTrue(p)
343 p.setHeadString('inserted')
344 self.assertTrue(p.back())
345 self.assertEqual(p.back().h, 'A')
346 self.assertEqual(p.next().h, 'B')
347 # With the new undo logic, it takes 2 undoes.
348 # The first undo undoes the headline changes,
349 # the second undo undoes the insert node.
350 c.undoer.undo()
351 c.undoer.undo()
352 p = c.p
353 self.assertEqual(p, p2)
354 self.assertEqual(p.next(), p3)
355 c.undoer.redo()
356 p = c.p
357 self.assertTrue(p.back())
358 self.assertEqual(p.back().h, 'A')
359 self.assertEqual(p.next().h, 'B')
360 c.undoer.undo()
361 p = c.p
362 self.assertEqual(p, p2)
363 self.assertEqual(p.next(), p3)
364 c.undoer.redo()
365 p = c.p
366 self.assertEqual(p.back().h, 'A')
367 self.assertEqual(p.next().h, 'B')
368 #@+node:ekr.20210830095545.18: *4* TestNodes.test_leoNodes_properties
369 def test_leoNodes_properties(self):
370 c, p = self.c, self.c.p
371 v = p.v
372 b = p.b
373 p.b = b
374 self.assertEqual(p.b, b)
375 v.b = b
376 self.assertEqual(v.b, b)
377 h = p.h
378 p.h = h
379 self.assertEqual(p.h, h)
380 v.h = h
381 self.assertEqual(v.h, h)
382 for p in c.all_positions():
383 self.assertEqual(p.b, p.bodyString())
384 self.assertEqual(p.v.b, p.v.bodyString())
385 self.assertEqual(p.h, p.headString())
386 self.assertEqual(p.v.h, p.v.headString())
387 #@+node:ekr.20210830095545.47: *4* TestNodes.test_move_outline_down__undo_redo
388 def test_move_outline_down__undo_redo(self):
389 c, p = self.c, self.c.p
390 p2 = p.insertAsNthChild(0)
391 p2.setHeadString('A')
392 p3 = p.insertAsNthChild(1)
393 p3.setHeadString('B')
394 p4 = p.insertAsNthChild(2)
395 p4.setHeadString('C')
396 p5 = p.insertAsNthChild(3)
397 p5.setHeadString('D')
398 p.expand()
399 c.setCurrentPosition(p3)
400 c.moveOutlineDown()
401 moved = c.p
402 self.assertEqual(moved.h, 'B')
403 self.assertEqual(moved.back().h, 'C')
404 self.assertEqual(moved.next().h, 'D')
405 self.assertEqual(moved.next(), p5)
406 c.undoer.undo()
407 moved = c.p
408 self.assertEqual(moved.back(), p2)
409 self.assertEqual(moved.next(), p4)
410 c.undoer.redo()
411 moved = c.p
412 self.assertEqual(moved.h, 'B')
413 self.assertEqual(moved.back().h, 'C')
414 self.assertEqual(moved.next().h, 'D')
415 c.undoer.undo()
416 moved = c.p
417 self.assertEqual(moved.back(), p2)
418 self.assertEqual(moved.next(), p4)
419 c.undoer.redo()
420 moved = c.p
421 self.assertEqual(moved.h, 'B')
422 self.assertEqual(moved.back().h, 'C')
423 self.assertEqual(moved.next().h, 'D')
424 #@+node:ekr.20210830095545.48: *4* TestNodes.test_move_outline_left
425 def test_move_outline_left(self):
426 c, p = self.c, self.c.p
427 p2 = p.insertAsNthChild(0)
428 p2.setHeadString('A')
429 p.expand()
430 c.setCurrentPosition(p2)
431 c.moveOutlineLeft()
432 moved = c.p
433 self.assertEqual(moved.h, 'A')
434 self.assertEqual(moved.back(), p)
435 c.undoer.undo()
436 c.undoer.redo()
437 c.undoer.undo()
438 c.undoer.redo()
439 moved.doDelete(newNode=p)
440 #@+node:ekr.20210830095545.49: *4* TestNodes.test_move_outline_right
441 def test_move_outline_right(self):
442 c, p = self.c, self.c.p
443 p2 = p.insertAsNthChild(0)
444 p2.setHeadString('A')
445 p3 = p.insertAsNthChild(1)
446 p3.setHeadString('B')
447 p4 = p.insertAsNthChild(2)
448 p4.setHeadString('C')
449 p.expand()
450 c.setCurrentPosition(p3)
451 c.moveOutlineRight()
452 moved = c.p
453 self.assertEqual(moved.h, 'B')
454 self.assertEqual(moved.parent(), p2)
455 c.undoer.undo()
456 c.undoer.redo()
457 c.undoer.undo()
458 c.undoer.redo()
459 #@+node:ekr.20210830095545.50: *4* TestNodes.test_move_outline_up
460 def test_move_outline_up(self):
461 c, p = self.c, self.c.p
462 p2 = p.insertAsNthChild(0)
463 p2.setHeadString('A')
464 p3 = p.insertAsNthChild(1)
465 p3.setHeadString('B')
466 p4 = p.insertAsNthChild(2)
467 p4.setHeadString('C')
468 p5 = p.insertAsNthChild(3)
469 p5.setHeadString('D')
470 p.expand()
471 c.setCurrentPosition(p4)
472 c.moveOutlineUp()
473 moved = c.p
474 self.assertEqual(moved.h, 'C')
475 self.assertEqual(moved.back().h, 'A')
476 self.assertEqual(moved.next().h, 'B')
477 self.assertEqual(moved.back(), p2)
478 c.undoer.undo()
479 c.undoer.redo()
480 c.undoer.undo()
481 c.undoer.redo()
482 #@+node:ekr.20210830095545.19: *4* TestNodes.test_new_vnodes_methods
483 def test_new_vnodes_methods(self):
484 c, p = self.c, self.c.p
485 parent_v = p.parent().v or c.hiddenRootNode
486 p.v.cloneAsNthChild(parent_v, p.childIndex())
487 v2 = p.v.insertAsFirstChild()
488 v2.h = 'insertAsFirstChild'
489 v2 = p.v.insertAsLastChild()
490 v2.h = 'insertAsLastChild'
491 v2 = p.v.insertAsNthChild(1)
492 v2.h = 'insertAsNthChild(1)'
493 #@+node:ekr.20210830095545.20: *4* TestNodes.test_newlines_in_headlines
494 def test_newlines_in_headlines(self):
495 # Bug https://bugs.launchpad.net/leo-editor/+bug/1245535
496 p = self.c.p
497 p.h = '\nab\nxy\n'
498 self.assertEqual(p.h, 'abxy')
500 #@+node:ekr.20210830095545.54: *4* TestNodes.test_node_that_does_nott_belong_to_a_derived_file
501 def test_node_that_does_not_belong_to_a_derived_file(self):
502 # Change @file activeUnitTests.txt to @@file activeUnitTests.txt
503 p = self.c.p
504 p1 = p.insertAsLastChild()
505 self.assertFalse(p1.textOffset())
507 #@+node:ekr.20210830095545.56: *4* TestNodes.test_organizer_node
508 def test_organizer_node(self):
509 p = self.c.p
510 p1 = p.insertAsLastChild()
511 p1.setHeadString('@file zzz')
512 p2 = p1.insertAsLastChild()
513 self.assertEqual(p1.textOffset(), 0)
514 self.assertEqual(p2.textOffset(), 0)
516 #@+node:ekr.20210830095545.21: *4* TestNodes.test_p__eq_
517 def test_p__eq_(self):
518 c, p = self.c, self.c.p
519 # These must not return NotImplemented!
520 root = c.rootPosition()
521 self.assertFalse(p.__eq__(None))
522 self.assertTrue(p.__ne__(None))
523 self.assertTrue(p.__eq__(root))
524 self.assertFalse(p.__ne__(root))
525 #@+node:ekr.20210830095545.24: *4* TestNodes.test_p_comparisons
526 def test_p_comparisons(self):
527 c, p = self.c, self.c.p
528 copy = p.copy()
529 self.assertEqual(p, copy)
530 self.assertNotEqual(p, p.threadNext())
531 root = c.rootPosition()
532 self.assertTrue(p.__eq__(copy))
533 self.assertFalse(p.__ne__(copy))
534 self.assertTrue(p.__eq__(root))
535 self.assertFalse(p.__ne__(root))
536 #@+node:ekr.20210830095545.25: *4* TestNodes.test_p_deletePositionsInList
537 def test_p_deletePositionsInList(self):
538 c, p = self.c, self.c.p
539 root = p.insertAsLastChild()
540 root.h = 'root'
541 # Top level
542 a1 = root.insertAsLastChild()
543 a1.h = 'a'
544 a1.clone()
545 d1 = a1.insertAfter()
546 d1.h = 'd'
547 b1 = root.insertAsLastChild()
548 b1.h = 'b'
549 # Children of a.
550 b11 = b1.clone()
551 b11.moveToLastChildOf(a1)
552 b11.clone()
553 c2 = b11.insertAfter()
554 c2.h = 'c'
555 # Children of d
556 b11 = b1.clone()
557 b11.moveToLastChildOf(d1)
558 # Count number of 'b' nodes.
559 aList = []
560 nodes = 0
561 for p in root.subtree():
562 nodes += 1
563 if p.h == 'b':
564 aList.append(p.copy())
565 self.assertEqual(len(aList), 6)
566 c.deletePositionsInList(aList)
567 c.redraw()
569 #@+node:ekr.20210830095545.26: *4* TestNodes.test_p_hasNextBack
570 def test_p_hasNextBack(self):
571 c, p = self.c, self.c.p
572 for p in c.all_positions():
573 back = p.back()
574 next = p.next()
575 assert(
576 (back and p.hasBack()) or
577 (not back and not p.hasBack()))
578 assert(
579 (next and p.hasNext()) or
580 (not next and not p.hasNext()))
581 #@+node:ekr.20210830095545.27: *4* TestNodes.test_p_hasParentChild
582 def test_p_hasParentChild(self):
583 c, p = self.c, self.c.p
584 for p in c.all_positions():
585 child = p.firstChild()
586 parent = p.parent()
587 assert(
588 (child and p.hasFirstChild()) or
589 (not child and not p.hasFirstChild()))
590 assert(
591 (parent and p.hasParent()) or
592 (not parent and not p.hasParent()))
593 #@+node:ekr.20210830095545.28: *4* TestNodes.test_p_hasThreadNextBack
594 def test_p_hasThreadNextBack(self):
595 c, p = self.c, self.c.p
596 for p in c.all_positions():
597 threadBack = p.getThreadBack()
598 threadNext = p.getThreadNext()
599 assert(
600 (threadBack and p.hasThreadBack()) or
601 (not threadBack and not p.hasThreadBack()))
602 assert(
603 (threadNext and p.hasThreadNext()) or
604 (not threadNext and not p.hasThreadNext()))
605 #@+node:ekr.20210830095545.29: *4* TestNodes.test_p_isAncestorOf
606 def test_p_isAncestorOf(self):
607 c, p = self.c, self.c.p
608 for p in c.all_positions():
609 child = p.firstChild()
610 while child:
611 for parent in p.self_and_parents_iter():
612 assert parent.isAncestorOf(child)
613 child.moveToNext()
614 next = p.next()
615 self.assertFalse(p.isAncestorOf(next))
616 #@+node:ekr.20210830095545.30: *4* TestNodes.test_p_isCurrentPosition
617 def test_p_isCurrentPosition(self):
618 c, p = self.c, self.c.p
619 self.assertFalse(c.isCurrentPosition(None))
620 self.assertTrue(c.isCurrentPosition(p))
621 #@+node:ekr.20210830095545.31: *4* TestNodes.test_p_isRootPosition
622 def test_p_isRootPosition(self):
623 c, p = self.c, self.c.p
624 self.assertFalse(c.isRootPosition(None))
625 self.assertTrue(c.isRootPosition(p))
626 #@+node:ekr.20210830095545.33: *4* TestNodes.test_p_moveToFirst_LastChild
627 def test_p_moveToFirst_LastChild(self):
628 c, p = self.c, self.c.p
629 root2 = p.next()
630 self.assertTrue(root2)
631 p2 = root2.insertAfter()
632 p2.h = "test"
633 self.assertTrue(c.positionExists(p2))
634 p2.moveToFirstChildOf(root2)
635 self.assertTrue(c.positionExists(p2))
636 p2.moveToLastChildOf(root2)
637 self.assertTrue(c.positionExists(p2))
638 #@+node:ekr.20210830095545.34: *4* TestNodes.test_p_moveToVisBack_in_a_chapter
639 def test_p_moveToVisBack_in_a_chapter(self):
640 # Verify a fix for bug https://bugs.launchpad.net/leo-editor/+bug/1264350
641 import leo.core.leoChapters as leoChapters
642 c, p = self.c, self.c.p
643 cc = c.chapterController
644 settings_p = p.insertAsNthChild(0)
645 settings_p.h = '@settings'
646 chapter_p = settings_p.insertAsLastChild()
647 chapter_p.h = '@chapter aaa'
648 node_p = chapter_p.insertAsNthChild(0)
649 node_p.h = 'aaa node 1'
650 # Hack the chaptersDict.
651 cc.chaptersDict['aaa'] = leoChapters.Chapter(c, cc, 'aaa')
652 # Select the chapter.
653 cc.selectChapterByName('aaa')
654 self.assertEqual(c.p.h, 'aaa node 1')
655 p2 = c.p.moveToVisBack(c)
656 self.assertEqual(p2, None)
657 #@+node:ekr.20210830095545.35: *4* TestNodes.test_p_nosentinels
658 def test_p_nosentinels(self):
660 p = self.c.p
661 p.b = textwrap.dedent("""\
663 def not_a_sentinel(x):
664 pass
666 @not_a_sentinel
667 def spam():
668 pass
670 """)
671 self.assertEqual(p.b, p.nosentinels)
672 #@+node:ekr.20210830095545.22: *4* TestNodes.test_p_relinkAsCloneOf
673 def test_p_relinkAsCloneOf(self):
675 # test-outline: root
676 # child clone a
677 # node clone 1
678 # child b
679 # child clone a
680 # node clone 1
681 # child c
682 # node clone 1
683 # child clone a
684 # node clone 1
685 # child b
686 # child clone a
687 # node clone 1
688 c, u = self.c, self.c.undoer
689 p = c.p.next()
690 child_b = g.findNodeAnywhere(c, 'child b')
691 self.assertTrue(child_b)
692 self.assertTrue(child_b.isCloned())
693 #
694 # child_c must *not* be a clone at first.
695 child_c = g.findNodeAnywhere(c, 'child c')
696 self.assertTrue(child_c)
697 self.assertFalse(child_c.isCloned())
698 #
699 # Change the tree.
700 bunch = u.beforeChangeTree(p)
701 child_c._relinkAsCloneOf(child_b)
702 u.afterChangeTree(p, 'relink-clone', bunch)
703 # self.dump_tree('Before...')
704 u.undo()
705 # self.dump_tree('After...')
706 self.assertTrue(child_b.isCloned())
707 self.assertFalse(child_c.isCloned())
709 #@+node:ekr.20210830095545.36: *4* TestNodes.test_p_setBodyString
710 def test_p_setBodyString(self):
711 # Test that c.setBodyString works immediately.
712 c, w = self.c, self.c.frame.body.wrapper
713 next = self.root_p.next()
714 c.setBodyString(next, "after")
715 c.selectPosition(next)
716 s = w.get("1.0", "end")
717 self.assertEqual(s.rstrip(), "after")
718 #@+node:ekr.20210830095545.37: *4* TestNodes.test_p_u
719 def test_p_u(self):
720 p = self.c.p
721 self.assertEqual(p.u, p.v.u)
722 p.v.u = None
723 self.assertEqual(p.u, {})
724 self.assertEqual(p.v.u, {})
725 d = {'my_plugin': 'val'}
726 p.u = d
727 self.assertEqual(p.u, d)
728 self.assertEqual(p.v.u, d)
729 #@+node:ekr.20210830095545.38: *4* TestNodes.test_p_unique_nodes
730 def test_p_unique_nodes(self):
732 self.assertEqual(len(list(self.root_p.unique_nodes())), 5)
733 #@+node:ekr.20210830095545.51: *4* TestNodes.test_paste_node
734 def test_paste_node(self):
735 c, p = self.c, self.c.p
736 child = p.insertAsNthChild(0)
737 child.setHeadString('child')
738 child2 = p.insertAsNthChild(1)
739 child2.setHeadString('child2')
740 grandChild = child.insertAsNthChild(0)
741 grandChild.setHeadString('grand child')
742 c.selectPosition(grandChild)
743 c.clone()
744 c.selectPosition(child)
745 p.expand()
746 c.selectPosition(child)
747 self.assertEqual(c.p.h, 'child')
748 c.copyOutline()
749 oldVnodes = [p2.v for p2 in child.self_and_subtree()]
750 c.selectPosition(child)
751 c.p.contract() # Essential
752 c.pasteOutline()
753 assert c.p != child
754 self.assertEqual(c.p.h, 'child')
755 newVnodes = [p2.v for p2 in c.p.self_and_subtree()]
756 for v in newVnodes:
757 assert v not in oldVnodes
758 c.undoer.undo()
759 c.undoer.redo()
760 c.undoer.undo()
761 c.undoer.redo()
762 #@+node:ekr.20210830095545.52: *4* TestNodes.test_paste_retaining_clones
763 def test_paste_retaining_clones(self):
764 c, p = self.c, self.c.p
765 child = p.insertAsNthChild(0)
766 child.setHeadString('child')
767 self.assertTrue(child)
768 grandChild = child.insertAsNthChild(0)
769 grandChild.setHeadString('grand child')
770 c.selectPosition(child)
771 c.copyOutline()
772 oldVnodes = [p2.v for p2 in child.self_and_subtree()]
773 c.p.contract() # Essential
774 c.pasteOutlineRetainingClones()
775 self.assertNotEqual(c.p, child)
776 newVnodes = [p2.v for p2 in c.p.self_and_subtree()]
777 for v in newVnodes:
778 self.assertTrue(v in oldVnodes)
779 #@+node:ekr.20210830095545.4: *4* TestNodes.test_position_not_hashable
780 def test_position_not_hashable(self):
781 p = self.c.p
782 try:
783 a = set()
784 a.add(p)
785 assert False, 'Adding position to set should throw exception'
786 except TypeError:
787 pass
788 #@+node:ekr.20210830095545.53: *4* TestNodes.test_promote
789 def test_promote(self):
790 c, p = self.c, self.c.p
791 p2 = p.insertAsNthChild(0)
792 p2.setHeadString('A')
793 p3 = p.insertAsNthChild(1)
794 p3.setHeadString('B')
795 p4 = p3.insertAsNthChild(0)
796 p4.setHeadString('child 1')
797 p5 = p3.insertAsNthChild(1)
798 p5.setHeadString('child 2')
799 p.expand()
800 p6 = p.insertAsNthChild(2)
801 p6.setHeadString('C')
802 c.setCurrentPosition(p3)
803 c.promote()
804 p = c.p
805 self.assertEqual(p, p3)
806 self.assertEqual(p.h, 'B')
807 self.assertEqual(p.next().h, 'child 1')
808 self.assertEqual(p.next().next().h, 'child 2')
809 self.assertEqual(p.next().next().next().h, 'C')
810 c.undoer.undo()
811 p = c.p
812 self.assertEqual(p, p3)
813 self.assertEqual(p.back(), p2)
814 self.assertEqual(p.next(), p6)
815 self.assertEqual(p.firstChild().h, 'child 1')
816 self.assertEqual(p.firstChild().next().h, 'child 2')
817 c.undoer.redo()
818 p = c.p
819 self.assertEqual(p, p3)
820 self.assertEqual(p.h, 'B')
821 self.assertEqual(p.next().h, 'child 1')
822 self.assertEqual(p.next().next().h, 'child 2')
823 self.assertEqual(p.next().next().next().h, 'C')
824 c.undoer.undo()
825 p = c.p
826 self.assertEqual(p, p3)
827 self.assertEqual(p.back(), p2)
828 self.assertEqual(p.next(), p6)
829 self.assertEqual(p.firstChild().h, 'child 1')
830 self.assertEqual(p.firstChild().next().h, 'child 2')
831 c.undoer.redo()
832 p = c.p
833 self.assertEqual(p, p3)
834 self.assertEqual(p.h, 'B')
835 self.assertEqual(p.next().h, 'child 1')
836 self.assertEqual(p.next().next().h, 'child 2')
837 self.assertEqual(p.next().next().next().h, 'C')
838 #@+node:ekr.20210830095545.55: *4* TestNodes.test_root_of_a_derived_file
839 def test_root_of_a_derived_file(self):
840 p = self.c.p
841 p1 = p.insertAsLastChild()
842 p1.setHeadString('@file zzz')
843 self.assertEqual(p1.textOffset(), 0)
844 #@+node:ekr.20210830095545.57: *4* TestNodes.test_section_node
845 def test_section_node(self):
846 p = self.c.p
847 p1 = p.insertAsLastChild()
848 p1.setHeadString('@file zzz')
849 body = ''' %s
850 ''' % (g.angleBrackets(' section '))
851 p1.setBodyString(body)
852 p2 = p1.insertAsLastChild()
853 head = g.angleBrackets(' section ')
854 p2.setHeadString(head)
855 self.assertEqual(p1.textOffset(), 0)
856 self.assertEqual(p2.textOffset(), 3)
857 # Section nodes can appear in with @others nodes,
858 # so they don't get special treatment.
859 #@+node:ekr.20210830095545.39: *4* TestNodes.test_v_atAutoNodeName_and_v_atAutoRstNodeName
860 def test_v_atAutoNodeName_and_v_atAutoRstNodeName(self):
861 p = self.c.p
862 table = (
863 ('@auto-rst rst-file', 'rst-file', 'rst-file'),
864 ('@auto x', 'x', ''),
865 ('xyz', '', ''),
866 )
867 for s, expected1, expected2 in table:
868 result1 = p.v.atAutoNodeName(h=s)
869 result2 = p.v.atAutoRstNodeName(h=s)
870 self.assertEqual(result1, expected1, msg=s)
871 self.assertEqual(result2, expected2, msg=s)
872 #@-others
873#@-others
875#@-leo