krz/orgstar

A native macOS editor for org-mode files. editor org-mode swift

Tests/OrgCoreTests/ColumnViewTests.swift

3a3dedba062790e1580c66d38606eda4b02cb501
orgstar/Tests/OrgCoreTests/ColumnViewTests.swift history · blame · raw

86 lines · 3362 bytes

 1import Foundation
 2import Testing
 3@testable import OrgCore
 4
 5struct ColumnViewTests {
 6    static let oracle = ProcessInfo.processInfo.environment["ORGSTAR_SKIP_ORACLE"] == nil
 7
 8    static let text = """
 9        #+COLUMNS: %25ITEM %TODO %3PRIORITY %Effort{:} %Cost{+;%.1f} %Done{X/} %TAGS
10        * Project :work:
11        :PROPERTIES:
12        :Effort:   9:00
13        :END:
14        ** TODO [#A] Design <<target>> [1/2]
15        :PROPERTIES:
16        :Effort:   2:30
17        :Cost:     10
18        :Done:     [X]
19        :END:
20        ** DONE Build | it
21        DEADLINE: <2026-10-01 Thu> SCHEDULED: <2026-09-20 Sun>
22        :PROPERTIES:
23        :Effort:   1d
24        :Cost:     2.5
25        :Done:     [ ]
26        :END:
27        *** Sub task :home:
28        :PROPERTIES:
29        :Effort:   0:45
30        :END:
31        ** Archived :ARCHIVE:
32        :PROPERTIES:
33        :Effort:   5:00
34        :END:
35        * COMMENT Hidden
36        * Other
37        :PROPERTIES:
38        :COLUMNS:  %ITEM(Task) %SCHEDULED %DEADLINE %ALLTAGS %Cost{max} %Cost{mean}
39        :END:
40        ** One thing
41        :PROPERTIES:
42        :Cost:     4
43        :END:
44        ** Two things
45        SCHEDULED: <2026-11-01 Sun 10:00>
46        :PROPERTIES:
47        :Cost:     7
48        :END:
49        """ + "\n"
50
51    @Test(.enabled(if: oracle))
52    func writesColumnViewBlocksLikeOrg() throws {
53        let blocks = [
54            ("Project", "#+BEGIN: columnview :hlines 1 :id local\n#+END:\n"),
55            ("Other", "#+BEGIN: columnview :hlines 1 :id local\n#+END:\n"),
56            ("Project", "#+BEGIN: columnview :id global :indent t :hlines t\n#+END:\n"),
57            ("Project", "#+BEGIN: columnview :id local :maxlevel 2 :skip-empty-rows t :exclude-tags (\"home\")\n#+END:\n"),
58            ("Project", "#+BEGIN: columnview :id local :format \"%ITEM %Effort{:max} %Effort{:mean} %Cost{$}\"\n| x |\n#+TBLFM: $4=$4*2\n#+END:\n"),
59        ]
60        var cases: [EmacsOracle.Case] = []
61        var texts: [String] = []
62        for (heading, block) in blocks {
63            // The block goes under the heading's drawer.
64            let ns = Self.text as NSString
65            let start = ns.range(of: "* " + heading).location
66            let drawerEnd = ns.range(of: ":END:\n", range: NSRange(location: start, length: ns.length - start))
67            let at = NSMaxRange(drawerEnd)
68            let text = ns.replacingCharacters(in: NSRange(location: at, length: 0), with: block)
69            texts.append(text)
70            cases.append(EmacsOracle.Case(text: text, point: EmacsOracle.point(at, in: text), form: "(org-update-dblock)"))
71        }
72        let emacs = try EmacsOracle.run(cases)
73        for (i, text) in texts.enumerated() {
74            let at = Int(cases[i].point) - 1
75            let ours = runCommand(UpdateDynamicBlock(), text, caret: EmacsOracle.offset(at + 1, in: text))
76            #expect(ours.text == emacs[i].text, "\(blocks[i].1)\nours:\n\(ours.text)\n\(ours.failure ?? "")\nemacs:\n\(emacs[i].text)\n\(emacs[i].error)")
77        }
78    }
79
80    @Test func compilesFormats() {
81        let specs = ColumnView.compile("%25ITEM(Task) %Effort{:} %3PRIORITY %Cost{+;%.2f}")
82        #expect(specs.map(\.property) == ["ITEM", "EFFORT", "PRIORITY", "COST"])
83        #expect(specs[0].title == "Task" && specs[0].width == 25)
84        #expect(specs[3].summary == "+" && specs[3].format == "%.2f")
85    }
86}