aboutsummaryrefslogtreecommitdiff
path: root/tests/test-calendar-sync--apply-recurrence-exceptions.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-07-18 12:57:32 -0500
committerCraig Jennings <c@cjennings.net>2026-07-18 12:57:32 -0500
commitb426cd089503053fd203a034f3cbbe173252d5c3 (patch)
tree583c679fb3daa94445efd818313ce0805c6abdbc /tests/test-calendar-sync--apply-recurrence-exceptions.el
parentb5a7ac309217a1aeece1c043cf29002cfea6c9ef (diff)
downloaddotemacs-b426cd089503053fd203a034f3cbbe173252d5c3.tar.gz
dotemacs-b426cd089503053fd203a034f3cbbe173252d5c3.zip
fix(calendar-sync): honor BYDAY rules and drop cancelled events
The expander ignored BYDAY on monthly and yearly rules and stepped DTSTART's day-of-month instead, so a "2nd Wednesday" series rendered on the 12th of every month, the wrong weekday most months. It now resolves nth-weekday entries (2WE, -1TU), bare weekdays with BYSETPOS, and yearly BYMONTH+BYDAY, so each occurrence lands on the day the rule names. Nothing read the VEVENT STATUS property, so cancelled events rendered as normal meetings: a cancelled instance of a series reappeared at its original time, and standalone cancelled events stayed on the agenda. parse-event now drops STATUS:CANCELLED events, which also kills cancelled series masters. A cancelled RECURRENCE-ID override removes its occurrence instead of overriding it. The fixes are coupled: until BYDAY generates the right dates, a cancelled override can't match the occurrence it removes.
Diffstat (limited to 'tests/test-calendar-sync--apply-recurrence-exceptions.el')
-rw-r--r--tests/test-calendar-sync--apply-recurrence-exceptions.el31
1 files changed, 31 insertions, 0 deletions
diff --git a/tests/test-calendar-sync--apply-recurrence-exceptions.el b/tests/test-calendar-sync--apply-recurrence-exceptions.el
index 7711c5cb..999296fb 100644
--- a/tests/test-calendar-sync--apply-recurrence-exceptions.el
+++ b/tests/test-calendar-sync--apply-recurrence-exceptions.el
@@ -153,5 +153,36 @@ NEW-* values are the rescheduled time."
(and (= 1 (length result))
(= 9 (nth 3 (plist-get (car result) :start)))))))))
+;;; STATUS:CANCELLED Cases
+
+(ert-deftest test-calendar-sync--apply-recurrence-exceptions-normal-cancelled-removes ()
+ "Normal: a cancelled exception removes its occurrence instead of overriding it."
+ (let* ((occurrences (list (test-make-occurrence 2026 2 3 9 0 "Weekly Meeting")
+ (test-make-occurrence 2026 2 10 9 0 "Weekly Meeting")
+ (test-make-occurrence 2026 2 17 9 0 "Weekly Meeting")))
+ (exceptions (make-hash-table :test 'equal)))
+ ;; Feb 10 is cancelled.
+ (puthash "test-event@google.com"
+ (list (append (test-make-exception-data 2026 2 10 9 0 2026 2 10 9 0)
+ '(:cancelled t)))
+ exceptions)
+ (let ((result (calendar-sync--apply-recurrence-exceptions occurrences exceptions)))
+ (should (= 2 (length result)))
+ ;; Feb 3 and Feb 17 remain; Feb 10 is gone.
+ (should (equal '(3 17)
+ (mapcar (lambda (occ) (nth 2 (plist-get occ :start))) result))))))
+
+(ert-deftest test-calendar-sync--apply-recurrence-exceptions-boundary-cancelled-no-match-keeps-all ()
+ "Boundary: a cancelled exception that matches nothing removes nothing."
+ (let* ((occurrences (list (test-make-occurrence 2026 2 3 9 0 "Weekly Meeting")))
+ (exceptions (make-hash-table :test 'equal)))
+ ;; Cancelled exception targets a different date.
+ (puthash "test-event@google.com"
+ (list (append (test-make-exception-data 2026 3 3 9 0 2026 3 3 9 0)
+ '(:cancelled t)))
+ exceptions)
+ (let ((result (calendar-sync--apply-recurrence-exceptions occurrences exceptions)))
+ (should (= 1 (length result))))))
+
(provide 'test-calendar-sync--apply-recurrence-exceptions)
;;; test-calendar-sync--apply-recurrence-exceptions.el ends here