Tests/OrgCoreTests/InlineTests.swift
89 lines · 4467 bytes
1import Testing
2@testable import OrgCore
3
4/// `kind:text` for each object directly inside the first paragraph.
5func objects(_ text: String) -> [String] {
6 let paragraph = OrgParser.parse(text).root.descendants().first { $0.kind == .paragraph }!
7 return paragraph.children.map { "\($0.kind.rawValue):\($0.text)" }
8}
9
10struct InlineTests {
11 @Test(arguments: [
12 ("*b* /i/ _u_ +s+ =v= ~c~", ["bold:*b*", "italic:/i/", "underline:_u_", "strikeThrough:+s+", "verbatim:=v=", "code:~c~"]),
13 ("a*b* (*c*) \"*d*\"", ["bold:*c*", "bold:*d*"]),
14 ("x *y * z", []),
15 ("*y*z", []),
16 ("*a\nb*", ["bold:*a\nb*"]),
17 ("*a\nb\nc*", []),
18 ("=*not bold*=", ["verbatim:=*not bold*="]),
19 ("[[https://a.b][the *site*]]", ["link:[[https://a.b][the *site*]]"]),
20 ("[[file:x.org]]", ["link:[[file:x.org]]"]),
21 ("<https://a.b/c>", ["link:<https://a.b/c>"]),
22 ("see https://a.b/c.", ["link:https://a.b/c"]),
23 ("<2026-10-04 Sun 10:00-11:30 +1w -2d>", ["timestamp:<2026-10-04 Sun 10:00-11:30 +1w -2d>"]),
24 ("[2026-10-04 Sun]--[2026-10-06 Tue]", ["timestamp:[2026-10-04 Sun]--[2026-10-06 Tue]"]),
25 ("a [fn:1] and [fn::inline [x] note]", ["footnoteReference:[fn:1]", "footnoteReference:[fn::inline [x] note]"]),
26 ("a [1/3] [50%]", ["statisticsCookie:[1/3]", "statisticsCookie:[50%]"]),
27 ("a <<target>> {{{m(x, y)}}}", ["target:<<target>>", "macro:{{{m(x, y)}}}"]),
28 ("\\(x^2\\) and src_sh[:results raw]{echo {a}}", ["latexFragment:\\(x^2\\)", "inlineSourceBlock:src_sh[:results raw]{echo {a}}"]),
29 ("N^2 and e^{i}", ["superscript:^2", "superscript:^{i}"]),
30 ("end\\\\\nnext", ["lineBreak:\\\\"]),
31 ])
32 func recognizes(text: String, expected: [String]) {
33 #expect(objects(text) == expected)
34 }
35
36 @Test func emphasisNests() {
37 let bold = OrgParser.parse("*bold /italic/ x*\n").root.descendants().first { $0.kind == .bold }!
38 #expect(bold.children.map(\.kind) == [.italic])
39 #expect(bold.tokens.first?.kind == .marker)
40 }
41
42 @Test func linkParts() {
43 let link = OrgParser.parse("[[id:abc][desc]]\n").root.descendants().first { $0.kind == .link }!
44 #expect(link.tokens.map(\.kind) == [.marker, .linkPath, .marker, .marker])
45 #expect(link.tokens.first { $0.kind == .linkPath }?.text == "id:abc")
46 #expect(link.children.map(\.kind) == [.linkDescription])
47 }
48
49 @Test func noLinksInsideLinkDescriptions() {
50 let link = OrgParser.parse("[[a][see https://b.c]]\n").root.descendants().first { $0.kind == .link }!
51 #expect(link.descendants().filter { $0.kind == .link }.count == 1)
52 }
53
54 @Test func headingTitlesHoldObjects() {
55 let title = OrgParser.parse("* TODO Read [[https://a.b][it]] [1/2]\n").root.descendants().first { $0.kind == .title }!
56 #expect(title.children.map(\.kind) == [.link, .statisticsCookie])
57 }
58
59 @Test func planningHoldsTimestamps() {
60 let planning = OrgParser.parse("* a\nDEADLINE: <2026-10-04 Sun -2d> SCHEDULED: <2026-10-01 Thu>\n").root
61 .descendants().first { $0.kind == .planning }!
62 #expect(planning.children.map(\.kind) == [.timestamp, .timestamp])
63 }
64
65 @Test func itemsSplitBulletAndCheckbox() {
66 let item = OrgParser.parse(" - [X] done *now*\n more\n").root.descendants().first { $0.kind == .item }!
67 #expect(item.tokens.map(\.kind) == [.whitespace, .bullet, .whitespace, .checkbox, .whitespace])
68 #expect(item.children.map(\.kind) == [.paragraph])
69 #expect(item.children[0].text == "done *now*\n more\n")
70 }
71
72 @Test func emptyItem() {
73 let item = OrgParser.parse("-\n").root.descendants().first { $0.kind == .item }!
74 #expect(item.tokens.map(\.kind) == [.bullet, .newline])
75 }
76
77 @Test func tableCells() {
78 let rows = OrgParser.parse("| *a* || b\n|---+---|\n").root.descendants().filter { $0.kind == .tableRow }
79 #expect(rows[0].children.map(\.text) == [" *a* ", "", " b"])
80 #expect(rows[0].children[0].children.map(\.kind) == [.bold])
81 #expect(rows[1].children.isEmpty)
82 }
83
84 @Test func footnoteDefinitionLabelIsNotAReference() {
85 let definition = OrgParser.parse("[fn:1] see [fn:2]\n").root.descendants().first { $0.kind == .footnoteDefinition }!
86 #expect(definition.tokens.first?.text == "[fn:1]")
87 #expect(definition.children.map(\.kind) == [.footnoteReference])
88 }
89}