diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-25 20:26:50 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-25 20:26:50 -0500 |
| commit | 684068a81103e9a9dace2f5cc6fd49edc1f01ab1 (patch) | |
| tree | 1a38b043c64f77be4370aa9a9c82d6579fbb9a44 /tests/test-pearl-save.el | |
| parent | 09cf1f02161aaef9bb1ad26907472bea52f53a24 (diff) | |
| download | pearl-684068a81103e9a9dace2f5cc6fd49edc1f01ab1.tar.gz pearl-684068a81103e9a9dace2f5cc6fd49edc1f01ab1.zip | |
feat(save): add the priority, state, and labels savers
These are three more savers on the atomic engine, each the same spec shape the assignee saver proved, with its own field handling. Priority reads the cookie's number, diffs it against LINEAR-PRIORITY, and pushes priority. State is the picker arm — the explicit LINEAR-STATE-ID against LINEAR-STATE-ID-SYNCED, pushing stateId, with use-remote rewriting the keyword and name from the fetched node (the keyword-cycle arm stays gated on the derivation task). Labels canonicalize the id set to a sorted space-joined string so the diff is order-insensitive, and push labelIds.
Canonicalizing labels to a string also keeps the missing-baseline check honest: an issue with no labels has a present-but-empty baseline, which a nil-vs-empty-list comparison would misread as a legacy file. A shared set of pearl--node-* helpers pulls each field out of the raw issue node.
I also fixed pearl--get-linear-priority-name, which mapped None to "Medium" — it now reads "None", so the conflict prompt names the priority honestly.
It's still not wired into save-issue — the next commit does that.
Diffstat (limited to 'tests/test-pearl-save.el')
| -rw-r--r-- | tests/test-pearl-save.el | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/tests/test-pearl-save.el b/tests/test-pearl-save.el index edd2c2d..8df7b3b 100644 --- a/tests/test-pearl-save.el +++ b/tests/test-pearl-save.el @@ -397,6 +397,70 @@ the conflict choice (stubbed). Returns (:outcome :fetched :pushed :applied (should (string= "a2" pushed)) (should (string= "a2" (org-entry-get marker "LINEAR-ASSIGNEE-ID-SYNCED"))))))) +;;; --save-priority-field / --save-state-field / --save-labels-field + +(ert-deftest test-pearl-save-priority-clean-push-advances-baseline () + "A cookie-changed priority with an unmoved remote pushes and advances LINEAR-PRIORITY." + (test-pearl-save--in-rendered + '(:id "u" :identifier "ENG-1" :title "t" :priority 2 + :state (:id "s1" :name "Todo") :description "body") + (org-back-to-heading t) + (let ((org-priority-highest ?A) (org-priority-lowest ?D)) + (org-priority ?C)) ; [#B] (2) -> [#C] (3) + (let ((marker (point-marker)) outcome pushed) + (cl-letf (((symbol-function 'pearl--fetch-issue-async) + (lambda (_id cb) (funcall cb '((priority . 2))))) ; remote unmoved + ((symbol-function 'pearl--update-issue-async) + (lambda (_id input cb) + (setq pushed (cdr (assoc "priority" input))) + (funcall cb '(:success t))))) + (pearl--save-priority-field marker (lambda (o) (setq outcome o))) + (should (eq 'pushed (plist-get outcome :status))) + (should (eql 3 pushed)) + (should (string= "3" (org-entry-get marker "LINEAR-PRIORITY"))))))) + +(ert-deftest test-pearl-save-state-picker-clean-push-advances-baseline () + "A picker-changed state with an unmoved remote pushes stateId and advances the baseline." + (test-pearl-save--in-rendered + '(:id "u" :identifier "ENG-1" :title "t" :priority 2 + :state (:id "s1" :name "Todo") :description "body") + (org-back-to-heading t) + (org-entry-put nil "LINEAR-STATE-ID" "s2") ; the picker chose another state + (let ((marker (point-marker)) outcome pushed) + (cl-letf (((symbol-function 'pearl--fetch-issue-async) + (lambda (_id cb) (funcall cb '((state (id . "s1") (name . "Todo")))))) + ((symbol-function 'pearl--update-issue-async) + (lambda (_id input cb) + (setq pushed (cdr (assoc "stateId" input))) + (funcall cb '(:success t))))) + (pearl--save-state-field marker (lambda (o) (setq outcome o))) + (should (eq 'pushed (plist-get outcome :status))) + (should (string= "s2" pushed)) + (should (string= "s2" (org-entry-get marker "LINEAR-STATE-ID-SYNCED"))))))) + +(ert-deftest test-pearl-save-labels-clean-push-advances-baseline () + "A changed label set with an unmoved remote pushes labelIds and advances the baseline." + (test-pearl-save--in-rendered + '(:id "u" :identifier "ENG-1" :title "t" :priority 2 + :state (:id "s1" :name "Todo") + :labels ((:id "l1" :name "bug") (:id "l2" :name "backend")) + :description "body") + (org-back-to-heading t) + (org-entry-put nil "LINEAR-LABEL-IDS" "l1 l3") ; dropped l2, added l3 + (let ((marker (point-marker)) outcome pushed) + (cl-letf (((symbol-function 'pearl--fetch-issue-async) + (lambda (_id cb) + (funcall cb '((labels (nodes ((id . "l1") (name . "bug")) + ((id . "l2") (name . "backend")))))))) + ((symbol-function 'pearl--update-issue-async) + (lambda (_id input cb) + (setq pushed (cdr (assoc "labelIds" input))) + (funcall cb '(:success t))))) + (pearl--save-labels-field marker (lambda (o) (setq outcome o))) + (should (eq 'pushed (plist-get outcome :status))) + (should (equal ["l1" "l3"] pushed)) + (should (string= "l1 l3" (org-entry-get marker "LINEAR-LABEL-IDS-SYNCED"))))))) + ;;; --save-description-field (advances both provenance hashes) (ert-deftest test-pearl-save-description-advances-both-hashes () |
