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") } }