diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-10 14:04:22 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-10 14:04:22 -0500 |
| commit | c75e36f4ec6764142499a3ec965d25895c564cb0 (patch) | |
| tree | a6435a99ee57afa47ea6905faea6078938ae1578 /tests/test-system-lib-executable-find-or-warn.el | |
| parent | 502bcf41c7258b169d6481676c59c42e0e931e7c (diff) | |
| download | dotemacs-c75e36f4ec6764142499a3ec965d25895c564cb0.tar.gz dotemacs-c75e36f4ec6764142499a3ec965d25895c564cb0.zip | |
refactor(system-lib): extract cj/executable-find-or-warn from mail-config
Phase 2 of utility-consolidation, first commit per the spec's recommended order. `cj/mail--executable-or-warn' was the right pattern -- check executable-find, return the path, otherwise emit a clear `display-warning' naming the feature -- but it was trapped in mail-config and only mail callers benefited. Lift it into `cj/executable-find-or-warn' in system-lib.el with one new argument: an optional GROUP symbol that flows through to `display-warning' (defaulting to `cj/system-lib') so per-feature warning filters keep working. Mail callers pass `mail-config' explicitly.
Migrate `cj/mail--mbsync-command' and `cj/mail-configure-smtpmail' to the new helper. Drop the local definition. Add `(require \='system-lib)' to mail-config.el per the spec's Phase 2 exit criterion ("consumer modules explicitly require system-lib").
Five Normal/Boundary tests cover the four return-shape cases (program found / program missing / warning content / default vs explicit group).
Other consumers (prog-*.el, dirvish-config.el, browser-config.el) still call `executable-find' directly. Migrating them is a follow-up commit, audited per call site -- the spec flags some `:if' silent checks as intentional and they should NOT switch to the warning helper.
Diffstat (limited to 'tests/test-system-lib-executable-find-or-warn.el')
| -rw-r--r-- | tests/test-system-lib-executable-find-or-warn.el | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/tests/test-system-lib-executable-find-or-warn.el b/tests/test-system-lib-executable-find-or-warn.el new file mode 100644 index 00000000..e9a540bd --- /dev/null +++ b/tests/test-system-lib-executable-find-or-warn.el @@ -0,0 +1,80 @@ +;;; test-system-lib-executable-find-or-warn.el --- Tests for cj/executable-find-or-warn -*- lexical-binding: t; -*- + +;;; Commentary: +;; `cj/executable-find-or-warn' generalizes the mail-specific +;; `cj/mail--executable-or-warn' pattern. Returns the program's +;; executable path when found. When the program is missing, returns +;; nil AND emits a `display-warning' naming the feature that's +;; unavailable, so the user gets a clear hint about what won't work. +;; The optional GROUP argument controls `display-warning' grouping so +;; per-feature filters keep working. + +;;; Code: + +(require 'ert) +(require 'cl-lib) + +(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory)) +(require 'system-lib) + +(defmacro test-system-lib-find-or-warn--with-stubs (executable-fn warning-capture &rest body) + "Run BODY with `executable-find' and `display-warning' stubbed. + +EXECUTABLE-FN replaces `executable-find' (takes a string program name, +returns path or nil). WARNING-CAPTURE is a symbol bound in BODY's scope +to a list of (TYPE MESSAGE LEVEL) entries collected from +`display-warning' calls." + (declare (indent 2)) + `(let ((,warning-capture nil)) + (cl-letf (((symbol-function 'executable-find) ,executable-fn) + ((symbol-function 'display-warning) + (lambda (type message &optional level) + (push (list type message level) ,warning-capture)))) + ,@body))) + +(ert-deftest test-cj-executable-find-or-warn-program-found-returns-path () + "Normal: when the program exists, return its path and emit no warning." + (test-system-lib-find-or-warn--with-stubs + (lambda (prog) (when (string= prog "mbsync") "/usr/bin/mbsync")) + warnings + (let ((result (cj/executable-find-or-warn "mbsync" "mu4e mail sync"))) + (should (equal result "/usr/bin/mbsync")) + (should-not warnings)))) + +(ert-deftest test-cj-executable-find-or-warn-program-missing-returns-nil () + "Normal: when the program is missing, return nil." + (test-system-lib-find-or-warn--with-stubs + (lambda (_prog) nil) + _warnings + (should-not (cj/executable-find-or-warn "missing-prog" "fake feature")))) + +(ert-deftest test-cj-executable-find-or-warn-missing-emits-warning () + "Normal: a missing program produces a warning that names PROGRAM and FEATURE." + (test-system-lib-find-or-warn--with-stubs + (lambda (_prog) nil) + warnings + (cj/executable-find-or-warn "missing-prog" "fake feature") + (should (= 1 (length warnings))) + (let ((entry (car warnings))) + (should (string-match-p "missing-prog" (nth 1 entry))) + (should (string-match-p "fake feature" (nth 1 entry))) + (should (eq :warning (nth 2 entry)))))) + +(ert-deftest test-cj-executable-find-or-warn-default-group () + "Boundary: with no GROUP arg, the warning uses the default `cj/system-lib' symbol." + (test-system-lib-find-or-warn--with-stubs + (lambda (_prog) nil) + warnings + (cj/executable-find-or-warn "missing-prog" "feature") + (should (eq 'cj/system-lib (car (car warnings)))))) + +(ert-deftest test-cj-executable-find-or-warn-explicit-group () + "Normal: an explicit GROUP arg flows through to `display-warning'." + (test-system-lib-find-or-warn--with-stubs + (lambda (_prog) nil) + warnings + (cj/executable-find-or-warn "missing-prog" "feature" 'mail-config) + (should (eq 'mail-config (car (car warnings)))))) + +(provide 'test-system-lib-executable-find-or-warn) +;;; test-system-lib-executable-find-or-warn.el ends here |
