Coverage for core\test_leoImport.py: 100%
595 statements
« prev ^ index » next coverage.py v6.4, created at 2022-05-24 10:21 -0500
« prev ^ index » next coverage.py v6.4, created at 2022-05-24 10:21 -0500
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 if sys.version_info < (3, 9, 0):
2724 self.skipTest('Requires Python 3.9') # pragma: no cover
2726 txt = ('class A:\n'
2727 ' a=1\n'
2728 ' b=1\n'
2729 ' c=1\n'
2730 ' d=1\n'
2731 ' e=1\n'
2732 ' f=1\n'
2733 ' g=1\n'
2734 ' h=1\n'
2735 ' i=1\n'
2736 ' j=1\n'
2737 ' k=1\n'
2738 ' l=1\n'
2739 ' m=1\n'
2740 ' n=1\n'
2741 ' o=1\n'
2742 ' p=1\n'
2743 ' q=1\n'
2744 ' r=1\n'
2745 ' s=1\n'
2746 ' t=1\n'
2747 ' u=1\n'
2748 ' v=1\n'
2749 ' w=1\n'
2750 ' x=1\n'
2751 ' y=1\n'
2752 ' x=1\n'
2753 '\n'
2754 )
2755 exp_nodes = [
2756 (0, 'ignored h',
2757 '@language python\n'
2758 '@tabwidth -4\n'
2759 '@others\n'
2760 ),
2761 (1, 'A',
2762 'class A:\n'
2763 ' a=1\n'
2764 ' b=1\n'
2765 ' c=1\n'
2766 ' d=1\n'
2767 ' e=1\n'
2768 ' f=1\n'
2769 ' g=1\n'
2770 ' h=1\n'
2771 ' i=1\n'
2772 ' j=1\n'
2773 ' k=1\n'
2774 ' l=1\n'
2775 ' m=1\n'
2776 ' n=1\n'
2777 ' o=1\n'
2778 ' p=1\n'
2779 ' q=1\n'
2780 ' r=1\n'
2781 ' s=1\n'
2782 ' t=1\n'
2783 ' u=1\n'
2784 ' v=1\n'
2785 ' w=1\n'
2786 ' x=1\n'
2787 ' y=1\n'
2788 ' x=1\n'
2789 '\n'
2790 )
2791 ]
2792 p = self.run_test(txt)
2793 ok, msg = self.check_outline(p, exp_nodes)
2794 assert ok, msg
2795 #@+node:vitalije.20211213125307.1: *3* TestPython: test_large_class_no_methods
2796 def test_large_class_under_indented(self):
2797 txt = ('class A:\n'
2798 ' a=1\n'
2799 ' b=1\n'
2800 ' c=1\n'
2801 ' d=1\n'
2802 ' e=1\n'
2803 ' def f(self):\n'
2804 ' self._f = """dummy\n'
2805 'dummy2\n'
2806 'dummy3"""\n'
2807 ' g=1\n'
2808 ' h=1\n'
2809 ' i=1\n'
2810 ' j=1\n'
2811 ' k=1\n'
2812 ' l=1\n'
2813 ' m=1\n'
2814 ' n=1\n'
2815 ' o=1\n'
2816 ' p=1\n'
2817 ' q=1\n'
2818 ' r=1\n'
2819 ' s=1\n'
2820 ' t=1\n'
2821 ' u=1\n'
2822 ' v=1\n'
2823 ' w=1\n'
2824 ' x=1\n'
2825 ' y=1\n'
2826 ' x=1\n'
2827 '\n'
2828 )
2829 exp_nodes = [
2830 (0, 'ignored h',
2831 '@language python\n'
2832 '@tabwidth -4\n'
2833 '@others\n'
2834 ),
2835 (1, 'A',
2836 'class A:\n'
2837 ' a=1\n'
2838 ' b=1\n'
2839 ' c=1\n'
2840 ' d=1\n'
2841 ' e=1\n'
2842 ' @others\n'
2843 ' g=1\n'
2844 ' h=1\n'
2845 ' i=1\n'
2846 ' j=1\n'
2847 ' k=1\n'
2848 ' l=1\n'
2849 ' m=1\n'
2850 ' n=1\n'
2851 ' o=1\n'
2852 ' p=1\n'
2853 ' q=1\n'
2854 ' r=1\n'
2855 ' s=1\n'
2856 ' t=1\n'
2857 ' u=1\n'
2858 ' v=1\n'
2859 ' w=1\n'
2860 ' x=1\n'
2861 ' y=1\n'
2862 ' x=1\n'
2863 '\n'
2864 ),
2865 (2, 'f',
2866 'def f(self):\n'
2867 ' self._f = """dummy\n'
2868 '\\\\-4.dummy2\n'
2869 '\\\\-4.dummy3"""\n'
2870 )
2871 ]
2872 p = self.run_test(txt)
2873 ok, msg = self.check_outline(p, exp_nodes)
2874 assert ok, msg
2875 #@+node:vitalije.20211206180043.1: *3* check_outline
2876 def check_outline(self, p, nodes):
2877 it = iter(nodes)
2878 zlev = p.level()
2879 for p1 in p.self_and_subtree():
2880 lev, h, b = next(it)
2881 assert p1.level() - zlev == lev, f'lev:{p1.level()-zlev} != {lev}'
2882 if lev > 0:
2883 assert p1.h == h, f'"{p1.h}" != "{h}"'
2884 assert p1.b == b, f'\n{repr(p1.b)} !=\n{repr(b)}'
2885 try:
2886 next(it)
2887 return False, 'extra nodes' # pragma: no cover
2888 except StopIteration:
2889 return True, 'ok'
2890 #@-others
2891#@+node:ekr.20211108050827.1: ** class TestRst (BaseTestImporter)
2892class TestRst(BaseTestImporter):
2894 ext = '.rst'
2895 treeType = '@auto-rst'
2897 #@+others
2898 #@+node:ekr.20210904065459.115: *3* TestRst.test_rst_1
2899 def test_rst_1(self):
2901 try:
2902 import docutils
2903 assert docutils
2904 except Exception: # pragma: no cover
2905 self.skipTest('no docutils')
2907 s = """
2908 .. toc
2910 ====
2911 top
2912 ====
2914 The top section
2916 section 1
2917 ---------
2919 section 1, line 1
2920 --
2921 section 1, line 2
2923 section 2
2924 ---------
2926 section 2, line 1
2928 section 2.1
2929 ~~~~~~~~~~~
2931 section 2.1, line 1
2933 section 2.1.1
2934 .............
2936 section 2.2.1 line 1
2938 section 3
2939 ---------
2941 section 3, line 1
2943 section 3.1.1
2944 .............
2946 section 3.1.1, line 1
2947 """
2948 p = self.run_test(s)
2949 self.check_headlines(p, (
2950 (1, '!Dummy chapter'),
2951 (1, 'top'),
2952 (1, 'section 1'),
2953 (1, 'section 2'),
2954 (2, 'section 2.1'),
2955 (3, 'section 2.1.1'),
2956 (1, 'section 3'),
2957 (2, 'placeholder'),
2958 (3, 'section 3.1.1'),
2959 ))
2960 #@+node:ekr.20210904065459.116: *3* TestRst.test_simple
2961 def test_simple(self):
2963 try:
2964 import docutils
2965 assert docutils
2966 except Exception: # pragma: no cover
2967 self.skipTest('no docutils')
2969 s = """
2970 .. toc
2972 .. The section name contains trailing whitespace.
2974 =======
2975 Chapter
2976 =======
2978 The top chapter.
2979 """
2980 p = self.run_test(s)
2981 self.check_headlines(p, (
2982 (1, "!Dummy chapter"),
2983 (1, "Chapter"),
2984 ))
2985 #@+node:ekr.20210904065459.117: *3* TestRst.test_no_double_underlines
2986 def test_no_double_underlines(self):
2988 try:
2989 import docutils
2990 assert docutils
2991 except Exception: # pragma: no cover
2992 self.skipTest('no docutils')
2994 s = """
2995 .. toc
2997 top
2998 ====
3000 The top section
3002 section 1
3003 ---------
3005 section 1, line 1
3006 --
3007 section 1, line 2
3009 section 2
3010 ---------
3012 section 2, line 1
3014 section 2.1
3015 ~~~~~~~~~~~
3017 section 2.1, line 1
3019 section 2.1.1
3020 .............
3022 section 2.2.1 line 1
3024 section 3
3025 ---------
3027 section 3, line 1
3029 section 3.1.1
3030 .............
3032 section 3.1.1, line 1
3033 """
3034 p = self.run_test(s)
3035 self.check_headlines(p, (
3036 (1, '!Dummy chapter'),
3037 (1, 'top'),
3038 (1, 'section 1'),
3039 (1, 'section 2'),
3040 (2, 'section 2.1'),
3041 (3, 'section 2.1.1'),
3042 (1, 'section 3'),
3043 (2, 'placeholder'),
3044 (3, 'section 3.1.1'),
3045 ))
3046 #@+node:ekr.20210904065459.118: *3* TestRst.test_long_underlines
3047 def test_long_underlines(self):
3049 try:
3050 import docutils
3051 assert docutils
3052 except Exception: # pragma: no cover
3053 self.skipTest('no docutils')
3055 s = """
3056 .. toc
3058 top
3059 -------------
3061 The top section
3062 """
3063 p = self.run_test(s)
3064 self.check_headlines(p, (
3065 (1, '!Dummy chapter'),
3066 (1, 'top'),
3067 ))
3068 #@+node:ekr.20210904065459.119: *3* TestRst.test_test_long_overlines
3069 def test_test_long_overlines(self):
3071 try:
3072 import docutils
3073 assert docutils
3074 except Exception: # pragma: no cover
3075 self.skipTest('no docutils')
3077 s = """
3078 .. toc
3080 ======
3081 top
3082 ======
3084 The top section
3085 """
3086 p = self.run_test(s)
3087 self.check_headlines(p, (
3088 (1, "!Dummy chapter"),
3089 (1, "top"),
3090 ))
3091 #@+node:ekr.20210904065459.120: *3* TestRst.test_trailing_whitespace
3092 def test_trailing_whitespace(self):
3094 try:
3095 import docutils
3096 assert docutils
3097 except Exception: # pragma: no cover
3098 self.skipTest('no docutils')
3100 s = """
3101 .. toc
3103 .. The section name contains trailing whitespace.
3105 ======
3106 top
3107 ======
3109 The top section.
3110 """
3111 p = self.run_test(s)
3112 self.check_headlines(p, (
3113 (1, "!Dummy chapter"),
3114 (1, "top"),
3115 ))
3116 #@+node:ekr.20210904065459.121: *3* TestRst.test_leo_rst
3117 def test_leo_rst(self):
3119 try:
3120 import docutils
3121 assert docutils
3122 except Exception: # pragma: no cover
3123 self.skipTest('no docutils')
3125 # All heading must be followed by an empty line.
3126 s = """\
3127 #########
3128 Chapter 1
3129 #########
3131 It was a dark and stormy night.
3133 section 1
3134 +++++++++
3136 Sec 1.
3138 section 2
3139 +++++++++
3141 Sec 2.
3142 """
3143 p = self.run_test(s)
3144 self.check_headlines(p, (
3145 (1, 'Chapter 1'),
3146 (2, 'section 1'),
3147 (2, 'section 2'),
3148 ))
3149 #@-others
3150#@+node:ekr.20211108083038.1: ** class TestTypescript (BaseTestImporter)
3151class TestTypescript(BaseTestImporter):
3153 ext = '.ts'
3155 #@+others
3156 #@+node:ekr.20210904065459.103: *3* TestTypescript.test_class
3157 def test_class(self):
3159 s = '''
3160 class Greeter {
3161 greeting: string;
3162 constructor (message: string) {
3163 this.greeting = message;
3164 }
3165 greet() {
3166 return "Hello, " + this.greeting;
3167 }
3168 }
3170 var greeter = new Greeter("world");
3172 var button = document.createElement('button')
3173 button.innerText = "Say Hello"
3174 button.onclick = function() {
3175 alert(greeter.greet())
3176 }
3178 document.body.appendChild(button)
3180 '''
3181 self.run_test(s)
3182 #@+node:ekr.20210904065459.104: *3* TestTypescript.test_module
3183 def test_module(self):
3184 s = '''
3185 module Sayings {
3186 export class Greeter {
3187 greeting: string;
3188 constructor (message: string) {
3189 this.greeting = message;
3190 }
3191 greet() {
3192 return "Hello, " + this.greeting;
3193 }
3194 }
3195 }
3196 var greeter = new Sayings.Greeter("world");
3198 var button = document.createElement('button')
3199 button.innerText = "Say Hello"
3200 button.onclick = function() {
3201 alert(greeter.greet())
3202 }
3204 document.body.appendChild(button)
3205 '''
3206 self.run_test(s)
3207 #@-others
3208#@+node:ekr.20211108065014.1: ** class TestXML (BaseTestImporter)
3209class TestXML(BaseTestImporter):
3211 ext = '.xml'
3213 def setUp(self):
3214 super().setUp()
3215 c = self.c
3216 # Simulate @data import-xml-tags, with *only* standard tags.
3217 tags_list = ['html', 'body', 'head', 'div', 'table']
3218 settingsDict, junk = g.app.loadManager.createDefaultSettingsDicts()
3219 c.config.settingsDict = settingsDict
3220 c.config.set(c.p, 'data', 'import-xml-tags', tags_list, warn=True)
3222 #@+others
3223 #@+node:ekr.20210904065459.105: *3* TestXml.test_standard_opening_elements
3224 def test_standard_opening_elements(self):
3225 c = self.c
3226 s = """
3227 <?xml version="1.0" encoding="UTF-8"?>
3228 <!DOCTYPE note SYSTEM "Note.dtd">
3229 <html>
3230 <head>
3231 <title>Bodystring</title>
3232 </head>
3233 <body class='bodystring'>
3234 <div id='bodydisplay'></div>
3235 </body>
3236 </html>
3237 """
3238 table = (
3239 (1, "<html>"),
3240 (2, "<head>"),
3241 (2, "<body class='bodystring'>"),
3242 )
3243 p = c.p
3244 self.run_test(s)
3245 after = p.nodeAfterTree()
3246 root = p.lastChild()
3247 self.assertEqual(root.h, f"@file {self.short_id}")
3248 p = root.firstChild()
3249 for n, h in table:
3250 n2 = p.level() - root.level()
3251 self.assertEqual(h, p.h)
3252 self.assertEqual(n, n2)
3253 p.moveToThreadNext()
3254 self.assertEqual(p, after)
3255 #@+node:ekr.20210904065459.106: *3* TestXml.test_xml_1
3256 def test_xml_11(self):
3258 s = """
3259 <html>
3260 <head>
3261 <title>Bodystring</title>
3262 </head>
3263 <body class='bodystring'>
3264 <div id='bodydisplay'></div>
3265 </body>
3266 </html>
3267 """
3268 p = self.run_test(s)
3269 self.check_headlines(p, (
3270 (1, "<html>"),
3271 (2, "<head>"),
3272 (2, "<body class='bodystring'>"),
3273 ))
3274 #@+node:ekr.20210904065459.108: *3* TestXml.test_non_ascii_tags
3275 def test_non_ascii_tags(self):
3276 s = """
3277 <:À.Ç>
3278 <Ì>
3279 <_.ÌÑ>
3280 """
3281 self.run_test(s)
3282 #@+node:ekr.20210904065459.132: *3* TestXml.test_is_ws_line
3283 def test_is_ws_line(self):
3284 c = self.c
3285 x = xml.Xml_Importer(importCommands=c.importCommands, atAuto=False)
3286 table = (
3287 (1, ' \n'),
3288 (1, '\n'),
3289 (1, ' '),
3290 (1, '<!-- comment -->'),
3291 (0, ' <!-- comment --> Help'),
3292 (0, 'x <!-- comment -->'),
3293 (0, 'Help'),
3294 )
3295 for expected, line in table:
3296 got = x.is_ws_line(line)
3297 self.assertEqual(expected, got, msg=repr(line))
3298 #@+node:ekr.20210904065459.133: *3* TestXml.test_scan_line
3299 def test_scan_line(self):
3300 c = self.c
3301 x = xml.Xml_Importer(importCommands=c.importCommands, atAuto=False)
3302 x.start_tags.append('html') # Don't rely on settings.
3303 table = (
3304 (0, '<tag>'),
3305 (0, '<tag></tag'),
3306 (1, '<html'),
3307 (1, '<html attrib="<">'),
3308 (0, '<html attrib="<" />'),
3309 (0, '<html>x</html>'),
3310 (0, '</br>'), # Tag underflow
3311 (0, '<br />'),
3312 (0, '<br/>'),
3313 )
3314 for level, line in table:
3315 prev_state = x.state_class() # Start in level 0
3316 self.assertEqual(prev_state.tag_level, 0, msg=line)
3317 new_state = x.scan_line(line, prev_state)
3318 self.assertEqual(new_state.tag_level, level, msg=line)
3319 #@-others
3320#@-others
3323#@-leo