Tests/OrgCoreTests/PropertyCommandTests.swift
72 lines · 3803 bytes
4 symbols in this file
1import Foundation
2import Testing
3@testable import OrgCore
4
5struct PropertyCommandTests {
6 static let oracle = ProcessInfo.processInfo.environment["ORGSTAR_SKIP_ORACLE"] == nil
7
8 static let text = """
9 #+PROPERTY: Color_ALL red green "dark blue" :ETC
10 * Parent
11 :PROPERTIES:
12 :Size_ALL: S M L 010
13 :Size: M
14 :END:
15 ** Child
16 :PROPERTIES:
17 :Size: L
18 :Color: green
19 :Done: [ ]
20 :END:
21 body
22 ** Bare
23 SCHEDULED: <2026-10-05 Mon>
24 * Other
25 :PROPERTIES:
26 :Size: S
27 :END:
28 """ + "\n"
29
30 func compare(_ cases: [(at: String, command: any OrgCommand, answers: [String: String], form: String)]) throws {
31 let ns = Self.text as NSString
32 let emacs = try EmacsOracle.run(cases.map { c in
33 EmacsOracle.Case(text: Self.text, point: EmacsOracle.point(ns.range(of: c.at).location, in: Self.text), form: c.form)
34 })
35 for (c, theirs) in zip(cases, emacs) {
36 let ours = runCommand(c.command, Self.text, caret: ns.range(of: c.at).location, answers: c.answers)
37 #expect(ours.text == theirs.text, "\(c.form) at \(c.at)\nours: \(ours.text.debugDescription) \(ours.failure ?? "")\nemacs: \(theirs.text.debugDescription) \(theirs.error)")
38 #expect((ours.failure != nil) == !theirs.error.isEmpty, "\(c.form): \(ours.failure ?? "") vs \(theirs.error)")
39 }
40 }
41
42 @Test(.enabled(if: oracle))
43 func setsAndDeletesLikeOrg() throws {
44 try compare([
45 ("Child", ReadAndSetProperty(), ["property": "Color", "value": "red"], "(org-set-property \"Color\" \"red\")"),
46 ("Bare", ReadAndSetProperty(), ["property": "Size", "value": "S"], "(org-set-property \"Size\" \"S\")"),
47 ("Other", ReadAndSetProperty(), ["property": "Size", "value": "S"], "(org-set-property \"Size\" \"S\")"),
48 ("Child", DeleteProperty(), ["property": "Color"], "(org-delete-property \"Color\")"),
49 ("Other", DeleteProperty(), [:], "(org-delete-property \"Size\")"),
50 ("Parent", DeleteProperty(globally: true), ["property": "Size"], "(org-delete-property-globally \"Size\")"),
51 (":Size: L", NextAllowedValue(previous: false), [:], "(org-property-next-allowed-value)"),
52 (":Size: L", NextAllowedValue(previous: true), [:], "(org-property-next-allowed-value t)"),
53 (":Size: M", NextAllowedValue(previous: false), [:], "(org-property-next-allowed-value)"),
54 (":Color: green", NextAllowedValue(previous: false), [:], "(org-property-next-allowed-value)"),
55 (":Done:", NextAllowedValue(previous: false), [:], "(org-property-next-allowed-value)"),
56 (":Size: S", NextAllowedValue(previous: false), [:], "(org-property-next-allowed-value)"),
57 ])
58 }
59
60 @Test(.enabled(if: oracle))
61 func findsAllowedValuesLikeOrg() throws {
62 let ns = Self.text as NSString
63 let spots = [("Child", "Size"), ("Child", "Color"), ("Other", "Size"), ("Child", "TODO"), ("Child", "PRIORITY"), ("Bare", "Shape")]
64 let forms = spots.map { at, key in
65 "(progn (goto-char \(EmacsOracle.point(ns.range(of: at).location, in: Self.text))) (mapconcat #'identity (org-property-get-allowed-values (point) \(lispString(key))) \"|\"))"
66 }
67 let emacs = try EmacsOracle.evaluate(Self.text, "(with-current-buffer (find-file-noselect \"oracle.org\") (list \(forms.joined(separator: " "))))")
68 let tree = OrgParser.parse(Self.text)
69 let ours = spots.map { at, key in PropertyValues.allowed(key, at: ns.range(of: at).location, text: Self.text, tree: tree)?.values.joined(separator: "|") ?? "" }
70 #expect(ours == emacs)
71 }
72}