diff options
| author | Ruben Beltran del Rio <jj@r.bdr.sh> | 2026-06-15 14:35:36 +0200 |
|---|---|---|
| committer | Ruben Beltran del Rio <jj@r.bdr.sh> | 2026-06-16 14:47:30 +0200 |
| commit | 657aa83a5ca24dc35572c040df64a0abb85e8612 (patch) | |
| tree | fe0b6fd425d8cad9dc6a28ada4ad8600e42b367e /Tests | |
Initial extraction from Norganize
Diffstat (limited to 'Tests')
| -rw-r--r-- | Tests/NorgUITests/InlineTextTests.swift | 79 | ||||
| -rw-r--r-- | Tests/NorgUITests/NorgLinkURLTests.swift | 30 | ||||
| -rw-r--r-- | Tests/NorgUITests/NorgThemeTests.swift | 35 | ||||
| -rw-r--r-- | Tests/NorgUITests/OrdinalTests.swift | 38 | ||||
| -rw-r--r-- | Tests/NorgUITests/RenderingSmokeTests.swift | 51 | ||||
| -rw-r--r-- | Tests/NorgUITests/TaskStatusUITests.swift | 29 |
6 files changed, 262 insertions, 0 deletions
diff --git a/Tests/NorgUITests/InlineTextTests.swift b/Tests/NorgUITests/InlineTextTests.swift new file mode 100644 index 0000000..c2c6537 --- /dev/null +++ b/Tests/NorgUITests/InlineTextTests.swift @@ -0,0 +1,79 @@ +import NorgKit +import SwiftUI +import Testing + +@testable import NorgUI + +@Suite struct InlineTextTests { + @Test func plainSpanCarriesText() { + let attributed = AttributedString(norg: [InlineSpan(text: "hello")]) + #expect(String(attributed.characters) == "hello") + } + + @Test func multipleSpansConcatenate() { + let attributed = AttributedString(norg: [ + InlineSpan(text: "foo"), + InlineSpan(text: "bar"), + ]) + #expect(String(attributed.characters) == "foobar") + } + + @Test func verbatimUsesThemeColor() { + let attributed = AttributedString(norg: [InlineSpan(text: "x", styles: .verbatim)]) + let run = attributed.runs.first + #expect(run?.foregroundColor == NorgTheme.default.verbatimColor) + } + + @Test func spoilerAppliesForegroundAndBackground() { + let attributed = AttributedString(norg: [InlineSpan(text: "x", styles: .spoiler)]) + let run = attributed.runs.first + #expect(run?.foregroundColor == NorgTheme.default.spoilerForeground) + #expect(run?.backgroundColor == NorgTheme.default.spoilerBackground) + } + + @Test func superscriptUsesThemeOffset() { + let attributed = AttributedString(norg: [InlineSpan(text: "x", styles: .superscript)]) + #expect(attributed.runs.first?.baselineOffset == NorgTheme.default.superscriptOffset) + } + + @Test func subscriptUsesThemeOffset() { + let attributed = AttributedString(norg: [InlineSpan(text: "x", styles: .subscript)]) + #expect(attributed.runs.first?.baselineOffset == NorgTheme.default.subscriptOffset) + } + + @Test func externalLinkBecomesTappable() { + let attributed = AttributedString(norg: [ + InlineSpan(text: "site", link: InlineLink(kind: .link, target: "https://example.com")) + ]) + let run = attributed.runs.first + #expect(run?.link == URL(string: "https://example.com")) + #expect(run?.foregroundColor == NorgTheme.default.linkColor) + } + + @Test func internalLinkIsEncodedForRouting() { + let attributed = AttributedString(norg: [ + InlineSpan(text: "note", link: InlineLink(kind: .link, target: "* Some heading")) + ]) + let run = attributed.runs.first + let decoded = run?.link.flatMap(NorgLinkURL.decode) + #expect(decoded == InlineLink(kind: .link, target: "* Some heading")) + #expect(run?.foregroundColor == NorgTheme.default.linkColor) + } + + @Test func anchorIsEncodedForRouting() { + let attributed = AttributedString(norg: [ + InlineSpan(text: "ref", link: InlineLink(kind: .anchor, target: "footnote")) + ]) + let run = attributed.runs.first + let decoded = run?.link.flatMap(NorgLinkURL.decode) + #expect(decoded == InlineLink(kind: .anchor, target: "footnote")) + } + + @Test func customThemeOverridesColors() { + var theme = NorgTheme.default + theme.verbatimColor = .orange + let attributed = AttributedString( + norg: [InlineSpan(text: "x", styles: .verbatim)], theme: theme) + #expect(attributed.runs.first?.foregroundColor == .orange) + } +} diff --git a/Tests/NorgUITests/NorgLinkURLTests.swift b/Tests/NorgUITests/NorgLinkURLTests.swift new file mode 100644 index 0000000..dcd5446 --- /dev/null +++ b/Tests/NorgUITests/NorgLinkURLTests.swift @@ -0,0 +1,30 @@ +import Foundation +import NorgKit +import Testing + +@testable import NorgUI + +@Suite struct NorgLinkURLTests { + @Test func roundTripsLink() throws { + let link = InlineLink(kind: .link, target: "* My Heading") + let url = try #require(NorgLinkURL.encode(link)) + #expect(NorgLinkURL.decode(url) == link) + } + + @Test func roundTripsAnchor() throws { + let link = InlineLink(kind: .anchor, target: "some anchor") + let url = try #require(NorgLinkURL.encode(link)) + #expect(NorgLinkURL.decode(url) == link) + } + + @Test func roundTripsMissingTarget() throws { + let link = InlineLink(kind: .link, target: nil) + let url = try #require(NorgLinkURL.encode(link)) + #expect(NorgLinkURL.decode(url) == link) + } + + @Test func ignoresForeignURLs() throws { + let url = try #require(URL(string: "https://example.com")) + #expect(NorgLinkURL.decode(url) == nil) + } +} diff --git a/Tests/NorgUITests/NorgThemeTests.swift b/Tests/NorgUITests/NorgThemeTests.swift new file mode 100644 index 0000000..a621d90 --- /dev/null +++ b/Tests/NorgUITests/NorgThemeTests.swift @@ -0,0 +1,35 @@ +import NorgKit +import SwiftUI +import Testing + +@testable import NorgUI + +@Suite struct NorgThemeTests { + @Test func defaultStatusTints() { + let theme = NorgTheme.default + #expect(theme.statusTint(.done) == .green) + #expect(theme.statusTint(.urgent) == .red) + #expect(theme.statusTint(.pending) == .blue) + #expect(theme.statusTint(.undone) == .secondary) + #expect(theme.statusTint(.cancelled) == .secondary) + #expect(theme.statusTint(.onHold) == .secondary) + } + + @Test func defaultScalarValues() { + let theme = NorgTheme.default + #expect(theme.superscriptOffset == 5) + #expect(theme.subscriptOffset == -3) + #expect(theme.indentWidth == 18) + #expect(theme.linkColor == .accentColor) + #expect(theme.verbatimColor == .pink) + } + + @Test func defaultStatusSymbols() { + let theme = NorgTheme.default + #expect(theme.statusSymbol(.undone) == "circle") + #expect(theme.statusSymbol(.done) == "checkmark.circle.fill") + for status in TaskStatus.allCases { + #expect(!theme.statusSymbol(status).isEmpty) + } + } +} diff --git a/Tests/NorgUITests/OrdinalTests.swift b/Tests/NorgUITests/OrdinalTests.swift new file mode 100644 index 0000000..954477c --- /dev/null +++ b/Tests/NorgUITests/OrdinalTests.swift @@ -0,0 +1,38 @@ +import NorgKit +import Testing + +@testable import NorgUI + +@Suite struct OrdinalTests { + private func ordered(_ level: Int) -> NorgBlock { + .orderedListItem(level: level, status: nil, content: [], line: 0) + } + private func unordered(_ level: Int) -> NorgBlock { + .unorderedListItem(level: level, status: nil, content: [], line: 0) + } + private var paragraph: NorgBlock { .paragraph(content: [], line: 0) } + + @Test func numbersConsecutiveItems() { + #expect(orderedOrdinals([ordered(1), ordered(1), ordered(1)]) == [1, 2, 3]) + } + + @Test func countsEachLevelIndependently() { + let blocks = [ordered(1), ordered(2), ordered(2), ordered(1)] + #expect(orderedOrdinals(blocks) == [1, 1, 2, 2]) + } + + @Test func paragraphResetsNumbering() { + let blocks = [ordered(1), paragraph, ordered(1)] + #expect(orderedOrdinals(blocks) == [1, nil, 1]) + } + + @Test func unorderedItemInterruptsNumbering() { + let blocks = [ordered(1), unordered(1), ordered(1)] + #expect(orderedOrdinals(blocks) == [1, nil, 1]) + } + + @Test func siblingOrdinalsNumberOrderedNodesOnly() { + let nodes = [ordered(1), unordered(1), ordered(1), paragraph].map { NorgNode(block: $0) } + #expect(ordinals(forSiblings: nodes) == [1, nil, 2, nil]) + } +} diff --git a/Tests/NorgUITests/RenderingSmokeTests.swift b/Tests/NorgUITests/RenderingSmokeTests.swift new file mode 100644 index 0000000..39c9eb5 --- /dev/null +++ b/Tests/NorgUITests/RenderingSmokeTests.swift @@ -0,0 +1,51 @@ +import NorgKit +import Testing + +@testable import NorgUI + +@Suite struct RenderingSmokeTests { + @Test func rangeableBlockExposesBodyForRecursion() { + let doc = NorgParser.parse("$ Norg\nA structured note format.") + guard case .definition(_, _, let body, _) = doc.blocks.first else { + Issue.record("Expected a definition") + return + } + #expect(!body.isEmpty) + } + + @Test func headingNestsContentAsTreeChildren() { + let nodes = NorgParser.parse("* Title\nbody text below").tree() + guard let heading = nodes.first, case .heading = heading.block else { + Issue.record("Expected a heading root") + return + } + #expect(!heading.children.isEmpty) + } + + @Test func nestedListNestsAsTreeChildren() { + let nodes = NorgParser.parse("- one\n-- nested").tree() + guard let item = nodes.first else { + Issue.record("Expected a list item") + return + } + #expect(item.children.count == 1) + } + + @Test func nonCodeRangedTagIsRouted() { + let doc = NorgParser.parse("@math\nx^2 + y^2 = z^2\n@end") + guard case .rangedTag(let name, _, _, _) = doc.blocks.first else { + Issue.record("Expected a ranged tag") + return + } + #expect(name == ["math"]) + } + + @Test func codeFenceBecomesCodeBlock() { + let doc = NorgParser.parse("@code swift\nlet x = 1\n@end") + guard case .codeBlock(let language, _, _) = doc.blocks.first else { + Issue.record("Expected a code block") + return + } + #expect(language == "swift") + } +} diff --git a/Tests/NorgUITests/TaskStatusUITests.swift b/Tests/NorgUITests/TaskStatusUITests.swift new file mode 100644 index 0000000..0b5dd53 --- /dev/null +++ b/Tests/NorgUITests/TaskStatusUITests.swift @@ -0,0 +1,29 @@ +import Foundation +import NorgKit +import Testing + +@testable import NorgUI + +@Suite struct TaskStatusUITests { + private func resolved(_ status: TaskStatus) -> String { + String(localized: status.displayName) + } + + @Test func everyStatusHasADisplayName() { + for status in TaskStatus.allCases { + #expect(!resolved(status).isEmpty) + } + } + + @Test func displayNamesAreDistinct() { + let names = Set(TaskStatus.allCases.map(resolved)) + #expect(names.count == TaskStatus.allCases.count) + } + + @Test func themeStatusLabelDefaultsToDisplayName() { + let theme = NorgTheme.default + for status in TaskStatus.allCases { + #expect(String(localized: theme.statusLabel(status)) == resolved(status)) + } + } +} |