aboutsummaryrefslogtreecommitdiff
path: root/tests/test-calendar-sync--apply-single-exception.el
blob: f23104d9834fa09fd3c09e3654fa2186b3b67d18 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
;;; test-calendar-sync--apply-single-exception.el --- Tests for exception application -*- lexical-binding: t; -*-

;;; Commentary:
;; Tests for calendar-sync--apply-single-exception.
;; Applies exception overrides to an occurrence plist, returning a modified copy.

;;; Code:

(require 'ert)
(require 'testutil-calendar-sync)
(require 'calendar-sync)

;;; Normal Cases

(ert-deftest test-calendar-sync--apply-single-exception-normal-updates-time ()
  "Exception start/end override the occurrence times."
  (let ((occ (list :start '(2026 3 15 14 0) :end '(2026 3 15 15 0)
                   :summary "Standup" :uid "abc"))
        (exc (list :start '(2026 3 15 16 0) :end '(2026 3 15 17 0))))
    (let ((result (calendar-sync--apply-single-exception occ exc)))
      (should (equal '(2026 3 15 16 0) (plist-get result :start)))
      (should (equal '(2026 3 15 17 0) (plist-get result :end))))))

(ert-deftest test-calendar-sync--apply-single-exception-normal-updates-summary ()
  "Exception with summary overrides the occurrence summary."
  (let ((occ (list :start '(2026 3 15 14 0) :summary "Original"))
        (exc (list :start '(2026 3 15 14 0) :summary "Modified")))
    (let ((result (calendar-sync--apply-single-exception occ exc)))
      (should (equal "Modified" (plist-get result :summary))))))

(ert-deftest test-calendar-sync--apply-single-exception-normal-preserves-unset-fields ()
  "Fields not present in exception are preserved from occurrence."
  (let ((occ (list :start '(2026 3 15 14 0) :summary "Keep" :uid "abc"
                   :location "Room 1"))
        (exc (list :start '(2026 3 15 16 0))))
    (let ((result (calendar-sync--apply-single-exception occ exc)))
      (should (equal "Keep" (plist-get result :summary)))
      (should (equal "abc" (plist-get result :uid)))
      (should (equal "Room 1" (plist-get result :location))))))

;;; Boundary Cases

(ert-deftest test-calendar-sync--apply-single-exception-boundary-nil-end ()
  "Exception without :end preserves occurrence :end."
  (let ((occ (list :start '(2026 3 15 14 0) :end '(2026 3 15 15 0)))
        (exc (list :start '(2026 3 15 16 0))))
    (let ((result (calendar-sync--apply-single-exception occ exc)))
      (should (equal '(2026 3 15 15 0) (plist-get result :end))))))

(ert-deftest test-calendar-sync--apply-single-exception-boundary-does-not-mutate ()
  "Original occurrence plist is not mutated."
  (let ((occ (list :start '(2026 3 15 14 0) :summary "Original"))
        (exc (list :start '(2026 3 15 16 0) :summary "Changed")))
    (calendar-sync--apply-single-exception occ exc)
    (should (equal "Original" (plist-get occ :summary)))))

;;; Error Cases

(ert-deftest test-calendar-sync--apply-single-exception-error-empty-exception ()
  "Exception with no fields still returns a valid plist with occurrence data."
  (let ((occ (list :start '(2026 3 15 14 0) :summary "Keep"))
        (exc (list :start nil)))
    (let ((result (calendar-sync--apply-single-exception occ exc)))
      (should (equal "Keep" (plist-get result :summary))))))

;;; Normal Cases — remaining overridable fields

(ert-deftest test-calendar-sync--apply-single-exception-overrides-description ()
  "Normal: an exception :description overrides the occurrence's."
  (let ((occ (list :start '(2026 3 15 14 0) :description "old"))
        (exc (list :start '(2026 3 15 14 0) :description "new")))
    (should (equal "new"
                   (plist-get (calendar-sync--apply-single-exception occ exc)
                              :description)))))

(ert-deftest test-calendar-sync--apply-single-exception-overrides-location ()
  "Normal: an exception :location overrides the occurrence's."
  (let ((occ (list :start '(2026 3 15 14 0) :location "Room A"))
        (exc (list :start '(2026 3 15 14 0) :location "Room B")))
    (should (equal "Room B"
                   (plist-get (calendar-sync--apply-single-exception occ exc)
                              :location)))))

(ert-deftest test-calendar-sync--apply-single-exception-overrides-attendees ()
  "Normal: an exception :attendees overrides the occurrence's."
  (let ((occ (list :start '(2026 3 15 14 0) :attendees '("a")))
        (exc (list :start '(2026 3 15 14 0) :attendees '("b" "c"))))
    (should (equal '("b" "c")
                   (plist-get (calendar-sync--apply-single-exception occ exc)
                              :attendees)))))

(ert-deftest test-calendar-sync--apply-single-exception-overrides-organizer ()
  "Normal: an exception :organizer overrides the occurrence's."
  (let ((occ (list :start '(2026 3 15 14 0) :organizer "old@x"))
        (exc (list :start '(2026 3 15 14 0) :organizer "new@x")))
    (should (equal "new@x"
                   (plist-get (calendar-sync--apply-single-exception occ exc)
                              :organizer)))))

(ert-deftest test-calendar-sync--apply-single-exception-overrides-url ()
  "Normal: an exception :url overrides the occurrence's."
  (let ((occ (list :start '(2026 3 15 14 0) :url "http://old"))
        (exc (list :start '(2026 3 15 14 0) :url "http://new")))
    (should (equal "http://new"
                   (plist-get (calendar-sync--apply-single-exception occ exc)
                              :url)))))

;;; Status re-derivation from overridden attendees (chime handoff 2026-06-24)

(ert-deftest test-calendar-sync--apply-single-exception-declined-occurrence-rederives-status ()
  "Normal: a declined single occurrence re-derives :status from the override attendees."
  (let ((calendar-sync-user-emails '("craig@example.com"))
        (occ (list :start '(2026 6 24 16 0) :status "accepted" :uid "abc"))
        (exc (list :start '(2026 6 24 16 0)
                   :attendees (list (list :email "craig@example.com" :partstat "DECLINED")))))
    (should (equal "declined"
                   (plist-get (calendar-sync--apply-single-exception occ exc) :status)))))

(ert-deftest test-calendar-sync--apply-single-exception-no-attendee-override-keeps-status ()
  "Boundary: an exception with no attendee block leaves the inherited :status intact."
  (let ((calendar-sync-user-emails '("craig@example.com"))
        (occ (list :start '(2026 6 24 16 0) :status "accepted" :uid "abc"))
        (exc (list :start '(2026 6 24 16 0) :summary "Moved")))
    (should (equal "accepted"
                   (plist-get (calendar-sync--apply-single-exception occ exc) :status)))))

(ert-deftest test-calendar-sync--apply-single-exception-accepted-override-stays-accepted ()
  "Normal: an accepted attendee override keeps :status accepted."
  (let ((calendar-sync-user-emails '("craig@example.com"))
        (occ (list :start '(2026 6 24 16 0) :status "accepted" :uid "abc"))
        (exc (list :start '(2026 6 24 16 0)
                   :attendees (list (list :email "craig@example.com" :partstat "ACCEPTED")))))
    (should (equal "accepted"
                   (plist-get (calendar-sync--apply-single-exception occ exc) :status)))))

(ert-deftest test-calendar-sync--apply-single-exception-override-without-user-keeps-status ()
  "Boundary: override attendees that don't include the user leave :status intact."
  (let ((calendar-sync-user-emails '("craig@example.com"))
        (occ (list :start '(2026 6 24 16 0) :status "accepted" :uid "abc"))
        (exc (list :start '(2026 6 24 16 0)
                   :attendees (list (list :email "someone@else.com" :partstat "DECLINED")))))
    (should (equal "accepted"
                   (plist-get (calendar-sync--apply-single-exception occ exc) :status)))))

(provide 'test-calendar-sync--apply-single-exception)
;;; test-calendar-sync--apply-single-exception.el ends here