Coverage for core\test_leoCommands.py : 94%

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.20210903162431.1: * @file ../unittests/core/test_leoCommands.py
4#@@first
5"""Tests of leoCommands.py"""
6# pylint: disable=no-member
7import inspect
8import textwrap
9from leo.core import leoGlobals as g
10from leo.core.leoTest2 import LeoUnitTest
12#@+others
13#@+node:ekr.20210903162431.2: ** class TestCommands(LeoUnitTest)
14class TestCommands(LeoUnitTest):
15 """Test cases for leoCommands.py"""
16 #@+others
17 #@+node:ekr.20210906075242.28: *3* TestCommands.test_add_comments_with_multiple_language_directives
18 def test_add_comments_with_multiple_language_directives(self):
19 c, p, w = self.c, self.c.p, self.c.frame.body.wrapper
20 p.b = textwrap.dedent("""\
21 @language rest
22 rest text.
23 @language python
24 def spam():
25 pass
26 # after
27 """)
28 expected = textwrap.dedent("""\
29 @language rest
30 rest text.
31 @language python
32 def spam():
33 # pass
34 # after
35 """)
36 i = p.b.find('pass')
37 assert i > -1, 'fail1: %s' % (repr(p.b))
38 w.setSelectionRange(i, i + 4)
39 c.addComments()
40 self.assertEqual(p.b, expected)
41 #@+node:ekr.20210906075242.30: *3* TestCommands.test_add_html_comments
42 def test_add_html_comments(self):
43 c, p, w = self.c, self.c.p, self.c.frame.body.wrapper
44 p.b = textwrap.dedent("""\
45 @language html
46 <html>
47 text
48 </html>
49 """)
50 expected = textwrap.dedent("""\
51 @language html
52 <html>
53 <!-- text -->
54 </html>
55 """)
56 i = p.b.find('text')
57 w.setSelectionRange(i, i + 4)
58 c.addComments()
59 self.assertEqual(p.b, expected)
60 #@+node:ekr.20210906075242.32: *3* TestCommands.test_add_python_comments
61 def test_add_python_comments(self):
62 c, p, w = self.c, self.c.p, self.c.frame.body.wrapper
63 p.b = textwrap.dedent("""\
64 @language python
65 def spam():
66 pass
67 # after
68 """)
69 expected = textwrap.dedent("""\
70 @language python
71 def spam():
72 # pass
73 # after
74 """)
75 i = p.b.find('pass')
76 w.setSelectionRange(i, i + 4)
77 c.addComments()
78 self.assertEqual(p.b, expected)
79 #@+node:ekr.20210901140645.2: *3* TestCommands.test_all_commands_have_an_event_arg
80 def test_all_commands_have_an_event_arg(self):
81 c = self.c
82 d = c.commandsDict
83 keys = sorted(d.keys())
84 table = ('bookmark', 'quickmove_', 'screen-capture', 'stickynote')
85 for key in keys:
86 continue_flag = False
87 for prefix in table:
88 if key.startswith(prefix):
89 continue_flag = True
90 break # These plugins have their own signatures.
91 if continue_flag:
92 continue
93 f = d.get(key)
94 # print(key, f.__name__ if f else repr(f))
95 # Test true __call__ methods if they exist.
96 name = getattr(f, '__name__', None) or repr(f)
97 if hasattr(f, '__call__') and inspect.ismethod(f.__call__):
98 f = getattr(f, '__call__')
99 t = inspect.getfullargspec(f) # t is a named tuple.
100 args = t.args
101 arg0 = len(args) > 0 and args[0]
102 arg1 = len(args) > 1 and args[1]
103 expected = ('event',)
104 message = f"no event arg for command {key}, func: {name}, args: {args}"
105 assert arg0 in expected or arg1 in expected, message
106 #@+node:ekr.20210906075242.2: *3* TestCommands.test_c_alert
107 def test_c_alert(self):
108 c = self.c
109 c.alert('test of c.alert')
110 #@+node:ekr.20210906075242.3: *3* TestCommands.test_c_checkOutline
111 def test_c_checkOutline(self):
112 c = self.c
113 errors = c.checkOutline()
114 self.assertEqual(errors, 0)
115 #@+node:ekr.20210901140645.15: *3* TestCommands.test_c_checkPythonCode
116 def test_c_checkPythonCode(self):
117 c = self.c
118 c.checkPythonCode(event=None, ignoreAtIgnore=False, checkOnSave=False)
119 #@+node:ekr.20210901140645.16: *3* TestCommands.test_c_checkPythonNode
120 def test_c_checkPythonNode(self):
121 c, p = self.c, self.c.p
122 p.b = textwrap.dedent("""\
123 @language python
125 def abc: # missing parens.
126 pass
127 """)
128 result = c.checkPythonCode(event=None, checkOnSave=False, ignoreAtIgnore=True)
129 self.assertEqual(result, 'error')
130 #@+node:ekr.20210901140645.7: *3* TestCommands.test_c_config_initIvar_sets_commander_ivars
131 def test_c_config_initIvar_sets_commander_ivars(self):
132 c = self.c
133 for ivar, setting_type, default in g.app.config.ivarsData:
134 assert hasattr(c, ivar), ivar
135 assert hasattr(c.config, ivar), ivar
136 val = getattr(c.config, ivar)
137 val2 = c.config.get(ivar, setting_type)
138 self.assertEqual(val, val2)
139 #@+node:ekr.20210906075242.4: *3* TestCommands.test_c_contractAllHeadlines
140 def test_c_contractAllHeadlines(self):
141 c = self.c
142 c.contractAllHeadlines()
143 p = c.rootPosition()
144 while p.hasNext():
145 p.moveToNext()
146 c.redraw(p)
147 #@+node:ekr.20210906075242.6: *3* TestCommands.test_c_demote_illegal_clone_demote
148 def test_c_demote_illegal_clone_demote(self):
149 c, p = self.c, self.c.p
150 # Create two cloned children.
151 c.selectPosition(p)
152 c.insertHeadline()
153 p2 = c.p
154 p2.moveToFirstChildOf(p)
155 p2.setHeadString('aClone')
156 c.selectPosition(p2)
157 c.clone()
158 self.assertEqual(2, p.numberOfChildren())
159 # Select the first clone and demote (it should be illegal)
160 c.selectPosition(p2)
161 c.demote() # This should do nothing.
162 self.assertEqual(0, c.checkOutline())
163 self.assertEqual(2, p.numberOfChildren())
164 #@+node:ekr.20210906075242.7: *3* TestCommands.test_c_expand_path_expression
165 def test_c_expand_path_expression(self):
166 c = self.c
167 import os
168 sep = os.sep
169 table = (
170 ('~{{sep}}tmp{{sep}}x.py', '~%stmp%sx.py' % (sep, sep)),
171 )
172 for s, expected in table:
173 if g.isWindows:
174 expected = expected.replace('\\', '/')
175 got = c.expand_path_expression(s)
176 self.assertEqual(got, expected, msg=repr(s))
177 #@+node:ekr.20210906075242.8: *3* TestCommands.test_c_findMatchingBracket
178 def test_c_findMatchingBracket(self):
179 c, w = self.c, self.c.frame.body.wrapper
180 s = '(abc)'
181 c.p.b = s
182 table = (
183 (-1, -1),
184 (len(s), len(s)),
185 (0, 0),
186 (1, 1),
187 )
188 for i, j in table:
189 w.setSelectionRange(-1, len(s))
190 c.findMatchingBracket(event=None)
191 i2, j2 = w.getSelectionRange()
192 self.assertTrue(i2 < j2, msg=f"i: {i}, j: {j}")
194 #@+node:ekr.20210906075242.9: *3* TestCommands.test_c_hiddenRootNode_fileIndex
195 def test_c_hiddenRootNode_fileIndex(self):
196 c = self.c
197 assert c.hiddenRootNode.fileIndex.startswith('hidden-root-vnode-gnx'), c.hiddenRootNode.fileIndex
198 #@+node:ekr.20210906075242.10: *3* TestCommands.test_c_hoist_chapter_node
199 def test_c_hoist_chapter_node(self):
200 c = self.c
201 # Create the @settings and @chapter nodes.
202 settings = c.rootPosition().insertAfter()
203 settings.h = '@settings'
204 chapter = settings.insertAsLastChild()
205 chapter.h = '@chapter aaa'
206 aaa = chapter.insertAsLastChild()
207 aaa.h = 'aaa node 1'
208 assert not c.hoistStack
209 c.selectPosition(aaa)
210 # Test.
211 c.hoist() # New in Leo 5.3: should do nothing
212 self.assertEqual(c.p, aaa)
213 c.dehoist() # New in Leo 5.3: should do nothing:
214 self.assertEqual(c.p, aaa)
215 self.assertEqual(c.hoistStack, [])
216 #@+node:ekr.20210906075242.11: *3* TestCommands.test_c_hoist_followed_by_goto_first_node
217 def test_c_hoist_followed_by_goto_first_node(self):
218 c = self.c
219 # Create the @settings and @chapter nodes.
220 settings = c.rootPosition().insertAfter()
221 settings.h = '@settings'
222 chapter = settings.insertAsLastChild()
223 chapter.h = '@chapter aaa'
224 aaa = chapter.insertAsLastChild()
225 aaa.h = 'aaa node 1'
226 # Test.
227 assert not c.hoistStack
228 c.selectPosition(aaa)
229 assert not c.hoistStack
231 # The de-hoist happens in c.expandOnlyAncestorsOfNode, the call to c.selectPosition.
232 if 1:
233 c.hoist()
234 c.goToFirstVisibleNode()
235 self.assertEqual(c.p, aaa)
236 else:
237 c.hoist()
238 c.goToFirstNode()
239 assert not c.hoistStack # The hoist stack must be cleared to show the first node.
240 self.assertEqual(c.p, c.rootPosition())
241 assert c.p.isVisible(c)
242 #@+node:ekr.20210906075242.12: *3* TestCommands.test_c_hoist_with_no_children
243 def test_c_hoist_with_no_children(self):
244 c = self.c
245 c.hoist()
246 c.dehoist()
247 #@+node:ekr.20210906075242.13: *3* TestCommands.test_c_insertBodyTime
248 def test_c_insertBodyTime(self):
249 c = self.c
250 # p = c.p
251 # w = c.frame.body.wrapper
252 # s = w.getAllText()
253 # w.setInsertPoint(len(s))
254 c.insertBodyTime()
255 #@+node:ekr.20210906075242.14: *3* TestCommands.test_c_markAllAtFileNodesDirty
256 def test_c_markAllAtFileNodesDirty(self):
257 c = self.c
258 marks = [p.v for p in c.all_positions() if p.isMarked()]
259 try:
260 ok = True
261 try:
262 c.markAllAtFileNodesDirty()
263 except Exception:
264 g.es_exception()
265 ok = False
266 finally:
267 for p in c.all_positions():
268 if p.v in marks:
269 if not p.isMarked():
270 c.setMarked(p)
271 else:
272 if p.isMarked():
273 c.clearMarked(p)
275 assert ok
276 #@+node:ekr.20210906075242.15: *3* TestCommands.test_c_markSubheads
277 def test_c_markSubheads(self):
278 c = self.c
279 child1 = c.rootPosition().insertAsLastChild()
280 child2 = c.rootPosition().insertAsLastChild()
281 assert child1 and child2
282 c.markSubheads()
283 #@+node:ekr.20210906075242.16: *3* TestCommands.test_c_pasteOutline_does_not_clone_top_node
284 def test_c_pasteOutline_does_not_clone_top_node(self):
285 c = self.c
286 p = c.p
287 p.b = '# text.'
288 # child1 = c.rootPosition().insertAsLastChild()
289 # c.selectPosition(child)
290 c.copyOutline()
291 p2 = c.pasteOutline()
292 assert p2
293 assert not p2.isCloned()
294 #@+node:ekr.20210906075242.17: *3* TestCommands.test_c_scanAllDirectives
295 def test_c_scanAllDirectives(self):
296 c = self.c
297 d = c.scanAllDirectives(c.p)
298 # These are the commander defaults, without any settings.
299 self.assertEqual(d.get('language'), 'python')
300 self.assertEqual(d.get('tabwidth'), -4)
301 self.assertEqual(d.get('pagewidth'), 132)
302 #@+node:ekr.20210906075242.18: *3* TestCommands.test_c_scanAtPathDirectives
303 def test_c_scanAtPathDirectives(self):
304 c, p = self.c, self.c.p
305 child = p.insertAfter()
306 child.h = '@path one'
307 grand = child.insertAsLastChild()
308 grand.h = '@path two'
309 great = grand.insertAsLastChild()
310 great.h = 'xyz'
311 aList = g.get_directives_dict_list(great)
312 path = c.scanAtPathDirectives(aList)
313 endpath = g.os_path_normpath('one/two')
314 assert path.endswith(endpath), f"expected '{endpath}' got '{path}'"
315 #@+node:ekr.20210906075242.19: *3* TestCommands.test_c_scanAtPathDirectives_same_name_subdirs
316 def test_c_scanAtPathDirectives_same_name_subdirs(self):
317 c = self.c
318 # p2 = p.firstChild().firstChild().firstChild()
319 p = c.p
320 child = p.insertAfter()
321 child.h = '@path again'
322 grand = child.insertAsLastChild()
323 grand.h = '@path again'
324 great = grand.insertAsLastChild()
325 great.h = 'xyz'
326 aList = g.get_directives_dict_list(great)
327 path = c.scanAtPathDirectives(aList)
328 endpath = g.os_path_normpath('again/again')
329 self.assertTrue(path and path.endswith(endpath))
330 #@+node:ekr.20210901140645.17: *3* TestCommands.test_c_tabNannyNode
331 def test_c_tabNannyNode(self):
332 c, p = self.c, self.c.p
333 # Test 1.
334 s = textwrap.dedent("""\
335 # no error
336 def spam():
337 pass
338 """)
339 c.tabNannyNode(p, headline=p.h, body=s)
340 # Test 2.
341 s2 = textwrap.dedent("""\
342 # syntax error
343 def spam:
344 pass
345 a = 2
346 """)
347 try:
348 c.tabNannyNode(p, headline=p.h, body=s2)
349 except IndentationError:
350 pass
351 #@+node:ekr.20210906075242.20: *3* TestCommands.test_c_unmarkAll
352 def test_c_unmarkAll(self):
353 c = self.c
354 c.unmarkAll()
355 for p in c.all_positions():
356 assert not p.isMarked(), p.h
357 #@+node:ekr.20210906075242.21: *3* TestCommands.test_class_StubConfig
358 def test_class_StubConfig(self):
359 c = self.c
360 class StubConfig(g.NullObject):
361 pass
363 x = StubConfig()
364 assert not x.getBool(c, 'mySetting')
365 assert not x.enabledPluginsFileName
366 #@+node:ekr.20210906075242.29: *3* TestCommands.test_delete_comments_with_multiple_at_language_directives
367 def test_delete_comments_with_multiple_at_language_directives(self):
368 c, p, w = self.c, self.c.p, self.c.frame.body.wrapper
369 p.b = textwrap.dedent("""\
370 @language rest
371 rest text.
372 @language python
373 def spam():
374 pass
375 # after
376 """)
377 expected = textwrap.dedent("""\
378 @language rest
379 rest text.
380 @language python
381 def spam():
382 pass
383 # after
384 """)
385 i = p.b.find('pass')
386 w.setSelectionRange(i, i + 4)
387 c.deleteComments()
388 self.assertEqual(p.b, expected)
390 #@+node:ekr.20210906075242.31: *3* TestCommands.test_delete_html_comments
391 def test_delete_html_comments(self):
392 c, p, w = self.c, self.c.p, self.c.frame.body.wrapper
393 p.b = textwrap.dedent("""\
394 @language html
395 <html>
396 <!-- text -->
397 </html>
398 """)
399 expected = textwrap.dedent("""\
400 @language html
401 <html>
402 text
403 </html>
404 """)
405 i = p.b.find('text')
406 w.setSelectionRange(i, i + 4)
407 c.deleteComments()
408 self.assertEqual(p.b, expected)
409 #@+node:ekr.20210906075242.33: *3* TestCommands.test_delete_python_comments
410 def test_delete_python_comments(self):
411 c, p, w = self.c, self.c.p, self.c.frame.body.wrapper
412 p.b = textwrap.dedent("""\
413 @language python
414 def spam():
415 # pass
416 # after
417 """)
418 expected = textwrap.dedent("""\
419 @language python
420 def spam():
421 pass
422 # after
423 """)
424 i = p.b.find('pass')
425 w.setSelectionRange(i, i + 4)
426 c.deleteComments()
427 self.assertEqual(p.b, expected)
428 #@+node:ekr.20210906075242.22: *3* TestCommands.test_efc_ask
429 def test_efc_ask(self):
430 c = self.c
431 p = c.p
432 # Not a perfect test, but stil significant.
433 efc = g.app.externalFilesController
434 if not efc:
435 self.skipTest('No externalFilesController')
436 result = efc.ask(c, p.h)
437 assert result in (True, False), result
438 #@+node:ekr.20210906075242.23: *3* TestCommands.test_efc_compute_ext
439 def test_efc_compute_ext(self):
440 c, p = self.c, self.c.p
441 efc = g.app.externalFilesController
442 if not efc:
443 self.skipTest('No externalFilesController')
444 table = (
445 # (None,'.py'),
446 # ('','.py'),
447 ('txt', '.txt'),
448 ('.txt', '.txt'),
449 )
450 for ext, result in table:
451 result2 = efc.compute_ext(c, p, ext)
452 self.assertEqual(result, result2, msg=repr(ext))
453 #@+node:ekr.20210906075242.24: *3* TestCommands.test_efc_compute_temp_file_path
454 def test_efc_compute_temp_file_path(self):
455 c = self.c
456 p = c.p
457 efc = g.app.externalFilesController
458 if not efc:
459 self.skipTest('no externalFilesController')
460 s = efc.compute_temp_file_path(c, p, '.py')
461 assert s.endswith('.py')
462 #@+node:ekr.20210901140645.27: *3* TestCommands.test_koi8_r_encoding
463 def test_koi8_r_encoding(self):
464 c, p = self.c, self.c.p
465 p1 = p.insertAsLastChild()
466 s = '\xd4\xc5\xd3\xd4' # the word 'test' in Russian, koi8-r
467 assert isinstance(s, str), repr(s)
468 p1.setBodyString(s)
469 c.selectPosition(p1)
470 c.copyOutline()
471 c.pasteOutline()
472 p2 = p1.next()
473 self.assertEqual(p1.b, p2.b)
475 #@+node:ekr.20210901140645.9: *3* TestCommands.test_official_commander_ivars
476 def test_official_commander_ivars(self):
477 c = self.c
478 f = c.frame
479 self.assertEqual(c, f.c)
480 self.assertEqual(f, c.frame)
481 ivars = (
482 '_currentPosition',
483 'hoistStack',
484 'mFileName',
485 # Subcommanders...
486 'atFileCommands', 'fileCommands', 'importCommands', 'undoer',
487 # Args...
488 'page_width', 'tab_width', 'target_language',
489 )
490 for ivar in ivars:
491 self.assertTrue(hasattr(c, ivar), msg=ivar)
492 #@-others
493#@-others
494#@-leo