summaryrefslogtreecommitdiff
path: root/tests/testutil-calendar-sync.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2025-11-16 18:09:17 -0600
committerCraig Jennings <c@cjennings.net>2025-11-16 18:09:17 -0600
commitda0bd6883a4032054aef4b59c338f60796a0fd99 (patch)
treee95369646441b35058c89dfb9c31bad9410243fa /tests/testutil-calendar-sync.el
parent6280a13c87412a6ff50bbaa43e821c518bd2bd0e (diff)
feat(calendar-sync): Add automatic timezone detection and chronological sorting
Implemented calendar-sync.el as a complete replacement for org-gcal, featuring: **Core Functionality:** - One-way sync from Google Calendar to Org (via .ics URL) - UTC to local timezone conversion for all event timestamps - Chronological event sorting (past → present → future) - Non-blocking sync using curl (works reliably in daemon mode) **Automatic Timezone Detection:** - Detects timezone changes when traveling between timezones - Tracks timezone offset in seconds (-21600 for CST, -28800 for PST, etc.) - Triggers automatic re-sync when timezone changes detected - Shows informative messages: "Timezone change detected (UTC-6 → UTC-8)" **State Persistence:** - Saves sync state to ~/.emacs.d/data/calendar-sync-state.el - Persists timezone and last sync time across Emacs sessions - Enables detection even after closing Emacs before traveling **User Features:** - Interactive commands: calendar-sync-now, calendar-sync-start/stop - Keybindings: C-; g s (sync), C-; g a (start auto-sync), C-; g x (stop) - Optional auto-sync every 15 minutes (disabled by default) - Clear status messages for all operations **Code Quality:** - Comprehensive test coverage: 51 ERT tests (100% passing) - Refactored UTC conversion into separate function - Clean separation of concerns (parsing, conversion, formatting, sorting) - Well-documented with timezone behavior guide and changelog **Migration:** - Removed org-gcal-config.el (archived in modules/archived/) - Updated init.el to use calendar-sync - Moved gcal.org to .emacs.d/data/ for machine-independent syncing - Removed org-gcal appointment capture template Files modified: modules/calendar-sync.el:442, tests/test-calendar-sync.el:577 Files created: data/calendar-sync-state.el, tests/testutil-calendar-sync.el Documentation: docs/calendar-sync-timezones.md, docs/calendar-sync-changelog.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Diffstat (limited to 'tests/testutil-calendar-sync.el')
-rw-r--r--tests/testutil-calendar-sync.el110
1 files changed, 110 insertions, 0 deletions
diff --git a/tests/testutil-calendar-sync.el b/tests/testutil-calendar-sync.el
new file mode 100644
index 00000000..c83006b5
--- /dev/null
+++ b/tests/testutil-calendar-sync.el
@@ -0,0 +1,110 @@
+;;; testutil-calendar-sync.el --- Test utilities for calendar-sync -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Utilities for testing calendar-sync module, especially dynamic timestamp generation.
+;; Following quality-engineer.org guidelines: no hardcoded dates!
+
+;;; Code:
+
+(require 'calendar)
+
+;;; Dynamic Timestamp Generation
+
+(defun test-calendar-sync-time-today-at (hour minute)
+ "Generate time for today at HOUR:MINUTE.
+Returns (year month day hour minute) list suitable for tests."
+ (let* ((now (decode-time))
+ (year (nth 5 now))
+ (month (nth 4 now))
+ (day (nth 3 now)))
+ (list year month day hour minute)))
+
+(defun test-calendar-sync-time-tomorrow-at (hour minute)
+ "Generate time for tomorrow at HOUR:MINUTE."
+ (let* ((tomorrow (time-add (current-time) (* 24 3600)))
+ (decoded (decode-time tomorrow))
+ (year (nth 5 decoded))
+ (month (nth 4 decoded))
+ (day (nth 3 decoded)))
+ (list year month day hour minute)))
+
+(defun test-calendar-sync-time-days-from-now (days hour minute)
+ "Generate time for DAYS from now at HOUR:MINUTE."
+ (let* ((future (time-add (current-time) (* days 24 3600)))
+ (decoded (decode-time future))
+ (year (nth 5 decoded))
+ (month (nth 4 decoded))
+ (day (nth 3 decoded)))
+ (list year month day hour minute)))
+
+(defun test-calendar-sync-time-days-ago (days hour minute)
+ "Generate time for DAYS ago at HOUR:MINUTE."
+ (let* ((past (time-subtract (current-time) (* days 24 3600)))
+ (decoded (decode-time past))
+ (year (nth 5 decoded))
+ (month (nth 4 decoded))
+ (day (nth 3 decoded)))
+ (list year month day hour minute)))
+
+(defun test-calendar-sync-time-date-only (offset-days)
+ "Generate date-only timestamp for OFFSET-DAYS from now.
+Returns (year month day) list for all-day events."
+ (let* ((future (time-add (current-time) (* offset-days 24 3600)))
+ (decoded (decode-time future))
+ (year (nth 5 decoded))
+ (month (nth 4 decoded))
+ (day (nth 3 decoded)))
+ (list year month day)))
+
+;;; .ics Test Data Generation
+
+(defun test-calendar-sync-ics-datetime (time-list)
+ "Convert TIME-LIST to iCal DATETIME format.
+TIME-LIST is (year month day hour minute).
+Returns string like '20251116T140000Z'."
+ (format "%04d%02d%02dT%02d%02d00Z"
+ (nth 0 time-list)
+ (nth 1 time-list)
+ (nth 2 time-list)
+ (nth 3 time-list)
+ (nth 4 time-list)))
+
+(defun test-calendar-sync-ics-date (time-list)
+ "Convert TIME-LIST to iCal DATE format.
+TIME-LIST is (year month day).
+Returns string like '20251116'."
+ (format "%04d%02d%02d"
+ (nth 0 time-list)
+ (nth 1 time-list)
+ (nth 2 time-list)))
+
+(defun test-calendar-sync-make-vevent (summary start end &optional description location)
+ "Create a VEVENT block for testing.
+START and END are time lists from test-calendar-sync-time-* functions.
+Returns .ics formatted VEVENT string."
+ (let* ((dtstart (if (= (length start) 5)
+ (test-calendar-sync-ics-datetime start)
+ (test-calendar-sync-ics-date start)))
+ (dtend (when end
+ (if (= (length end) 5)
+ (test-calendar-sync-ics-datetime end)
+ (test-calendar-sync-ics-date end)))))
+ (concat "BEGIN:VEVENT\n"
+ "SUMMARY:" summary "\n"
+ "DTSTART:" dtstart "\n"
+ (when dtend (concat "DTEND:" dtend "\n"))
+ (when description (concat "DESCRIPTION:" description "\n"))
+ (when location (concat "LOCATION:" location "\n"))
+ "END:VEVENT")))
+
+(defun test-calendar-sync-make-ics (&rest events)
+ "Create complete .ics file with EVENTS.
+Each event should be a VEVENT string from `test-calendar-sync-make-vevent'."
+ (concat "BEGIN:VCALENDAR\n"
+ "VERSION:2.0\n"
+ "PRODID:-//Test//Test//EN\n"
+ (string-join events "\n")
+ "\nEND:VCALENDAR"))
+
+(provide 'testutil-calendar-sync)
+;;; testutil-calendar-sync.el ends here