summaryrefslogtreecommitdiff
path: root/tests/test-calendar-sync--collect-exdates.el
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test-calendar-sync--collect-exdates.el')
-rw-r--r--tests/test-calendar-sync--collect-exdates.el147
1 files changed, 147 insertions, 0 deletions
diff --git a/tests/test-calendar-sync--collect-exdates.el b/tests/test-calendar-sync--collect-exdates.el
new file mode 100644
index 00000000..b70277e1
--- /dev/null
+++ b/tests/test-calendar-sync--collect-exdates.el
@@ -0,0 +1,147 @@
+;;; test-calendar-sync--collect-exdates.el --- Tests for EXDATE collection -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Unit tests for calendar-sync--collect-exdates function.
+;; Tests collection of all excluded dates from an event, handling timezone conversion.
+;; Following quality-engineer.org guidelines: one function per file.
+
+;;; Code:
+
+(require 'ert)
+(add-to-list 'load-path (expand-file-name "." (file-name-directory load-file-name)))
+(add-to-list 'load-path (expand-file-name "../modules" (file-name-directory load-file-name)))
+(require 'testutil-calendar-sync)
+(require 'calendar-sync)
+
+;;; Normal Cases
+
+(ert-deftest test-calendar-sync--collect-exdates-normal-single-returns-list ()
+ "Test collecting single EXDATE returns list with one parsed value."
+ (let ((event "BEGIN:VEVENT
+DTSTART:20260203T130000
+RRULE:FREQ=WEEKLY;BYDAY=TU
+EXDATE:20260210T130000
+SUMMARY:Weekly Meeting
+END:VEVENT"))
+ (let ((result (calendar-sync--collect-exdates event)))
+ (should (listp result))
+ (should (= 1 (length result)))
+ (should (equal '(2026 2 10 13 0) (car result))))))
+
+(ert-deftest test-calendar-sync--collect-exdates-normal-multiple-returns-all ()
+ "Test collecting multiple EXDATEs returns all parsed values."
+ (let ((event "BEGIN:VEVENT
+DTSTART:20260203T130000
+RRULE:FREQ=WEEKLY;BYDAY=TU
+EXDATE:20260210T130000
+EXDATE:20260217T130000
+EXDATE:20260224T130000
+SUMMARY:Weekly Meeting
+END:VEVENT"))
+ (let ((result (calendar-sync--collect-exdates event)))
+ (should (= 3 (length result)))
+ (should (member '(2026 2 10 13 0) result))
+ (should (member '(2026 2 17 13 0) result))
+ (should (member '(2026 2 24 13 0) result)))))
+
+(ert-deftest test-calendar-sync--collect-exdates-normal-tzid-converts-to-local ()
+ "Test that TZID-qualified EXDATEs are converted to local time."
+ ;; Use a timezone different from local to verify conversion
+ ;; We'll use Europe/London and check that conversion happens
+ (let ((event "BEGIN:VEVENT
+DTSTART;TZID=Europe/London:20260203T130000
+RRULE:FREQ=WEEKLY;BYDAY=TU
+EXDATE;TZID=Europe/London:20260210T130000
+SUMMARY:London Meeting
+END:VEVENT"))
+ (let ((result (calendar-sync--collect-exdates event)))
+ (should (= 1 (length result)))
+ ;; Result should be a valid datetime list (conversion may differ based on local TZ)
+ (let ((parsed (car result)))
+ (should (= 5 (length parsed)))
+ (should (numberp (nth 0 parsed))) ; year
+ (should (numberp (nth 1 parsed))) ; month
+ (should (numberp (nth 2 parsed))) ; day
+ (should (numberp (nth 3 parsed))) ; hour
+ (should (numberp (nth 4 parsed))))))) ; minute
+
+;;; Boundary Cases
+
+(ert-deftest test-calendar-sync--collect-exdates-boundary-no-exdates-returns-empty ()
+ "Test that event without EXDATE returns empty list."
+ (let ((event "BEGIN:VEVENT
+DTSTART:20260203T130000
+RRULE:FREQ=WEEKLY;BYDAY=TU
+SUMMARY:Weekly Meeting
+END:VEVENT"))
+ (let ((result (calendar-sync--collect-exdates event)))
+ (should (listp result))
+ (should (= 0 (length result))))))
+
+(ert-deftest test-calendar-sync--collect-exdates-boundary-utc-converts-to-local ()
+ "Test that UTC (Z suffix) EXDATEs are converted to local time."
+ (let ((event "BEGIN:VEVENT
+DTSTART:20260203T180000Z
+RRULE:FREQ=WEEKLY;BYDAY=TU
+EXDATE:20260210T180000Z
+SUMMARY:UTC Meeting
+END:VEVENT"))
+ (let ((result (calendar-sync--collect-exdates event)))
+ (should (= 1 (length result)))
+ ;; Result should be converted to local time
+ (let ((parsed (car result)))
+ (should (= 5 (length parsed)))
+ ;; Date should be valid
+ (should (numberp (nth 0 parsed)))))))
+
+(ert-deftest test-calendar-sync--collect-exdates-boundary-mixed-formats-handles-all ()
+ "Test handling mix of TZID, UTC, and local time EXDATEs."
+ (let ((event "BEGIN:VEVENT
+DTSTART:20260203T130000
+RRULE:FREQ=WEEKLY;BYDAY=TU
+EXDATE:20260210T130000
+EXDATE:20260217T180000Z
+SUMMARY:Mixed Meeting
+END:VEVENT"))
+ (let ((result (calendar-sync--collect-exdates event)))
+ (should (= 2 (length result)))
+ ;; Both should be valid parsed datetimes
+ (dolist (parsed result)
+ (should (= 5 (length parsed)))
+ (should (numberp (nth 0 parsed)))))))
+
+(ert-deftest test-calendar-sync--collect-exdates-boundary-date-only-returns-date ()
+ "Test collecting all-day EXDATE returns date with nil for time."
+ (let ((event "BEGIN:VEVENT
+DTSTART;VALUE=DATE:20260203
+RRULE:FREQ=WEEKLY;BYDAY=TU
+EXDATE;VALUE=DATE:20260210
+SUMMARY:All Day Event
+END:VEVENT"))
+ (let ((result (calendar-sync--collect-exdates event)))
+ (should (= 1 (length result)))
+ (let ((parsed (car result)))
+ (should (equal '(2026 2 10 nil nil) parsed))))))
+
+;;; Error Cases
+
+(ert-deftest test-calendar-sync--collect-exdates-error-empty-string-returns-empty ()
+ "Test that empty string returns empty list."
+ (let ((result (calendar-sync--collect-exdates "")))
+ (should (listp result))
+ (should (= 0 (length result)))))
+
+(ert-deftest test-calendar-sync--collect-exdates-error-nil-returns-empty ()
+ "Test that nil input returns empty list."
+ (let ((result (calendar-sync--collect-exdates nil)))
+ (should (listp result))
+ (should (= 0 (length result)))))
+
+(ert-deftest test-calendar-sync--collect-exdates-error-malformed-returns-empty ()
+ "Test that malformed event returns empty list."
+ (let ((result (calendar-sync--collect-exdates "not a vevent")))
+ (should (listp result))
+ (should (= 0 (length result)))))
+
+(provide 'test-calendar-sync--collect-exdates)
+;;; test-calendar-sync--collect-exdates.el ends here