From b7cb1c51e5663419344d8b55766635801f3ee4c8 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Thu, 5 Feb 2026 15:13:57 -0600 Subject: =?UTF-8?q?feat(calendar-sync):=20add=20event=20details=20?= =?UTF-8?q?=E2=80=94=20attendees,=20organizer,=20status,=20URL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add ICS text unescaping (RFC 5545), HTML stripping, and new fields (attendees/status, organizer, meeting URL) to calendar-sync.el. event-to-org now outputs org property drawers. 88 new tests across 10 test files, 146/146 pass. Also fix pre-existing test require order and keymap guard issues. --- tests/test-calendar-sync--event-to-org.el | 126 ++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 tests/test-calendar-sync--event-to-org.el (limited to 'tests/test-calendar-sync--event-to-org.el') diff --git a/tests/test-calendar-sync--event-to-org.el b/tests/test-calendar-sync--event-to-org.el new file mode 100644 index 00000000..e6609e20 --- /dev/null +++ b/tests/test-calendar-sync--event-to-org.el @@ -0,0 +1,126 @@ +;;; test-calendar-sync--event-to-org.el --- Tests for updated event-to-org formatter -*- lexical-binding: t; -*- + +;;; Commentary: +;; Unit tests for calendar-sync--event-to-org function (updated version). +;; Tests the new property drawer format with LOCATION, ORGANIZER, STATUS, URL. +;; Covers Normal, Boundary, and Error cases. + +;;; Code: + +(require 'ert) +(require 'testutil-calendar-sync) +(require 'calendar-sync) + +;;; Normal Cases + +(ert-deftest test-calendar-sync--event-to-org-normal-all-fields () + "Test event with all fields produces property drawer + description." + (let* ((start (test-calendar-sync-time-days-from-now 5 14 0)) + (end (test-calendar-sync-time-days-from-now 5 15 0)) + (event (list :summary "Team Standup" + :start start + :end end + :description "Daily sync meeting" + :location "Conference Room A" + :organizer (list :cn "John Smith" :email "john@example.com") + :status "accepted" + :url "https://meet.google.com/abc-defg-hij"))) + (let ((result (calendar-sync--event-to-org event))) + (should (string-match-p "\\* Team Standup" result)) + (should (string-match-p ":PROPERTIES:" result)) + (should (string-match-p ":LOCATION: Conference Room A" result)) + (should (string-match-p ":ORGANIZER: John Smith" result)) + (should (string-match-p ":STATUS: accepted" result)) + (should (string-match-p ":URL: https://meet.google.com/abc-defg-hij" result)) + (should (string-match-p ":END:" result)) + (should (string-match-p "Daily sync meeting" result))))) + +(ert-deftest test-calendar-sync--event-to-org-normal-summary-and-time-only () + "Test event with only summary and time (no drawer)." + (let* ((start (test-calendar-sync-time-days-from-now 5 14 0)) + (end (test-calendar-sync-time-days-from-now 5 15 0)) + (event (list :summary "Quick Chat" + :start start + :end end))) + (let ((result (calendar-sync--event-to-org event))) + (should (string-match-p "\\* Quick Chat" result)) + (should-not (string-match-p ":PROPERTIES:" result))))) + +;;; Boundary Cases + +(ert-deftest test-calendar-sync--event-to-org-boundary-no-description () + "Test event with location but no description." + (let* ((start (test-calendar-sync-time-days-from-now 5 14 0)) + (end (test-calendar-sync-time-days-from-now 5 15 0)) + (event (list :summary "Meeting" + :start start + :end end + :location "Room B"))) + (let ((result (calendar-sync--event-to-org event))) + (should (string-match-p ":LOCATION: Room B" result)) + ;; After :END: there should be no body text + (should-not (string-match-p ":END:\n." result))))) + +(ert-deftest test-calendar-sync--event-to-org-boundary-no-location-no-attendees () + "Test event without location or attendees produces no drawer." + (let* ((start (test-calendar-sync-time-days-from-now 5 14 0)) + (end (test-calendar-sync-time-days-from-now 5 15 0)) + (event (list :summary "Simple Event" + :start start + :end end + :description "Just a note"))) + (let ((result (calendar-sync--event-to-org event))) + (should (string-match-p "\\* Simple Event" result)) + ;; Description goes after timestamp, no drawer needed + (should (string-match-p "Just a note" result))))) + +(ert-deftest test-calendar-sync--event-to-org-boundary-only-status () + "Test event with only status produces drawer." + (let* ((start (test-calendar-sync-time-days-from-now 5 14 0)) + (end (test-calendar-sync-time-days-from-now 5 15 0)) + (event (list :summary "Status Only" + :start start + :end end + :status "tentative"))) + (let ((result (calendar-sync--event-to-org event))) + (should (string-match-p ":PROPERTIES:" result)) + (should (string-match-p ":STATUS: tentative" result)) + (should (string-match-p ":END:" result))))) + +(ert-deftest test-calendar-sync--event-to-org-boundary-description-with-asterisks () + "Test event description containing org-special asterisks." + (let* ((start (test-calendar-sync-time-days-from-now 5 14 0)) + (end (test-calendar-sync-time-days-from-now 5 15 0)) + (event (list :summary "Meeting" + :start start + :end end + :description "* agenda item 1\n** sub-item"))) + (let ((result (calendar-sync--event-to-org event))) + ;; Description should be present + (should (string-match-p "agenda item" result))))) + +(ert-deftest test-calendar-sync--event-to-org-boundary-organizer-email-only () + "Test organizer without CN shows email." + (let* ((start (test-calendar-sync-time-days-from-now 5 14 0)) + (end (test-calendar-sync-time-days-from-now 5 15 0)) + (event (list :summary "Meeting" + :start start + :end end + :organizer (list :cn nil :email "org@example.com")))) + (let ((result (calendar-sync--event-to-org event))) + (should (string-match-p ":ORGANIZER: org@example.com" result))))) + +;;; Error Cases + +(ert-deftest test-calendar-sync--event-to-org-error-missing-summary () + "Test event with nil summary still produces output." + (let* ((start (test-calendar-sync-time-days-from-now 5 14 0)) + (end (test-calendar-sync-time-days-from-now 5 15 0)) + (event (list :summary nil + :start start + :end end))) + ;; Should not error - produce some output + (should (stringp (calendar-sync--event-to-org event))))) + +(provide 'test-calendar-sync--event-to-org) +;;; test-calendar-sync--event-to-org.el ends here -- cgit v1.2.3