krz/orgstar

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

Tests/OrgCoreTests/DiarySexpTests.swift

778058aafc7ddacee4a613b1da87c60aa0c8e113
orgstar/Tests/OrgCoreTests/DiarySexpTests.swift history · blame · raw

74 lines · 3664 bytes

 1import Foundation
 2import Testing
 3@testable import OrgCore
 4
 5/// Diary sexps in the agenda (`org-agenda-get-sexps`, diary timestamps and planning).
 6struct DiarySexpTests {
 7    static let oracle = ProcessInfo.processInfo.environment["ORGSTAR_SKIP_ORACLE"] == nil
 8
 9    static let file = """
10        #+FILETAGS: :ft:
11        * Holidays :hol:
12        %%(diary-float t 4 4) Fourth Thursday
13        %%(diary-anniversary 10 7 1990) Birthday %d%s
14        %%(org-anniversary 2000 10 8) Org %d years
15        %%(diary-anniversary 2 29 2000) Leap %d
16        %%(diary-block 10 5 2026 10 7 2026) Conference
17        %%(diary-cyclic 3 10 1 2026) Every third, %d%s time
18        %%(diary-date t 6 t) Sixth of month
19        %%(diary-date '(10 11) '(5 9) 2026) List date
20        %%(diary-remind '(diary-date 10 9 2026) 2) Remind me
21        %%(diary-remind '(diary-date 10 12 2026) -3) Remind range
22        %%(diary-remind '(diary-anniversary 10 14 2000) 7) Week ahead %d
23        %%(org-class 2026 9 1 2026 12 20 2 41) Class on Tuesdays
24        %%(org-block 2026 10 6 2026 10 6) Meeting at 10:30
25        %%(memq (calendar-day-of-week date) '(1 3 5)) Gym
26        %%(and (= (calendar-extract-day date) 2) "Custom; second part")
27        %%(let ((d (calendar-extract-day date))) (when (= (% d 5) 0) (format "Day %d is a fifth" d)))
28        %%(diary-float 10 1 -1) Last Monday of October
29        %%(diary-float t 0 1 8) First Sunday after the 8th
30        %%(diary-date 10 8 2026)
31        &%%(diary-date 10 9 2026) Ampersand  
32        * TODO Task with a diary stamp <%%(diary-float t 2 1)>
33        * Meeting
34          <%%(diary-date t 7 t) 14:00>
35        * Due
36          DEADLINE: <%%(diary-date 10 8 2026)>
37        * Sched
38          SCHEDULED: <%%(diary-float t 5 1)>
39        * COMMENT Skipped tree
40        %%(diary-date t t t) Never shown
41        """ + "\n"
42
43    @Test func evaluatesDiaryFunctions() throws {
44        let day = Days.absolute(year: 2026, month: 10, day: 7)
45        func run(_ text: String, _ entry: String = "E") throws -> [String]? {
46            DiarySexp.entries(try LispReader.readFirst(text).sexp, entry: entry, day: day)
47        }
48        #expect(try run("(diary-anniversary 10 7 1990)", "%d%s") == ["36th"])
49        #expect(try run("(diary-date 10 8 2026)") == nil)
50        #expect(try run("(diary-float 10 3 1)") == ["E"])
51        #expect(try run("\"a; b\"") == ["a", "b"])
52        #expect(try run("(undefined)") == nil)
53        #expect(try run("(diary-ordinal-suffix -3)") == nil)
54    }
55
56    @Test func skipsSexpsBeforeTheFirstHeading() {
57        let source = AgendaSource(path: "a.org", text: "%%(diary-date t t t) Before\n* H\n%%(diary-date t t t) Under\n")
58        let day = Days.absolute(year: 2026, month: 10, day: 7)
59        #expect(Agenda.list([source], start: day, days: 1, today: day, now: (9, 0))[0].items.map(\.text) == ["Under"])
60    }
61
62    @Test(.enabled(if: oracle))
63    func agendaMatchesEmacs() throws {
64        let files = [("diary.org", Self.file)]
65        let october = Days.absolute(year: 2026, month: 10, day: 1)
66        let ours = Agenda.list([AgendaSource(path: "diary.org", text: Self.file)], start: october, days: 15, today: october + 4, now: (9, 30))
67        let kinds = Set(ours.flatMap(\.items).map(\.kind))
68        #expect(kinds.isSuperset(of: [.sexp, .timestamp, .deadline, .pastScheduled]))
69        try AgendaOracle.compare(files: files, start: october, span: 15, today: october + 4)
70        try AgendaOracle.compare(files: files, start: october + 20, span: 10, today: october + 26)
71        let leap = Days.absolute(year: 2027, month: 2, day: 27)
72        try AgendaOracle.compare(files: files, start: leap, span: 4, today: leap)
73    }
74}