aboutsummaryrefslogtreecommitdiff
path: root/tests/test-pearl-saved-query-sync.el
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test-pearl-saved-query-sync.el')
-rw-r--r--tests/test-pearl-saved-query-sync.el128
1 files changed, 128 insertions, 0 deletions
diff --git a/tests/test-pearl-saved-query-sync.el b/tests/test-pearl-saved-query-sync.el
index 7a40566..ebf4622 100644
--- a/tests/test-pearl-saved-query-sync.el
+++ b/tests/test-pearl-saved-query-sync.el
@@ -375,5 +375,133 @@ team-key lookups."
(should captured-query)
(should (string-match-p "key" captured-query)))))
+;;; pearl--customview-delete-async
+
+(ert-deftest test-pearl-customview-delete-async-success ()
+ "A successful `customViewDelete' invokes the callback with `:success' t."
+ (testutil-linear-with-response
+ '((data (customViewDelete (success . t))))
+ (let (result)
+ (pearl--customview-delete-async "view-uuid" (lambda (r) (setq result r)))
+ (should (eq t (plist-get result :success))))))
+
+(ert-deftest test-pearl-customview-delete-async-failure ()
+ "A non-success `customViewDelete' invokes the callback with `:success' nil."
+ (testutil-linear-with-response
+ '((data (customViewDelete (success . :json-false))))
+ (let (result)
+ (pearl--customview-delete-async "view-uuid" (lambda (r) (setq result r)))
+ (should-not (plist-get result :success)))))
+
+;;; pearl-delete-saved-query — synced-entry second-stage prompt
+
+(defun test-pearl--make-yes-no-stub (answers)
+ "Return a `yes-or-no-p' replacement that returns each ANSWERS in order.
+Each call pops the head; the test fails the call sequence assertion if
+more prompts fire than answers were prepared for."
+ (let ((remaining answers))
+ (lambda (&rest _)
+ (if remaining
+ (pop remaining)
+ (error "Unexpected extra yes-or-no-p prompt")))))
+
+(ert-deftest test-pearl-delete-saved-query-synced-yes-yes-calls-customview-delete ()
+ "Synced entry, both prompts yes: customViewDelete fires and the local entry is removed."
+ (let ((pearl-saved-queries
+ (copy-tree '(("Q" :filter (:open t)
+ :linear-view-id "view-uuid"
+ :linear-view-team-id nil
+ :linear-view-shared :json-false))))
+ (delete-called-with nil))
+ (cl-letf (((symbol-function 'yes-or-no-p)
+ (test-pearl--make-yes-no-stub '(t t)))
+ ((symbol-function 'customize-save-variable) (lambda (_ _) nil))
+ ((symbol-function 'pearl--progress) (lambda (&rest _) nil))
+ ((symbol-function 'message) (lambda (&rest _) nil))
+ ((symbol-function 'pearl--customview-delete-async)
+ (lambda (vid cb)
+ (setq delete-called-with vid)
+ (funcall cb (list :success t)))))
+ (pearl-delete-saved-query "Q")
+ (should (equal "view-uuid" delete-called-with))
+ (should-not (assoc "Q" pearl-saved-queries)))))
+
+(ert-deftest test-pearl-delete-saved-query-synced-yes-no-unlinks-only ()
+ "Synced entry, first prompt yes second prompt no: local entry removed, customViewDelete not called."
+ (let ((pearl-saved-queries
+ (copy-tree '(("Q" :filter (:open t)
+ :linear-view-id "view-uuid"))))
+ (delete-called nil))
+ (cl-letf (((symbol-function 'yes-or-no-p)
+ (test-pearl--make-yes-no-stub '(t nil)))
+ ((symbol-function 'customize-save-variable) (lambda (_ _) nil))
+ ((symbol-function 'pearl--progress) (lambda (&rest _) nil))
+ ((symbol-function 'message) (lambda (&rest _) nil))
+ ((symbol-function 'pearl--customview-delete-async)
+ (lambda (_ _) (setq delete-called t))))
+ (pearl-delete-saved-query "Q")
+ (should-not delete-called)
+ (should-not (assoc "Q" pearl-saved-queries)))))
+
+(ert-deftest test-pearl-delete-saved-query-synced-api-failure-then-delete-anyway ()
+ "Synced entry, customViewDelete fails, user accepts delete-anyway prompt: local removed, message names the orphan id."
+ (let ((pearl-saved-queries
+ (copy-tree '(("Q" :filter (:open t)
+ :linear-view-id "ORPHAN-UUID"))))
+ (last-message nil))
+ (cl-letf (((symbol-function 'yes-or-no-p)
+ (test-pearl--make-yes-no-stub '(t t t))) ; delete? + also-on-Linear? + delete-anyway?
+ ((symbol-function 'customize-save-variable) (lambda (_ _) nil))
+ ((symbol-function 'pearl--progress) (lambda (&rest _) nil))
+ ((symbol-function 'message)
+ (lambda (fmt &rest args)
+ (setq last-message (apply #'format fmt args))))
+ ((symbol-function 'pearl--customview-delete-async)
+ (lambda (_ cb)
+ (funcall cb (list :success nil :error "permission denied")))))
+ (pearl-delete-saved-query "Q")
+ (should-not (assoc "Q" pearl-saved-queries))
+ (should (string-match-p "ORPHAN-UUID" last-message))
+ (should (string-match-p "orphan" last-message)))))
+
+(ert-deftest test-pearl-delete-saved-query-synced-api-failure-then-keep ()
+ "Synced entry, customViewDelete fails, user rejects delete-anyway: both kept untouched.
+Verifies the API call actually fires (so the keep branch only runs when the
+delete-anyway prompt explicitly declines), guarding against a future refactor
+that silently routes to the unlink branch and skips the API call."
+ (let ((pearl-saved-queries
+ (copy-tree '(("Q" :filter (:open t)
+ :linear-view-id "view-uuid"))))
+ (delete-called-with nil))
+ (cl-letf (((symbol-function 'yes-or-no-p)
+ (test-pearl--make-yes-no-stub '(t t nil))) ; yes / yes / no on delete-anyway
+ ((symbol-function 'customize-save-variable) (lambda (_ _) nil))
+ ((symbol-function 'pearl--progress) (lambda (&rest _) nil))
+ ((symbol-function 'message) (lambda (&rest _) nil))
+ ((symbol-function 'pearl--customview-delete-async)
+ (lambda (vid cb)
+ (setq delete-called-with vid)
+ (funcall cb (list :success nil :error "permission denied")))))
+ (pearl-delete-saved-query "Q")
+ (should (equal "view-uuid" delete-called-with))
+ (should (assoc "Q" pearl-saved-queries)))))
+
+(ert-deftest test-pearl-delete-saved-query-local-only-entry-unchanged-behavior ()
+ "Local-only entry (no `:linear-view-id'): one yes-or-no-p, no second prompt, no API call."
+ (let ((pearl-saved-queries
+ (copy-tree '(("Q" :filter (:open t)))))
+ (delete-called nil)
+ (prompt-count 0))
+ (cl-letf (((symbol-function 'yes-or-no-p)
+ (lambda (&rest _) (cl-incf prompt-count) t))
+ ((symbol-function 'customize-save-variable) (lambda (_ _) nil))
+ ((symbol-function 'message) (lambda (&rest _) nil))
+ ((symbol-function 'pearl--customview-delete-async)
+ (lambda (_ _) (setq delete-called t))))
+ (pearl-delete-saved-query "Q")
+ (should (= 1 prompt-count))
+ (should-not delete-called)
+ (should-not (assoc "Q" pearl-saved-queries)))))
+
(provide 'test-pearl-saved-query-sync)
;;; test-pearl-saved-query-sync.el ends here