diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test-calendar-sync--api-command.el | 99 | ||||
| -rw-r--r-- | tests/test-calendar-sync--sync-dispatch.el | 81 |
2 files changed, 180 insertions, 0 deletions
diff --git a/tests/test-calendar-sync--api-command.el b/tests/test-calendar-sync--api-command.el new file mode 100644 index 00000000..21c09f51 --- /dev/null +++ b/tests/test-calendar-sync--api-command.el @@ -0,0 +1,99 @@ +;;; test-calendar-sync--api-command.el --- Tests for API command builder -*- lexical-binding: t; -*- + +;;; Commentary: +;; Unit tests for the Google Calendar API fetch path's pure helpers: +;; `calendar-sync--api-script' (resolves the helper script path) and +;; `calendar-sync--api-command' (builds the make-process argument list). +;; Covers Normal, Boundary, and Error cases. + +;;; Code: + +(require 'ert) +(require 'calendar-sync) + +;;; calendar-sync--api-script + +(ert-deftest test-calendar-sync--api-script-normal-resolves-to-helper () + "Normal: the script path ends with the helper filename and is absolute." + (let ((path (calendar-sync--api-script))) + (should (file-name-absolute-p path)) + (should (string-suffix-p "scripts/calendar_sync_api.py" path)))) + +(ert-deftest test-calendar-sync--api-script-normal-no-dotdot () + "Normal: the resolved path is collapsed (no literal ../ segment)." + (let ((path (calendar-sync--api-script))) + (should-not (string-match-p "\\.\\./" path)))) + +;;; calendar-sync--api-command — Normal + +(ert-deftest test-calendar-sync--api-command-normal-structure () + "Normal: command starts with the python binary + script, then the flags." + (let ((calendar-sync-python-command "python3") + (calendar-sync-past-months 3) + (calendar-sync-future-months 12) + (calendar-sync-skip-declined t)) + (let ((cmd (calendar-sync--api-command "work" "primary" "/tmp/out.org"))) + (should (equal (nth 0 cmd) "python3")) + (should (string-suffix-p "calendar_sync_api.py" (nth 1 cmd))) + (should (member "--account" cmd)) + (should (member "work" cmd)) + (should (member "--calendar-id" cmd)) + (should (member "primary" cmd)) + (should (member "--output" cmd)) + (should (member "/tmp/out.org" cmd))))) + +(ert-deftest test-calendar-sync--api-command-normal-flag-pairing () + "Normal: each value immediately follows its flag." + (let ((calendar-sync-python-command "python3") + (calendar-sync-skip-declined t)) + (let ((cmd (calendar-sync--api-command "personal" "abc123" "/tmp/gcal.org"))) + (should (equal "personal" (nth (1+ (cl-position "--account" cmd :test #'equal)) cmd))) + (should (equal "abc123" (nth (1+ (cl-position "--calendar-id" cmd :test #'equal)) cmd))) + (should (equal "/tmp/gcal.org" (nth (1+ (cl-position "--output" cmd :test #'equal)) cmd)))))) + +(ert-deftest test-calendar-sync--api-command-normal-window-from-defvars () + "Normal: past/future month flags reflect the configured defvars." + (let ((calendar-sync-python-command "python3") + (calendar-sync-past-months 6) + (calendar-sync-future-months 9) + (calendar-sync-skip-declined t)) + (let ((cmd (calendar-sync--api-command "work" "primary" "/tmp/out.org"))) + (should (equal "6" (nth (1+ (cl-position "--past-months" cmd :test #'equal)) cmd))) + (should (equal "9" (nth (1+ (cl-position "--future-months" cmd :test #'equal)) cmd)))))) + +(ert-deftest test-calendar-sync--api-command-normal-honors-python-command () + "Normal: a custom python command is used as argv[0]." + (let ((calendar-sync-python-command "/usr/bin/python3.14") + (calendar-sync-skip-declined t)) + (let ((cmd (calendar-sync--api-command "work" "primary" "/tmp/out.org"))) + (should (equal "/usr/bin/python3.14" (nth 0 cmd)))))) + +;;; calendar-sync--api-command — Boundary (declined toggle) + +(ert-deftest test-calendar-sync--api-command-boundary-skip-declined-omits-flag () + "Boundary: with skip-declined on (default), --keep-declined is absent. +The helper filters declines by default, matching the .ics path." + (let ((calendar-sync-python-command "python3") + (calendar-sync-skip-declined t)) + (let ((cmd (calendar-sync--api-command "work" "primary" "/tmp/out.org"))) + (should-not (member "--keep-declined" cmd))))) + +(ert-deftest test-calendar-sync--api-command-boundary-keep-declined-adds-flag () + "Boundary: with skip-declined nil, --keep-declined is passed through. +This keeps the API path honoring the same toggle as the parser path." + (let ((calendar-sync-python-command "python3") + (calendar-sync-skip-declined nil)) + (let ((cmd (calendar-sync--api-command "work" "primary" "/tmp/out.org"))) + (should (member "--keep-declined" cmd))))) + +;;; calendar-sync--api-command — Error + +(ert-deftest test-calendar-sync--api-command-error-returns-string-list () + "Error: every element of the command list is a string (make-process safe)." + (let ((calendar-sync-python-command "python3") + (calendar-sync-skip-declined nil)) + (let ((cmd (calendar-sync--api-command "work" "primary" "/tmp/out.org"))) + (should (cl-every #'stringp cmd))))) + +(provide 'test-calendar-sync--api-command) +;;; test-calendar-sync--api-command.el ends here diff --git a/tests/test-calendar-sync--sync-dispatch.el b/tests/test-calendar-sync--sync-dispatch.el new file mode 100644 index 00000000..22deeef0 --- /dev/null +++ b/tests/test-calendar-sync--sync-dispatch.el @@ -0,0 +1,81 @@ +;;; test-calendar-sync--sync-dispatch.el --- Tests for fetcher dispatch -*- lexical-binding: t; -*- + +;;; Commentary: +;; Unit tests for `calendar-sync--sync-calendar' dispatch. It routes a +;; calendar plist to the API helper when :fetcher is \\='api, and to the .ics +;; path otherwise (\\='ics, nil, or any other value). The two leaf syncers are +;; stubbed so no external process runs. +;; Covers Normal, Boundary, and Error cases. + +;;; Code: + +(require 'ert) +(require 'calendar-sync) + +(defmacro test-sync-dispatch--with-stubs (&rest body) + "Run BODY with both leaf syncers stubbed to record their calls. +Binds `api-calls' and `ics-calls' to lists of the calendars each received." + (declare (indent 0)) + `(let ((api-calls '()) + (ics-calls '())) + (cl-letf (((symbol-function 'calendar-sync--sync-calendar-api) + (lambda (cal) (push cal api-calls))) + ((symbol-function 'calendar-sync--sync-calendar-ics) + (lambda (cal) (push cal ics-calls)))) + ,@body))) + +;;; Normal + +(ert-deftest test-calendar-sync--sync-dispatch-normal-api-fetcher () + "Normal: :fetcher \\='api routes to the API syncer only." + (test-sync-dispatch--with-stubs + (let ((cal '(:name "google" :fetcher api :account "work" + :calendar-id "primary" :file "/tmp/gcal.org"))) + (calendar-sync--sync-calendar cal) + (should (equal (list cal) api-calls)) + (should (null ics-calls))))) + +(ert-deftest test-calendar-sync--sync-dispatch-normal-ics-fetcher () + "Normal: :fetcher \\='ics routes to the .ics syncer only." + (test-sync-dispatch--with-stubs + (let ((cal '(:name "proton" :fetcher ics :url "https://x/y.ics" + :file "/tmp/pcal.org"))) + (calendar-sync--sync-calendar cal) + (should (equal (list cal) ics-calls)) + (should (null api-calls))))) + +;;; Boundary + +(ert-deftest test-calendar-sync--sync-dispatch-boundary-missing-fetcher-defaults-ics () + "Boundary: a calendar with no :fetcher key defaults to the .ics path. +This is what keeps existing Proton/.ics config working unchanged." + (test-sync-dispatch--with-stubs + (let ((cal '(:name "legacy" :url "https://x/y.ics" :file "/tmp/c.org"))) + (calendar-sync--sync-calendar cal) + (should (equal (list cal) ics-calls)) + (should (null api-calls))))) + +(ert-deftest test-calendar-sync--sync-dispatch-boundary-nil-fetcher-defaults-ics () + "Boundary: an explicit :fetcher nil also defaults to the .ics path." + (test-sync-dispatch--with-stubs + (let ((cal '(:name "legacy" :fetcher nil :url "https://x/y.ics" + :file "/tmp/c.org"))) + (calendar-sync--sync-calendar cal) + (should (equal (list cal) ics-calls)) + (should (null api-calls))))) + +;;; Error + +(ert-deftest test-calendar-sync--sync-dispatch-error-unknown-fetcher-defaults-ics () + "Error: an unrecognized :fetcher value falls back to the .ics path. +Only \\='api is special-cased; anything else takes the safe default rather +than crashing." + (test-sync-dispatch--with-stubs + (let ((cal '(:name "weird" :fetcher carrier-pigeon :url "https://x/y.ics" + :file "/tmp/c.org"))) + (calendar-sync--sync-calendar cal) + (should (equal (list cal) ics-calls)) + (should (null api-calls))))) + +(provide 'test-calendar-sync--sync-dispatch) +;;; test-calendar-sync--sync-dispatch.el ends here |
