Coverage for core\test_leoImport.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
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
1# -*- coding: utf-8 -*-
2#@+leo-ver=5-thin
3#@+node:ekr.20210904064440.2: * @file ../unittests/core/test_leoImport.py
4#@@first
5"""Tests of leoImport.py"""
7import glob
8import importlib
9import sys
10import textwrap
11from leo.core import leoGlobals as g
12from leo.core.leoTest2 import LeoUnitTest
13# Import all tested scanners.
14import leo.plugins.importers.coffeescript as cs
15import leo.plugins.importers.dart as dart
16import leo.plugins.importers.linescanner as linescanner
17import leo.plugins.importers.markdown as markdown
18import leo.plugins.importers.org as org
19import leo.plugins.importers.otl as otl
20import leo.plugins.importers.pascal as pascal
21import leo.plugins.importers.xml as xml
22#@+others
23#@+node:ekr.20210904064440.3: ** class BaseTestImporter(LeoUnitTest)
24class BaseTestImporter(LeoUnitTest):
25 """The base class for tests of leoImport.py"""
27 ext = None # Subclasses must set this to the language's extension.
28 treeType = '@file' # Fix #352.
30 def setUp(self):
31 super().setUp()
32 g.app.loadManager.createAllImporterData()
34 #@+others
35 #@+node:ekr.20211128045212.1: *3* BaseTestImporter.check_headlines
36 def check_headlines(self, p, table):
37 """Check that p and its subtree have the structure given in the table."""
38 # Check structure
39 p1 = p.copy()
40 try:
41 self.assertEqual(p1.h, f"{self.treeType} {self.short_id}")
42 i = 0
43 for p in p1.subtree():
44 self.assertTrue(i < len(table), msg=repr(p.h))
45 data = table[i]
46 i += 1
47 n, h = data
48 self.assertEqual(p.h, h)
49 # Subtract 1 for compatibility with values in previous tables.
50 self.assertEqual(p.level() - 1, n, msg=f"{p.h}: expected level {n}, got {p.level()}")
51 # Make sure there are no extra nodes in p's tree.
52 self.assertEqual(i, len(table), msg=f"i: {i}, len(table): {len(table)}")
53 except AssertionError: # pragma: no cover
54 g.trace(self.short_id)
55 self.dump_tree(p1)
56 raise
57 #@+node:ekr.20211126052156.1: *3* BaseTestImporter.compare_outlines
58 def compare_outlines(self, created_p, expected_p): # pragma: no cover
59 """
60 Ensure that the created and expected trees have equal shape and contents.
62 Also ensure that all created nodes have the expected node kind.
63 """
64 d = g.vnode_info
65 p1, p2 = created_p.copy(), expected_p.copy()
66 try:
67 after1, after2 = p1.nodeAfterTree(), p2.nodeAfterTree()
68 while p1 and p2 and p1 != after1 and p2 != after2:
69 aList1 = d.get(p1.v)['kind'].split(':')
70 aList2 = d.get(p2.v)['kind'].split(':')
71 kind1, kind2 = aList1[0], aList2[0]
72 self.assertEqual(p1.h, p2.h)
73 self.assertEqual(p1.numberOfChildren(), p2.numberOfChildren(), msg=p1.h)
74 self.assertEqual(p1.b.strip(), p2.b.strip(), msg=p1.h)
75 self.assertEqual(kind1, kind2, msg=p1.h)
76 p1.moveToThreadNext()
77 p2.moveToThreadNext()
78 # Make sure both trees end at the same time.
79 self.assertTrue(not p1 or p1 == after1)
80 self.assertTrue(not p2 or p2 == after2)
81 except AssertionError:
82 g.es_exception()
83 self.dump_tree(created_p, tag='===== Created')
84 self.dump_tree(expected_p, tag='===== Expected')
85 raise
86 #@+node:ekr.20211108044605.1: *3* BaseTestImporter.compute_unit_test_kind
87 def compute_unit_test_kind(self, ext):
88 """Return kind from the given extention."""
89 aClass = g.app.classDispatchDict.get(ext)
90 kind = {'.md': '@auto-md'
91 , '.org': '@auto-org'
92 , '.otl': '@auto-otl'
93 , '.rst': '@auto-rst'
94 }.get(ext)
95 if kind:
96 return kind
97 if aClass:
98 d2 = g.app.atAutoDict
99 for z in d2:
100 if d2.get(z) == aClass:
101 return z # pragma: no cover
102 return '@file'
103 #@+node:ekr.20211129062220.1: *3* BaseTestImporter.dump_tree
104 def dump_tree(self, root, tag=None): # pragma: no cover
105 """Dump root's tree just as as Importer.dump_tree."""
106 d = g.vnode_info # Same as Importer.vnode_info!
107 if tag:
108 print(tag)
109 for p in root.self_and_subtree():
110 print('')
111 print('level:', p.level(), p.h)
112 lines = d[p.v]['lines'] if p.v in d else g.splitLines(p.v.b)
113 g.printObj(lines)
114 #@+node:ekr.20211127042843.1: *3* BaseTestImporter.run_test
115 def run_test(self, s):
116 """
117 Run a unit test of an import scanner,
118 i.e., create a tree from string s at location p.
119 """
120 c, ext, p = self.c, self.ext, self.c.p
121 self.assertTrue(ext)
122 # Run the test.
123 parent = p.insertAsLastChild()
124 kind = self.compute_unit_test_kind(ext)
125 # TestCase.id() has the form leo.unittests.core.file.class.test_name
126 id_parts = self.id().split('.')
127 self.short_id = f"{id_parts[-2]}.{id_parts[-1]}"
128 parent.h = f"{kind} {self.short_id}"
129 # createOutline calls Importer.gen_lines and Importer.check.
130 test_s = textwrap.dedent(s).strip() + '\n\n'
131 ok = c.importCommands.createOutline(parent.copy(), ext, test_s)
132 if not ok: # pragma: no cover
133 self.dump_tree(parent)
134 self.fail('Perfect import failed') # pragma: no cover
135 return parent
136 #@-others
137#@+node:ekr.20211108052633.1: ** class TestAtAuto (BaseTestImporter)
138class TestAtAuto(BaseTestImporter):
140 #@+others
141 #@+node:ekr.20210904065459.122: *3* TestAtAuto.test_importers_can_be_imported
142 def test_importers_can_be_imported(self):
143 path = g.os_path_finalize_join(g.app.loadDir, '..', 'plugins', 'importers')
144 assert g.os_path_exists(path), repr(path)
145 pattern = g.os_path_finalize_join(path, '*.py')
146 for fn in glob.glob(pattern):
147 sfn = g.shortFileName(fn)
148 m = importlib.import_module('leo.plugins.importers.%s' % sfn[:-3])
149 assert m
150 #@-others
151#@+node:ekr.20211108062025.1: ** class TestC (BaseTestImporter)
152class TestC(BaseTestImporter):
154 ext = '.c'
156 #@+others
157 #@+node:ekr.20210904065459.3: *3* TestC.test_c_class_1
158 def test_c_class_1(self):
160 s = """
161 class cTestClass1 {
163 int foo (int a) {
164 a = 2 ;
165 }
167 char bar (float c) {
168 ;
169 }
170 }
171 """
172 p = self.run_test(s)
173 self.check_headlines(p, (
174 (1, 'class cTestClass1'),
175 (2, 'int foo'),
176 (2, 'char bar'),
177 ))
178 #@+node:ekr.20210904065459.4: *3* TestC.test_class_underindented_line
179 def test_class_underindented_line(self):
181 s = """
182 class cTestClass1 {
184 int foo (int a) {
185 // an underindented line.
186 a = 2 ;
187 }
189 // This should go with the next function.
191 char bar (float c) {
192 ;
193 }
194 }
195 """
196 p = self.run_test(s)
197 self.check_headlines(p, (
198 (1, 'class cTestClass1'),
199 (2, 'int foo'),
200 (2, 'char bar'),
201 ))
203 #@+node:ekr.20210904065459.5: *3* TestC.test_comment_follows_arg_list
204 def test_comment_follows_arg_list(self):
206 s = """
207 void
208 aaa::bbb::doit
209 (
210 awk* b
211 )
212 {
213 assert(false);
214 }
216 bool
217 aaa::bbb::dothat
218 (
219 xyz *b
220 ) // <---------------------problem
221 {
222 return true;
223 }
224 """
225 p = self.run_test(s)
226 self.check_headlines(p, (
227 (1, 'void aaa::bbb::doit'),
228 (1, 'bool aaa::bbb::dothat'),
229 ))
230 #@+node:ekr.20210904065459.6: *3* TestC.test_comment_follows_block_delim
231 def test_comment_follows_block_delim(self):
233 s = """
234 void
235 aaa::bbb::doit
236 (
237 awk* b
238 )
239 {
240 assert(false);
241 }
243 bool
244 aaa::bbb::dothat
245 (
246 xyz *b
247 )
248 {
249 return true;
250 } // <--------------------- problem
251 """
252 p = self.run_test(s)
253 self.check_headlines(p, (
254 (1, 'void aaa::bbb::doit'),
255 (1, 'bool aaa::bbb::dothat'),
256 ))
257 #@+node:ekr.20210904065459.10: *3* TestC.test_extern
258 def test_extern(self):
260 s = """
261 extern "C"
262 {
263 #include "stuff.h"
264 void init(void);
265 #include "that.h"
266 }
267 """
268 p = self.run_test(s)
269 self.check_headlines(p, (
270 (1, 'extern "C"'),
271 ))
272 #@+node:ekr.20210904065459.7: *3* TestC.test_intermixed_blanks_and_tabs
273 def test_intermixed_blanks_and_tabs(self):
275 s = """
276 void
277 aaa::bbb::doit
278 (
279 awk* b // leading blank
280 )
281 {
282 assert(false); // leading tab
283 }
284 """
285 p = self.run_test(s)
286 self.check_headlines(p, (
287 (1, 'void aaa::bbb::doit'),
288 ))
289 #@+node:ekr.20210904065459.8: *3* TestC.test_old_style_decl_1
290 def test_old_style_decl_1(self):
292 s = """
293 static void
294 ReleaseCharSet(cset)
295 CharSet *cset;
296 {
297 ckfree((char *)cset->chars);
298 if (cset->ranges) {
299 ckfree((char *)cset->ranges);
300 }
301 }
302 """
303 p = self.run_test(s)
304 self.check_headlines(p, (
305 (1, 'static void ReleaseCharSet'),
306 ))
307 #@+node:ekr.20210904065459.9: *3* TestC.test_old_style_decl_2
308 def test_old_style_decl_2(self):
310 s = """
311 Tcl_Obj *
312 Tcl_NewLongObj(longValue)
313 register long longValue; /* Long integer used to initialize the
314 * new object. */
315 {
316 return Tcl_DbNewLongObj(longValue, "unknown", 0);
317 }
318 """
319 p = self.run_test(s)
320 self.check_headlines(p, (
321 (1, 'Tcl_Obj * Tcl_NewLongObj'),
322 ))
323 #@-others
324#@+node:ekr.20211108063520.1: ** class TestCoffeescript (BaseTextImporter)
325class TestCoffeescript(BaseTestImporter):
327 ext = '.coffee'
329 #@+others
330 #@+node:ekr.20210904065459.15: *3* TestCoffeescript.test_1
331 def test_1(self):
333 s = r'''
335 # Js2coffee relies on Narcissus's parser.
337 {parser} = @Narcissus or require('./narcissus_packed')
339 # Main entry point
341 buildCoffee = (str) ->
342 str = str.replace /\r/g, ''
343 str += "\n"
345 builder = new Builder
346 scriptNode = parser.parse str
347 '''
348 p = self.run_test(s)
349 self.check_headlines(p, (
350 (1, 'buildCoffee = (str) ->'),
351 ))
352 #@+node:ekr.20210904065459.16: *3* TestCoffeescript.test_2
353 #@@tabwidth -2 # Required
355 def test_2(self):
357 s = """
358 class Builder
359 constructor: ->
360 @transformer = new Transformer
361 # `build()`
363 build: (args...) ->
364 node = args[0]
365 @transform node
367 name = 'other'
368 name = node.typeName() if node != undefined and node.typeName
370 fn = (@[name] or @other)
371 out = fn.apply(this, args)
373 if node.parenthesized then paren(out) else out
374 # `transform()`
376 transform: (args...) ->
377 @transformer.transform.apply(@transformer, args)
379 # `body()`
381 body: (node, opts={}) ->
382 str = @build(node, opts)
383 str = blockTrim(str)
384 str = unshift(str)
385 if str.length > 0 then str else ""
386 """
387 p = self.run_test(s)
388 self.check_headlines(p, (
389 (1, 'class Builder'),
390 (2, 'constructor: ->'),
391 (2, 'build: (args...) ->'),
392 (2, 'transform: (args...) ->'),
393 (2, 'body: (node, opts={}) ->'),
394 ))
396 #@+node:ekr.20211108085023.1: *3* TestCoffeescript.test_get_leading_indent
397 def test_get_leading_indent(self):
398 c = self.c
399 importer = linescanner.Importer(c.importCommands, language='coffeescript')
400 self.assertEqual(importer.single_comment, '#')
401 #@+node:ekr.20210904065459.126: *3* TestCoffeescript.test_scan_line
402 def test_scan_line(self):
403 c = self.c
404 x = cs.CS_Importer(c.importCommands, atAuto=True)
405 self.assertEqual(x.single_comment, '#')
406 #@-others
407#@+node:ekr.20211108062958.1: ** class TestCSharp (BaseTestImporter)
408class TestCSharp(BaseTestImporter):
410 ext = '.c#'
412 #@+others
413 #@+node:ekr.20210904065459.12: *3* TestCSharp.test_namespace_indent
414 def test_namespace_indent(self):
416 s = """
417 namespace {
418 class cTestClass1 {
419 ;
420 }
421 }
422 """
423 p = self.run_test(s)
424 self.check_headlines(p, (
425 (1, 'namespace'),
426 (2, 'class cTestClass1'),
427 ))
428 #@+node:ekr.20210904065459.13: *3* TestImport.test_namespace_no_indent
429 def test_namespace_no_indent(self):
431 s = """
432 namespace {
433 class cTestClass1 {
434 ;
435 }
436 }
437 """
438 p = self.run_test(s)
439 self.check_headlines(p, (
440 (1, 'namespace'),
441 (2, 'class cTestClass1')
442 ))
443 #@-others
444#@+node:ekr.20211108063908.1: ** class TestCython (BaseTestImporter)
445class TestCython(BaseTestImporter):
447 ext = '.pyx'
448 #@+others
449 #@+node:ekr.20210904065459.11: *3* TestCython.test_importer
450 def test_importer(self):
452 s = '''
453 from libc.math cimport pow
455 cdef double square_and_add (double x):
456 """Compute x^2 + x as double.
458 This is a cdef function that can be called from within
459 a Cython program, but not from Python.
460 """
461 return pow(x, 2.0) + x
463 cpdef print_result (double x):
464 """This is a cpdef function that can be called from Python."""
465 print("({} ^ 2) + {} = {}".format(x, x, square_and_add(x)))
467 '''
468 p = self.run_test(s)
469 self.check_headlines(p, (
470 (1, 'Organizer: Declarations'),
471 (1, 'double'),
472 (1, 'print_result'),
473 ))
474 #@-others
475#@+node:ekr.20211108064115.1: ** class TestDart (BaseTestImporter)
476class TestDart(BaseTestImporter):
478 ext = '.dart'
480 #@+others
481 #@+node:ekr.20210904065459.17: *3* TestDart.test_hello_world
482 def test_hello_world(self):
484 s = r'''
485 var name = 'Bob';
487 hello() {
488 print('Hello, World!');
489 }
491 // Define a function.
492 printNumber(num aNumber) {
493 print('The number is $aNumber.'); // Print to console.
494 }
496 // This is where the app starts executing.
497 void main() {
498 var number = 42; // Declare and initialize a variable.
499 printNumber(number); // Call a function.
500 }
501 '''
502 p = self.run_test(s)
503 self.check_headlines(p, (
504 (1, 'hello'),
505 (1, 'printNumber'),
506 (1, 'void main'),
507 ))
508 #@+node:ekr.20210904065459.127: *3* TestDart.test_clean_headline
509 def test_clean_headline(self):
510 c = self.c
511 x = dart.Dart_Importer(c.importCommands, atAuto=False)
512 table = (
513 ('func(abc) {', 'func'),
514 ('void foo() {', 'void foo'),
515 )
516 for s, expected in table:
517 got = x.clean_headline(s)
518 self.assertEqual(got, expected)
519 #@-others
520#@+node:ekr.20211108065659.1: ** class TestElisp (BaseTestImporter)
521class TestElisp(BaseTestImporter):
523 ext = '.el'
525 #@+others
526 #@+node:ekr.20210904065459.18: *3* TestElisp.test_1
527 def test_1(self):
529 s = """
530 ;;; comment
531 ;;; continue
532 ;;;
534 (defun abc (a b)
535 (+ 1 2 3))
537 ; comm
538 (defun cde (a b)
539 (+ 1 2 3))
540 """
541 p = self.run_test(s)
542 self.check_headlines(p, (
543 (1, 'defun abc'),
544 (1, 'defun cde'),
545 ))
547 #@-others
548#@+node:ekr.20211108064432.1: ** class TestHtml (BaseTestImporter)
549class TestHtml(BaseTestImporter):
551 ext = '.htm'
553 def setUp(self):
554 super().setUp()
555 c = self.c
556 # Simulate @data import-html-tags, with *only* standard tags.
557 tags_list = ['html', 'body', 'head', 'div', 'table']
558 settingsDict, junk = g.app.loadManager.createDefaultSettingsDicts()
559 c.config.settingsDict = settingsDict
560 c.config.set(c.p, 'data', 'import-html-tags', tags_list, warn=True)
562 #@+others
563 #@+node:ekr.20210904065459.19: *3* TestHtml.test_lowercase_tags
564 def test_lowercase_tags(self):
566 s = """
567 <html>
568 <head>
569 <title>Bodystring</title>
570 </head>
571 <body class="bodystring">
572 <div id='bodydisplay'></div>
573 </body>
574 </html>
575 """
576 p = self.run_test(s)
577 self.check_headlines(p, (
578 (1, '<html>'),
579 (2, '<head>'),
580 (2, '<body class="bodystring">'),
581 ))
583 #@+node:ekr.20210904065459.20: *3* TestHtml.test_multiple_tags_on_a_line
584 def test_multiple_tags_on_a_line(self):
586 # tags that cause nodes: html, head, body, div, table, nodeA, nodeB
587 # NOT: tr, td, tbody, etc.
588 s = """
589 <html>
590 <body>
591 <table id="0">
592 <tr valign="top">
593 <td width="619">
594 <table id="2"> <tr valign="top"> <td width="377">
595 <table id="3">
596 <tr>
597 <td width="368">
598 <table id="4">
599 <tbody id="5">
600 <tr valign="top">
601 <td width="550">
602 <table id="6">
603 <tbody id="6">
604 <tr>
605 <td class="blutopgrabot"><a href="href1">Listing Standards</a> | <a href="href2">Fees</a> | <strong>Non-compliant Issuers</strong> | <a href="href3">Form 25 Filings</a> </td>
606 </tr>
607 </tbody>
608 </table>
609 </td>
610 </tr><tr>
611 <td width="100%" colspan="2">
612 <br />
613 </td>
614 </tr>
615 </tbody>
616 </table>
617 </td>
618 </tr>
619 </table>
620 <!-- View First part --> </td> <td width="242"> <!-- View Second part -->
621 <!-- View Second part --> </td> </tr></table>
622 <DIV class="webonly">
623 <script src="/scripts/footer.js"></script>
624 </DIV>
625 </td>
626 </tr>
627 <script language="JavaScript1.1">var SA_ID="nyse;nyse";</script>
628 <script language="JavaScript1.1" src="/scripts/stats/track.js"></script>
629 <noscript><img src="/scripts/stats/track.js" height="1" width="1" alt="" border="0"></noscript>
630 </body>
631 </html>
632 """
633 p = self.run_test(s)
634 self.check_headlines(p, (
635 (1, '<html>'),
636 (2, '<body>'),
637 (3, '<table id="0">'),
638 (4, '<table id="2">'),
639 (5, '<table id="3">'),
640 (6, '<table id="4">'),
641 (7, '<table id="6">'),
642 (4, '<DIV class="webonly">'),
643 ))
645 #@+node:ekr.20210904065459.21: *3* TestHtml.test_multple_node_completed_on_a_line
646 def test_multple_node_completed_on_a_line(self):
648 s = """
649 <!-- tags that start nodes: html,body,head,div,table,nodeA,nodeB -->
650 <html><head>headline</head><body>body</body></html>
651 """
652 p = self.run_test(s)
653 self.check_headlines(p, (
654 # The new xml scanner doesn't generate any new nodes,
655 # because the scan state hasn't changed at the end of the line!
656 ))
657 #@+node:ekr.20210904065459.22: *3* TestHtml.test_multple_node_starts_on_a_line
658 def test_multple_node_starts_on_a_line(self):
660 s = '''
661 <html>
662 <head>headline</head>
663 <body>body</body>
664 </html>
665 '''
666 p = self.run_test(s)
667 self.check_headlines(p, (
668 (1, '<html>'),
669 # (2, '<head>'),
670 # (2, '<body>'),
671 ))
672 #@+node:ekr.20210904065459.23: *3* TestHtml.test_underindented_comment
673 def test_underindented_comment(self):
675 s = r'''
676 <td width="550">
677 <table cellspacing="0" cellpadding="0" width="600" border="0">
678 <td class="blutopgrabot" height="28"></td>
680 <!-- The indentation of this element causes the problem. -->
681 <table>
683 <!--
684 <div align="center">
685 <iframe src="http://www.amex.com/atamex/regulation/listingStatus/index.jsp"</iframe>
686 </div>
687 -->
689 </table>
690 </table>
692 <p>Paragraph</p>
693 </td>
694 '''
695 p = self.run_test(s)
696 self.check_headlines(p, (
697 (1, '<table cellspacing="0" cellpadding="0" width="600" border="0">'),
698 (2, '<table>'),
699 ))
700 #@+node:ekr.20210904065459.24: *3* TestHtml.test_uppercase_tags
701 def test_uppercase_tags(self):
703 s = """
704 <HTML>
705 <HEAD>
706 <title>Bodystring</title>
707 </HEAD>
708 <BODY class='bodystring'>
709 <DIV id='bodydisplay'></DIV>
710 </BODY>
711 </HTML>
712 """
713 p = self.run_test(s)
714 self.check_headlines(p, (
715 (1, '<HTML>'),
716 (2, '<HEAD>'),
717 (2, "<BODY class='bodystring'>"),
718 # (3, "<DIV id='bodydisplay'></DIV>"),
719 ))
720 #@+node:ekr.20210904065459.25: *3* TestHtml.test_improperly_nested_tags
721 def test_improperly_nested_tags(self):
723 s = """
724 <body>
726 <!-- OOPS: the div and p elements not properly nested.-->
727 <!-- OOPS: this table got generated twice. -->
729 <p id="P1">
730 <div id="D666">Paragraph</p> <!-- P1 -->
731 <p id="P2">
733 <TABLE id="T666"></TABLE></p> <!-- P2 -->
734 </div>
735 </p> <!-- orphan -->
737 </body>
738 """
739 p = self.run_test(s)
740 self.check_headlines(p, (
741 (1, '<body>'),
742 (2, '<div id="D666">'),
743 ))
745 #@+node:ekr.20210904065459.26: *3* TestHtml.test_improperly_terminated_tags
746 def test_improperly_terminated_tags(self):
748 s = '''
749 <html>
751 <head>
752 <!-- oops: link elements terminated two different ways -->
753 <link id="L1">
754 <link id="L2">
755 <link id="L3" />
756 <link id='L4' />
758 <title>TITLE</title>
760 <!-- oops: missing tags. -->
761 '''
762 p = self.run_test(s)
763 self.check_headlines(p, (
764 (1, '<html>'),
765 (2, '<head>'),
766 ))
768 #@+node:ekr.20210904065459.27: *3* TestHtml.test_improperly_terminated_tags2
769 def test_improperly_terminated_tags2(self):
771 s = '''
772 <html>
773 <head>
774 <!-- oops: link elements terminated two different ways -->
775 <link id="L1">
776 <link id="L2">
777 <link id="L3" />
778 <link id='L4' />
780 <title>TITLE</title>
782 </head>
783 </html>
784 '''
785 p = self.run_test(s)
786 self.check_headlines(p, (
787 (1, '<html>'),
788 (2, '<head>'),
789 ))
791 #@+node:ekr.20210904065459.28: *3* TestHtml.test_brython
792 def test_brython(self):
794 # https://github.com/leo-editor/leo-editor/issues/479
795 s = '''
796 <!DOCTYPE html>
797 <html>
798 <head>
799 <script type="text/python3">
800 """Code for the header menu"""
801 from browser import document as doc
802 from browser import html
803 import header
805 qs_lang,language = header.show()
807 doc["content"].html = doc["content_%s" %language].html
809 if qs_lang:
810 doc["c_%s" %qs_lang].href += "?lang=%s" %qs_lang
812 def ch_lang(ev):
813 sel = ev.target
814 new_lang = sel.options[sel.selectedIndex].value
815 doc.location.href = 'index.html?lang=%s' %new_lang
817 for elt in doc[html.SELECT]:
818 if elt.id.startswith('change_lang_'):
819 doc[elt.id].bind('change',ch_lang)
820 </script>
822 <script type="text/python3">
823 """Code for the clock"""
825 import time
826 import math
827 import datetime
829 from browser import document as doc
830 import browser.timer
832 sin,cos = math.sin,math.cos
833 width,height = 250,250 # canvas dimensions
834 ray = 100 # clock ray
836 def needle(angle,r1,r2,color="#000000"):
837 # draw a needle at specified angle in specified color
838 # r1 and r2 are percentages of clock ray
839 x1 = width/2-ray*cos(angle)*r1
840 y1 = height/2-ray*sin(angle)*r1
841 x2 = width/2+ray*cos(angle)*r2
842 y2 = height/2+ray*sin(angle)*r2
843 ctx.beginPath()
844 ctx.strokeStyle = color
845 ctx.moveTo(x1,y1)
846 ctx.lineTo(x2,y2)
847 ctx.stroke()
849 def set_clock():
850 # erase clock
851 ctx.beginPath()
852 ctx.fillStyle = "#FFF"
853 ctx.arc(width/2,height/2,ray*0.89,0,2*math.pi)
854 ctx.fill()
856 # redraw hours
857 show_hours()
859 # print day
860 now = datetime.datetime.now()
861 day = now.day
862 ctx.font = "bold 14px Arial"
863 ctx.textAlign = "center"
864 ctx.textBaseline = "middle"
865 ctx.fillStyle="#FFF"
866 ctx.fillText(day,width*0.7,height*0.5)
868 # draw needles for hour, minute, seconds
869 ctx.lineWidth = 3
870 hour = now.hour%12 + now.minute/60
871 angle = hour*2*math.pi/12 - math.pi/2
872 needle(angle,0.05,0.5)
873 minute = now.minute
874 angle = minute*2*math.pi/60 - math.pi/2
875 needle(angle,0.05,0.85)
876 ctx.lineWidth = 1
877 second = now.second+now.microsecond/1000000
878 angle = second*2*math.pi/60 - math.pi/2
879 needle(angle,0.05,0.85,"#FF0000") # in red
881 def show_hours():
882 ctx.beginPath()
883 ctx.arc(width/2,height/2,ray*0.05,0,2*math.pi)
884 ctx.fillStyle = "#000"
885 ctx.fill()
886 for i in range(1,13):
887 angle = i*math.pi/6-math.pi/2
888 x3 = width/2+ray*cos(angle)*0.75
889 y3 = height/2+ray*sin(angle)*0.75
890 ctx.font = "20px Arial"
891 ctx.textAlign = "center"
892 ctx.textBaseline = "middle"
893 ctx.fillText(i,x3,y3)
894 # cell for day
895 ctx.fillStyle = "#000"
896 ctx.fillRect(width*0.65,height*0.47,width*0.1,height*0.06)
898 canvas = doc["clock"]
899 # draw clock border
900 if hasattr(canvas,'getContext'):
901 ctx = canvas.getContext("2d")
902 ctx.beginPath()
903 ctx.lineWidth = 10
904 ctx.arc(width/2,height/2,ray,0,2*math.pi)
905 ctx.stroke()
907 for i in range(60):
908 ctx.lineWidth = 1
909 if i%5 == 0:
910 ctx.lineWidth = 3
911 angle = i*2*math.pi/60 - math.pi/3
912 x1 = width/2+ray*cos(angle)
913 y1 = height/2+ray*sin(angle)
914 x2 = width/2+ray*cos(angle)*0.9
915 y2 = height/2+ray*sin(angle)*0.9
916 ctx.beginPath()
917 ctx.moveTo(x1,y1)
918 ctx.lineTo(x2,y2)
919 ctx.stroke()
920 browser.timer.set_interval(set_clock,100)
921 show_hours()
922 else:
923 doc['navig_zone'].html = "On Internet Explorer 9 or more, use a Standard rendering engine"
924 </script>
926 <title>Brython</title>
927 <link rel="stylesheet" href="Brython_files/doc_brython.css">
928 </head>
929 <body onload="brython({debug:1, cache:'none'})">
930 </body></html>
931 '''
932 p = self.run_test(s)
933 self.check_headlines(p, (
934 (1, '<html>'),
935 (2, '<head>'),
936 (2, '<body onload="brython({debug:1, cache:\'none\'})">'),
937 ))
938 #@-others
939#@+node:ekr.20211108062617.1: ** class TestIni (BaseTestImporter)
940class TestIni(BaseTestImporter):
942 ext = '.ini'
944 #@+others
945 #@+node:ekr.20210904065459.29: *3* TestIni.test_1
946 def test_1(self):
948 s = '''
949 ; last modified 1 April 2001 by John Doe
950 [owner]
951 name=John Doe
952 organization=Acme Widgets Inc.
954 ; [ not a section ]
956 [database]
957 server=192.0.2.62
958 ; use IP address
959 port=143
960 file = "payroll.dat"
961 '''
962 p = self.run_test(s)
963 self.check_headlines(p, (
964 (1, '[owner]'),
965 (1, '[database]'),
966 ))
967 #@-others
968#@+node:ekr.20211108065916.1: ** class TestJava (BaseTestImporter)
969class TestJava(BaseTestImporter):
971 ext = '.java'
973 #@+others
974 #@+node:ekr.20210904065459.30: *3* TestJava.test_from_AdminPermission_java
975 def test_from_AdminPermission_java(self):
977 s = """
978 /**
979 * Indicates the caller's authority to perform lifecycle operations on
980 */
982 public final class AdminPermission extends BasicPermission
983 {
984 /**
985 * Creates a new <tt>AdminPermission</tt> object.
986 */
987 public AdminPermission()
988 {
989 super("AdminPermission");
990 }
991 }
992 """
993 p = self.run_test(s)
994 self.check_headlines(p, (
995 (1, 'public final class AdminPermission extends BasicPermission'),
996 (2, 'public AdminPermission'),
997 ))
998 #@+node:ekr.20210904065459.31: *3* TestJava.test_from_BundleException_java
999 def test_from_BundleException_java(self):
1001 s = """
1002 /*
1003 * $Header: /cvs/leo/test/unitTest.leo,v 1.247 2008/02/14 14:59:04 edream Exp $
1004 *
1005 * Copyright (c) OSGi Alliance (2000, 2005). All Rights Reserved.
1006 *
1007 * This program and the accompanying materials are made available under the
1008 * terms of the Eclipse Public License v1.0 which accompanies this
1009 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html.
1010 */
1012 package org.osgi.framework;
1014 /**
1015 * A Framework exception used to indicate that a bundle lifecycle problem
1016 * occurred.
1017 *
1018 * <p>
1019 * <code>BundleException</code> object is created by the Framework to denote
1020 * an exception condition in the lifecycle of a bundle.
1021 * <code>BundleException</code>s should not be created by bundle developers.
1022 *
1023 * <p>
1024 * This exception is updated to conform to the general purpose exception
1025 * chaining mechanism.
1026 *
1027 * @version $Revision: 1.247 $
1028 */
1030 public class BundleException extends Exception {
1031 static final long serialVersionUID = 3571095144220455665L;
1032 /**
1033 * Nested exception.
1034 */
1035 private Throwable cause;
1037 /**
1038 * Creates a <code>BundleException</code> that wraps another exception.
1039 *
1040 * @param msg The associated message.
1041 * @param cause The cause of this exception.
1042 */
1043 public BundleException(String msg, Throwable cause) {
1044 super(msg);
1045 this.cause = cause;
1046 }
1047 }
1049 """
1050 p = self.run_test(s)
1051 self.check_headlines(p, (
1052 (1, 'public class BundleException extends Exception'),
1053 (2, 'public BundleException'),
1054 ))
1055 #@+node:ekr.20210904065459.32: *3* TestJava.test_interface_test1
1056 def test_interface_test1(self):
1058 s = """
1059 interface Bicycle {
1060 void changeCadence(int newValue);
1061 void changeGear(int newValue);
1062 }
1063 """
1064 p = self.run_test(s)
1065 self.check_headlines(p, (
1066 (1, 'interface Bicycle'),
1067 ))
1068 #@+node:ekr.20210904065459.33: *3* TestJava.test_interface_test2
1069 def test_interface_test2(self):
1071 s = """
1072 interface Bicycle {
1073 void changeCadence(int newValue);
1074 void changeGear(int newValue);
1075 }
1076 """
1077 p = self.run_test(s)
1078 self.check_headlines(p, (
1079 (1, 'interface Bicycle'),
1080 ))
1081 #@-others
1082#@+node:ekr.20211108070310.1: ** class TestJavascript (BaseTestImporter)
1083class TestJavascript(BaseTestImporter):
1085 ext = '.js'
1087 #@+others
1088 #@+node:ekr.20210904065459.34: *3* TestJavascript.test_regex_1
1089 def test_regex_1(self):
1091 s = """
1092 String.prototype.toJSONString = function()
1093 {
1094 if(/["\\\\\\x00-\\x1f]/.test(this))
1095 return '"' + this.replace(/([\\x00-\\x1f\\"])/g,replaceFn) + '"';
1097 return '"' + this + '"';
1098 };
1099 """
1100 self.run_test(s)
1101 #@+node:ekr.20210904065459.35: *3* TestJavascript.test_3
1102 def test_3(self):
1104 s = """
1105 // Restarting
1106 function restart()
1107 {
1108 invokeParamifier(params,"onstart");
1109 if(story.isEmpty()) {
1110 var tiddlers = store.filterTiddlers(store.getTiddlerText("DefaultTiddlers"));
1111 for(var t=0; t<tiddlers.length; t++) {
1112 story.displayTiddler("bottom",tiddlers[t].title);
1113 }
1114 }
1115 window.scrollTo(0,0);
1116 }
1117 """
1118 self.run_test(s)
1119 #@+node:ekr.20210904065459.36: *3* TestJavascript.test_4
1120 def test_4(self):
1122 s = """
1123 var c3 = (function () {
1124 "use strict";
1126 // Globals
1127 var c3 = { version: "0.0.1" };
1129 c3.someFunction = function () {
1130 console.log("Just a demo...");
1131 };
1133 return c3;
1134 }());
1135 """
1136 self.run_test(s)
1137 #@+node:ekr.20210904065459.37: *3* TestJavascript.test_5
1138 def test_5(self):
1140 s = """
1141 var express = require('express');
1143 var app = express.createServer(express.logger());
1145 app.get('/', function(request, response) {
1146 response.send('Hello World!');
1147 });
1149 var port = process.env.PORT || 5000;
1150 app.listen(port, function() {
1151 console.log("Listening on " + port);
1152 });
1153 """
1154 self.run_test(s)
1155 #@+node:ekr.20210904065459.38: *3* TestJavascript.test_639_many_top_level_nodes
1156 def test_639_many_top_level_nodes(self):
1158 s = """
1159 // Easy test for #639: https://github.com/leo-editor/leo-editor/issues/639
1161 //=============================================================================
1162 // rpg_core.js v1.3.0
1163 //=============================================================================
1165 //-----------------------------------------------------------------------------
1166 /**
1167 * This is not a class, but contains some methods that will be added to the
1168 * standard Javascript objects.
1169 *
1170 * @class JsExtensions
1171 */
1172 function JsExtensions() {
1173 throw new Error('This is not a class');
1174 }
1176 /**
1177 * Returns a number whose value is limited to the given range.
1178 *
1179 * @method Number.prototype.clamp
1180 * @param {Number} min The lower boundary
1181 * @param {Number} max The upper boundary
1182 * @return {Number} A number in the range (min, max)
1183 */
1184 Number.prototype.clamp = function(min, max) {
1185 return Math.min(Math.max(this, min), max);
1186 };
1187 """
1188 self.run_test(s)
1189 #@+node:ekr.20210904065459.39: *3* TestJavascript.test_639_acid_test_1
1190 def test_639_acid_test_1(self):
1192 s = """
1193 // Acid test for #639: https://github.com/leo-editor/leo-editor/issues/639
1194 require([
1195 'jquery',
1196 ], function(
1197 $,
1198 termjs,
1199 ){
1200 var header = $("#header")[0];
1201 function calculate_size() {
1202 var height = $(window).height() - header.offsetHeight;
1203 }
1204 page.show_header();
1205 window.onresize = function() {
1206 terminal.socket.send(JSON.stringify([
1207 "set_size", geom.rows, geom.cols,
1208 $(window).height(), $(window).width()])
1209 );
1210 };
1211 window.terminal = terminal;
1212 });
1213 """
1214 self.run_test(s)
1215 #@+node:ekr.20210904065459.40: *3* TestJavascript.test_639_acid_test_2
1216 def test_639_acid_test_2(self):
1218 s = """
1219 // Acid test for #639: https://github.com/leo-editor/leo-editor/issues/639
1220 require([
1221 'jquery',
1222 ], function(
1223 $,
1224 termjs,
1225 ){
1226 var head = "head"
1227 function f1() {
1228 var head1 = "head1"
1229 function f11 () {
1230 var v11 ="v1.1"
1231 }
1232 var middle1 = "middle1"
1233 function f12 () {
1234 var v12 ="v1.2"
1235 }
1236 var tail1 = "tail1"
1237 }
1238 var middle = "middle"
1239 function f2() {
1240 var head2 = "head2"
1241 function f21 () {
1242 var v21 ="2.1"
1243 }
1244 var middle2 = "middle2"
1245 function f22 () {
1246 var v22 = "2.2.1"
1247 }
1248 var tail2 = "tail2"
1249 }
1250 var tail = "tail"
1251 });
1252 """
1253 self.run_test(s)
1254 #@-others
1255#@+node:ekr.20211108043230.1: ** class TestMarkdown (BaseTestImporter)
1256class TestMarkdown(BaseTestImporter):
1258 ext = '.md'
1259 treeType = '@auto-md'
1261 #@+others
1262 #@+node:ekr.20210904065459.109: *3* TestMarkdown.test_md_import
1263 def test_md_import(self):
1265 s = """\
1266 #Top
1267 The top section
1269 ##Section 1
1270 section 1, line 1
1271 section 1, line 2
1273 ##Section 2
1274 section 2, line 1
1276 ###Section 2.1
1277 section 2.1, line 1
1279 ####Section 2.1.1
1280 section 2.2.1 line 1
1281 The next section is empty. It must not be deleted.
1283 ###Section 2.2
1285 ##Section 3
1286 Section 3, line 1
1287 """
1288 p = self.run_test(s)
1289 self.check_headlines(p, (
1290 (1, 'Top'),
1291 (2, 'Section 1'),
1292 (2, 'Section 2'),
1293 (3, 'Section 2.1'),
1294 (4, 'Section 2.1.1'),
1295 (3, 'Section 2.2'),
1296 (2, 'Section 3'),
1297 ))
1298 #@+node:ekr.20210904065459.110: *3* TestMarkdown.test_md_import_rst_style
1299 def test_md_import_rst_style(self):
1301 s = """\
1302 Top
1303 ====
1305 The top section
1307 Section 1
1308 ---------
1310 section 1, line 1
1311 -- Not an underline
1312 secttion 1, line 2
1314 Section 2
1315 ---------
1317 section 2, line 1
1319 ###Section 2.1
1321 section 2.1, line 1
1323 ####Section 2.1.1
1325 section 2.2.1 line 1
1327 ###Section 2.2
1328 section 2.2, line 1.
1330 Section 3
1331 ---------
1333 section 3, line 1
1334 """
1335 p = self.run_test(s)
1336 self.check_headlines(p, (
1337 (1, 'Top'),
1338 (2, 'Section 1'),
1339 (2, 'Section 2'),
1340 (3, 'Section 2.1'),
1341 (4, 'Section 2.1.1'),
1342 (3, 'Section 2.2'),
1343 (2, 'Section 3'),
1344 ))
1345 #@+node:ekr.20210904065459.111: *3* TestMarkdown.test_markdown_importer_basic
1346 def test_markdown_importer_basic(self):
1348 # insert test for markdown here.
1349 s = """
1350 Decl line.
1351 #Header
1353 After header text
1355 ##Subheader
1357 Not an underline
1359 ----------------
1361 After subheader text
1363 #Last header: no text
1364 """
1365 p = self.run_test(s)
1366 self.check_headlines(p, (
1367 (1, '!Declarations'),
1368 (1, 'Header'),
1369 (2, 'Subheader'),
1370 (1, 'Last header: no text'),
1371 ))
1372 #@+node:ekr.20210904065459.112: *3* TestMarkdown.test_markdown_importer_implicit_section
1373 def test_markdown_importer_implicit_section(self):
1375 s = """
1376 Decl line.
1377 #Header
1379 After header text
1381 ##Subheader
1383 Not an underline
1385 ----------------
1387 This *should* be a section
1388 ==========================
1390 After subheader text
1392 #Last header: no text
1393 """
1394 # Implicit underlining *must* cause the perfect-import test to fail!
1395 g.app.suppressImportChecks = True
1396 p = self.run_test(s)
1397 self.check_headlines(p, (
1398 (1, '!Declarations'),
1399 (1, 'Header'),
1400 (2, 'Subheader'),
1401 (1, 'This *should* be a section'),
1402 (1, 'Last header: no text'),
1403 ))
1404 #@+node:ekr.20210904065459.114: *3* TestMarkdown.test_markdown_github_syntax
1405 def test_markdown_github_syntax(self):
1407 s = """
1408 Decl line.
1409 #Header
1411 ```python
1412 loads.init = {
1413 Chloride: 11.5,
1414 TotalP: 0.002,
1415 }
1416 ```
1417 #Last header
1418 """
1419 p = self.run_test(s)
1420 self.check_headlines(p, (
1421 (1, '!Declarations'),
1422 (1, 'Header'),
1423 (1, 'Last header'),
1424 ))
1425 #@+node:ekr.20210904065459.128: *3* TestMarkdown.test_is_hash
1426 def test_is_hash(self):
1427 c = self.c
1428 ic = c.importCommands
1429 x = markdown.Markdown_Importer(ic, atAuto=False)
1430 assert x.md_pattern_table
1431 table = (
1432 (1, 'name', '# name\n'),
1433 (2, 'a test', '## a test\n'),
1434 (3, 'a test', '### a test\n'),
1435 )
1436 for data in table:
1437 level, name, line = data
1438 level2, name2 = x.is_hash(line)
1439 self.assertEqual(level, level2)
1440 self.assertEqual(name, name2)
1441 level3, name = x.is_hash('Not a hash')
1442 assert level3 is None
1443 assert name is None
1444 #@+node:ekr.20210904065459.129: *3* TestMarkdown.test_is_underline
1445 def test_is_underline(self):
1446 c = self.c
1447 ic = c.importCommands
1448 x = markdown.Markdown_Importer(ic, atAuto=False)
1449 for line in ('----\n', '-----\n', '====\n', '====\n'):
1450 got = x.is_underline(line)
1451 assert got, repr(line)
1452 for line in ('-\n', '--\n', '---\n', '==\n', '===\n', '===\n', '==-==\n', 'abc\n'):
1453 got = x.is_underline(line)
1454 assert not got, repr(line)
1455 #@-others
1456#@+node:ekr.20211108080955.1: ** class TestOrg (BaseTestImporter)
1457class TestOrg(BaseTestImporter):
1459 ext = '.org'
1460 treeType = '@auto-org'
1462 #@+others
1463 #@+node:ekr.20210904065459.42: *3* TestOrg.test_1
1464 def test_1(self):
1466 s = """
1467 * Section 1
1468 Sec 1.
1469 * Section 2
1470 Sec 2.
1471 ** Section 2-1
1472 Sec 2.1
1473 *** Section 2-1-1
1474 Sec 2.1.1
1475 * Section 3
1476 ** Section 3.1
1477 Sec 3.1
1478 """
1479 p = self.run_test(s)
1480 self.check_headlines(p, (
1481 (1, 'Section 1'),
1482 (1, 'Section 2'),
1483 (2, 'Section 2-1'),
1484 (3, 'Section 2-1-1'),
1485 (1, 'Section 3'),
1486 (2, 'Section 3.1'),
1487 ))
1489 #@+node:ekr.20210904065459.46: *3* TestOrg.test_1074
1490 def test_1074(self):
1492 s = """
1493 * Test
1494 First line.
1495 """
1496 p = self.run_test(s)
1497 self.check_headlines(p, (
1498 (1, ' Test'),
1499 ))
1500 #@+node:ekr.20210904065459.45: *3* TestOrg.test_552
1501 def test_552(self):
1503 s = """
1504 * Events
1505 :PROPERTIES:
1506 :CATEGORY: events
1507 :END:
1508 ** 整理个人生活
1509 *** 每周惯例
1510 """
1511 p = self.run_test(s)
1512 self.check_headlines(p, (
1513 (1, 'Events'),
1514 (2, '整理个人生活'),
1515 (3, '每周惯例'),
1516 ))
1517 #@+node:ekr.20210904065459.44: *3* TestOrg.test_intro
1518 def test_intro(self):
1520 s = """
1521 Intro line.
1522 * Section 1
1523 Sec 1.
1524 * Section 2
1525 Sec 2.
1526 """
1527 p = self.run_test(s)
1528 self.check_headlines(p, (
1529 (1, 'Section 1'),
1530 (1, 'Section 2'),
1531 ))
1532 #@+node:ekr.20210904065459.41: *3* TestOrg.test_pattern
1533 def test_pattern(self):
1535 c = self.c
1536 x = org.Org_Importer(c.importCommands, atAuto=False)
1537 pattern = x.org_pattern
1538 table = (
1539 # 'body * line',
1540 '* line 1',
1541 '** level 2',
1542 )
1543 for line in table:
1544 m = pattern.match(line)
1545 # print('%20s ==> (%r)(%r)' % (line, m and m.group(1), m and m.group(2)))
1546 assert m, repr(line)
1547 #@+node:ekr.20210904065459.47: *3* TestOrg.test_placeholder
1548 def test_placeholder(self):
1550 # insert test for org here.
1551 s = """
1552 * Section 1
1553 Sec 1.
1554 * Section 2
1555 Sec 2.
1556 ** Section 2-1
1557 Sec 2.1
1558 *** Section 2-1-1
1559 Sec 2.1.1
1560 * Section 3
1561 ****** Section 3-1-1-1-1-1
1562 : Sec 3-1-1-1-1-1
1563 ** Section 3.1
1564 Sec 3.1
1565 """
1566 # Suppress perfect import checks.
1567 g.app.suppressImportChecks = True
1568 p = self.run_test(s)
1569 self.check_headlines(p, (
1570 (1, 'Section 1'),
1571 (1, 'Section 2'),
1572 (2, 'Section 2-1'),
1573 (3, 'Section 2-1-1'),
1574 (1, 'Section 3'),
1575 (2, 'placeholder'),
1576 (3, 'placeholder'),
1577 (4, 'placeholder'),
1578 (5, 'placeholder'),
1579 (6, 'Section 3-1-1-1-1-1'),
1580 (2, 'Section 3.1'),
1581 ))
1582 #@+node:ekr.20210904065459.43: *3* TestOrg.test_tags
1583 def test_tags(self):
1585 s = """
1586 * Section 1 :tag1:
1587 * Section 2 :tag2:
1588 * Section 3 :tag3:tag4:
1589 """
1590 p = self.run_test(s)
1591 self.check_headlines(p, (
1592 (1, 'Section 1 :tag1:'),
1593 (1, 'Section 2 :tag2:'),
1594 (1, 'Section 3 :tag3:tag4:'),
1595 ))
1596 #@-others
1597#@+node:ekr.20211108081327.1: ** class TestOtl (BaseTestImporter)
1598class TestOtl(BaseTestImporter):
1600 ext = '.otl'
1601 treeType = '@auto-otl'
1603 #@+others
1604 #@+node:ekr.20210904065459.49: *3* TestOtl.test_otl_1
1605 def test_otl_1(self):
1607 s = """\
1608 preamble.
1609 Section 1
1610 : Sec 1.
1611 Section 2
1612 : Sec 2.
1613 \tSection 2-1
1614 : Sec 2-1
1615 \t\tSection 2-1-1
1616 : Sect 2-1-1
1617 Section 3
1618 : Sec 3
1619 \tSection 3.1
1620 : Sec 3.1
1621 """
1622 p = self.run_test(s)
1623 self.check_headlines(p, (
1624 (1, 'preamble.'),
1625 (1, 'Section 1'),
1626 (1, 'Section 2'),
1627 (1, 'Section 2-1'),
1628 (1, 'Section 2-1-1'),
1629 (1, 'Section 3'),
1630 (1, 'Section 3.1'),
1631 (1, ''), # Due to the added blank line?
1632 ))
1633 #@+node:ekr.20210904065459.48: *3* TestOtl.test_vim_outline_mode
1634 def test_vim_outline_mode(self):
1636 c = self.c
1637 x = otl.Otl_Importer(c.importCommands, atAuto=False)
1638 pattern = x.otl_pattern
1639 table = (
1640 'body line',
1641 '\tline 1',
1642 ' \tlevel 2',
1643 )
1644 for line in table:
1645 m = pattern.match(line)
1646 self.assertTrue(m, msg=repr(line))
1647 #@-others
1648#@+node:ekr.20211108081719.1: ** class TestPascal (BaseTestImporter)
1649class TestPascal(BaseTestImporter):
1651 ext = '.pas'
1653 #@+others
1654 #@+node:ekr.20210904065459.50: *3* TestPascal.test_delphi_interface
1655 def test_delphi_interface(self):
1657 s = """
1658 unit Unit1;
1660 interface
1662 uses
1663 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
1664 Forms,
1665 Dialogs;
1667 type
1668 TForm1 = class(TForm)
1669 procedure FormCreate(Sender: TObject);
1670 private
1671 { Private declarations }
1672 public
1673 { Public declarations }
1674 end;
1676 var
1677 Form1: TForm1;
1679 implementation
1681 {$R *.dfm}
1683 procedure TForm1.FormCreate(Sender: TObject);
1684 var
1685 x,y: double;
1686 begin
1687 x:= 4;
1688 Y := x/2;
1689 end;
1691 end. // interface
1692 """
1693 p = self.run_test(s)
1694 self.check_headlines(p, (
1695 (1, 'interface'),
1696 (2, 'procedure FormCreate'),
1697 (2, 'procedure TForm1.FormCreate'),
1698 ))
1699 #@+node:ekr.20210904065459.130: *3* TestPascal.test_methods
1700 def test_methods(self):
1702 c = self.c
1703 x = pascal.Pascal_Importer(c.importCommands, atAuto=False)
1704 table = (
1705 ('procedure TForm1.FormCreate(Sender: TObject);\n', 'procedure TForm1.FormCreate'),
1706 )
1707 state = g.Bunch(context='')
1708 for line, cleaned in table:
1709 assert x.starts_block(0, [line], state, state)
1710 self.assertEqual(x.clean_headline(line), cleaned)
1711 #@-others
1712#@+node:ekr.20211108081950.1: ** class TestPerl (BaseTestImporter)
1713class TestPerl(BaseTestImporter):
1715 ext = '.pl'
1717 #@+others
1718 #@+node:ekr.20210904065459.51: *3* TestPerl.test_1
1719 def test_1(self):
1721 s = """
1722 #!/usr/bin/perl
1724 # Function definition
1725 sub Hello{
1726 print "Hello, World!\n";
1727 }
1729 sub Test{
1730 print "Test!\n";
1731 }
1732 "\N{LATIN SMALL LIGATURE FI}" =~ /fi/i;
1734 $bar = "foo";
1735 if ($bar =~ /foo/){
1736 print "Second time is matching\n";
1737 }else{
1738 print "Second time is not matching\n";
1739 }
1741 # Function call
1742 Hello();
1743 """
1744 self.run_test(s)
1745 #@+node:ekr.20210904065459.53: *3* TestPerl.test_multi_line_string
1746 def test_multi_line_string(self):
1748 s = """
1749 #!/usr/bin/perl
1751 # This would print with a line break in the middle
1752 print "Hello
1754 sub World {
1755 print "This is not a funtion!"
1756 }
1758 world\n";
1759 """
1760 self.run_test(s)
1761 #@+node:ekr.20210904065459.52: *3* TestPerl.test_perlpod_comment
1762 def test_perlpod_comment(self):
1764 s = """
1765 #!/usr/bin/perl
1767 sub Test{
1768 print "Test!\n";
1769 }
1771 =begin comment
1772 sub World {
1773 print "This is not a funtion!"
1774 }
1775 =cut
1777 # Function definition
1778 sub Hello{
1779 print "Hello, World!\n";
1780 }
1781 """
1782 self.run_test(s)
1783 #@+node:ekr.20210904065459.54: *3* TestPerl.test_regex_1
1784 def test_regex_1(self):
1786 # ('len', 'tr///', '/', context, 0, 0, 0),
1787 # ('len', 's///', '/', context, 0, 0, 0),
1788 # ('len', 'm//', '/', context, 0, 0, 0),
1789 # ('len', '/', '/', '', 0, 0, 0),
1790 s = """
1791 #!/usr/bin/perl
1793 sub test1 {
1794 s = /{/g;
1795 }
1797 sub test2 {
1798 s = m//{/;
1799 }
1801 sub test3 {
1802 s = s///{/;
1803 }
1805 sub test4 {
1806 s = tr///{/;
1807 }
1808 """
1809 self.run_test(s)
1811 #@+node:ekr.20210904065459.55: *3* TestPerl.test_regex_2
1812 def test_regex_2(self):
1814 s = """
1815 #!/usr/bin/perl
1817 sub test1 {
1818 s = /}/g;
1819 }
1821 sub test2 {
1822 s = m//}/;
1823 }
1825 sub test3 {
1826 s = s///}/;
1827 }
1829 sub test4 {
1830 s = tr///}/;
1831 }
1832 """
1833 p = self.run_test(s)
1834 self.check_headlines(p, (
1835 (1, 'sub test1'),
1836 (1, 'sub test2'),
1837 (1, 'sub test3'),
1838 (1, 'sub test4'),
1839 ))
1840 #@-others
1841#@+node:ekr.20211108082208.1: ** class TestPhp (BaseTestImporter)
1842class TestPhp(BaseTestImporter):
1844 ext = '.php'
1846 #@+others
1847 #@+node:ekr.20210904065459.56: *3* TestPhp.test_import_class
1848 def test_import_class(self):
1850 s = """
1851 <?php
1853 $type = 'cc';
1854 $obj = new $type; // outputs "hi!"
1856 class cc {
1857 function __construct() {
1858 echo 'hi!';
1859 }
1860 }
1862 ?>
1863 """
1864 self.run_test(s)
1865 #@+node:ekr.20210904065459.57: *3* TestPhp.test_import_conditional_class
1866 def test_import_conditional_class(self):
1868 s = """
1869 <?php
1871 if (expr) {
1872 class cc {
1873 // version 1
1874 }
1875 } else {
1876 class cc {
1877 // version 2
1878 }
1879 }
1881 ?>
1882 """
1883 self.run_test(s)
1884 #@+node:ekr.20210904065459.58: *3* TestPhp.test_import_classes__functions
1885 def test_import_classes__functions(self):
1887 s = """
1888 <?php
1889 class Enum {
1890 protected $self = array();
1891 public function __construct( /*...*/ ) {
1892 $args = func_get_args();
1893 for( $i=0, $n=count($args); $i<$n; $i++ )
1894 $this->add($args[$i]);
1895 }
1897 public function __get( /*string*/ $name = null ) {
1898 return $this->self[$name];
1899 }
1901 public function add( /*string*/ $name = null, /*int*/ $enum = null ) {
1902 if( isset($enum) )
1903 $this->self[$name] = $enum;
1904 else
1905 $this->self[$name] = end($this->self) + 1;
1906 }
1907 }
1909 class DefinedEnum extends Enum {
1910 public function __construct( /*array*/ $itms ) {
1911 foreach( $itms as $name => $enum )
1912 $this->add($name, $enum);
1913 }
1914 }
1916 class FlagsEnum extends Enum {
1917 public function __construct( /*...*/ ) {
1918 $args = func_get_args();
1919 for( $i=0, $n=count($args), $f=0x1; $i<$n; $i++, $f *= 0x2 )
1920 $this->add($args[$i], $f);
1921 }
1922 }
1923 ?>
1924 """
1925 self.run_test(s)
1926 #@+node:ekr.20210904065459.59: *3* TestPhp.test_here_doc
1927 def test_here_doc(self):
1929 s = """
1930 <?php
1931 class foo {
1932 public $bar = <<<EOT
1933 a test.
1934 bar
1935 EOT;
1936 }
1937 ?>
1938 """
1939 self.run_test(s)
1940 #@-others
1941#@+node:ekr.20211108082509.1: ** class TestPython (BaseTestImporter)
1942class TestPython(BaseTestImporter):
1944 check_tree = False
1945 ext = '.py'
1946 treeType = '@file'
1948 def setUp(self):
1949 super().setUp()
1950 if sys.version_info < (3, 7, 0):
1951 self.skipTest('The python importer requires python 3.7 or above') # pragma: no cover
1953 #@+others
1954 #@+node:ekr.20211126055349.1: *3* TestPython.test_short_file
1955 def test_short_file(self):
1957 input_s = (
1958 '"""A docstring"""\n'
1959 'switch = 1\n'
1960 'print(3)\n'
1961 'print(6)\n'
1962 'def a():\n'
1963 ' pass\n'
1964 'print(7)\n'
1965 )
1966 exp_nodes = [(0, 'ignored h',
1967 '@language python\n'
1968 '@tabwidth -4\n'
1969 '"""A docstring"""\n'
1970 'switch = 1\n'
1971 'print(3)\n'
1972 'print(6)\n'
1973 'def a():\n'
1974 ' pass\n'
1975 'print(7)\n\n'
1976 )]
1977 p = self.run_test(input_s)
1978 ok, msg = self.check_outline(p, exp_nodes)
1979 assert ok, msg
1980 #@+node:ekr.20210904065459.63: *3* TestPython.test_short_classes
1981 def test_short_classes(self):
1982 s = (
1983 'import sys\n'
1984 'def f1():\n'
1985 ' pass\n'
1986 '\n'
1987 'class Class1:\n'
1988 ' def method11():\n'
1989 ' pass\n'
1990 ' def method12():\n'
1991 ' pass\n'
1992 ' \n'
1993 'a = 2\n'
1994 '\n'
1995 'def f2():\n'
1996 ' pass\n'
1997 '\n'
1998 '# An outer comment\n'
1999 '@myClassDecorator\n'
2000 'class Class2:\n'
2001 ' @myDecorator\n'
2002 ' def method21():\n'
2003 ' pass\n'
2004 ' def method22():\n'
2005 ' pass\n'
2006 ' \n'
2007 '# About main.\n'
2008 'def main():\n'
2009 ' pass\n'
2010 '\n'
2011 "if __name__ == '__main__':\n"
2012 ' main()\n'
2013 )
2014 exp_nodes = [
2015 (0, 'ignored h', '@language python\n'
2016 '@tabwidth -4\n'
2017 'import sys\n'
2018 '@others\n'
2019 "if __name__ == '__main__':\n"
2020 ' main()\n\n'
2021 ),
2022 (1, 'f1', 'def f1():\n'
2023 ' pass\n'
2024 '\n'
2025 ),
2026 (1, 'Class1', 'class Class1:\n'
2027 ' def method11():\n'
2028 ' pass\n'
2029 ' def method12():\n'
2030 ' pass\n'
2031 '\n'
2032 ),
2033 (1, 'a = 2', 'a = 2\n\n'),
2034 (1, 'f2', 'def f2():\n'
2035 ' pass\n'
2036 '\n'
2037 ),
2038 (1, 'Class2', '# An outer comment\n'
2039 '@myClassDecorator\n'
2040 'class Class2:\n'
2041 ' @myDecorator\n'
2042 ' def method21():\n'
2043 ' pass\n'
2044 ' def method22():\n'
2045 ' pass\n'
2046 '\n'
2047 ),
2048 (1, 'main', '# About main.\n'
2049 'def main():\n'
2050 ' pass\n'
2051 '\n'
2052 )
2053 ]
2054 p = self.run_test(s)
2055 ok, msg = self.check_outline(p, exp_nodes)
2056 assert ok, msg
2057 #@+node:vitalije.20211206201240.1: *3* TestPython.test_longer_classes
2058 def test_longer_classes(self):
2059 s = ('import sys\n'
2060 'def f1():\n'
2061 ' pass\n'
2062 '\n'
2063 'class Class1:\n'
2064 ' def method11():\n'
2065 ' pass\n'
2066 ' def method12():\n'
2067 ' pass\n'
2068 ' \n'
2069 '#\n'
2070 '# Define a = 2\n'
2071 'a = 2\n'
2072 '\n'
2073 'def f2():\n'
2074 ' pass\n'
2075 '\n'
2076 '# An outer comment\n'
2077 '@myClassDecorator\n'
2078 'class Class2:\n'
2079 ' def meth00():\n'
2080 ' print(1)\n'
2081 ' print(2)\n'
2082 ' print(3)\n'
2083 ' print(4)\n'
2084 ' print(5)\n'
2085 ' print(6)\n'
2086 ' print(7)\n'
2087 ' print(8)\n'
2088 ' print(9)\n'
2089 ' print(10)\n'
2090 ' print(11)\n'
2091 ' print(12)\n'
2092 ' print(13)\n'
2093 ' print(14)\n'
2094 ' print(15)\n'
2095 ' @myDecorator\n'
2096 ' def method21():\n'
2097 ' pass\n'
2098 ' def method22():\n'
2099 ' pass\n'
2100 ' \n'
2101 '# About main.\n'
2102 'def main():\n'
2103 ' pass\n'
2104 '\n'
2105 "if __name__ == '__main__':\n"
2106 ' main()\n'
2107 )
2108 exp_nodes = [
2109 (0, 'ignored h',
2110 '@language python\n'
2111 '@tabwidth -4\n'
2112 'import sys\n'
2113 '@others\n'
2114 "if __name__ == '__main__':\n"
2115 ' main()\n\n'
2116 ),
2117 (1, 'f1',
2118 'def f1():\n'
2119 ' pass\n'
2120 '\n'
2121 ),
2122 (1, 'Class1',
2123 'class Class1:\n'
2124 ' def method11():\n'
2125 ' pass\n'
2126 ' def method12():\n'
2127 ' pass\n'
2128 '\n'
2129 ),
2130 (1, 'Define a = 2', # #2500
2131 '#\n'
2132 '# Define a = 2\n'
2133 'a = 2\n'
2134 '\n'
2135 ),
2136 (1, 'f2',
2137 'def f2():\n'
2138 ' pass\n'
2139 '\n'
2140 ),
2141 (1, 'Class2',
2142 '# An outer comment\n'
2143 '@myClassDecorator\n'
2144 'class Class2:\n'
2145 ' @others\n'
2146 ),
2147 (2, 'meth00',
2148 'def meth00():\n'
2149 ' print(1)\n'
2150 ' print(2)\n'
2151 ' print(3)\n'
2152 ' print(4)\n'
2153 ' print(5)\n'
2154 ' print(6)\n'
2155 ' print(7)\n'
2156 ' print(8)\n'
2157 ' print(9)\n'
2158 ' print(10)\n'
2159 ' print(11)\n'
2160 ' print(12)\n'
2161 ' print(13)\n'
2162 ' print(14)\n'
2163 ' print(15)\n'
2164 ),
2165 (2, 'method21',
2166 '@myDecorator\n'
2167 'def method21():\n'
2168 ' pass\n'
2169 ),
2170 (2, 'method22',
2171 'def method22():\n'
2172 ' pass\n'
2173 '\n'
2174 ),
2175 (1, 'main',
2176 '# About main.\n'
2177 'def main():\n'
2178 ' pass\n'
2179 '\n'
2180 )
2181 ]
2182 p = self.run_test(s)
2183 ok, msg = self.check_outline(p, exp_nodes)
2184 assert ok, msg
2185 #@+node:vitalije.20211206212507.1: *3* TestPython.test_oneliners
2186 def test_oneliners(self):
2187 s = ('import sys\n'
2188 'def f1():\n'
2189 ' pass\n'
2190 '\n'
2191 'class Class1:pass\n'
2192 'a = 2\n'
2193 '@dec_for_f2\n'
2194 'def f2(): pass\n'
2195 '\n'
2196 '\n'
2197 'class A: pass\n'
2198 '# About main.\n'
2199 'def main():\n'
2200 ' pass\n'
2201 '\n'
2202 "if __name__ == '__main__':\n"
2203 ' main()\n'
2204 )
2205 exp_nodes = [(0, 'ignored h',
2206 '@language python\n'
2207 '@tabwidth -4\n'
2208 'import sys\n'
2209 '@others\n'
2210 "if __name__ == '__main__':\n"
2211 ' main()\n\n'
2212 ),
2213 (1, 'f1',
2214 'def f1():\n'
2215 ' pass\n'
2216 '\n'
2217 ),
2218 (1, 'Class1',
2219 'class Class1:pass\n'
2220 ),
2221 (1, 'a = 2',
2222 'a = 2\n'
2223 ),
2224 (1, 'f2',
2225 '@dec_for_f2\n'
2226 'def f2(): pass\n'
2227 '\n'
2228 '\n'
2229 ),
2230 (1, 'A',
2231 'class A: pass\n'
2232 ),
2233 (1, 'main',
2234 '# About main.\n'
2235 'def main():\n'
2236 ' pass\n'
2237 '\n'
2238 )
2239 ]
2240 p = self.run_test(s)
2241 ok, msg = self.check_outline(p, exp_nodes)
2242 assert ok, msg
2244 #@+node:ekr.20211202064822.1: *3* TestPython: test_nested_classes
2245 def test_nested_classes(self):
2246 txt = ('class TestCopyFile(unittest.TestCase):\n'
2247 '\n'
2248 ' _delete = False\n'
2249 ' a00 = 1\n'
2250 ' a01 = 1\n'
2251 ' a02 = 1\n'
2252 ' a03 = 1\n'
2253 ' a04 = 1\n'
2254 ' a05 = 1\n'
2255 ' a06 = 1\n'
2256 ' a07 = 1\n'
2257 ' a08 = 1\n'
2258 ' a09 = 1\n'
2259 ' a10 = 1\n'
2260 ' a11 = 1\n'
2261 ' a12 = 1\n'
2262 ' a13 = 1\n'
2263 ' a14 = 1\n'
2264 ' a15 = 1\n'
2265 ' a16 = 1\n'
2266 ' a17 = 1\n'
2267 ' a18 = 1\n'
2268 ' a19 = 1\n'
2269 ' a20 = 1\n'
2270 ' a21 = 1\n'
2271 ' class Faux(object):\n'
2272 ' _entered = False\n'
2273 ' _exited_with = None # type: tuple\n'
2274 ' _raised = False\n'
2275 )
2276 exp_nodes = [
2277 (0, 'ignored h',
2278 '@language python\n'
2279 '@tabwidth -4\n'
2280 '@others\n'
2281 ),
2282 (1, 'TestCopyFile',
2283 'class TestCopyFile(unittest.TestCase):\n'
2284 '\n'
2285 ' _delete = False\n'
2286 ' a00 = 1\n'
2287 ' a01 = 1\n'
2288 ' a02 = 1\n'
2289 ' a03 = 1\n'
2290 ' a04 = 1\n'
2291 ' a05 = 1\n'
2292 ' a06 = 1\n'
2293 ' a07 = 1\n'
2294 ' a08 = 1\n'
2295 ' a09 = 1\n'
2296 ' a10 = 1\n'
2297 ' a11 = 1\n'
2298 ' a12 = 1\n'
2299 ' a13 = 1\n'
2300 ' a14 = 1\n'
2301 ' a15 = 1\n'
2302 ' a16 = 1\n'
2303 ' a17 = 1\n'
2304 ' a18 = 1\n'
2305 ' a19 = 1\n'
2306 ' a20 = 1\n'
2307 ' a21 = 1\n'
2308 ' @others\n'
2309 ),
2310 (2, 'Faux',
2311 'class Faux(object):\n'
2312 ' _entered = False\n'
2313 ' _exited_with = None # type: tuple\n'
2314 ' _raised = False\n\n'
2315 )
2316 ]
2317 # mypy/test-data/stdlib-samples/3.2/test/shutil.py
2318 p = self.run_test(txt)
2319 ok, msg = self.check_outline(p, exp_nodes)
2320 assert ok, msg
2321 #@+node:vitalije.20211213125810.1: *3* TestPython: test_nested_classes
2322 def test_nested_classes_with_async(self):
2323 txt = ('class TestCopyFile(unittest.TestCase):\n'
2324 '\n'
2325 ' _delete = False\n'
2326 ' a00 = 1\n'
2327 ' a01 = 1\n'
2328 ' a02 = 1\n'
2329 ' a03 = 1\n'
2330 ' a04 = 1\n'
2331 ' a05 = 1\n'
2332 ' a06 = 1\n'
2333 ' a07 = 1\n'
2334 ' a08 = 1\n'
2335 ' a09 = 1\n'
2336 ' a10 = 1\n'
2337 ' a11 = 1\n'
2338 ' a12 = 1\n'
2339 ' a13 = 1\n'
2340 ' a14 = 1\n'
2341 ' a15 = 1\n'
2342 ' a16 = 1\n'
2343 ' a17 = 1\n'
2344 ' a18 = 1\n'
2345 ' a19 = 1\n'
2346 ' a20 = 1\n'
2347 ' a21 = 1\n'
2348 ' async def a(self):\n'
2349 ' return await f(self)\n'
2350 ' class Faux(object):\n'
2351 ' _entered = False\n'
2352 ' _exited_with = None # type: tuple\n'
2353 ' _raised = False\n'
2354 )
2355 exp_nodes = [
2356 (0, 'ignored h',
2357 '@language python\n'
2358 '@tabwidth -4\n'
2359 '@others\n'
2360 ),
2361 (1, 'TestCopyFile',
2362 'class TestCopyFile(unittest.TestCase):\n'
2363 '\n'
2364 ' _delete = False\n'
2365 ' a00 = 1\n'
2366 ' a01 = 1\n'
2367 ' a02 = 1\n'
2368 ' a03 = 1\n'
2369 ' a04 = 1\n'
2370 ' a05 = 1\n'
2371 ' a06 = 1\n'
2372 ' a07 = 1\n'
2373 ' a08 = 1\n'
2374 ' a09 = 1\n'
2375 ' a10 = 1\n'
2376 ' a11 = 1\n'
2377 ' a12 = 1\n'
2378 ' a13 = 1\n'
2379 ' a14 = 1\n'
2380 ' a15 = 1\n'
2381 ' a16 = 1\n'
2382 ' a17 = 1\n'
2383 ' a18 = 1\n'
2384 ' a19 = 1\n'
2385 ' a20 = 1\n'
2386 ' a21 = 1\n'
2387 ' @others\n'
2388 ),
2389 (2, 'a',
2390 'async def a(self):\n'
2391 ' return await f(self)\n'
2392 ),
2393 (2, 'Faux',
2394 'class Faux(object):\n'
2395 ' _entered = False\n'
2396 ' _exited_with = None # type: tuple\n'
2397 ' _raised = False\n\n'
2398 )
2399 ]
2400 # mypy/test-data/stdlib-samples/3.2/test/shutil.py
2401 p = self.run_test(txt)
2402 ok, msg = self.check_outline(p, exp_nodes)
2403 assert ok, msg
2404 #@+node:ekr.20211202094115.1: *3* TestPython: test_strange_indentation
2405 def test_strange_indentation(self):
2406 txt = ('if 1:\n'
2407 " print('1')\n"
2408 'if 2:\n'
2409 " print('2')\n"
2410 'if 3:\n'
2411 " print('3')\n"
2412 '\n'
2413 'class StrangeClass:\n'
2414 ' a = 1\n'
2415 ' if 1:\n'
2416 " print('1')\n"
2417 ' if 2:\n'
2418 " print('2')\n"
2419 ' if 3:\n'
2420 " print('3')\n"
2421 ' if 4:\n'
2422 " print('4')\n"
2423 ' if 5:\n'
2424 " print('5')\n"
2425 ' if 6:\n'
2426 " print('6')\n"
2427 ' if 7:\n'
2428 " print('7')\n"
2429 ' if 8:\n'
2430 " print('8')\n"
2431 ' if 9:\n'
2432 " print('9')\n"
2433 ' if 10:\n'
2434 " print('10')\n"
2435 ' if 11:\n'
2436 " print('11')\n"
2437 ' if 12:\n'
2438 " print('12')\n"
2439 ' def a(self):\n'
2440 ' pass\n'
2441 )
2442 exp_nodes = [
2443 (0, 'ignored h',
2444 '@language python\n'
2445 '@tabwidth -4\n'
2446 'if 1:\n'
2447 " print('1')\n"
2448 'if 2:\n'
2449 " print('2')\n"
2450 'if 3:\n'
2451 " print('3')\n"
2452 '\n'
2453 '@others\n'
2454 ),
2455 (1, 'StrangeClass',
2456 'class StrangeClass:\n'
2457 ' a = 1\n'
2458 ' if 1:\n'
2459 " print('1')\n"
2460 ' if 2:\n'
2461 " print('2')\n"
2462 ' if 3:\n'
2463 " print('3')\n"
2464 ' if 4:\n'
2465 " print('4')\n"
2466 ' if 5:\n'
2467 " print('5')\n"
2468 ' if 6:\n'
2469 " print('6')\n"
2470 ' if 7:\n'
2471 " print('7')\n"
2472 ' if 8:\n'
2473 " print('8')\n"
2474 ' if 9:\n'
2475 " print('9')\n"
2476 ' if 10:\n'
2477 " print('10')\n"
2478 ' if 11:\n'
2479 " print('11')\n"
2480 ' if 12:\n'
2481 " print('12')\n"
2482 ' @others\n'
2483 ),
2484 (2, 'a',
2485 'def a(self):\n'
2486 ' pass\n\n'
2487 )
2488 ]
2489 p = self.run_test(txt)
2490 ok, msg = self.check_outline(p, exp_nodes)
2491 assert ok, msg
2492 #@+node:vitalije.20211208210459.1: *3* TestPython: test_strange_indentation
2493 def test_strange_indentation_with_added_class_in_the_headline(self):
2494 self.c.config.set(None, 'bool', 'put-class-in-imported-headlines', True)
2495 txt = ('if 1:\n'
2496 " print('1')\n"
2497 'if 2:\n'
2498 " print('2')\n"
2499 'if 3:\n'
2500 " print('3')\n"
2501 '\n'
2502 'class StrangeClass:\n'
2503 ' a = 1\n'
2504 ' if 1:\n'
2505 " print('1')\n"
2506 ' if 2:\n'
2507 " print('2')\n"
2508 ' if 3:\n'
2509 " print('3')\n"
2510 ' if 4:\n'
2511 " print('4')\n"
2512 ' if 5:\n'
2513 " print('5')\n"
2514 ' if 6:\n'
2515 " print('6')\n"
2516 ' if 7:\n'
2517 " print('7')\n"
2518 ' if 8:\n'
2519 " print('8')\n"
2520 ' if 9:\n'
2521 " print('9')\n"
2522 ' if 10:\n'
2523 " print('10')\n"
2524 ' if 11:\n'
2525 " print('11')\n"
2526 ' if 12:\n'
2527 " print('12')\n"
2528 ' def a(self):\n'
2529 ' pass\n'
2530 )
2531 exp_nodes = [
2532 (0, 'ignored h',
2533 '@language python\n'
2534 '@tabwidth -4\n'
2535 'if 1:\n'
2536 " print('1')\n"
2537 'if 2:\n'
2538 " print('2')\n"
2539 'if 3:\n'
2540 " print('3')\n"
2541 '\n'
2542 '@others\n'
2543 ),
2544 (1, 'class StrangeClass',
2545 'class StrangeClass:\n'
2546 ' a = 1\n'
2547 ' if 1:\n'
2548 " print('1')\n"
2549 ' if 2:\n'
2550 " print('2')\n"
2551 ' if 3:\n'
2552 " print('3')\n"
2553 ' if 4:\n'
2554 " print('4')\n"
2555 ' if 5:\n'
2556 " print('5')\n"
2557 ' if 6:\n'
2558 " print('6')\n"
2559 ' if 7:\n'
2560 " print('7')\n"
2561 ' if 8:\n'
2562 " print('8')\n"
2563 ' if 9:\n'
2564 " print('9')\n"
2565 ' if 10:\n'
2566 " print('10')\n"
2567 ' if 11:\n'
2568 " print('11')\n"
2569 ' if 12:\n'
2570 " print('12')\n"
2571 ' @others\n'
2572 ),
2573 (2, 'a',
2574 'def a(self):\n'
2575 ' pass\n\n'
2576 )
2577 ]
2578 p = self.run_test(txt)
2579 ok, msg = self.check_outline(p, exp_nodes)
2580 assert ok, msg
2581 #@+node:vitalije.20211207183645.1: *3* TestPython: test_no_defs
2582 def test_no_defs(self):
2583 txt = ('a = 1\n'
2584 'if 1:\n'
2585 " print('1')\n"
2586 'if 2:\n'
2587 " print('2')\n"
2588 'if 3:\n'
2589 " print('3')\n"
2590 'if 4:\n'
2591 " print('4')\n"
2592 'if 5:\n'
2593 " print('5')\n"
2594 'if 6:\n'
2595 " print('6')\n"
2596 'if 7:\n'
2597 " print('7')\n"
2598 'if 8:\n'
2599 " print('8')\n"
2600 'if 9:\n'
2601 " print('9')\n"
2602 'if 10:\n'
2603 " print('10')\n"
2604 'if 11:\n'
2605 " print('11')\n"
2606 'if 12:\n'
2607 " print('12')\n"
2608 )
2609 exp_nodes = [
2610 (0, 'ignored h', '@language python\n'
2611 '@tabwidth -4\n'
2612 'a = 1\n'
2613 'if 1:\n'
2614 " print('1')\n"
2615 'if 2:\n'
2616 " print('2')\n"
2617 'if 3:\n'
2618 " print('3')\n"
2619 'if 4:\n'
2620 " print('4')\n"
2621 'if 5:\n'
2622 " print('5')\n"
2623 'if 6:\n'
2624 " print('6')\n"
2625 'if 7:\n'
2626 " print('7')\n"
2627 'if 8:\n'
2628 " print('8')\n"
2629 'if 9:\n'
2630 " print('9')\n"
2631 'if 10:\n'
2632 " print('10')\n"
2633 'if 11:\n'
2634 " print('11')\n"
2635 'if 12:\n'
2636 " print('12')\n\n"
2637 )
2638 ]
2639 p = self.run_test(txt)
2640 ok, msg = self.check_outline(p, exp_nodes)
2641 assert ok, msg
2642 #@+node:vitalije.20211207185708.1: *3* TestPython: test_only_docs
2643 def test_only_docs(self):
2644 txt = ('class A:\n'
2645 ' """\n'
2646 ' dummy doc\n'
2647 " another line\n"
2648 " another line\n"
2649 " another line\n"
2650 " another line\n"
2651 " another line\n"
2652 " another line\n"
2653 " another line\n"
2654 " another line\n"
2655 " another line\n"
2656 " another line\n"
2657 " another line\n"
2658 " another line\n"
2659 " another line\n"
2660 " another line\n"
2661 " another line\n"
2662 " another line\n"
2663 " another line\n"
2664 " another line\n"
2665 " another line\n"
2666 " another line\n"
2667 " another line\n"
2668 " another line\n"
2669 " another line\n"
2670 ' """\n'
2671 ' def __init__(self):\n'
2672 ' pass\n'
2673 '\n'
2674 )
2675 exp_nodes = [
2676 (0, 'ignored h',
2677 '@language python\n'
2678 '@tabwidth -4\n'
2679 '@others\n'
2680 ),
2681 (1, 'A',
2682 'class A:\n'
2683 ' """\n'
2684 ' dummy doc\n'
2685 ' another line\n'
2686 ' another line\n'
2687 ' another line\n'
2688 ' another line\n'
2689 ' another line\n'
2690 ' another line\n'
2691 ' another line\n'
2692 ' another line\n'
2693 ' another line\n'
2694 ' another line\n'
2695 ' another line\n'
2696 ' another line\n'
2697 ' another line\n'
2698 ' another line\n'
2699 ' another line\n'
2700 ' another line\n'
2701 ' another line\n'
2702 ' another line\n'
2703 ' another line\n'
2704 ' another line\n'
2705 ' another line\n'
2706 ' another line\n'
2707 ' another line\n'
2708 ' """\n'
2709 ' @others\n'
2710 ),
2711 (2, '__init__',
2712 'def __init__(self):\n'
2713 ' pass\n'
2714 '\n'
2715 )
2716 ]
2717 p = self.run_test(txt)
2718 ok, msg = self.check_outline(p, exp_nodes)
2719 assert ok, msg
2720 #@+node:vitalije.20211207200701.1: *3* TestPython: test_large_class_no_methods
2721 def test_large_class_no_methods(self):
2723 import sys
2724 if sys.version_info < (3, 9, 0):
2725 self.skipTest('Requires Python 3.9') # pragma: no cover
2727 txt = ('class A:\n'
2728 ' a=1\n'
2729 ' b=1\n'
2730 ' c=1\n'
2731 ' d=1\n'
2732 ' e=1\n'
2733 ' f=1\n'
2734 ' g=1\n'
2735 ' h=1\n'
2736 ' i=1\n'
2737 ' j=1\n'
2738 ' k=1\n'
2739 ' l=1\n'
2740 ' m=1\n'
2741 ' n=1\n'
2742 ' o=1\n'
2743 ' p=1\n'
2744 ' q=1\n'
2745 ' r=1\n'
2746 ' s=1\n'
2747 ' t=1\n'
2748 ' u=1\n'
2749 ' v=1\n'
2750 ' w=1\n'
2751 ' x=1\n'
2752 ' y=1\n'
2753 ' x=1\n'
2754 '\n'
2755 )
2756 exp_nodes = [
2757 (0, 'ignored h',
2758 '@language python\n'
2759 '@tabwidth -4\n'
2760 '@others\n'
2761 ),
2762 (1, 'A',
2763 'class A:\n'
2764 ' a=1\n'
2765 ' b=1\n'
2766 ' c=1\n'
2767 ' d=1\n'
2768 ' e=1\n'
2769 ' f=1\n'
2770 ' g=1\n'
2771 ' h=1\n'
2772 ' i=1\n'
2773 ' j=1\n'
2774 ' k=1\n'
2775 ' l=1\n'
2776 ' m=1\n'
2777 ' n=1\n'
2778 ' o=1\n'
2779 ' p=1\n'
2780 ' q=1\n'
2781 ' r=1\n'
2782 ' s=1\n'
2783 ' t=1\n'
2784 ' u=1\n'
2785 ' v=1\n'
2786 ' w=1\n'
2787 ' x=1\n'
2788 ' y=1\n'
2789 ' x=1\n'
2790 '\n'
2791 )
2792 ]
2793 p = self.run_test(txt)
2794 ok, msg = self.check_outline(p, exp_nodes)
2795 assert ok, msg
2796 #@+node:vitalije.20211213125307.1: *3* TestPython: test_large_class_no_methods
2797 def test_large_class_under_indented(self):
2798 txt = ('class A:\n'
2799 ' a=1\n'
2800 ' b=1\n'
2801 ' c=1\n'
2802 ' d=1\n'
2803 ' e=1\n'
2804 ' def f(self):\n'
2805 ' self._f = """dummy\n'
2806 'dummy2\n'
2807 'dummy3"""\n'
2808 ' g=1\n'
2809 ' h=1\n'
2810 ' i=1\n'
2811 ' j=1\n'
2812 ' k=1\n'
2813 ' l=1\n'
2814 ' m=1\n'
2815 ' n=1\n'
2816 ' o=1\n'
2817 ' p=1\n'
2818 ' q=1\n'
2819 ' r=1\n'
2820 ' s=1\n'
2821 ' t=1\n'
2822 ' u=1\n'
2823 ' v=1\n'
2824 ' w=1\n'
2825 ' x=1\n'
2826 ' y=1\n'
2827 ' x=1\n'
2828 '\n'
2829 )
2830 exp_nodes = [
2831 (0, 'ignored h',
2832 '@language python\n'
2833 '@tabwidth -4\n'
2834 '@others\n'
2835 ),
2836 (1, 'A',
2837 'class A:\n'
2838 ' a=1\n'
2839 ' b=1\n'
2840 ' c=1\n'
2841 ' d=1\n'
2842 ' e=1\n'
2843 ' @others\n'
2844 ' g=1\n'
2845 ' h=1\n'
2846 ' i=1\n'
2847 ' j=1\n'
2848 ' k=1\n'
2849 ' l=1\n'
2850 ' m=1\n'
2851 ' n=1\n'
2852 ' o=1\n'
2853 ' p=1\n'
2854 ' q=1\n'
2855 ' r=1\n'
2856 ' s=1\n'
2857 ' t=1\n'
2858 ' u=1\n'
2859 ' v=1\n'
2860 ' w=1\n'
2861 ' x=1\n'
2862 ' y=1\n'
2863 ' x=1\n'
2864 '\n'
2865 ),
2866 (2, 'f',
2867 'def f(self):\n'
2868 ' self._f = """dummy\n'
2869 '\\\\-4.dummy2\n'
2870 '\\\\-4.dummy3"""\n'
2871 )
2872 ]
2873 p = self.run_test(txt)
2874 ok, msg = self.check_outline(p, exp_nodes)
2875 assert ok, msg
2876 #@+node:vitalije.20211206180043.1: *3* check_outline
2877 def check_outline(self, p, nodes):
2878 it = iter(nodes)
2879 zlev = p.level()
2880 for p1 in p.self_and_subtree():
2881 lev, h, b = next(it)
2882 assert p1.level() - zlev == lev, f'lev:{p1.level()-zlev} != {lev}'
2883 if lev > 0:
2884 assert p1.h == h, f'"{p1.h}" != "{h}"'
2885 assert p1.b == b, f'\n{repr(p1.b)} !=\n{repr(b)}'
2886 try:
2887 next(it)
2888 return False, 'extra nodes' # pragma: no cover
2889 except StopIteration:
2890 return True, 'ok'
2891 #@-others
2892#@+node:ekr.20211108050827.1: ** class TestRst (BaseTestImporter)
2893class TestRst(BaseTestImporter):
2895 ext = '.rst'
2896 treeType = '@auto-rst'
2898 #@+others
2899 #@+node:ekr.20210904065459.115: *3* TestRst.test_rst_1
2900 def test_rst_1(self):
2902 try:
2903 import docutils
2904 assert docutils
2905 except Exception: # pragma: no cover
2906 self.skipTest('no docutils')
2908 s = """
2909 .. toc
2911 ====
2912 top
2913 ====
2915 The top section
2917 section 1
2918 ---------
2920 section 1, line 1
2921 --
2922 section 1, line 2
2924 section 2
2925 ---------
2927 section 2, line 1
2929 section 2.1
2930 ~~~~~~~~~~~
2932 section 2.1, line 1
2934 section 2.1.1
2935 .............
2937 section 2.2.1 line 1
2939 section 3
2940 ---------
2942 section 3, line 1
2944 section 3.1.1
2945 .............
2947 section 3.1.1, line 1
2948 """
2949 p = self.run_test(s)
2950 self.check_headlines(p, (
2951 (1, '!Dummy chapter'),
2952 (1, 'top'),
2953 (1, 'section 1'),
2954 (1, 'section 2'),
2955 (2, 'section 2.1'),
2956 (3, 'section 2.1.1'),
2957 (1, 'section 3'),
2958 (2, 'placeholder'),
2959 (3, 'section 3.1.1'),
2960 ))
2961 #@+node:ekr.20210904065459.116: *3* TestRst.test_simple
2962 def test_simple(self):
2964 try:
2965 import docutils
2966 assert docutils
2967 except Exception: # pragma: no cover
2968 self.skipTest('no docutils')
2970 s = """
2971 .. toc
2973 .. The section name contains trailing whitespace.
2975 =======
2976 Chapter
2977 =======
2979 The top chapter.
2980 """
2981 p = self.run_test(s)
2982 self.check_headlines(p, (
2983 (1, "!Dummy chapter"),
2984 (1, "Chapter"),
2985 ))
2986 #@+node:ekr.20210904065459.117: *3* TestRst.test_no_double_underlines
2987 def test_no_double_underlines(self):
2989 try:
2990 import docutils
2991 assert docutils
2992 except Exception: # pragma: no cover
2993 self.skipTest('no docutils')
2995 s = """
2996 .. toc
2998 top
2999 ====
3001 The top section
3003 section 1
3004 ---------
3006 section 1, line 1
3007 --
3008 section 1, line 2
3010 section 2
3011 ---------
3013 section 2, line 1
3015 section 2.1
3016 ~~~~~~~~~~~
3018 section 2.1, line 1
3020 section 2.1.1
3021 .............
3023 section 2.2.1 line 1
3025 section 3
3026 ---------
3028 section 3, line 1
3030 section 3.1.1
3031 .............
3033 section 3.1.1, line 1
3034 """
3035 p = self.run_test(s)
3036 self.check_headlines(p, (
3037 (1, '!Dummy chapter'),
3038 (1, 'top'),
3039 (1, 'section 1'),
3040 (1, 'section 2'),
3041 (2, 'section 2.1'),
3042 (3, 'section 2.1.1'),
3043 (1, 'section 3'),
3044 (2, 'placeholder'),
3045 (3, 'section 3.1.1'),
3046 ))
3047 #@+node:ekr.20210904065459.118: *3* TestRst.test_long_underlines
3048 def test_long_underlines(self):
3050 try:
3051 import docutils
3052 assert docutils
3053 except Exception: # pragma: no cover
3054 self.skipTest('no docutils')
3056 s = """
3057 .. toc
3059 top
3060 -------------
3062 The top section
3063 """
3064 p = self.run_test(s)
3065 self.check_headlines(p, (
3066 (1, '!Dummy chapter'),
3067 (1, 'top'),
3068 ))
3069 #@+node:ekr.20210904065459.119: *3* TestRst.test_test_long_overlines
3070 def test_test_long_overlines(self):
3072 try:
3073 import docutils
3074 assert docutils
3075 except Exception: # pragma: no cover
3076 self.skipTest('no docutils')
3078 s = """
3079 .. toc
3081 ======
3082 top
3083 ======
3085 The top section
3086 """
3087 p = self.run_test(s)
3088 self.check_headlines(p, (
3089 (1, "!Dummy chapter"),
3090 (1, "top"),
3091 ))
3092 #@+node:ekr.20210904065459.120: *3* TestRst.test_trailing_whitespace
3093 def test_trailing_whitespace(self):
3095 try:
3096 import docutils
3097 assert docutils
3098 except Exception: # pragma: no cover
3099 self.skipTest('no docutils')
3101 s = """
3102 .. toc
3104 .. The section name contains trailing whitespace.
3106 ======
3107 top
3108 ======
3110 The top section.
3111 """
3112 p = self.run_test(s)
3113 self.check_headlines(p, (
3114 (1, "!Dummy chapter"),
3115 (1, "top"),
3116 ))
3117 #@+node:ekr.20210904065459.121: *3* TestRst.test_leo_rst
3118 def test_leo_rst(self):
3120 try:
3121 import docutils
3122 assert docutils
3123 except Exception: # pragma: no cover
3124 self.skipTest('no docutils')
3126 # All heading must be followed by an empty line.
3127 s = """\
3128 #########
3129 Chapter 1
3130 #########
3132 It was a dark and stormy night.
3134 section 1
3135 +++++++++
3137 Sec 1.
3139 section 2
3140 +++++++++
3142 Sec 2.
3143 """
3144 p = self.run_test(s)
3145 self.check_headlines(p, (
3146 (1, 'Chapter 1'),
3147 (2, 'section 1'),
3148 (2, 'section 2'),
3149 ))
3150 #@-others
3151#@+node:ekr.20211108083038.1: ** class TestTypescript (BaseTestImporter)
3152class TestTypescript(BaseTestImporter):
3154 ext = '.ts'
3156 #@+others
3157 #@+node:ekr.20210904065459.103: *3* TestTypescript.test_class
3158 def test_class(self):
3160 s = '''
3161 class Greeter {
3162 greeting: string;
3163 constructor (message: string) {
3164 this.greeting = message;
3165 }
3166 greet() {
3167 return "Hello, " + this.greeting;
3168 }
3169 }
3171 var greeter = new Greeter("world");
3173 var button = document.createElement('button')
3174 button.innerText = "Say Hello"
3175 button.onclick = function() {
3176 alert(greeter.greet())
3177 }
3179 document.body.appendChild(button)
3181 '''
3182 self.run_test(s)
3183 #@+node:ekr.20210904065459.104: *3* TestTypescript.test_module
3184 def test_module(self):
3185 s = '''
3186 module Sayings {
3187 export class Greeter {
3188 greeting: string;
3189 constructor (message: string) {
3190 this.greeting = message;
3191 }
3192 greet() {
3193 return "Hello, " + this.greeting;
3194 }
3195 }
3196 }
3197 var greeter = new Sayings.Greeter("world");
3199 var button = document.createElement('button')
3200 button.innerText = "Say Hello"
3201 button.onclick = function() {
3202 alert(greeter.greet())
3203 }
3205 document.body.appendChild(button)
3206 '''
3207 self.run_test(s)
3208 #@-others
3209#@+node:ekr.20211108065014.1: ** class TestXML (BaseTestImporter)
3210class TestXML(BaseTestImporter):
3212 ext = '.xml'
3214 def setUp(self):
3215 super().setUp()
3216 c = self.c
3217 # Simulate @data import-xml-tags, with *only* standard tags.
3218 tags_list = ['html', 'body', 'head', 'div', 'table']
3219 settingsDict, junk = g.app.loadManager.createDefaultSettingsDicts()
3220 c.config.settingsDict = settingsDict
3221 c.config.set(c.p, 'data', 'import-xml-tags', tags_list, warn=True)
3223 #@+others
3224 #@+node:ekr.20210904065459.105: *3* TestXml.test_standard_opening_elements
3225 def test_standard_opening_elements(self):
3226 c = self.c
3227 s = """
3228 <?xml version="1.0" encoding="UTF-8"?>
3229 <!DOCTYPE note SYSTEM "Note.dtd">
3230 <html>
3231 <head>
3232 <title>Bodystring</title>
3233 </head>
3234 <body class='bodystring'>
3235 <div id='bodydisplay'></div>
3236 </body>
3237 </html>
3238 """
3239 table = (
3240 (1, "<html>"),
3241 (2, "<head>"),
3242 (2, "<body class='bodystring'>"),
3243 )
3244 p = c.p
3245 self.run_test(s)
3246 after = p.nodeAfterTree()
3247 root = p.lastChild()
3248 self.assertEqual(root.h, f"@file {self.short_id}")
3249 p = root.firstChild()
3250 for n, h in table:
3251 n2 = p.level() - root.level()
3252 self.assertEqual(h, p.h)
3253 self.assertEqual(n, n2)
3254 p.moveToThreadNext()
3255 self.assertEqual(p, after)
3256 #@+node:ekr.20210904065459.106: *3* TestXml.test_xml_1
3257 def test_xml_11(self):
3259 s = """
3260 <html>
3261 <head>
3262 <title>Bodystring</title>
3263 </head>
3264 <body class='bodystring'>
3265 <div id='bodydisplay'></div>
3266 </body>
3267 </html>
3268 """
3269 p = self.run_test(s)
3270 self.check_headlines(p, (
3271 (1, "<html>"),
3272 (2, "<head>"),
3273 (2, "<body class='bodystring'>"),
3274 ))
3275 #@+node:ekr.20210904065459.108: *3* TestXml.test_non_ascii_tags
3276 def test_non_ascii_tags(self):
3277 s = """
3278 <:À.Ç>
3279 <Ì>
3280 <_.ÌÑ>
3281 """
3282 self.run_test(s)
3283 #@+node:ekr.20210904065459.132: *3* TestXml.test_is_ws_line
3284 def test_is_ws_line(self):
3285 c = self.c
3286 x = xml.Xml_Importer(importCommands=c.importCommands, atAuto=False)
3287 table = (
3288 (1, ' \n'),
3289 (1, '\n'),
3290 (1, ' '),
3291 (1, '<!-- comment -->'),
3292 (0, ' <!-- comment --> Help'),
3293 (0, 'x <!-- comment -->'),
3294 (0, 'Help'),
3295 )
3296 for expected, line in table:
3297 got = x.is_ws_line(line)
3298 self.assertEqual(expected, got, msg=repr(line))
3299 #@+node:ekr.20210904065459.133: *3* TestXml.test_scan_line
3300 def test_scan_line(self):
3301 c = self.c
3302 x = xml.Xml_Importer(importCommands=c.importCommands, atAuto=False)
3303 x.start_tags.append('html') # Don't rely on settings.
3304 table = (
3305 (0, '<tag>'),
3306 (0, '<tag></tag'),
3307 (1, '<html'),
3308 (1, '<html attrib="<">'),
3309 (0, '<html attrib="<" />'),
3310 (0, '<html>x</html>'),
3311 (0, '</br>'), # Tag underflow
3312 (0, '<br />'),
3313 (0, '<br/>'),
3314 )
3315 for level, line in table:
3316 prev_state = x.state_class() # Start in level 0
3317 self.assertEqual(prev_state.tag_level, 0, msg=line)
3318 new_state = x.scan_line(line, prev_state)
3319 self.assertEqual(new_state.tag_level, level, msg=line)
3320 #@-others
3321#@-others
3324#@-leo