diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test-pearl-mapping.el | 28 | ||||
| -rw-r--r-- | tests/test-pearl-save.el | 75 | ||||
| -rw-r--r-- | tests/test-pearl-todo-keywords.el | 22 |
3 files changed, 104 insertions, 21 deletions
diff --git a/tests/test-pearl-mapping.el b/tests/test-pearl-mapping.el index 2a96163..b5faa3d 100644 --- a/tests/test-pearl-mapping.el +++ b/tests/test-pearl-mapping.el @@ -37,27 +37,13 @@ (pearl--todo-states-pattern-source nil)) ,@body)) -;;; pearl--map-linear-state-to-org - -(ert-deftest test-pearl-map-linear-state-to-org-mapped-returns-keyword () - "A Linear state present in the mapping returns its org keyword." - (test-pearl--with-mapping '(("Todo" . "TODO") ("In Progress" . "DOING")) - (should (string-equal "DOING" (pearl--map-linear-state-to-org "In Progress"))))) - -(ert-deftest test-pearl-map-linear-state-to-org-unmapped-defaults-todo () - "An unmapped Linear state falls back to TODO." - (test-pearl--with-mapping '(("Todo" . "TODO") ("Done" . "DONE")) - (should (string-equal "TODO" (pearl--map-linear-state-to-org "Triage"))))) - -(ert-deftest test-pearl-map-linear-state-to-org-nil-defaults-todo () - "A nil state falls back to TODO rather than erroring." - (test-pearl--with-mapping '(("Todo" . "TODO")) - (should (string-equal "TODO" (pearl--map-linear-state-to-org nil))))) - -;; pearl--map-org-state-to-linear (the keyword->state reverse map) was removed -;; with the org-sync push path in save-model-v2; the keyword-cycle save will -;; resolve through the team's states (the keyword-derivation task), not a flat -;; reverse mapping. +;; pearl--map-linear-state-to-org (the static name->keyword lookup) was removed +;; in the keyword-cycle save: the keyword is now always the slug of the state +;; name (`pearl--state-name-to-keyword'), matching the workspace-derived #+TODO +;; header, and the keyword->state-id direction resolves through the team's +;; states (`pearl--resolve-keyword-to-state'), not a flat mapping. The mapping +;; alist itself survives only as the source for `pearl--get-todo-states-pattern' +;; (tested below). ;;; pearl--get-todo-states-pattern diff --git a/tests/test-pearl-save.el b/tests/test-pearl-save.el index 1f4f273..22df84e 100644 --- a/tests/test-pearl-save.el +++ b/tests/test-pearl-save.el @@ -153,6 +153,21 @@ (org-entry-put nil "LINEAR-STATE-ID" "s2") (should (plist-get (pearl--issue-dirty-fields) :state)))) +(ert-deftest test-pearl-dirty-fields-state-keyword-cycle () + "Cycling the TODO keyword away from the synced state-name slug marks state dirty, +even when the explicit state id still matches its baseline." + (test-pearl-save--in-rendered (test-pearl-save--structured-issue) + (org-back-to-heading t) + (let ((org-after-todo-state-change-hook nil)) + (org-todo "DONE")) ; TODO -> DONE, id untouched + (should (plist-get (pearl--issue-dirty-fields) :state)))) + +(ert-deftest test-pearl-dirty-fields-state-fresh-keyword-not-dirty () + "A freshly rendered state (keyword equals the state-name slug) is not state dirty." + (test-pearl-save--in-rendered (test-pearl-save--structured-issue) + (org-back-to-heading t) + (should-not (plist-get (pearl--issue-dirty-fields) :state)))) + (ert-deftest test-pearl-dirty-fields-assignee-change () "An assignee id different from the synced baseline marks assignee dirty." (test-pearl-save--in-rendered (test-pearl-save--structured-issue) @@ -495,6 +510,66 @@ skipped (the remote push already landed), not signal." (should (string= "s2" pushed)) (should (string= "s2" (org-entry-get marker "LINEAR-STATE-ID-SYNCED"))))))) +(ert-deftest test-pearl-save-state-keyword-cycle-resolves-and-pushes () + "A keyword-cycled state (id unmoved) resolves the keyword to its team state id +by slug match, pushes that id, and writes the resolved name/id/baseline." + (test-pearl-save--in-rendered + '(:id "u" :identifier "ENG-1" :title "t" :priority 2 + :state (:id "s1" :name "Todo") :description "body") + (goto-char (point-min)) + (insert "#+TODO: TODO IN-PROGRESS | DONE\n") + (org-mode) ; re-init so the keywords take + (goto-char (point-min)) + (re-search-forward "ENG-1") + (org-back-to-heading t) + (org-entry-put nil "LINEAR-TEAM-ID" "team-1") + (progn + (let ((org-after-todo-state-change-hook nil)) + (org-todo "IN-PROGRESS")) ; cycle keyword, leave id = s1 + (let ((marker (point-marker)) outcome pushed) + (cl-letf (((symbol-function 'pearl--team-states) + (lambda (_tid) + '(((id . "s1") (name . "Todo") (type . "unstarted") (position . 1.0)) + ((id . "s2") (name . "In Progress") (type . "started") (position . 2.0))))) + ((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"))) + (should (string= "In Progress" (org-entry-get marker "LINEAR-STATE-NAME"))) + (should (string= "s2" (org-entry-get marker "LINEAR-STATE-ID-SYNCED")))))))) + +(ert-deftest test-pearl-save-state-keyword-cycle-unknown-keyword-skips () + "A keyword no team state slugifies to cannot be resolved, so the save is skipped +with no push." + (test-pearl-save--in-rendered + '(:id "u" :identifier "ENG-1" :title "t" :priority 2 + :state (:id "s1" :name "Todo") :description "body") + (goto-char (point-min)) + (insert "#+TODO: TODO BLOCKED | DONE\n") + (org-mode) + (goto-char (point-min)) + (re-search-forward "ENG-1") + (org-back-to-heading t) + (org-entry-put nil "LINEAR-TEAM-ID" "team-1") + (progn + (let ((org-after-todo-state-change-hook nil)) + (org-todo "BLOCKED")) ; no team state slugifies to BLOCKED + (let ((marker (point-marker)) outcome (pushed :none)) + (cl-letf (((symbol-function 'pearl--team-states) + (lambda (_tid) + '(((id . "s1") (name . "Todo") (type . "unstarted") (position . 1.0))))) + ((symbol-function 'pearl--update-issue-async) + (lambda (_id _input cb) (setq pushed :called) (funcall cb '(:success t))))) + (pearl--save-state-field marker (lambda (o) (setq outcome o))) + (should (eq 'skipped (plist-get outcome :status))) + (should (eq :none pushed))))))) + (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 diff --git a/tests/test-pearl-todo-keywords.el b/tests/test-pearl-todo-keywords.el index 281beea..0555a4e 100644 --- a/tests/test-pearl-todo-keywords.el +++ b/tests/test-pearl-todo-keywords.el @@ -150,5 +150,27 @@ ;; SHIPPED is an org done-keyword, so it lands on the done side (should (re-search-forward "^#\\+TODO: *\\| SHIPPED$" nil t))))) +;;; --resolve-keyword-to-state (keyword -> team state id, save-time) + +(ert-deftest test-pearl-resolve-keyword-to-state-collision-first-by-position () + "When two state names slugify to the same keyword, the lower position wins." + (cl-letf (((symbol-function 'pearl--team-states) + (lambda (_tid) + '(((id . "s-hi") (name . "Dev Review") (type . "started") (position . 5.0)) + ((id . "s-lo") (name . "Dev-Review") (type . "started") (position . 2.0)))))) + (let ((r (pearl--resolve-keyword-to-state "DEV-REVIEW" "t1"))) + (should (string= "s-lo" (plist-get r :id))) + (should (string= "Dev-Review" (plist-get r :name))) + (should (string= "started" (plist-get r :type)))))) + +(ert-deftest test-pearl-resolve-keyword-to-state-no-match-or-empty-returns-nil () + "A keyword no state slugifies to yields nil, as does an empty/failed fetch." + (cl-letf (((symbol-function 'pearl--team-states) + (lambda (_tid) + '(((id . "s1") (name . "Todo") (type . "unstarted") (position . 1.0)))))) + (should-not (pearl--resolve-keyword-to-state "BLOCKED" "t1"))) + (cl-letf (((symbol-function 'pearl--team-states) (lambda (_tid) nil))) + (should-not (pearl--resolve-keyword-to-state "TODO" "t1")))) + (provide 'test-pearl-todo-keywords) ;;; test-pearl-todo-keywords.el ends here |
