krz/orgstar

A native macOS editor for org-mode files. editor org-mode swift

Tests/OrgCoreTests/ParserSectionTests.swift

2fa201330f61c801f777baa3f2943d49d8758cda
orgstar/Tests/OrgCoreTests/ParserSectionTests.swift history · blame · raw

73 lines · 3170 bytes

 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}