Coverage for core\test_leoImport.py : 87%

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