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.20210901172411.1: * @file ../unittests/core/test_leoAtFile.py 

4#@@first 

5"""Tests of leoAtFile.py""" 

6import os 

7import tempfile 

8import textwrap 

9from leo.core import leoGlobals as g 

10from leo.core import leoAtFile 

11from leo.core import leoBridge 

12from leo.core.leoTest2 import LeoUnitTest 

13 

14#@+others 

15#@+node:ekr.20210901172446.1: ** class TestAtFile(LeoUnitTest) 

16class TestAtFile(LeoUnitTest): 

17 """Test cases for leoAtFile.py""" 

18 

19 def setUp(self): 

20 # Create a pristine instance of the AtFile class. 

21 super().setUp() 

22 self.at = leoAtFile.AtFile(self.c) 

23 

24 #@+others 

25 #@+node:ekr.20200204095726.1: *3* TestAtFile.bridge 

26 def bridge(self): 

27 """Return an instance of Leo's bridge.""" 

28 return leoBridge.controller(gui='nullGui', 

29 loadPlugins=False, 

30 readSettings=False, 

31 silent=True, 

32 verbose=False, 

33 ) 

34 #@+node:ekr.20210905052021.28: *3* TestAtFile.test_at_scanAllDirectives 

35 def test_at_scanAllDirectives(self): 

36 

37 at, c = self.at, self.c 

38 d = at.scanAllDirectives(c.p) 

39 # These are the commander defaults, without any settings. 

40 self.assertEqual(d.get('language'), 'python') 

41 self.assertEqual(d.get('tabwidth'), -4) 

42 self.assertEqual(d.get('pagewidth'), 132) 

43 #@+node:ekr.20210905052021.29: *3* TestAtFile.test_at_scanAllDirectives_minimal_ 

44 def test_at_scanAllDirectives_minimal_(self): 

45 

46 at, c = self.at, self.c 

47 d = at.scanAllDirectives(c.p) 

48 d = c.atFileCommands.scanAllDirectives(c.p) 

49 assert d 

50 #@+node:ekr.20200204094139.1: *3* TestAtFile.test_bug_1469 

51 def test_bug_1469(self): 

52 # Test #1469: saves renaming an external file 

53 # Create a new outline with @file node and save it 

54 bridge = self.bridge() 

55 with tempfile.TemporaryDirectory() as temp_dir: 

56 filename = f"{temp_dir}{os.sep}test_file.leo" 

57 c = bridge.openLeoFile(filename) 

58 p = c.rootPosition() 

59 p.h = '@file 1' 

60 p.b = 'b1' 

61 c.save() 

62 # Rename the @file node and save 

63 p1 = c.rootPosition() 

64 p1.h = "@file 1_renamed" 

65 c.save() 

66 # Remove the original "@file 1" from the disk 

67 external_filename = f"{temp_dir}{os.sep}1" 

68 assert os.path.exists(external_filename) 

69 os.remove(external_filename) 

70 assert not os.path.exists(external_filename) 

71 # Change the @file contents, save and reopen the outline 

72 p1.b = "b_1_changed" 

73 c.save() 

74 c.close() 

75 c = bridge.openLeoFile(c.fileName()) 

76 p1 = c.rootPosition() 

77 self.assertEqual(p1.h, "@file 1_renamed") 

78 #@+node:ekr.20210421035527.1: *3* TestAtFile.test_bug_1889 

79 def test_bug_1889(self): 

80 # Test #1889: Honor ~ in ancestor @path nodes. 

81 # Create a new outline with @file node and save it 

82 bridge = self.bridge() 

83 with tempfile.TemporaryDirectory() as temp_dir: 

84 filename = f"{temp_dir}{os.sep}test_file.leo" 

85 c = bridge.openLeoFile(filename) 

86 root = c.rootPosition() 

87 root.h = '@path ~/sub-directory/' 

88 child = root.insertAsLastChild() 

89 child.h = '@file test_bug_1889.py' 

90 child.b = '@language python\n# test #1889' 

91 path = g.fullPath(c, child) 

92 assert '~' not in path, repr(path) 

93 #@+node:ekr.20210901140645.13: *3* TestAtFile.test_checkPythonSyntax 

94 def test_checkPythonSyntax(self): 

95 

96 at, p = self.at, self.c.p 

97 s = textwrap.dedent('''\ 

98 # no error 

99 def spam(): 

100 pass 

101 ''') 

102 assert at.checkPythonSyntax(p, s), 'fail 1' 

103 

104 s2 = textwrap.dedent('''\ 

105 # syntax error 

106 def spam: # missing parens. 

107 pass 

108 ''') 

109 

110 assert not at.checkPythonSyntax(p, s2), 'fail2' 

111 #@+node:ekr.20210905052021.19: *3* TestAtFile.test_directiveKind4 

112 def test_directiveKind4(self): 

113 

114 at = self.at 

115 at.language = 'python' # Usually set by atFile read/write logic. 

116 table = [ 

117 ('@=', 0, at.noDirective), 

118 ('@', 0, at.atDirective), 

119 ('@ ', 0, at.atDirective), 

120 ('@\t', 0, at.atDirective), 

121 ('@\n', 0, at.atDirective), 

122 ('@all', 0, at.allDirective), 

123 (' @all', 4, at.allDirective), 

124 (' @all', 0, at.allDirective), # 2021/11/04 

125 ("@c", 0, at.cDirective), 

126 ("@code", 0, at.codeDirective), 

127 ("@doc", 0, at.docDirective), 

128 ('@others', 0, at.othersDirective), 

129 (' @others', 4, at.othersDirective), 

130 # ("@end_raw", 0, at.endRawDirective), # #2276. 

131 # ("@raw", 0, at.rawDirective), # #2276. 

132 ] 

133 for name in g.globalDirectiveList: 

134 # Note: entries in g.globalDirectiveList do not start with '@' 

135 if name not in ('all', 'c', 'code', 'doc', 'end_raw', 'others', 'raw',): 

136 table.append(('@' + name, 0, at.miscDirective),) 

137 for s, i, expected in table: 

138 result = at.directiveKind4(s, i) 

139 self.assertEqual(result, expected, msg=f"i: {i}, s: {s!r}") 

140 #@+node:ekr.20210905052021.20: *3* TestAtFile.test_directiveKind4_2 

141 def test_directiveKind4_2(self): 

142 

143 at = self.at 

144 at.language = 'python' # Usually set by atFile read/write logic. 

145 table = ( 

146 (at.othersDirective, '@others'), 

147 (at.othersDirective, '@others\n'), 

148 (at.othersDirective, ' @others'), 

149 (at.miscDirective, '@tabwidth -4'), 

150 (at.miscDirective, '@tabwidth -4\n'), 

151 (at.miscDirective, '@encoding'), 

152 (at.noDirective, '@encoding.setter'), 

153 (at.noDirective, '@encoding("abc")'), 

154 (at.noDirective, 'encoding = "abc"'), 

155 (at.noDirective, '@directive'), # A crucial new test. 

156 (at.noDirective, '@raw'), # 2021/11/04. 

157 ) 

158 for expected, s in table: 

159 result = at.directiveKind4(s, 0) 

160 self.assertEqual(expected, result, msg=repr(s)) 

161 #@+node:ekr.20211106034202.1: *3* TsetAtFile.test_findSectionName 

162 def test_findSectionName(self): 

163 # Test code per #2303. 

164 at, p = self.at, self.c.p 

165 at.initWriteIvars(p) 

166 ref = g.angleBrackets(' abc ') 

167 table = ( 

168 (True, f"{ref}\n"), 

169 (True, f"{ref}"), 

170 (True, f" {ref} \n"), 

171 (False, f"if {ref}:\n"), 

172 (False, f"{ref} # comment\n"), 

173 (False, f"# {ref}\n"), 

174 ) 

175 for valid, s in table: 

176 name, n1, n2 = at.findSectionName(s, 0, p) 

177 self.assertEqual(valid, bool(name), msg=repr(s)) 

178 #@+node:ekr.20210905052021.23: *3* TestAtFile.test_parseLeoSentinel 

179 def test_parseLeoSentinel(self): 

180 

181 at = self.at 

182 table = ( 

183 # start, end, new_df, isThin, encoding 

184 # pre 4.2 formats... 

185 ('#', '', False, True, 'utf-8', '#@+leo-thin-encoding=utf-8.'), 

186 ('#', '', False, False, 'utf-8', '#@+leo-encoding=utf-8.'), 

187 # 4.2 formats... 

188 ('#', '', True, True, 'utf-8', '#@+leo-ver=4-thin-encoding=utf-8,.'), 

189 ('/*', '*/', True, True, 'utf-8', r'\*@+leo-ver=5-thin-encoding=utf-8,.*/'), 

190 ('#', '', True, True, 'utf-8', '#@+leo-ver=5-thin'), 

191 ('#', '', True, True, 'utf-16', '#@+leo-ver=5-thin-encoding=utf-16,.'), 

192 ) 

193 try: 

194 for start, end, new_df, isThin, encoding, s in table: 

195 valid, new_df2, start2, end2, isThin2 = at.parseLeoSentinel(s) 

196 # g.trace('start',start,'end',repr(end),'len(s)',len(s)) 

197 assert valid, s 

198 self.assertEqual(new_df, new_df2, msg=repr(s)) 

199 self.assertEqual(isThin, isThin2, msg=repr(s)) 

200 self.assertEqual(end, end2, msg=repr(s)) 

201 self.assertEqual(at.encoding, encoding, msg=repr(s)) 

202 finally: 

203 at.encoding = 'utf-8' 

204 #@+node:ekr.20211102110237.1: *3* TestAtFile.test_putBody_adjacent_at_doc_part 

205 def test_putBody_adjacent_at_doc_part(self): 

206 

207 at, c = self.at, self.c 

208 root = c.rootPosition() 

209 root.h = '@file test.html' 

210 contents = textwrap.dedent('''\ 

211 @doc 

212 First @doc part 

213 @doc 

214 Second @doc part 

215 ''') 

216 expected = textwrap.dedent('''\ 

217 <!--@+doc--> 

218 <!-- 

219 First @doc part 

220 --> 

221 <!--@+doc--> 

222 <!-- 

223 Second @doc part 

224 --> 

225 ''') 

226 root.b = contents 

227 at.initWriteIvars(root) 

228 at.putBody(root) 

229 result = ''.join(at.outputList) 

230 self.assertEqual(result, expected) 

231 #@+node:ekr.20211102110833.1: *3* TestAtFile.test_putBody_at_all 

232 def test_putBody_at_all(self): 

233 

234 at, c = self.at, self.c 

235 root = c.rootPosition() 

236 root.h = '@file test.py' 

237 child = root.insertAsLastChild() 

238 child.h = 'child' 

239 child.b = textwrap.dedent('''\ 

240 def spam(): 

241 pass 

242  

243 @ A single-line doc part.''') 

244 child.v.fileIndex = '<GNX>' 

245 contents = textwrap.dedent('''\ 

246 ATall 

247 ''').replace('AT', '@') 

248 expected = textwrap.dedent('''\ 

249 #AT+all 

250 #AT+node:<GNX>: ** child 

251 def spam(): 

252 pass 

253  

254 @ A single-line doc part. 

255 #AT-all 

256 ''').replace('AT', '@') 

257 root.b = contents 

258 at.initWriteIvars(root) 

259 at.putBody(root) 

260 result = ''.join(at.outputList) 

261 self.assertEqual(result, expected) 

262 #@+node:ekr.20211102111413.1: *3* TestAtFile.test_putBody_at_all_after_at_doc 

263 def test_putBody_at_all_after_at_doc(self): 

264 

265 at, c = self.at, self.c 

266 root = c.rootPosition() 

267 root.h = '@file test.py' 

268 contents = textwrap.dedent('''\ 

269 ATdoc 

270 doc line 1 

271 ATall 

272 ''').replace('AT', '@') 

273 expected = textwrap.dedent('''\ 

274 #AT+doc 

275 # doc line 1 

276 # ATall 

277 ''').replace('AT', '@') 

278 root.b = contents 

279 at.initWriteIvars(root) 

280 at.putBody(root) 

281 result = ''.join(at.outputList) 

282 self.assertEqual(result, expected) 

283 #@+node:ekr.20211102150707.1: *3* TestAtFile.test_putBody_at_others 

284 def test_putBody_at_others(self): 

285 

286 at, c = self.at, self.c 

287 root = c.rootPosition() 

288 root.h = '@file test_putBody_at_others.py' 

289 child = root.insertAsLastChild() 

290 child.h = 'child' 

291 child.b = '@others\n' 

292 child.v.fileIndex = '<GNX>' 

293 contents = textwrap.dedent('''\ 

294 ATothers 

295 ''').replace('AT', '@') 

296 expected = textwrap.dedent('''\ 

297 #AT+others 

298 #AT+node:<GNX>: ** child 

299 #AT+others 

300 #AT-others 

301 #AT-others 

302 ''').replace('AT', '@') 

303 root.b = contents 

304 at.initWriteIvars(root) 

305 at.putBody(root) 

306 result = ''.join(at.outputList) 

307 self.assertEqual(result, expected) 

308 #@+node:ekr.20211102102024.1: *3* TestAtFile.test_putBody_unterminated_at_doc_part 

309 def test_putBody_unterminated_at_doc_part(self): 

310 

311 at, c = self.at, self.c 

312 root = c.rootPosition() 

313 root.h = '@file test.html' 

314 contents = textwrap.dedent('''\ 

315 @doc 

316 Unterminated @doc parts (not an error) 

317 ''') 

318 expected = textwrap.dedent('''\ 

319 <!--@+doc--> 

320 <!-- 

321 Unterminated @doc parts (not an error) 

322 --> 

323 ''') 

324 root.b = contents 

325 at.initWriteIvars(root) 

326 at.putBody(root) 

327 result = ''.join(at.outputList) 

328 self.assertEqual(result, expected) 

329 #@+node:ekr.20211104154501.1: *3* TestAtFile.test_putCodeLine 

330 def test_putCodeLine(self): 

331 

332 at, p = self.at, self.c.p 

333 at.initWriteIvars(p) 

334 at.startSentinelComment = '#' 

335 table = ( 

336 'Line without newline', 

337 'Line with newline', 

338 ' ', 

339 ) 

340 for line in table: 

341 at.putCodeLine(line, 0) 

342 #@+node:ekr.20211104161927.1: *3* TestAtFile.test_putDelims 

343 def test_putDelims(self): 

344 

345 at, p = self.at, self.c.p 

346 at.initWriteIvars(p) 

347 # Cover the missing code. 

348 directive = '@delims' 

349 s = ' @delims <! !>\n' 

350 at.putDelims(directive, s, 0) 

351 #@+node:ekr.20211104155139.1: *3* TestAtFile.test_putLeadInSentinel 

352 def test_putLeadInSentinel(self): 

353 

354 at, p = self.at, self.c.p 

355 at.initWriteIvars(p) 

356 # Cover the special case code. 

357 s = ' @others\n' 

358 at.putLeadInSentinel(s, 0, 2) 

359 #@+node:ekr.20211104142459.1: *3* TestAtFile.test_putLine 

360 def test_putLine(self): 

361 

362 at, p = self.at, self.c.p 

363 at.initWriteIvars(p) 

364 

365 class Status: # at.putBody defines the status class. 

366 at_comment_seen=False 

367 at_delims_seen=False 

368 at_warning_given=True # Always suppress warning messages. 

369 has_at_others=False 

370 in_code=True 

371 

372 # For now, test only the case that hasn't been covered: 

373 # kind == at.othersDirective and not status.in_code 

374 status = Status() 

375 status.in_code = False 

376 i, kind = 0, at.othersDirective 

377 s = 'A doc line\n' 

378 at.putLine(i, kind, p, s, status) 

379 

380 

381 #@+node:ekr.20211104163122.1: *3* TestAtFile.test_putRefLine 

382 def test_putRefLine(self): 

383 

384 at, p = self.at, self.c.p 

385 at.initWriteIvars(p) 

386 # Create one section definition node. 

387 name1 = g.angleBrackets('section 1') 

388 child1 = p.insertAsLastChild() 

389 child1.h = name1 

390 child1.b = "print('test_putRefLine')\n" 

391 # Create the valid section reference. 

392 s = f" {name1}\n" 

393 # Careful: init n2 and n2. 

394 name, n1, n2 = at.findSectionName(s, 0, p) 

395 self.assertTrue(name) 

396 at.putRefLine(s, 0, n1, n2, name, p) 

397 

398 

399 #@+node:ekr.20210905052021.24: *3* TestAtFile.test_remove 

400 def test_remove(self): 

401 

402 at = self.at 

403 exists = g.os_path_exists 

404 

405 path = g.os_path_join(g.app.testDir, 'xyzzy') 

406 if exists(path): 

407 os.remove(path) 

408 

409 assert not exists(path) 

410 assert not at.remove(path) 

411 

412 f = open(path, 'w') 

413 f.write('test') 

414 f.close() 

415 

416 assert exists(path) 

417 assert at.remove(path) 

418 assert not exists(path) 

419 #@+node:ekr.20210905052021.25: *3* TestAtFile.test_replaceFile_different_contents 

420 def test_replaceFile_different_contents(self): 

421 

422 at, c = self.at, self.c 

423 # Duplicate init logic... 

424 at.initCommonIvars() 

425 at.scanAllDirectives(c.p) 

426 encoding = 'utf-8' 

427 try: 

428 # https://stackoverflow.com/questions/23212435 

429 f = tempfile.NamedTemporaryFile(delete=False, encoding=encoding, mode='w') 

430 fn = f.name 

431 contents = 'test contents' 

432 val = at.replaceFile(contents, encoding, fn, at.root) 

433 assert val, val 

434 finally: 

435 f.close() 

436 os.unlink(f.name) 

437 #@+node:ekr.20210905052021.26: *3* TestAtFile.test_replaceFile_no_target_file 

438 def test_replaceFile_no_target_file(self): 

439 

440 at, c = self.at, self.c 

441 # Duplicate init logic... 

442 at.initCommonIvars() 

443 at.scanAllDirectives(c.p) 

444 encoding = 'utf-8' 

445 at.outputFileName = None # The point of this test, but I'm not sure it matters. 

446 try: 

447 # https://stackoverflow.com/questions/23212435 

448 f = tempfile.NamedTemporaryFile(delete=False, encoding=encoding, mode='w') 

449 fn = f.name 

450 contents = 'test contents' 

451 val = at.replaceFile(contents, encoding, fn, at.root) 

452 assert val, val 

453 finally: 

454 f.close() 

455 os.unlink(f.name) 

456 #@+node:ekr.20210905052021.27: *3* TestAtFile.test_replaceFile_same_contents 

457 def test_replaceFile_same_contents(self): 

458 

459 at, c = self.at, self.c 

460 # Duplicate init logic... 

461 at.initCommonIvars() 

462 at.scanAllDirectives(c.p) 

463 encoding = 'utf-8' 

464 try: 

465 # https://stackoverflow.com/questions/23212435 

466 f = tempfile.NamedTemporaryFile(delete=False, encoding=encoding, mode='w') 

467 fn = f.name 

468 contents = 'test contents' 

469 f.write(contents) 

470 f.flush() 

471 val = at.replaceFile(contents, encoding, fn, at.root) 

472 assert not val, val 

473 finally: 

474 f.close() 

475 os.unlink(f.name) 

476 #@+node:ekr.20210905052021.21: *3* TestAtFile.test_setPathUa 

477 def test_setPathUa(self): 

478 

479 at, p = self.at, self.c.p 

480 at.setPathUa(p, 'abc') 

481 d = p.v.tempAttributes 

482 d2 = d.get('read-path') 

483 val1 = d2.get('path') 

484 val2 = at.getPathUa(p) 

485 table = ( 

486 ('d2.get', val1), 

487 ('at.getPathUa', val2), 

488 ) 

489 for kind, val in table: 

490 self.assertEqual(val, 'abc', msg=kind) 

491 #@+node:ekr.20210901140645.14: *3* TestAtFile.test_tabNannyNode 

492 def test_tabNannyNode(self): 

493 

494 at, p = self.at, self.c.p 

495 # Test 1. 

496 s = textwrap.dedent("""\ 

497 # no error 

498 def spam(): 

499 pass 

500 """) 

501 at.tabNannyNode(p, body=s) 

502 # Test 2. 

503 s2 = textwrap.dedent("""\ 

504 # syntax error 

505 def spam: 

506 pass 

507 a = 2 

508 """) 

509 try: 

510 at.tabNannyNode(p, body=s2) 

511 except IndentationError: 

512 pass 

513 #@+node:ekr.20211104154115.1: *3* TestAtFile.test_validInAtOthers 

514 def test_validInAtOthers(self): 

515 

516 at, p = self.at, self.c.p 

517 

518 # Just test the last line. 

519 at.sentinels = False 

520 at.validInAtOthers(p) 

521 #@-others 

522#@+node:ekr.20211031085414.1: ** class TestFastAtRead(LeoUnitTest) 

523class TestFastAtRead(LeoUnitTest): 

524 """Test the FastAtRead class.""" 

525 

526 def setUp(self): 

527 super().setUp() 

528 self.x = leoAtFile.FastAtRead(self.c, gnx2vnode={}) 

529 

530 #@+others 

531 #@+node:ekr.20211104162514.1: *3* TestFast.test_afterref 

532 def test_afterref(self): 

533 

534 c, x = self.c, self.x 

535 h = '@file /test/test_afterLastRef.py' 

536 root = c.rootPosition() 

537 root.h = h # To match contents. 

538 #@+<< define contents >> 

539 #@+node:ekr.20211106112233.1: *4* << define contents >> 

540 # Be careful: no line should look like a Leo sentinel! 

541 contents = textwrap.dedent(f'''\ 

542 #AT+leo-ver=5-thin 

543 #AT+node:{root.gnx}: * {h} 

544 #AT@language python 

545  

546 a = 1 

547 if ( 

548 #AT+LB test >> 

549 #AT+node:ekr.20211107051401.1: ** LB test >> 

550 a == 2 

551 #AT-LB test >> 

552 #ATafterref 

553 ): 

554 a = 2 

555 #AT-leo 

556 ''').replace('AT', '@').replace('LB', '<<') 

557 #@-<< define contents >> 

558 #@+<< define expected_body >> 

559 #@+node:ekr.20211106115654.1: *4* << define expected_body >> 

560 expected_body = textwrap.dedent('''\ 

561 ATlanguage python 

562  

563 a = 1 

564 if ( 

565 LB test >> ): 

566 a = 2 

567 ''').replace('AT', '@').replace('LB', '<<') 

568 #@-<< define expected_body >> 

569 #@+<< define expected_contents >> 

570 #@+node:ekr.20211107053133.1: *4* << define expected_contents >> 

571 # Be careful: no line should look like a Leo sentinel! 

572 expected_contents = textwrap.dedent(f'''\ 

573 #AT+leo-ver=5-thin 

574 #AT+node:{root.gnx}: * {h} 

575 #AT@language python 

576  

577 a = 1 

578 if ( 

579 LB test >> ): 

580 a = 2 

581 #AT-leo 

582 ''').replace('AT', '@').replace('LB', '<<') 

583 #@-<< define expected_contents >> 

584 x.read_into_root(contents, path='test', root=root) 

585 self.assertEqual(root.b, expected_body, msg='mismatch in body') 

586 s = c.atFileCommands.atFileToString(root, sentinels=True) 

587 # Leo has *never* round-tripped the contents without change! 

588 ### g.printObj(s, tag='s') 

589 ### g.printObj(expected_contents, tag='expected_contents') 

590 self.assertEqual(s, expected_contents, msg='mismatch in contents') 

591 

592 #@+node:ekr.20211103093332.1: *3* TestFast.test_at_all 

593 def test_at_all(self): 

594 

595 c, x = self.c, self.x 

596 h = '@file /test/test_at_all.txt' 

597 root = c.rootPosition() 

598 root.h = h # To match contents. 

599 #@+<< define contents >> 

600 #@+node:ekr.20211103093424.1: *4* << define contents >> (test_at_all) 

601 # Be careful: no line should look like a Leo sentinel! 

602 contents = textwrap.dedent(f'''\ 

603 #AT+leo-ver=5-thin 

604 #AT+node:{root.gnx}: * {h} 

605 # This is Leo's final resting place for dead code. 

606 # Much easier to access than a git repo. 

607 

608 #AT@language python 

609 #AT@killbeautify 

610 #AT+all 

611 #AT+node:ekr.20211103093559.1: ** node 1 

612 Section references can be undefined. 

613 

614 LB missing reference >> 

615 #AT+node:ekr.20211103093633.1: ** node 2 

616 # ATothers doesn't matter 

617 

618 ATothers 

619 #AT-all 

620 #AT@nosearch 

621 #AT-leo 

622 ''').replace('AT', '@').replace('LB', '<<') 

623 #@-<< define contents >> 

624 x.read_into_root(contents, path='test', root=root) 

625 s = c.atFileCommands.atFileToString(root, sentinels=True) 

626 self.assertEqual(contents, s) 

627 #@+node:ekr.20211101085019.1: *3* TestFast.test_at_comment (and @first) 

628 def test_at_comment(self): 

629 

630 c, x = self.c, self.x 

631 h = '@file /test/test_at_comment.txt' 

632 root = c.rootPosition() 

633 root.h = h # To match contents. 

634 #@+<< define contents >> 

635 #@+node:ekr.20211101090447.1: *4* << define contents >> (test_at_comment) 

636 # Be careful: no line should look like a Leo sentinel! 

637 contents = textwrap.dedent(f'''\ 

638 !!! -*- coding: utf-8 -*- 

639 !!!AT+leo-ver=5-thin 

640 !!!AT+node:{root.gnx}: * {h} 

641 !!!AT@first 

642 

643 """Classes to read and write @file nodes.""" 

644 

645 !!!AT@comment !!! 

646 

647 !!!AT+LB test >> 

648 !!!AT+node:ekr.20211101090015.2: ** LB test >> 

649 print('in test section') 

650 print('done') 

651 !!!AT-LB test >> 

652 

653 !!!AT+others 

654 !!!AT+node:ekr.20211101090015.3: ** spam 

655 def spam(): 

656 pass 

657 !!!AT+node:ekr.20211101090015.4: ** eggs 

658 def eggs(): 

659 pass 

660 !!!AT-others 

661 

662 !!!AT@language plain 

663 !!!AT-leo 

664 ''').replace('AT', '@').replace('LB', '<<') 

665 #@-<< define contents >> 

666 x.read_into_root(contents, path='test', root=root) 

667 s = c.atFileCommands.atFileToString(root, sentinels=True) 

668 self.assertEqual(contents, s) 

669 child1 = root.firstChild() 

670 child2 = child1.next() 

671 child3 = child2.next() 

672 table = ( 

673 (child1, g.angleBrackets(' test ')), 

674 (child2, 'spam'), 

675 (child3, 'eggs'), 

676 ) 

677 for child, h in table: 

678 self.assertEqual(child.h, h) 

679 #@+node:ekr.20211101111636.1: *3* TestFast.test_at_delims 

680 def test_at_delims(self): 

681 c, x = self.c, self.x 

682 h = '@file /test/test_at_delims.txt' 

683 root = c.rootPosition() 

684 root.h = h # To match contents. 

685 #@+<< define contents >> 

686 #@+node:ekr.20211101111652.1: *4* << define contents >> (test_at_delims) 

687 # Be careful: no line should look like a Leo sentinel! 

688 contents = textwrap.dedent(f'''\ 

689 !! -*- coding: utf-8 -*- 

690 #AT+leo-ver=5-thin 

691 #AT+node:{root.gnx}: * {h} 

692 #AT@first 

693 

694 #ATdelims !!  

695 

696 !!AT+LB test >> 

697 !!AT+node:ekr.20211101111409.2: ** LB test >> 

698 print('in test section') 

699 print('done') 

700 !!AT-LB test >> 

701 

702 !!AT+others 

703 !!AT+node:ekr.20211101111409.3: ** spam 

704 def spam(): 

705 pass 

706 !!AT+node:ekr.20211101111409.4: ** eggs 

707 def eggs(): 

708 pass 

709 !!AT-others 

710 

711 !!AT@language python 

712 !!AT-leo 

713 ''').replace('AT', '@').replace('LB', '<<') 

714 #@-<< define contents >> 

715 x.read_into_root(contents, path='test', root=root) 

716 s = c.atFileCommands.atFileToString(root, sentinels=True) 

717 self.assertEqual(contents, s) 

718 child1 = root.firstChild() 

719 child2 = child1.next() 

720 child3 = child2.next() 

721 table = ( 

722 (child1, g.angleBrackets(' test ')), 

723 (child2, 'spam'), 

724 (child3, 'eggs'), 

725 ) 

726 for child, h in table: 

727 self.assertEqual(child.h, h) 

728 #@+node:ekr.20211103095616.1: *3* TestFast.test_at_last 

729 def test_at_last(self): 

730 

731 c, x = self.c, self.x 

732 h = '@file /test/test_at_last.py' 

733 root = c.rootPosition() 

734 root.h = h # To match contents. 

735 #@+<< define contents >> 

736 #@+node:ekr.20211103095959.1: *4* << define contents >> (test_at_last) 

737 # Be careful: no line should look like a Leo sentinel! 

738 contents = textwrap.dedent(f'''\ 

739 #AT+leo-ver=5-thin 

740 #AT+node:{root.gnx}: * {h} 

741 # Test of ATlast 

742 #AT+others 

743 #AT+node:ekr.20211103095810.1: ** spam 

744 def spam(): 

745 pass 

746 #AT-others 

747 #AT@language python 

748 #AT@last 

749 #AT-leo 

750 # last line 

751 ''').replace('AT', '@') 

752 #@-<< define contents >> 

753 #@+<< define expected_body >> 

754 #@+node:ekr.20211104052937.1: *4* << define expected_body >> (test_at_last) 

755 expected_body = textwrap.dedent('''\ 

756 # Test of ATlast 

757 ATothers 

758 ATlanguage python 

759 ATlast # last line 

760 ''').replace('AT', '@') 

761 #@-<< define expected_body >> 

762 x.read_into_root(contents, path='test', root=root) 

763 self.assertEqual(root.b, expected_body) 

764 s = c.atFileCommands.atFileToString(root, sentinels=True) 

765 self.assertEqual(contents, s) 

766 #@+node:ekr.20211103092228.1: *3* TestFast.test_at_others 

767 def test_at_others(self): 

768 

769 # In particular, we want to test indented @others. 

770 c, x = self.c, self.x 

771 h = '@file /test/test_at_others' 

772 root = c.rootPosition() 

773 root.h = h # To match contents. 

774 #@+<< define contents >> 

775 #@+node:ekr.20211103092228.2: *4* << define contents >> (test_at_others) 

776 # Be careful: no line should look like a Leo sentinel! 

777 contents = textwrap.dedent(f'''\ 

778 #AT+leo-ver=5-thin 

779 #AT+node:{root.gnx}: * {h} 

780 #AT@language python 

781 

782 class AtOthersTestClass: 

783 #AT+others 

784 #AT+node:ekr.20211103092443.1: ** method1 

785 def method1(self): 

786 pass 

787 #AT-others 

788 #AT-leo 

789 ''').replace('AT', '@').replace('LB', '<<') 

790 #@-<< define contents >> 

791 x.read_into_root(contents, path='test', root=root) 

792 s = c.atFileCommands.atFileToString(root, sentinels=True) 

793 self.assertEqual(contents, s) 

794 #@+node:ekr.20211031093209.1: *3* TestFast.test_at_section_delim 

795 def test_at_section_delim(self): 

796 

797 import sys 

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

799 self.skipTest('Requires Python 3.9') 

800 

801 c, x = self.c, self.x 

802 h = '@file /test/at_section_delim.py' 

803 root = c.rootPosition() 

804 root.h = h # To match contents. 

805 #@+<< define contents >> 

806 #@+node:ekr.20211101050923.1: *4* << define contents >> (test_at_section_delim) 

807 # The contents of a personal test file, slightly altered. 

808 contents = textwrap.dedent(f'''\ 

809 # -*- coding: utf-8 -*- 

810 #AT+leo-ver=5-thin 

811 #AT+node:{root.gnx}: * {h} 

812 #AT@first 

813 

814 """Classes to read and write @file nodes.""" 

815 

816 #AT@section-delims <!< >!> 

817 

818 #AT+<!< test >!> 

819 #AT+node:ekr.20211029054238.1: ** <!< test >!> 

820 print('in test section') 

821 print('done') 

822 #AT-<!< test >!> 

823 

824 #AT+others 

825 #AT+node:ekr.20211030052810.1: ** spam 

826 def spam(): 

827 pass 

828 #AT+node:ekr.20211030053502.1: ** eggs 

829 def eggs(): 

830 pass 

831 #AT-others 

832 

833 #AT@language python 

834 #AT-leo 

835 ''').replace('#AT', '#@') 

836 #@-<< define contents >> 

837 x.read_into_root(contents, path='test', root=root) 

838 s = c.atFileCommands.atFileToString(root, sentinels=True) 

839 self.assertEqual(contents, s) 

840 child1 = root.firstChild() 

841 child2 = child1.next() 

842 child3 = child2.next() 

843 table = ( 

844 (child1, '<!< test >!>'), 

845 (child2, 'spam'), 

846 (child3, 'eggs'), 

847 ) 

848 for child, h in table: 

849 self.assertEqual(child.h, h) 

850 #@+node:ekr.20211101155930.1: *3* TestFast.test_clones 

851 def test_clones(self): 

852 

853 c, x = self.c, self.x 

854 h = '@file /test/test_clones.py' 

855 root = c.rootPosition() 

856 root.h = h # To match contents. 

857 #@+<< define contents >> 

858 #@+node:ekr.20211101155930.2: *4* << define contents >> (test_clones) 

859 # Be careful: no line should look like a Leo sentinel! 

860 contents = textwrap.dedent(f'''\ 

861 #AT+leo-ver=5-thin 

862 #AT+node:{root.gnx}: * {h} 

863 #AT@language python 

864 

865 a = 1 

866 

867 #AT+others 

868 #AT+node:ekr.20211101152631.1: ** cloned node 

869 a = 2 

870 #AT+node:ekr.20211101153300.1: *3* child 

871 a = 3 

872 #AT+node:ekr.20211101152631.1: ** cloned node 

873 a = 2 

874 #AT+node:ekr.20211101153300.1: *3* child 

875 a = 3 

876 #AT-others 

877 #AT-leo 

878 ''').replace('AT', '@').replace('LB', '<<') 

879 #@-<< define contents >> 

880 x.read_into_root(contents, path='test', root=root) 

881 s = c.atFileCommands.atFileToString(root, sentinels=True) 

882 self.assertEqual(contents, s) 

883 child1 = root.firstChild() 

884 child2 = child1.next() 

885 grand_child1 = child1.firstChild() 

886 grand_child2 = child2.firstChild() 

887 table = ( 

888 (child1, 'cloned node'), 

889 (child2, 'cloned node'), 

890 (grand_child1, 'child'), 

891 (grand_child2, 'child'), 

892 ) 

893 for child, h in table: 

894 self.assertEqual(child.h, h) 

895 self.assertTrue(child1.isCloned()) 

896 self.assertTrue(child2.isCloned()) 

897 self.assertEqual(child1.v, child2.v) 

898 self.assertFalse(grand_child1.isCloned()) 

899 self.assertFalse(grand_child2.isCloned()) 

900 #@+node:ekr.20211103080718.1: *3* TestFast.test_cweb 

901 #@@language python 

902 

903 def test_cweb(self): 

904 

905 c, x = self.c, self.x 

906 h = '@file /test/test_cweb.w' 

907 root = c.rootPosition() 

908 root.h = h # To match contents. 

909 #@+<< define contents >> 

910 #@+node:ekr.20211103080718.2: *4* << define contents >> (test_cweb) 

911 # pylint: disable=anomalous-backslash-in-string 

912 contents = textwrap.dedent(f'''\ 

913 ATq@@+leo-ver=5-thin@> 

914 ATq@@+node:{root.gnx}: * @{h}@> 

915 ATq@@@@language cweb@> 

916 ATq@@@@comment @@q@@ @@>@> 

917  

918 % This is limbo in cweb mode... It should be in BSLaTeX mode, not BSc mode. 

919 % The following should not be colorized: class,if,else. 

920  

921 @* this is a _cweb_ comment. Code is written in BSc. 

922 "strings" should not be colorized. 

923 It should be colored in BSLaTeX mode. 

924 The following are not keywords in latex mode: if, else, etc. 

925 Section references are _valid_ in cweb comments! 

926 ATq@@+LB section ref 1 >>@> 

927 ATq@@+node:ekr.20211103082104.1: ** LB section ref 1 >>@> 

928 This is section 1. 

929 ATq@@-LB section ref 1 >>@> 

930 @c 

931  

932 and this is C code. // It is colored in BSLaTeX mode by default. 

933 /* This is a C block comment. It may also be colored in restricted BSLaTeX mode. */ 

934  

935 // Section refs are valid in code too, of course. 

936 ATq@@+LB section ref 2 >>@> 

937 ATq@@+node:ekr.20211103083538.1: ** LB section ref 2 >>@> 

938 This is section 2. 

939 ATq@@-LB section ref 2 >>@> 

940  

941 BSLaTeX and BSc should not be colored. 

942 if else, while, do // C keywords. 

943 ATq@@-leo@> 

944 ''').replace('AT', '@').replace('LB', '<<').replace('BS', '\\') 

945 #@-<< define contents >> 

946 x.read_into_root(contents, path='test', root=root) 

947 s = c.atFileCommands.atFileToString(root, sentinels=True) 

948 self.assertEqual(contents, s) 

949 #@+node:ekr.20211101152817.1: *3* TestFast.test_doc_parts 

950 def test_doc_parts(self): 

951 

952 c, x = self.c, self.x 

953 h = '@file /test/test_directives.py' 

954 root = c.rootPosition() 

955 root.h = h # To match contents. 

956 #@+<< define contents >> 

957 #@+node:ekr.20211101152843.1: *4* << define contents >> (test_doc_parts) 

958 # Be careful: no line should look like a Leo sentinel! 

959 contents = textwrap.dedent(f'''\ 

960 #AT+leo-ver=5-thin 

961 #AT+node:{root.gnx}: * {h} 

962 #AT@language python 

963 

964 a = 1 

965 

966 #AT+at A doc part 

967 # Line 2. 

968 #AT@c 

969 

970 #AT+doc 

971 # Line 2 

972 # 

973 # Line 3 

974 #AT@c 

975 

976 #AT-leo 

977 ''').replace('AT', '@').replace('LB', '<<') 

978 #@-<< define contents >> 

979 x.read_into_root(contents, path='test', root=root) 

980 s = c.atFileCommands.atFileToString(root, sentinels=True) 

981 self.assertEqual(contents, s) 

982 #@+node:ekr.20211101154632.1: *3* TestFast.test_html_doc_part 

983 def test_html_doc_part(self): 

984 

985 c, x = self.c, self.x 

986 h = '@file /test/test_html_doc_part.py' 

987 root = c.rootPosition() 

988 root.h = h # To match contents. 

989 #@+<< define contents >> 

990 #@+node:ekr.20211101154651.1: *4* << define contents >> (test_html_doc_part) 

991 # Be careful: no line should look like a Leo sentinel! 

992 contents = textwrap.dedent(f'''\ 

993 <!--AT+leo-ver=5-thin--> 

994 <!--AT+node:{root.gnx}: * {h}--> 

995 <!--AT@language html--> 

996 

997 <!--AT+at--> 

998 <!-- 

999 Line 1. 

1000 

1001 Line 2. 

1002 --> 

1003 <!--AT@c--> 

1004 <!--AT-leo--> 

1005 ''').replace('AT', '@').replace('LB', '<<') 

1006 #@-<< define contents >> 

1007 x.read_into_root(contents, path='test', root=root) 

1008 s = c.atFileCommands.atFileToString(root, sentinels=True) 

1009 self.assertEqual(contents, s) 

1010 #@+node:ekr.20211101180354.1: *3* TestFast.test_verbatim 

1011 def test_verbatim(self): 

1012 

1013 c, x = self.c, self.x 

1014 h = '@file /test/test_verbatim.py' 

1015 root = c.rootPosition() 

1016 root.h = h # To match contents. 

1017 #@+<< define contents >> 

1018 #@+node:ekr.20211101180404.1: *4* << define contents >> (test_verbatim) 

1019 # Be careful: no line should look like a Leo sentinel! 

1020 contents = textwrap.dedent(f'''\ 

1021 #AT+leo-ver=5-thin 

1022 #AT+node:{root.gnx}: * {h} 

1023 #AT@language python 

1024 # Test of @verbatim 

1025 print('hi') 

1026 #ATverbatim 

1027 #AT+node (should be protected by verbatim) 

1028 #AT-leo 

1029 ''').replace('AT', '@').replace('LB', '<<') 

1030 #@-<< define contents >> 

1031 #@+<< define expected_body >> 

1032 #@+node:ekr.20211106070035.1: *4* << define expected_body >> (test_verbatim) 

1033 expected_body = textwrap.dedent('''\ 

1034 ATlanguage python 

1035 # Test of @verbatim 

1036 print('hi') 

1037 #AT+node (should be protected by verbatim) 

1038 ''').replace('AT', '@') 

1039 #@-<< define expected_body >> 

1040 x.read_into_root(contents, path='test', root=root) 

1041 self.assertEqual(root.b, expected_body) 

1042 s = c.atFileCommands.atFileToString(root, sentinels=True) 

1043 self.assertEqual(contents, s) 

1044 #@-others 

1045#@-others 

1046#@-leo