aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-07-13 23:19:36 -0500
committerCraig Jennings <c@cjennings.net>2026-07-13 23:19:36 -0500
commit00f1246fa32fa65571a141b1b685b95994fbfbc9 (patch)
treec86af3372d6e4c019aeaa782b44d011a4f8e10b5 /tests
parent9927367c02c4e8723af27efb1dedbb8f89149c85 (diff)
downloaddotemacs-00f1246fa32fa65571a141b1b685b95994fbfbc9.tar.gz
dotemacs-00f1246fa32fa65571a141b1b685b95994fbfbc9.zip
fix(mu4e-attachments): reject stale MIME handles at save time
The selection buffer captures MIME handles when it opens, but viewing another message kills the buffer a handle points at. Saving through such a handle died deep in mm-decode, or could write another message's bytes. The save path now signals a user-error naming the attachment when its handle's buffer is dead, and it checks before any mu4e MIME support loads, in the same spot as the existing no-handle check. I added tests for the stale-handle error, the healthy live-handle save, and the mid-batch failure behavior (the error propagates and files already written stay).
Diffstat (limited to 'tests')
-rw-r--r--tests/test-mu4e-attachments.el50
1 files changed, 50 insertions, 0 deletions
diff --git a/tests/test-mu4e-attachments.el b/tests/test-mu4e-attachments.el
index 0a780977..986c2746 100644
--- a/tests/test-mu4e-attachments.el
+++ b/tests/test-mu4e-attachments.el
@@ -75,6 +75,56 @@ so this fails the same way whether or not mu4e's MIME support is loadable."
(should-error (cj/mu4e--save-attachment-part part "/downloads")
:type 'user-error)))
+(ert-deftest test-mu4e-attachments-save-part-errors-on-stale-handle ()
+ "Error: a handle whose MIME buffer was killed fails with a clear error.
+The selection buffer captures handles when it opens; a real MIME handle's
+car is the buffer holding the part's bytes, and viewing another message
+kills it. Saving through it must signal a `user-error' naming the file,
+not die in `mm-save-part-to-file' (or save another message's bytes)."
+ (let* ((dead (generate-new-buffer "stale-mime-part"))
+ (part (test-mu4e-attachments--part "invoice.pdf" 3 (list dead))))
+ (kill-buffer dead)
+ (should-error (cj/mu4e--save-attachment-part part "/downloads")
+ :type 'user-error)
+ (condition-case err
+ (cj/mu4e--save-attachment-part part "/downloads")
+ (user-error (should (string-match-p "invoice\\.pdf" (cadr err)))))))
+
+(ert-deftest test-mu4e-attachments-save-part-live-buffer-handle-saves ()
+ "Normal: a handle whose MIME buffer is alive saves normally."
+ (let* ((live (generate-new-buffer "live-mime-part"))
+ (part (test-mu4e-attachments--part "invoice.pdf" 3 (list live)))
+ (mu4e-uniquify-save-file-name-function #'identity)
+ saved)
+ (unwind-protect
+ (cl-letf (((symbol-function 'mu4e-join-paths)
+ (lambda (&rest pieces) (mapconcat #'identity pieces "/")))
+ ((symbol-function 'mm-save-part-to-file)
+ (lambda (_handle path) (setq saved path))))
+ (should (equal (cj/mu4e--save-attachment-part part "/downloads")
+ "/downloads/invoice.pdf"))
+ (should (equal saved "/downloads/invoice.pdf")))
+ (kill-buffer live))))
+
+(ert-deftest test-mu4e-attachments-save-parts-mid-batch-failure-propagates ()
+ "Error: a mid-batch save failure propagates; earlier parts stay saved.
+Characterizes the batch path: no silent skip of the failing part, and the
+files already written are not rolled back."
+ (let ((parts (list (test-mu4e-attachments--part "a.pdf" 1)
+ (test-mu4e-attachments--part "b.pdf" 2)
+ (test-mu4e-attachments--part "c.pdf" 3)))
+ (saved '()))
+ (cl-letf (((symbol-function 'cj/mu4e--save-attachment-part)
+ (lambda (part _dir)
+ (let ((name (plist-get part :filename)))
+ (when (equal name "b.pdf")
+ (user-error "Stale handle: %s" name))
+ (push name saved)
+ name))))
+ (should-error (cj/mu4e--save-attachment-parts parts "/downloads")
+ :type 'user-error))
+ (should (equal (nreverse saved) '("a.pdf")))))
+
(ert-deftest test-mu4e-attachments-save-all-prompts-once ()
"Normal: the save-all command prompts for a directory once and saves all parts."
(let ((parts (list (test-mu4e-attachments--part "a.pdf" 1)