diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-23 03:46:39 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-23 03:46:39 -0500 |
| commit | 0c1ba4a21228c8adc338b2652dd4b80d3ca84b2d (patch) | |
| tree | cc77a1fea96ab0ee9d27a415a020cca12ce7eda6 /tests | |
| parent | b6eb76f1b9483bf6282f7d1c8a05b23f38241ee8 (diff) | |
| download | dotemacs-0c1ba4a21228c8adc338b2652dd4b80d3ca84b2d.tar.gz dotemacs-0c1ba4a21228c8adc338b2652dd4b80d3ca84b2d.zip | |
test(flyspell-abbrev): cover checker gate, overlay search, mode dispatch
flyspell-and-abbrev.el had no tests. I added eight: cj/--require-spell-checker (errors when no checker is on PATH, passes when one is), cj/find-previous-flyspell-overlay against synthetic overlays (finds the closest previous flyspell overlay, ignores non-flyspell ones, returns nil when none exist), and cj/flyspell-on-for-buffer-type dispatching to flyspell-prog-mode in code buffers and flyspell-mode in text buffers.
I left cj/flyspell-then-abbrev to manual testing. Pinning its flyspell-UI orchestration would mean mocking flyspell internals rather than our own logic.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test-flyspell-and-abbrev.el | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/tests/test-flyspell-and-abbrev.el b/tests/test-flyspell-and-abbrev.el new file mode 100644 index 00000000..793fdc0f --- /dev/null +++ b/tests/test-flyspell-and-abbrev.el @@ -0,0 +1,101 @@ +;;; test-flyspell-and-abbrev.el --- Tests for flyspell-and-abbrev.el -*- lexical-binding: t; -*- + +;;; Commentary: +;; Coverage for the testable seams in flyspell-and-abbrev.el: +;; +;; - `cj/--require-spell-checker' (executable-find gate, mocked PATH) +;; - `cj/find-previous-flyspell-overlay' (overlay sort + flyspell/face filter, +;; exercised against synthetic overlays so no aspell is needed) +;; - `cj/flyspell-on-for-buffer-type' (prog-mode vs text-mode dispatch, with +;; the flyspell entry points mocked) +;; +;; `cj/flyspell-then-abbrev' is left to manual testing — it orchestrates +;; flyspell's interactive correction UI, and pinning it would mean mocking +;; flyspell internals rather than testing our logic. + +;;; Code: + +(require 'ert) +(require 'cl-lib) +(require 'flyspell) +(require 'flyspell-and-abbrev) + +(defun test-flyspell--make-incorrect-overlay (beg end) + "Make a flyspell `incorrect' overlay spanning BEG..END in the current buffer." + (let ((o (make-overlay beg end))) + (overlay-put o 'flyspell-overlay t) + (overlay-put o 'face 'flyspell-incorrect) + o)) + +;; ------------------------ cj/--require-spell-checker ------------------------- + +(ert-deftest test-flyspell-require-spell-checker-present () + "Normal: a checker on PATH means no error." + (cl-letf (((symbol-function 'executable-find) + (lambda (cmd) (equal cmd (car cj/--spell-checker-executables))))) + (should-not (cj/--require-spell-checker)))) + +(ert-deftest test-flyspell-require-spell-checker-missing () + "Error: no checker on PATH signals user-error." + (cl-letf (((symbol-function 'executable-find) (lambda (_) nil))) + (should-error (cj/--require-spell-checker) :type 'user-error))) + +;; --------------------- cj/find-previous-flyspell-overlay --------------------- + +(ert-deftest test-flyspell-find-previous-overlay-returns-start () + "Normal: a flyspell overlay before POSITION returns its start position." + (with-temp-buffer + (insert "hello world") + (test-flyspell--make-incorrect-overlay 1 6) + (should (= (cj/find-previous-flyspell-overlay (point-max)) 1)))) + +(ert-deftest test-flyspell-find-previous-overlay-picks-closest () + "Normal: with several, the closest overlay before POSITION wins." + (with-temp-buffer + (insert "alpha beta gamma delta") + (test-flyspell--make-incorrect-overlay 1 6) ; alpha + (test-flyspell--make-incorrect-overlay 12 17) ; gamma + (should (= (cj/find-previous-flyspell-overlay (point-max)) 12)))) + +(ert-deftest test-flyspell-find-previous-overlay-none () + "Boundary: no overlays at all yields nil." + (with-temp-buffer + (insert "nothing flagged here") + (should-not (cj/find-previous-flyspell-overlay (point-max))))) + +(ert-deftest test-flyspell-find-previous-overlay-skips-non-flyspell () + "Boundary: an overlay without the flyspell marker is ignored." + (with-temp-buffer + (insert "plain overlay text") + (let ((o (make-overlay 1 6))) + (overlay-put o 'face 'flyspell-incorrect)) ; face but not a flyspell overlay + (should-not (cj/find-previous-flyspell-overlay (point-max))))) + +;; --------------------- cj/flyspell-on-for-buffer-type ------------------------ + +(ert-deftest test-flyspell-on-for-buffer-type-prog-mode () + "Normal: in a prog-mode buffer, flyspell-prog-mode is used." + (let (prog-called) + (cl-letf (((symbol-function 'flyspell-prog-mode) (lambda () (setq prog-called t))) + ((symbol-function 'flyspell-mode) + (lambda (&rest _) (error "flyspell-mode should not run in prog-mode"))) + ((symbol-function 'flyspell-buffer) #'ignore)) + (with-temp-buffer + (emacs-lisp-mode) + (cj/flyspell-on-for-buffer-type))) + (should prog-called))) + +(ert-deftest test-flyspell-on-for-buffer-type-text-mode () + "Normal: in a text-mode buffer, flyspell-mode is used." + (let (mode-called) + (cl-letf (((symbol-function 'flyspell-mode) (lambda (&rest _) (setq mode-called t))) + ((symbol-function 'flyspell-prog-mode) + (lambda () (error "flyspell-prog-mode should not run in text-mode"))) + ((symbol-function 'flyspell-buffer) #'ignore)) + (with-temp-buffer + (text-mode) + (cj/flyspell-on-for-buffer-type))) + (should mode-called))) + +(provide 'test-flyspell-and-abbrev) +;;; test-flyspell-and-abbrev.el ends here |
