Tests/OrgCoreTests/SparseTreeTests.swift
78 lines · 3962 bytes
1import Foundation
2import Testing
3@testable import OrgCore
4
5struct SparseTreeTests {
6 static let oracle = ProcessInfo.processInfo.environment["ORGSTAR_SKIP_ORACLE"] == nil
7 static let seconds = 1_789_000_000
8
9 static let text = """
10 Preamble text
11 * TODO Alpha :work:
12 alpha body with foo
13 ** DONE Beta
14 beta body
15 ** TODO Gamma :home:
16 DEADLINE: <2026-09-15 Tue>
17 gamma Foo
18 *** Delta
19 SCHEDULED: <2026-09-01 Tue>
20 delta
21 **** Deep
22 deep text
23 * Epsilon :ARCHIVE:
24 ** Zeta foo
25 * DONE Eta
26 DEADLINE: <2026-08-01 Sat>
27 * Theta
28 SCHEDULED: <2026-10-01 Thu 10:00>
29 theta
30
31 * TODO Iota
32 DEADLINE: <2026-11-30 Mon>
33 """ + "\n"
34
35 @Test(.enabled(if: oracle))
36 func buildsSparseTreesLikeOrg() throws {
37 var utc = Calendar(identifier: .gregorian)
38 utc.timeZone = TimeZone(identifier: "UTC")!
39 let now = Date(timeIntervalSince1970: Double(Self.seconds))
40 let tree = OrgParser.parse(Self.text)
41 let cases: [(String, SparseTree.Matches)] = [
42 ("(org-occur \"foo\")", try SparseTree.occur("foo", in: Self.text)),
43 ("(org-occur \"^\\\\*+ .*a$\")", try SparseTree.occur("^\\*+ .*a$", in: Self.text)),
44 ("(org-show-todo-tree nil)", SparseTree.todo(nil, in: Self.text, settings: tree.settings)),
45 ("(org-match-sparse-tree nil \"home|work\")", SparseTree.match("home|work", in: Self.text, now: now, calendar: utc)),
46 ("(org-match-sparse-tree nil \"LEVEL>2\")", SparseTree.match("LEVEL>2", in: Self.text, now: now, calendar: utc)),
47 ("(org-check-deadlines nil)", SparseTree.deadlines(within: 14, in: Self.text, settings: tree.settings, now: now, calendar: utc)),
48 ("(org-check-before-date \"2026-09-20\")", SparseTree.planning(from: nil, to: "2026-09-20", in: Self.text, calendar: utc)),
49 ("(org-check-after-date \"2026-09-20\")", SparseTree.planning(from: "2026-09-20", to: nil, in: Self.text, calendar: utc)),
50 ("(org-check-dates-range \"2026-09-01\" \"2026-10-01 10:00\")", SparseTree.planning(from: "2026-09-01", to: "2026-10-01 10:00", in: Self.text, calendar: utc)),
51 ]
52 let forms = cases.map { form, _ in
53 frozenClock(Self.seconds, """
54 (with-current-buffer (find-file-noselect "oracle.org")
55 (org-fold-show-all) \(form)
56 (list (mapconcat (lambda (o) (format "%d-%d" (1- (overlay-start o)) (1- (overlay-end o))))
57 (sort (copy-sequence org-occur-highlights) (lambda (a b) (< (overlay-start a) (overlay-start b)))) " ")
58 (let (vis) (goto-char (point-min))
59 (while (not (eobp)) (push (if (if (eolp) (and (not (bobp)) (org-invisible-p (1- (point)))) (org-invisible-p (point))) "0" "1") vis) (forward-line 1))
60 (apply #'concat (nreverse vis)))))
61 """)
62 }
63 let emacs = try EmacsOracle.evaluate(Self.text, "(apply (function append) (list \(forms.joined(separator: " "))))", prelude: "(setenv \"TZ\" \"UTC0\")")
64 for (i, (form, matches)) in cases.enumerated() {
65 let hidden = SparseTree.hidden(matches.points, in: Self.text, tree: tree)
66 let ns = Self.text as NSString
67 var visibility = ""
68 var offset = 0
69 while offset < ns.length {
70 visibility += hidden.contains { $0.contains(offset) } ? "0" : "1"
71 offset = NSMaxRange(ns.lineRange(for: NSRange(location: offset, length: 0)))
72 }
73 let highlights = matches.highlights.map { "\($0.lowerBound)-\($0.upperBound)" }.joined(separator: " ")
74 #expect(highlights == emacs[2 * i], "\(form) highlights")
75 #expect(visibility == emacs[2 * i + 1], "\(form) visibility")
76 }
77 }
78}