1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
import Testing
@testable import NorgKit
struct NorgInlineParserTests {
private func span(_ spans: [InlineSpan], withText text: String) -> InlineSpan? {
spans.first { $0.text == text }
}
@Test func parsesBold() {
let spans = NorgInlineParser.parse("This is *bold*.")
#expect(spans.plainText == "This is bold.")
#expect(span(spans, withText: "bold")?.styles.contains(.bold) == true)
}
@Test func parsesMixedStyles() {
let spans = NorgInlineParser.parse("a /italic/ and _underline_ and -strike-")
#expect(span(spans, withText: "italic")?.styles.contains(.italic) == true)
#expect(span(spans, withText: "underline")?.styles.contains(.underline) == true)
#expect(span(spans, withText: "strike")?.styles.contains(.strikethrough) == true)
}
@Test func parsesNestedStyles() {
let spans = NorgInlineParser.parse("_under /italic/_")
let inner = span(spans, withText: "italic")
#expect(inner?.styles.contains(.italic) == true)
#expect(inner?.styles.contains(.underline) == true)
}
@Test func verbatimIsLiteral() {
let spans = NorgInlineParser.parse("a `b*c*d` e")
let verbatim = span(spans, withText: "b*c*d")
#expect(verbatim?.styles.contains(.verbatim) == true)
#expect(spans.plainText == "a b*c*d e")
}
@Test func dropsComments() {
let spans = NorgInlineParser.parse("visible %hidden% text")
#expect(!spans.plainText.contains("hidden"))
#expect(spans.plainText.contains("visible"))
#expect(spans.plainText.contains("text"))
}
@Test func escapesModifier() {
let spans = NorgInlineParser.parse("\\*not bold\\*")
#expect(spans.plainText == "*not bold*")
#expect(spans.allSatisfy { !$0.styles.contains(.bold) })
}
@Test func doesNotMatchMidWordHyphen() {
let spans = NorgInlineParser.parse("well-known value")
#expect(spans.plainText == "well-known value")
#expect(spans.allSatisfy { !$0.styles.contains(.strikethrough) })
}
@Test func parsesLinkWithDescription() {
let spans = NorgInlineParser.parse("see {https://example.com}[the site] now")
let link = span(spans, withText: "the site")
#expect(link?.link == InlineLink(kind: .link, target: "https://example.com"))
}
@Test func linkDescriptionIsLiteralNotPrefixStripped() {
// A `*`-prefixed description must not be mistaken for a location prefix.
let spans = NorgInlineParser.parse("{https://example.com}[* keep me]")
#expect(spans.first?.text == "* keep me")
#expect(spans.first?.link?.target == "https://example.com")
}
@Test func stripsLocationPrefixFromBareLink() {
let spans = NorgInlineParser.parse("{* Some Heading}")
#expect(spans.first?.text == "Some Heading")
#expect(spans.first?.link == InlineLink(kind: .link, target: "* Some Heading"))
}
@Test func parsesAnchorDefinition() {
let spans = NorgInlineParser.parse("[my label]{https://example.com}")
#expect(spans.first?.text == "my label")
#expect(spans.first?.link == InlineLink(kind: .anchor, target: "https://example.com"))
}
@Test func bareAnchorDeclarationHasNoInlineTarget() {
// `[Neorg]` references a target defined elsewhere; its target is unknown
// at the declaration site, so it must not echo the label as the target.
let spans = NorgInlineParser.parse("I like [Neorg] a lot")
let anchor = span(spans, withText: "Neorg")
#expect(anchor?.link == InlineLink(kind: .anchor, target: nil))
}
@Test func anchorDeclarationWithDescription() {
let spans = NorgInlineParser.parse("[anchor name][shown text]")
#expect(spans.first?.text == "shown text")
#expect(spans.first?.link == InlineLink(kind: .anchor, target: nil))
}
@Test func unterminatedModifierIsLiteral() {
let spans = NorgInlineParser.parse("a * b c")
#expect(spans.plainText == "a * b c")
}
@Test func unterminatedAttachedModifierWithOpenerIsLiteral() {
// A valid opener (`*` followed by non-space) with no closing modifier
// falls through to plain text rather than styling the rest of the line.
let spans = NorgInlineParser.parse("*bold but never closed")
#expect(spans.plainText == "*bold but never closed")
#expect(spans.allSatisfy { !$0.styles.contains(.bold) })
}
@Test func unterminatedVerbatimIsLiteral() {
let spans = NorgInlineParser.parse("a `b c d")
#expect(spans.plainText == "a `b c d")
#expect(spans.allSatisfy { !$0.styles.contains(.verbatim) })
}
@Test func unmatchedLinkBraceIsLiteral() {
let spans = NorgInlineParser.parse("see {never closed here")
#expect(spans.plainText == "see {never closed here")
#expect(spans.allSatisfy { $0.link == nil })
}
@Test func unmatchedAnchorBracketIsLiteral() {
let spans = NorgInlineParser.parse("see [never closed here")
#expect(spans.plainText == "see [never closed here")
#expect(spans.allSatisfy { $0.link == nil })
}
@Test func stripsFileSpecifierAndLocationPrefixFromBareLink() {
// `{:path:* Heading}` carries a `:file:` specifier before the location
// prefix; both are stripped to derive the display label.
let spans = NorgInlineParser.parse("{:notes.norg:* Some Heading}")
#expect(spans.first?.text == "Some Heading")
#expect(spans.first?.link == InlineLink(kind: .link, target: ":notes.norg:* Some Heading"))
}
@Test func plainTextHelperReturnsUnstyledText() {
// Exercises the static plainText(_:) entry used by the task scanner.
#expect(NorgInlineParser.plainText("just *bold* here") == "just bold here")
#expect(NorgInlineParser.plainText("") == "")
#expect(NorgInlineParser.plainText("no markup at all") == "no markup at all")
}
}
|