From 899c55f230d96649bdd3a3f4a8a0302ecf2df994 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Tue, 26 May 2026 19:28:05 -0500 Subject: feat(refresh): prompt instead of silently deferring a dirty refresh Running pearl-list-issues on a buffer with unsaved edits used to print a passive "refresh deferred" message and do nothing visible, so it read as a no-op. Now it prompts: (d)iscard and rebuild, (m)erge by LINEAR-ID keeping the edits, or (q) cancel. Branch C of pearl--update-org-from-issues dispatches on the choice: discard rebuilds in place, merge hands off to the same by-id merge that pearl-refresh-current-view uses, and cancel leaves the buffer untouched. --- tests/test-pearl-output.el | 59 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) (limited to 'tests/test-pearl-output.el') diff --git a/tests/test-pearl-output.el b/tests/test-pearl-output.el index eb5c671..58cd446 100644 --- a/tests/test-pearl-output.el +++ b/tests/test-pearl-output.el @@ -184,5 +184,64 @@ (kill-buffer buf)) (ignore-errors (delete-file tmp))))) +;;; --update-org-from-issues on a dirty buffer (prompted: discard / merge / cancel) + +(defconst test-pearl-output--issue + '(:id "u" :identifier "ENG-1" :title "Hello" :priority 2 :state (:name "Todo")) + "A minimal normalized issue for the dirty-buffer branch tests.") + +(defmacro test-pearl-output--with-dirty-buffer (choice &rest body) + "Run BODY with a modified buffer visiting a temp active file and the dirty +refresh prompt stubbed to return CHOICE. BUF and TMP are bound in BODY." + (declare (indent 1)) + `(let* ((tmp (make-temp-file "pearl-dirty" nil ".org")) + (pearl-org-file-path tmp) + (buf (find-file-noselect tmp))) + (unwind-protect + (with-current-buffer buf + (insert "DIRTYMARKER not yet saved\n") ; buffer is now modified + (cl-letf (((symbol-function 'pearl--surface-buffer) #'ignore) + ((symbol-function 'pearl--dirty-refresh-choice) + (lambda (_path) ,choice))) + ,@body)) + (when (buffer-live-p buf) + (with-current-buffer buf (set-buffer-modified-p nil)) + (kill-buffer buf)) + (ignore-errors (delete-file tmp))))) + +(ert-deftest test-pearl-update-org-dirty-discard-rebuilds () + "Choosing discard rebuilds the buffer from the fetch and clears the edits." + (test-pearl-output--with-dirty-buffer ?d + (pearl--update-org-from-issues (list test-pearl-output--issue) + '(:type filter :name "X" :filter nil) nil) + (should-not (buffer-modified-p)) + (should-not (string-match-p "DIRTYMARKER" (buffer-string))) + (should (string-match-p "ENG-1" (buffer-string))))) + +(ert-deftest test-pearl-update-org-dirty-cancel-leaves-buffer () + "Choosing cancel leaves the dirty buffer untouched." + (test-pearl-output--with-dirty-buffer ?q + (pearl--update-org-from-issues (list test-pearl-output--issue) + '(:type filter :name "X" :filter nil) nil) + (should (buffer-modified-p)) + (should (string-match-p "DIRTYMARKER" (buffer-string))) + (should-not (string-match-p "ENG-1" (buffer-string))))) + +(ert-deftest test-pearl-update-org-dirty-merge-routes-to-merge () + "Choosing merge routes to the by-LINEAR-ID merge instead of a rebuild." + (let ((merged nil)) + (test-pearl-output--with-dirty-buffer ?m + (cl-letf (((symbol-function 'pearl--merge-issues-into-buffer) + (lambda (_issues) (setq merged t) '(:updated 1 :added 0 :dropped 0 :skipped 0))) + ((symbol-function 'pearl--update-source-header) #'ignore) + ((symbol-function 'pearl--update-derived-todo-header) #'ignore) + ((symbol-function 'pearl-highlight-comments) #'ignore) + ((symbol-function 'pearl--restore-page-visibility) #'ignore)) + (pearl--update-org-from-issues (list test-pearl-output--issue) + '(:type filter :name "X" :filter nil) nil)) + (should merged) + ;; merge does not rebuild, so the marker is not wiped by a full replace + (should (string-match-p "DIRTYMARKER" (buffer-string)))))) + (provide 'test-pearl-output) ;;; test-pearl-output.el ends here -- cgit v1.2.3