Hide keyboard shortcuts

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""" 

6 

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""" 

26 

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. 

30 

31 def setUp(self): 

32 super().setUp() 

33 g.app.loadManager.createAllImporterData() 

34 

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. 

62  

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. 

74  

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. 

120  

121 root_p: The root of the expected outline. 

122 expect_s: A string representing the outline in enhanced MORE format. 

123  

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() 

143 

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): 

214 

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): 

228 

229 ext = '.c' 

230 

231 #@+others 

232 #@+node:ekr.20210904065459.3: *3* TestC.test_c_class_1 

233 def test_c_class_1(self): 

234 

235 s = """ 

236 class cTestClass1 { 

237 

238 int foo (int a) { 

239 a = 2 ; 

240 } 

241 

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): 

255 

256 s = """ 

257 class cTestClass1 { 

258 

259 int foo (int a) { 

260 // an underindented line. 

261 a = 2 ; 

262 } 

263 

264 // This should go with the next function. 

265 

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 )) 

277 

278 #@+node:ekr.20210904065459.5: *3* TestC.test_comment_follows_arg_list 

279 def test_comment_follows_arg_list(self): 

280 

281 s = """ 

282 void 

283 aaa::bbb::doit 

284 ( 

285 awk* b 

286 ) 

287 { 

288 assert(false); 

289 } 

290 

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): 

307 

308 s = """ 

309 void 

310 aaa::bbb::doit 

311 ( 

312 awk* b 

313 ) 

314 { 

315 assert(false); 

316 } 

317 

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): 

334 

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): 

349 

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): 

366 

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): 

384 

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): 

401 

402 ext = '.coffee' 

403 

404 #@+others 

405 #@+node:ekr.20210904065459.15: *3* TestCoffeescript.test_1 

406 def test_1(self): 

407 

408 s = r''' 

409 

410 # Js2coffee relies on Narcissus's parser. 

411 

412 {parser} = @Narcissus or require('./narcissus_packed') 

413 

414 # Main entry point 

415 

416 buildCoffee = (str) -> 

417 str = str.replace /\r/g, '' 

418 str += "\n" 

419 

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 

429 

430 def test_2(self): 

431 

432 s = """ 

433 class Builder 

434 constructor: -> 

435 @transformer = new Transformer 

436 # `build()` 

437  

438 build: (args...) -> 

439 node = args[0] 

440 @transform node 

441  

442 name = 'other' 

443 name = node.typeName() if node != undefined and node.typeName 

444  

445 fn = (@[name] or @other) 

446 out = fn.apply(this, args) 

447  

448 if node.parenthesized then paren(out) else out 

449 # `transform()` 

450  

451 transform: (args...) -> 

452 @transformer.transform.apply(@transformer, args) 

453  

454 # `body()` 

455  

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 )) 

470 

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): 

484 

485 ext = '.c#' 

486 

487 #@+others 

488 #@+node:ekr.20210904065459.12: *3* TestCSharp.test_namespace_indent 

489 def test_namespace_indent(self): 

490 

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): 

505 

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): 

521 

522 ext = '.pyx' 

523 #@+others 

524 #@+node:ekr.20210904065459.11: *3* TestCython.test_importer 

525 def test_importer(self): 

526 

527 s = ''' 

528 from libc.math cimport pow 

529 

530 cdef double square_and_add (double x): 

531 """Compute x^2 + x as double. 

532 

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 

537 

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))) 

541 

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): 

552 

553 ext = '.dart' 

554 

555 #@+others 

556 #@+node:ekr.20210904065459.17: *3* TestDart.test_hello_world 

557 def test_hello_world(self): 

558 

559 s = r''' 

560 var name = 'Bob'; 

561 

562 hello() { 

563 print('Hello, World!'); 

564 } 

565 

566 // Define a function. 

567 printNumber(num aNumber) { 

568 print('The number is $aNumber.'); // Print to console. 

569 } 

570 

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): 

597 

598 ext = '.el' 

599 

600 #@+others 

601 #@+node:ekr.20210904065459.18: *3* TestElisp.test_1 

602 def test_1(self): 

603 

604 s = """ 

605 ;;; comment 

606 ;;; continue 

607 ;;; 

608 

609 (defun abc (a b) 

610 (+ 1 2 3)) 

611 

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 )) 

621 

622 #@-others 

623#@+node:ekr.20211108064432.1: ** class TestHtml (BaseTestImporter) 

624class TestHtml (BaseTestImporter): 

625 

626 ext = '.htm' 

627 

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) 

636 

637 #@+others 

638 #@+node:ekr.20210904065459.19: *3* TestHtml.test_lowercase_tags 

639 def test_lowercase_tags(self): 

640 

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 )) 

657 

658 #@+node:ekr.20210904065459.20: *3* TestHtml.test_multiple_tags_on_a_line 

659 def test_multiple_tags_on_a_line(self): 

660 

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 )) 

719 

720 #@+node:ekr.20210904065459.21: *3* TestHtml.test_multple_node_completed_on_a_line 

721 def test_multple_node_completed_on_a_line(self): 

722 

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): 

734 

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): 

749 

750 s = r''' 

751 <td width="550"> 

752 <table cellspacing="0" cellpadding="0" width="600" border="0"> 

753 <td class="blutopgrabot" height="28"></td> 

754  

755 <!-- The indentation of this element causes the problem. --> 

756 <table> 

757  

758 <!-- 

759 <div align="center"> 

760 <iframe src="http://www.amex.com/atamex/regulation/listingStatus/index.jsp"</iframe> 

761 </div> 

762 --> 

763  

764 </table> 

765 </table> 

766  

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): 

777 

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): 

797 

798 s = """ 

799 <body> 

800 

801 <!-- OOPS: the div and p elements not properly nested.--> 

802 <!-- OOPS: this table got generated twice. --> 

803 

804 <p id="P1"> 

805 <div id="D666">Paragraph</p> <!-- P1 --> 

806 <p id="P2"> 

807 

808 <TABLE id="T666"></TABLE></p> <!-- P2 --> 

809 </div> 

810 </p> <!-- orphan --> 

811 

812 </body> 

813 """ 

814 p = self.run_test(s) 

815 self.check_headlines(p, ( 

816 (1, '<body>'), 

817 (2, '<div id="D666">'), 

818 )) 

819 

820 #@+node:ekr.20210904065459.26: *3* TestHtml.test_improperly_terminated_tags 

821 def test_improperly_terminated_tags(self): 

822 

823 s = ''' 

824 <html> 

825  

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' /> 

832  

833 <title>TITLE</title> 

834  

835 <!-- oops: missing tags. --> 

836 ''' 

837 p = self.run_test(s) 

838 self.check_headlines(p, ( 

839 (1, '<html>'), 

840 (2, '<head>'), 

841 )) 

842 

843 #@+node:ekr.20210904065459.27: *3* TestHtml.test_improperly_terminated_tags2 

844 def test_improperly_terminated_tags2(self): 

845 

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' /> 

854  

855 <title>TITLE</title> 

856  

857 </head> 

858 </html> 

859 ''' 

860 p = self.run_test(s) 

861 self.check_headlines(p, ( 

862 (1, '<html>'), 

863 (2, '<head>'), 

864 )) 

865 

866 #@+node:ekr.20210904065459.28: *3* TestHtml.test_brython 

867 def test_brython(self): 

868 

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 

879 

880 qs_lang,language = header.show() 

881 

882 doc["content"].html = doc["content_%s" %language].html 

883 

884 if qs_lang: 

885 doc["c_%s" %qs_lang].href += "?lang=%s" %qs_lang 

886 

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 

891 

892 for elt in doc[html.SELECT]: 

893 if elt.id.startswith('change_lang_'): 

894 doc[elt.id].bind('change',ch_lang) 

895 </script> 

896 

897 <script type="text/python3"> 

898 """Code for the clock""" 

899 

900 import time 

901 import math 

902 import datetime 

903 

904 from browser import document as doc 

905 import browser.timer 

906 

907 sin,cos = math.sin,math.cos 

908 width,height = 250,250 # canvas dimensions 

909 ray = 100 # clock ray 

910 

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() 

923 

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() 

930 

931 # redraw hours 

932 show_hours() 

933 

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) 

942 

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 

955 

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) 

972 

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() 

981 

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> 

1000 

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): 

1016 

1017 ext = '.ini' 

1018 

1019 #@+others 

1020 #@+node:ekr.20210904065459.29: *3* TestIni.test_1 

1021 def test_1(self): 

1022 

1023 s = ''' 

1024 ; last modified 1 April 2001 by John Doe 

1025 [owner] 

1026 name=John Doe 

1027 organization=Acme Widgets Inc. 

1028 

1029 ; [ not a section ] 

1030 

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): 

1045 

1046 ext = '.java' 

1047 

1048 #@+others 

1049 #@+node:ekr.20210904065459.30: *3* TestJava.test_from_AdminPermission_java 

1050 def test_from_AdminPermission_java(self): 

1051 

1052 s = """ 

1053 /** 

1054 * Indicates the caller's authority to perform lifecycle operations on 

1055 */ 

1056 

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): 

1075 

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 */ 

1086 

1087 package org.osgi.framework; 

1088 

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 */ 

1104 

1105 public class BundleException extends Exception { 

1106 static final long serialVersionUID = 3571095144220455665L; 

1107 /** 

1108 * Nested exception. 

1109 */ 

1110 private Throwable cause; 

1111 

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 } 

1123 

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): 

1132 

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): 

1145 

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): 

1159 

1160 ext = '.js' 

1161 

1162 #@+others 

1163 #@+node:ekr.20210904065459.34: *3* TestJavascript.test_regex_1 

1164 def test_regex_1(self): 

1165 

1166 s = """ 

1167 String.prototype.toJSONString = function() 

1168 { 

1169 if(/["\\\\\\x00-\\x1f]/.test(this)) 

1170 return '"' + this.replace(/([\\x00-\\x1f\\"])/g,replaceFn) + '"'; 

1171 

1172 return '"' + this + '"'; 

1173 }; 

1174 """ 

1175 self.run_test(s) 

1176 #@+node:ekr.20210904065459.35: *3* TestJavascript.test_3 

1177 def test_3(self): 

1178 

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): 

1196 

1197 s = """ 

1198 var c3 = (function () { 

1199 "use strict"; 

1200 

1201 // Globals 

1202 var c3 = { version: "0.0.1" }; 

1203 

1204 c3.someFunction = function () { 

1205 console.log("Just a demo..."); 

1206 }; 

1207 

1208 return c3; 

1209 }()); 

1210 """ 

1211 self.run_test(s) 

1212 #@+node:ekr.20210904065459.37: *3* TestJavascript.test_5 

1213 def test_5(self): 

1214 

1215 s = """ 

1216 var express = require('express'); 

1217 

1218 var app = express.createServer(express.logger()); 

1219 

1220 app.get('/', function(request, response) { 

1221 response.send('Hello World!'); 

1222 }); 

1223 

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): 

1232 

1233 s = """ 

1234 // Easy test for #639: https://github.com/leo-editor/leo-editor/issues/639 

1235 

1236 //============================================================================= 

1237 // rpg_core.js v1.3.0 

1238 //============================================================================= 

1239 

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 } 

1250 

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): 

1266 

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): 

1292 

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): 

1332 

1333 ext = '.md' 

1334 treeType = '@auto-md' 

1335 

1336 #@+others 

1337 #@+node:ekr.20210904065459.109: *3* TestMarkdown.test_md_import 

1338 def test_md_import(self): 

1339 

1340 s = """\ 

1341 #Top 

1342 The top section 

1343 

1344 ##Section 1 

1345 section 1, line 1 

1346 section 1, line 2 

1347 

1348 ##Section 2 

1349 section 2, line 1 

1350 

1351 ###Section 2.1 

1352 section 2.1, line 1 

1353 

1354 ####Section 2.1.1 

1355 section 2.2.1 line 1 

1356 The next section is empty. It must not be deleted. 

1357 

1358 ###Section 2.2 

1359 

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): 

1375 

1376 s = """\ 

1377 Top 

1378 ==== 

1379 

1380 The top section 

1381 

1382 Section 1 

1383 --------- 

1384 

1385 section 1, line 1 

1386 -- Not an underline 

1387 secttion 1, line 2 

1388 

1389 Section 2 

1390 --------- 

1391 

1392 section 2, line 1 

1393 

1394 ###Section 2.1 

1395 

1396 section 2.1, line 1 

1397 

1398 ####Section 2.1.1 

1399 

1400 section 2.2.1 line 1 

1401 

1402 ###Section 2.2 

1403 section 2.2, line 1. 

1404 

1405 Section 3 

1406 --------- 

1407 

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): 

1422 

1423 # insert test for markdown here. 

1424 s = """ 

1425 Decl line. 

1426 #Header 

1427 

1428 After header text 

1429 

1430 ##Subheader 

1431 

1432 Not an underline 

1433 

1434 ---------------- 

1435 

1436 After subheader text 

1437 

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): 

1449 

1450 s = """ 

1451 Decl line. 

1452 #Header 

1453 

1454 After header text 

1455 

1456 ##Subheader 

1457 

1458 Not an underline 

1459 

1460 ---------------- 

1461 

1462 This *should* be a section 

1463 ========================== 

1464 

1465 After subheader text 

1466 

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): 

1481 

1482 s = """ 

1483 Decl line. 

1484 #Header 

1485 

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): 

1533 

1534 ext = '.org' 

1535 treeType = '@auto-org' 

1536 

1537 #@+others 

1538 #@+node:ekr.20210904065459.42: *3* TestOrg.test_1 

1539 def test_1(self): 

1540 

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 )) 

1563 

1564 #@+node:ekr.20210904065459.46: *3* TestOrg.test_1074 

1565 def test_1074(self): 

1566 

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): 

1577 

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): 

1594 

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): 

1609 

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): 

1624 

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): 

1659 

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): 

1674 

1675 ext = '.otl' 

1676 treeType = '@auto-otl' 

1677 

1678 #@+others 

1679 #@+node:ekr.20210904065459.49: *3* TestOtl.test_otl_1 

1680 def test_otl_1(self): 

1681 

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): 

1710 

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): 

1725 

1726 ext = '.pas' 

1727 

1728 #@+others 

1729 #@+node:ekr.20210904065459.50: *3* TestPascal.test_delphi_interface 

1730 def test_delphi_interface(self): 

1731 

1732 s = """ 

1733 unit Unit1; 

1734 

1735 interface 

1736 

1737 uses 

1738 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, 

1739 Forms, 

1740 Dialogs; 

1741 

1742 type 

1743 TForm1 = class(TForm) 

1744 procedure FormCreate(Sender: TObject); 

1745 private 

1746 { Private declarations } 

1747 public 

1748 { Public declarations } 

1749 end; 

1750 

1751 var 

1752 Form1: TForm1; 

1753 

1754 implementation 

1755 

1756 {$R *.dfm} 

1757 

1758 procedure TForm1.FormCreate(Sender: TObject); 

1759 var 

1760 x,y: double; 

1761 begin 

1762 x:= 4; 

1763 Y := x/2; 

1764 end; 

1765 

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): 

1776 

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): 

1789 

1790 ext = '.pl' 

1791 

1792 #@+others 

1793 #@+node:ekr.20210904065459.51: *3* TestPerl.test_1 

1794 def test_1(self): 

1795 

1796 s = """ 

1797 #!/usr/bin/perl 

1798 

1799 # Function definition 

1800 sub Hello{ 

1801 print "Hello, World!\n"; 

1802 } 

1803 

1804 sub Test{ 

1805 print "Test!\n"; 

1806 } 

1807 "\N{LATIN SMALL LIGATURE FI}" =~ /fi/i; 

1808 

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 } 

1815 

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): 

1822 

1823 s = """ 

1824 #!/usr/bin/perl 

1825 

1826 # This would print with a line break in the middle 

1827 print "Hello 

1828 

1829 sub World { 

1830 print "This is not a funtion!" 

1831 } 

1832 

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): 

1838 

1839 s = """ 

1840 #!/usr/bin/perl 

1841 

1842 sub Test{ 

1843 print "Test!\n"; 

1844 } 

1845 

1846 =begin comment 

1847 sub World { 

1848 print "This is not a funtion!" 

1849 } 

1850 =cut 

1851 

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): 

1860 

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 

1867 

1868 sub test1 { 

1869 s = /{/g; 

1870 } 

1871 

1872 sub test2 { 

1873 s = m//{/; 

1874 } 

1875 

1876 sub test3 { 

1877 s = s///{/; 

1878 } 

1879 

1880 sub test4 { 

1881 s = tr///{/; 

1882 } 

1883 """ 

1884 self.run_test(s) 

1885 

1886 #@+node:ekr.20210904065459.55: *3* TestPerl.test_regex_2 

1887 def test_regex_2(self): 

1888 

1889 s = """ 

1890 #!/usr/bin/perl 

1891 

1892 sub test1 { 

1893 s = /}/g; 

1894 } 

1895 

1896 sub test2 { 

1897 s = m//}/; 

1898 } 

1899 

1900 sub test3 { 

1901 s = s///}/; 

1902 } 

1903 

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): 

1918 

1919 ext = '.php' 

1920 

1921 #@+others 

1922 #@+node:ekr.20210904065459.56: *3* TestPhp.test_import_class 

1923 def test_import_class(self): 

1924 

1925 s = """ 

1926 <?php 

1927 

1928 $type = 'cc'; 

1929 $obj = new $type; // outputs "hi!" 

1930 

1931 class cc { 

1932 function __construct() { 

1933 echo 'hi!'; 

1934 } 

1935 } 

1936 

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): 

1942 

1943 s = """ 

1944 <?php 

1945 

1946 if (expr) { 

1947 class cc { 

1948 // version 1 

1949 } 

1950 } else { 

1951 class cc { 

1952 // version 2 

1953 } 

1954 } 

1955 

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): 

1961 

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 } 

1971 

1972 public function __get( /*string*/ $name = null ) { 

1973 return $this->self[$name]; 

1974 } 

1975 

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 } 

1983 

1984 class DefinedEnum extends Enum { 

1985 public function __construct( /*array*/ $itms ) { 

1986 foreach( $itms as $name => $enum ) 

1987 $this->add($name, $enum); 

1988 } 

1989 } 

1990 

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): 

2003 

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): 

2018 

2019 check_tree = False 

2020 ext = '.py' 

2021 treeType = '@file' 

2022 

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') 

2027 

2028 #@+others 

2029 #@+node:ekr.20211126055349.1: *3* TestPython.test_short_file 

2030 def test_short_file(self): 

2031 

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 

2314 

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): 

2793 

2794 import sys 

2795 if sys.version_info < (3, 9, 0): 

2796 self.skipTest('Requires Python 3.9') 

2797 

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): 

2965 

2966 ext = '.rst' 

2967 treeType = '@auto-rst' 

2968 

2969 #@+others 

2970 #@+node:ekr.20210904065459.115: *3* TestRst.test_rst_1 

2971 def test_rst_1(self): 

2972 

2973 try: 

2974 import docutils 

2975 assert docutils 

2976 except Exception: 

2977 self.skipTest('no docutils') 

2978 

2979 s = """ 

2980 .. toc 

2981 

2982 ==== 

2983 top 

2984 ==== 

2985 

2986 The top section 

2987 

2988 section 1 

2989 --------- 

2990 

2991 section 1, line 1 

2992 -- 

2993 section 1, line 2 

2994 

2995 section 2 

2996 --------- 

2997 

2998 section 2, line 1 

2999 

3000 section 2.1 

3001 ~~~~~~~~~~~ 

3002 

3003 section 2.1, line 1 

3004 

3005 section 2.1.1 

3006 ............. 

3007 

3008 section 2.2.1 line 1 

3009 

3010 section 3 

3011 --------- 

3012 

3013 section 3, line 1 

3014 

3015 section 3.1.1 

3016 ............. 

3017 

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): 

3034 

3035 try: 

3036 import docutils 

3037 assert docutils 

3038 except Exception: 

3039 self.skipTest('no docutils') 

3040 

3041 s = """ 

3042 .. toc 

3043 

3044 .. The section name contains trailing whitespace. 

3045 

3046 ======= 

3047 Chapter 

3048 ======= 

3049 

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): 

3059 

3060 try: 

3061 import docutils 

3062 assert docutils 

3063 except Exception: 

3064 self.skipTest('no docutils') 

3065 

3066 s = """ 

3067 .. toc 

3068 

3069 top 

3070 ==== 

3071 

3072 The top section 

3073 

3074 section 1 

3075 --------- 

3076 

3077 section 1, line 1 

3078 -- 

3079 section 1, line 2 

3080 

3081 section 2 

3082 --------- 

3083 

3084 section 2, line 1 

3085 

3086 section 2.1 

3087 ~~~~~~~~~~~ 

3088 

3089 section 2.1, line 1 

3090 

3091 section 2.1.1 

3092 ............. 

3093 

3094 section 2.2.1 line 1 

3095 

3096 section 3 

3097 --------- 

3098 

3099 section 3, line 1 

3100 

3101 section 3.1.1 

3102 ............. 

3103 

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): 

3120 

3121 try: 

3122 import docutils 

3123 assert docutils 

3124 except Exception: 

3125 self.skipTest('no docutils') 

3126 

3127 s = """ 

3128 .. toc 

3129 

3130 top 

3131 ------------- 

3132 

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): 

3142 

3143 try: 

3144 import docutils 

3145 assert docutils 

3146 except Exception: 

3147 self.skipTest('no docutils') 

3148 

3149 s = """ 

3150 .. toc 

3151 

3152 ====== 

3153 top 

3154 ====== 

3155 

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): 

3165 

3166 try: 

3167 import docutils 

3168 assert docutils 

3169 except Exception: 

3170 self.skipTest('no docutils') 

3171 

3172 s = """ 

3173 .. toc 

3174 

3175 .. The section name contains trailing whitespace. 

3176 

3177 ====== 

3178 top 

3179 ====== 

3180 

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): 

3190 

3191 try: 

3192 import docutils 

3193 assert docutils 

3194 except Exception: 

3195 self.skipTest('no docutils') 

3196 

3197 # All heading must be followed by an empty line. 

3198 s = """\ 

3199 ######### 

3200 Chapter 1 

3201 ######### 

3202 

3203 It was a dark and stormy night. 

3204 

3205 section 1 

3206 +++++++++ 

3207 

3208 Sec 1. 

3209 

3210 section 2 

3211 +++++++++ 

3212 

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): 

3224 

3225 ext = '.ts' 

3226 

3227 #@+others 

3228 #@+node:ekr.20210904065459.103: *3* TestTypescript.test_class 

3229 def test_class(self): 

3230 

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 } 

3241  

3242 var greeter = new Greeter("world"); 

3243  

3244 var button = document.createElement('button') 

3245 button.innerText = "Say Hello" 

3246 button.onclick = function() { 

3247 alert(greeter.greet()) 

3248 } 

3249  

3250 document.body.appendChild(button) 

3251 

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"); 

3269 

3270 var button = document.createElement('button') 

3271 button.innerText = "Say Hello" 

3272 button.onclick = function() { 

3273 alert(greeter.greet()) 

3274 } 

3275 

3276 document.body.appendChild(button) 

3277 ''' 

3278 self.run_test(s) 

3279 #@-others 

3280#@+node:ekr.20211108065014.1: ** class TestXML (BaseTestImporter) 

3281class TestXML (BaseTestImporter): 

3282 

3283 ext = '.xml' 

3284 

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) 

3293 

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): 

3329 

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 

3393 

3394 

3395#@-leo