From 61ddfe9f7a9b2838e9c791027e5692cfd6ee128c Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Thu, 14 May 2026 01:17:12 -0500 Subject: test(custom-buffer-file): cover print spooler, diff, eww, email helpers Sibling tests cover the move/rename/copy/clear family. The remaining helpers and dispatchers were uncovered: - `cj/print--resolve-spooler`: explicit-string on PATH, explicit-string missing (error), `auto` prefers lpr, `auto` falls back to lp, `auto` with nothing on PATH (error), `auto` returns cached value, invalid spooler symbol (error). - `cj/copy-buffer-name`: places the current buffer's name on the kill ring with a confirmation message. - `cj/view-buffer-in-eww`: hands the file off to `eww-open-file` when visiting a file, errors otherwise. - `cj/--email-handle-is-type-p`: prefix-matches content-types, handles nil handle without signaling. - `cj/--diff-with-regular-diff`: writes a unified diff into the target buffer with header + diff output. - `cj/diff-buffer-with-file`: errors when not visiting a file, messages "No differences" when diff -q returns 0. 16 new tests total. `call-process`, `executable-find`, `eww-open-file`, `mm-handle-type`, `diff-mode` are stubbed. --- tests/test-custom-buffer-file-print-diff-eww.el | 189 ++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 tests/test-custom-buffer-file-print-diff-eww.el diff --git a/tests/test-custom-buffer-file-print-diff-eww.el b/tests/test-custom-buffer-file-print-diff-eww.el new file mode 100644 index 00000000..9aa73cbe --- /dev/null +++ b/tests/test-custom-buffer-file-print-diff-eww.el @@ -0,0 +1,189 @@ +;;; test-custom-buffer-file-print-diff-eww.el --- Tests for the print/diff/eww/email helpers -*- lexical-binding: t; -*- + +;;; Commentary: +;; Sibling tests cover the move/rename/copy/clear family. This file +;; fills in the remaining helpers and dispatchers: +;; +;; cj/print--resolve-spooler +;; cj/copy-buffer-name +;; cj/--diff-with-regular-diff +;; cj/diff-buffer-with-file +;; cj/view-buffer-in-eww +;; cj/--email-handle-is-type-p +;; +;; External processes (`call-process', `executable-find', `lpr', `lp', +;; `difft', `diff', `eww-open-file') are stubbed so the tests don't +;; require any of those tools. + +;;; Code: + +(require 'ert) +(require 'cl-lib) + +(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory)) +(require 'custom-buffer-file) + +;;; ---------- cj/print--resolve-spooler ---------- + +(ert-deftest test-cbf-resolve-spooler-explicit-string-and-on-path () + "Normal: explicit string spooler on PATH is returned verbatim." + (let ((cj/print-spooler-command "lpr") + (cj/print--spooler-cache nil)) + (cl-letf (((symbol-function 'executable-find) + (lambda (cmd) (when (equal cmd "lpr") "/usr/bin/lpr")))) + (should (equal (cj/print--resolve-spooler) "lpr"))))) + +(ert-deftest test-cbf-resolve-spooler-explicit-string-missing-errors () + "Error: explicit string spooler not on PATH signals user-error." + (let ((cj/print-spooler-command "notathing") + (cj/print--spooler-cache nil)) + (cl-letf (((symbol-function 'executable-find) (lambda (_) nil))) + (should-error (cj/print--resolve-spooler) :type 'user-error)))) + +(ert-deftest test-cbf-resolve-spooler-auto-detects-lpr-first () + "Normal: `auto' prefers lpr over lp and caches the result." + (let ((cj/print-spooler-command 'auto) + (cj/print--spooler-cache nil)) + (cl-letf (((symbol-function 'executable-find) + (lambda (cmd) (when (equal cmd "lpr") "/usr/bin/lpr")))) + (should (equal (cj/print--resolve-spooler) "lpr")) + (should (equal cj/print--spooler-cache "lpr"))))) + +(ert-deftest test-cbf-resolve-spooler-auto-falls-back-to-lp () + "Boundary: when lpr is missing but lp is on PATH, lp wins." + (let ((cj/print-spooler-command 'auto) + (cj/print--spooler-cache nil)) + (cl-letf (((symbol-function 'executable-find) + (lambda (cmd) (when (equal cmd "lp") "/usr/bin/lp")))) + (should (equal (cj/print--resolve-spooler) "lp"))))) + +(ert-deftest test-cbf-resolve-spooler-auto-no-tool-errors () + "Error: `auto' with neither lpr nor lp signals user-error." + (let ((cj/print-spooler-command 'auto) + (cj/print--spooler-cache nil)) + (cl-letf (((symbol-function 'executable-find) (lambda (_) nil))) + (should-error (cj/print--resolve-spooler) :type 'user-error)))) + +(ert-deftest test-cbf-resolve-spooler-auto-returns-cached-value () + "Boundary: a non-nil cache short-circuits the auto-detect." + (let ((cj/print-spooler-command 'auto) + (cj/print--spooler-cache "cached-cmd")) + (cl-letf (((symbol-function 'executable-find) + (lambda (_) (error "should not be called")))) + (should (equal (cj/print--resolve-spooler) "cached-cmd"))))) + +(ert-deftest test-cbf-resolve-spooler-invalid-value-errors () + "Error: a value that's neither a string nor `auto' signals user-error." + (let ((cj/print-spooler-command 'something-weird) + (cj/print--spooler-cache nil)) + (should-error (cj/print--resolve-spooler) :type 'user-error))) + +;;; ---------- cj/copy-buffer-name ---------- + +(ert-deftest test-cbf-copy-buffer-name-kills-buffer-name () + "Normal: the current buffer's name lands on the kill ring with a message." + (let ((killed nil) + (msg nil)) + (with-temp-buffer + (rename-buffer "*test-cbf-copy-name*" t) + (cl-letf (((symbol-function 'kill-new) + (lambda (s) (setq killed s))) + ((symbol-function 'message) + (lambda (fmt &rest args) + (setq msg (apply #'format fmt args))))) + (cj/copy-buffer-name))) + (should (string-prefix-p "*test-cbf-copy-name*" killed)) + (should (string-match-p "Copied" msg)))) + +;;; ---------- cj/view-buffer-in-eww ---------- + +(ert-deftest test-cbf-view-buffer-in-eww-normal-hands-off-to-eww () + "Normal: with a file-visiting buffer, `eww-open-file' is called with the file." + (let ((opened nil)) + (with-temp-buffer + (setq buffer-file-name "/tmp/sample.html") + (cl-letf (((symbol-function 'eww-open-file) + (lambda (f) (setq opened f)))) + (cj/view-buffer-in-eww)) + (setq buffer-file-name nil)) + (should (equal opened "/tmp/sample.html")))) + +(ert-deftest test-cbf-view-buffer-in-eww-error-not-visiting-file () + "Error: a buffer not visiting a file signals user-error; eww isn't called." + (with-temp-buffer + (let ((called nil)) + (cl-letf (((symbol-function 'eww-open-file) + (lambda (_) (setq called t)))) + (should-error (cj/view-buffer-in-eww) :type 'user-error)) + (should-not called)))) + +;;; ---------- cj/--email-handle-is-type-p ---------- + +(ert-deftest test-cbf-email-handle-is-type-p-matches-prefix () + "Normal: `text/html' matches a content-type with charset suffix." + (let ((handle '("buffer" ("text/html" "charset" . "utf-8")))) + (cl-letf (((symbol-function 'mm-handle-type) + (lambda (_) '("text/html" "charset" . "utf-8")))) + (should (cj/--email-handle-is-type-p handle "text/html"))))) + +(ert-deftest test-cbf-email-handle-is-type-p-no-match () + "Boundary: a plain-text handle doesn't match a text/html request." + (let ((handle '("buffer" ("text/plain")))) + (cl-letf (((symbol-function 'mm-handle-type) + (lambda (_) '("text/plain")))) + (should-not (cj/--email-handle-is-type-p handle "text/html"))))) + +(ert-deftest test-cbf-email-handle-is-type-p-nil-handle-returns-nil () + "Error: a nil handle returns nil instead of signaling." + (should-not (cj/--email-handle-is-type-p nil "text/html"))) + +;;; ---------- cj/--diff-with-regular-diff ---------- + +(ert-deftest test-cbf-diff-with-regular-diff-renders-buffer-content () + "Normal: regular diff helper writes a header and diff output into BUFFER." + (let ((called-with nil)) + (let ((buf (generate-new-buffer "*test-cbf-diff*"))) + (unwind-protect + (progn + (cl-letf (((symbol-function 'call-process) + (lambda (prog _infile _buf _disp &rest args) + (setq called-with (cons prog args)) + (with-current-buffer (current-buffer) + (insert "@@ -1 +1 @@\n-old\n+new\n")) + 0)) + ((symbol-function 'diff-mode) #'ignore)) + (cj/--diff-with-regular-diff "/tmp/a.txt" "/tmp/b.txt" buf)) + (with-current-buffer buf + (should (string-match-p "Unified diff" (buffer-string))) + (should (string-match-p "@@" (buffer-string))))) + (when (buffer-live-p buf) (kill-buffer buf)))) + (should (equal (car called-with) "diff")))) + +;;; ---------- cj/diff-buffer-with-file ---------- + +(ert-deftest test-cbf-diff-buffer-with-file-error-not-visiting-file () + "Error: a buffer not visiting a file signals user-error." + (with-temp-buffer + (should-error (cj/diff-buffer-with-file) :type 'user-error))) + +(ert-deftest test-cbf-diff-buffer-with-file-no-changes-messages () + "Normal: when the saved file and buffer match, diff returns 0 -> messages \"No differences\"." + (let ((tmp (make-temp-file "test-cbf-diff-"))) + (with-temp-file tmp (insert "content")) + (unwind-protect + (let ((msg nil)) + (with-temp-buffer + (insert "content") + (setq buffer-file-name tmp) + (cl-letf (((symbol-function 'call-process) + (lambda (&rest _) 0)) ; pretend "diff -q" exits 0 + ((symbol-function 'message) + (lambda (fmt &rest args) + (setq msg (apply #'format fmt args))))) + (cj/diff-buffer-with-file)) + (setq buffer-file-name nil)) + (should (string-match-p "No differences" msg))) + (delete-file tmp)))) + +(provide 'test-custom-buffer-file-print-diff-eww) +;;; test-custom-buffer-file-print-diff-eww.el ends here -- cgit v1.2.3