summaryrefslogtreecommitdiff
path: root/tests/test-calendar-sync--collect-exdates.el
blob: b70277e1d3fc91c4fb6b2df4f43788a060c6e9b3 (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
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