diff options
| -rw-r--r-- | modules/calendar-sync.el | 16 | ||||
| -rw-r--r-- | tests/test-calendar-sync--event-to-org.el | 6 | ||||
| -rw-r--r-- | tests/test-calendar-sync--get-property.el | 20 |
3 files changed, 35 insertions, 7 deletions
diff --git a/modules/calendar-sync.el b/modules/calendar-sync.el index fadad6c0..06248531 100644 --- a/modules/calendar-sync.el +++ b/modules/calendar-sync.el @@ -413,9 +413,12 @@ Each exception plist contains :recurrence-id (parsed), :start, :end, :summary, e (end-tzid (calendar-sync--extract-tzid dtend-line)) (start-parsed (calendar-sync--parse-timestamp dtstart start-tzid)) (end-parsed (and dtend (calendar-sync--parse-timestamp dtend end-tzid))) - (summary (calendar-sync--get-property event-str "SUMMARY")) - (description (calendar-sync--get-property event-str "DESCRIPTION")) - (location (calendar-sync--get-property event-str "LOCATION"))) + (summary (calendar-sync--clean-text + (calendar-sync--get-property event-str "SUMMARY"))) + (description (calendar-sync--clean-text + (calendar-sync--get-property event-str "DESCRIPTION"))) + (location (calendar-sync--clean-text + (calendar-sync--get-property event-str "LOCATION")))) (when (and recurrence-id-parsed start-parsed) ;; Convert RECURRENCE-ID to local time ;; Handle: UTC (Z suffix), TZID, or assume local @@ -658,9 +661,10 @@ Returns nil if property not found." (when (string-match (format "^%s[^:\n]*:\\(.*\\)$" (regexp-quote property)) event) (let ((value (match-string 1 event)) (start (match-end 0))) - ;; Handle continuation lines (start with space or tab) + ;; Handle continuation lines (RFC 5545 ยง3.1: folded lines start with space or tab) (while (and (< start (length event)) - (string-match "^\n[ \t]\\(.*\\)$" event start)) + (string-match "\n[ \t]\\([^\n]*\\)" event start) + (= (match-beginning 0) start)) (setq value (concat value (match-string 1 event))) (setq start (match-end 0))) value))) @@ -1164,7 +1168,7 @@ Description appears as body text after the drawer." (push (format ":URL: %s" url) props)) (setq props (nreverse props)) ;; Build output - (let ((parts (list (format "* %s" summary) timestamp))) + (let ((parts (list timestamp (format "* %s" summary)))) ;; Add property drawer if any properties exist (when props (push ":PROPERTIES:" parts) diff --git a/tests/test-calendar-sync--event-to-org.el b/tests/test-calendar-sync--event-to-org.el index e6609e20..96ce49d5 100644 --- a/tests/test-calendar-sync--event-to-org.el +++ b/tests/test-calendar-sync--event-to-org.el @@ -26,7 +26,11 @@ :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)) + ;; Verify heading comes before timestamp + (should (string-match "\\* Team Standup" result)) + (let ((heading-pos (match-beginning 0))) + (should (string-match "<[0-9]" result)) + (should (< heading-pos (match-beginning 0)))) (should (string-match-p ":PROPERTIES:" result)) (should (string-match-p ":LOCATION: Conference Room A" result)) (should (string-match-p ":ORGANIZER: John Smith" result)) diff --git a/tests/test-calendar-sync--get-property.el b/tests/test-calendar-sync--get-property.el index 8b71f8e3..20551860 100644 --- a/tests/test-calendar-sync--get-property.el +++ b/tests/test-calendar-sync--get-property.el @@ -133,6 +133,26 @@ (should (equal (calendar-sync--get-property event "DESCRIPTION") "Tasks: setup; review; deploy"))) (test-calendar-sync--get-property-teardown))) +(ert-deftest test-calendar-sync--get-property-boundary-continuation-lines-joined () + "Test extracting property value with RFC 5545 continuation lines. +Folded lines start with a space or tab and should be joined." + (test-calendar-sync--get-property-setup) + (unwind-protect + (let ((event "BEGIN:VEVENT\nDESCRIPTION:This is a long\n description that spans\n multiple lines\nSUMMARY:Test\nEND:VEVENT")) + (should (equal (calendar-sync--get-property event "DESCRIPTION") + "This is a longdescription that spansmultiple lines"))) + (test-calendar-sync--get-property-teardown))) + +(ert-deftest test-calendar-sync--get-property-boundary-continuation-with-html () + "Test that HTML tags split across continuation lines are fully captured." + (test-calendar-sync--get-property-setup) + (unwind-protect + (let ((event "BEGIN:VEVENT\nDESCRIPTION:Created by <a href=\"https://ex\n ample.com\">link</a> here\nEND:VEVENT")) + (let ((value (calendar-sync--get-property event "DESCRIPTION"))) + (should (string-match-p "example.com" value)) + (should (string-match-p "</a>" value)))) + (test-calendar-sync--get-property-teardown))) + ;;; Error Cases (ert-deftest test-calendar-sync--get-property-error-missing-property-returns-nil () |
