Tests/OrgCoreTests/ParserSectionTests.swift
73 lines · 3170 bytes
13 symbols in this file
1import Testing
2@testable import OrgCore
3
4func nodeKinds(_ text: String) -> [SyntaxKind] {
5 OrgParser.parse(text).root.descendants().map(\.kind)
6}
7
8func tokens(of kind: SyntaxKind, in text: String) -> [SyntaxToken] {
9 OrgParser.parse(text).root.descendants().filter { $0.kind == kind }.flatMap(\.tokens)
10}
11
12struct ParserSectionTests {
13 @Test func emptyDocument() {
14 let tree = OrgParser.parse("")
15 #expect(tree.text == "")
16 #expect(nodeKinds("") == [.document])
17 }
18
19 @Test func zerothSectionHoldsPreamble() {
20 #expect(nodeKinds("text\n* a\n") == [.document, .zerothSection, .paragraph, .section, .heading, .title])
21 }
22
23 @Test func sectionsNestByLevel() {
24 let text = "* a\n** b\n*** c\n** d\n* e\n"
25 let root = OrgParser.parse(text).root
26 let top = root.children
27 #expect(top.map(\.kind) == [.section, .section])
28 #expect(top[0].children.map(\.kind) == [.heading, .section, .section])
29 #expect(top[0].children[1].children.map(\.kind) == [.heading, .section])
30 }
31
32 @Test func headingTokens() {
33 let text = "** TODO [#A] Write the plan :work:urgent: \n"
34 let parts = tokens(of: .heading, in: text)
35 #expect(parts.map(\.kind) == [.stars, .whitespace, .todoKeyword, .whitespace, .priority, .whitespace, .whitespace, .tags, .whitespace, .newline])
36 #expect(parts.first { $0.kind == .tags }?.text == ":work:urgent:")
37 #expect(OrgParser.parse(text).root.descendants().first { $0.kind == .title }?.text == "Write the plan")
38 }
39
40 @Test func todoKeywordsComeFromSettings() {
41 let text = "#+TODO: NEXT | DONE\n* NEXT a\n* TODO b\n"
42 let todo = tokens(of: .heading, in: text).filter { $0.kind == .todoKeyword }.map(\.text)
43 #expect(todo == ["NEXT"])
44 }
45
46 @Test func todoKeywordNeedsASpaceAfterIt() {
47 #expect(tokens(of: .heading, in: "* TODO a\n").contains { $0.kind == .todoKeyword })
48 #expect(tokens(of: .heading, in: "* TODO\n").contains { $0.kind == .todoKeyword })
49 #expect(!tokens(of: .heading, in: "* TODO\ta\n").contains { $0.kind == .todoKeyword })
50 }
51
52 @Test func priorityNeedsValidValueAndSpace() {
53 #expect(tokens(of: .heading, in: "* [#B] x\n").contains { $0.kind == .priority })
54 #expect(tokens(of: .heading, in: "* [#10] x\n").contains { $0.kind == .priority })
55 #expect(!tokens(of: .heading, in: "* [#AB] x\n").contains { $0.kind == .priority })
56 #expect(!tokens(of: .heading, in: "* [#A]x\n").contains { $0.kind == .priority })
57 }
58
59 @Test func tagsNeedValidCharacters() {
60 #expect(tokens(of: .heading, in: "* a :b@c_1:\n").contains { $0.kind == .tags })
61 #expect(!tokens(of: .heading, in: "* a :b c:\n").contains { $0.kind == .tags })
62 #expect(!tokens(of: .heading, in: "* a :b:c\n").contains { $0.kind == .tags })
63 }
64
65 @Test func headingWithoutNewlineAtEnd() {
66 #expect(OrgParser.parse("* a").text == "* a")
67 }
68
69 @Test(arguments: ["* a\n", "*\n", "* TODO\n", "text\r\n* a\r\n** b\r\n", "\n\n* a\n\n"])
70 func roundTrip(text: String) {
71 #expect(OrgParser.parse(text).text == text)
72 }
73}