diff options
Diffstat (limited to 'Tests/NorgKitTests/Parsers/NorgInlineParserTests.swift')
| -rw-r--r-- | Tests/NorgKitTests/Parsers/NorgInlineParserTests.swift | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/Tests/NorgKitTests/Parsers/NorgInlineParserTests.swift b/Tests/NorgKitTests/Parsers/NorgInlineParserTests.swift new file mode 100644 index 0000000..d59fc35 --- /dev/null +++ b/Tests/NorgKitTests/Parsers/NorgInlineParserTests.swift @@ -0,0 +1,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") + } +} |