Subject: 31.0.50; Improve ispell.el documentation

From: Lockywolf <[email-masked]>
Date: Wed, 10 Sep 2025 10:12:57 +0800

Dear Emacs developers,

The following patch contains what I consider to be an improvement to the
Emacs Manual with respect to the ~ispell.el~ spell-checking component.

The patch is attached.

>From e5661b558e1ea0c4dbcc1ceef0c0c760ec5060f3 Mon Sep 17 00:00:00 2001
From: Lockywolf <[email-masked]>
Date: Mon, 8 Sep 2025 13:13:25 +0800
Subject: [PATCH] Add tests to inspell.el interactive functions.

* test/lisp/textmodes/ispell-tests/ispell-tests.el:
  Add tests for
  1. ispell-kill-ispell
  2. ispell-region
  3. ispell-buffer
  4. ispell-change-dictionary
  5. ispell-comments-and-strings
  6. ispell-comment-or-string-at-point
  7. ispell-pdict-save
  8. ispell-lookup-words
  9. ispell-complete-word
  10. ispell-complete-word-interior-frag
  11. ispell-completion-at-point
  12. ispell-minor-mode
  13. ispell-message
* test/lisp/textmodes/ispell-tests/ispell-aspell-tests.el:
  1. ispell-word
---
 lisp/textmodes/ispell.el                      |   3 +-
 .../ispell-resources/fake-aspell-new.bash     |  64 +-
 .../ispell-tests/ispell-aspell-tests.el       | 106 +++
 .../ispell-tests/ispell-hunspell-tests.el     |   5 +
 .../ispell-international-ispell-tests.el      |   3 +
 .../ispell-tests/ispell-tests-common.el       |  41 +-
 .../textmodes/ispell-tests/ispell-tests.el    | 653 +++++++++++++++---
 7 files changed, 758 insertions(+), 117 deletions(-)

diff --git a/lisp/textmodes/ispell.el b/lisp/textmodes/ispell.el
index ad7c8571f67..b37d07f5e62 100644
--- a/lisp/textmodes/ispell.el
+++ b/lisp/textmodes/ispell.el
@@ -1803,7 +1803,8 @@ ispell-accept-output
     (if (null ispell-process)
 	(error "No Ispell process to read output from!")
       (let ((buf ispell-output-buffer)
-	    ispell-output)
+	    (ispell-output nil))
+
 	(if (not (bufferp buf))
 	    (setq ispell-filter nil)
 	  (with-current-buffer buf
diff --git a/test/lisp/textmodes/ispell-resources/fake-aspell-new.bash b/test/lisp/textmodes/ispell-resources/fake-aspell-new.bash
index 7dd935bac3c..e3fd91d5196 100755
--- a/test/lisp/textmodes/ispell-resources/fake-aspell-new.bash
+++ b/test/lisp/textmodes/ispell-resources/fake-aspell-new.bash
@@ -1,5 +1,15 @@
 #!/bin/bash
 
+#exec aspell "$@"
+
+#rm -rf ~/lwf_mock-aspell.log
+
+#printf 'date="%s"\n' "$(date --iso=seconds)" > /tmp/lwf_mock-aspell.log
+
+#printf 'args="%s"\n' "$*" >> /tmp/lwf_mock-aspell.log || { printf "lwf:ERROR\n" ; exit 3 ; }
+
+# coproc aspell { aspell "$@" ; }
+
 vv=
 
 show_vv()
@@ -7,13 +17,51 @@ show_vv()
     printf  '%s\n' "@(#) International Ispell Version 3.1.20 (but really Aspell 0.60.0)"
 }
 
-imitate_repl()
+imitate_pipe()
+{
+    local a
+    declare -A sessiondict
+    show_vv
+    while read a ; do
+	#printf 'pipe="%s"\n' "$a" >> /tmp/lwf_mock-aspell.log
+	if [[ "$a" == '' ]] ; then
+	    printf ''
+	elif [[ "$a" == '+' || "$a" == '~nroff' || "$a" == '~tex' || "$a" == '!' || "$a" == '-' || "$a" == '%' ]] ; then
+	    printf ''
+	elif [[ "${a:0:1}" == '@' ]] ; then
+	    sessiondict["${a:1}"]="true"
+	    printf ''
+	else
+	    for b in $a ; do
+		if [[ "$b" == '^' ]] ; then
+		    printf ''
+		elif [[ ${sessiondict[$b]} == 'true' || ${sessiondict[${b#^}]} == 'true' ]] ; then
+		    printf '*\n'
+		elif [[ "$b" == '^tarampampamtararam' || "$b" == 'tarampampamtararam' ]] ; then
+		    printf '# tarampampamtararam 0\n' # wrong word
+		elif [[ "$b" == '^badworddd' || "$b" == 'badworddd' ]] ; then
+		    printf '# badworddd 0\n' # wrong word
+		elif [[ "$b" == '^hellooooooo' || "$b" == 'hellooooooo' ]] ; then
+		    printf '# hellooooooo 0\n' # wrong word
+		elif [[ "$b" == '^' ]] ; then
+		    printf '\n'
+		else
+		    printf "*\n"
+		fi
+	    done
+	    printf '\n'
+	fi
+    done
+}
+
+imitate_interactive()
 {
+    exit 6
     while true ; do
 	read a
-#	printf 'debug="%s"\n' "$a"
+#	printf 'interactive="%s"\n' "$a" >> /tmp/lwf_mock-aspell.log
 	if [[ "$a" == '' ]] ; then
-	    printf ''
+	    printf '\n'
 	elif [[ "$a" == 'tarampampamtararam' ]] ; then
 	    printf '# tarampampamtararam 0\n\n' # wrong word
 	else
@@ -22,16 +70,16 @@ imitate_repl()
     done
 }
 
-show_vv
 
 while :; do
     case $1 in
         -vv|-v)
-            #show_vv # for ispell.el error detection
+            show_vv # for ispell.el version detection
             exit
             ;;
         -a)       # imitate REPL
-	    imitate_repl
+	    imitate_pipe
+	    exit
             ;;
 	-?*)
             printf 'WARN: Unknown option (ignored): %s\n' "$1" >&2
@@ -41,3 +89,7 @@ while :; do
     esac
     shift
 done
+
+printf 'Usage: aspell [options] <command>\n'
+
+#printf 'this place should be unreachable\n' >> /tmp/lwf_mock-aspell.log
diff --git a/test/lisp/textmodes/ispell-tests/ispell-aspell-tests.el b/test/lisp/textmodes/ispell-tests/ispell-aspell-tests.el
index c24d284f426..f8f954fd430 100644
--- a/test/lisp/textmodes/ispell-tests/ispell-aspell-tests.el
+++ b/test/lisp/textmodes/ispell-tests/ispell-aspell-tests.el
@@ -25,9 +25,15 @@
 ;;; Code:
 
 (require 'ispell)
+(require 'ert-x)
 
+(eval-when-compile
+  (defconst ispell-tests-lib (expand-file-name "test/lisp/textmodes/ispell-tests/ispell-tests-common.el" source-directory))
+  (load ispell-tests-lib))
 (load (expand-file-name "test/lisp/textmodes/ispell-tests/ispell-tests-common.el" source-directory))
 
+(declare-function letopt (expand-file-name "test/lisp/textmodes/ispell-tests/ispell-tests-common.el" source-directory) t t)
+
 (ert-deftest ispell/aspell/ispell-check-version/works ()
   "Test that aspell is correctly detected."
   (skip-unless (and (executable-find "aspell")
@@ -68,6 +74,106 @@ ispell/aspell/ispell-check-version/version-lowlow
         (set-variable 'ispell-last-program-name
                       test-saved-ispell-last-program-name)))))
 
+(ert-deftest ispell/aspell/ispell-word/english/correct ()
+"This test checks that Russian spellchecking works for Aspell."
+  (skip-unless (executable-find "aspell"))
+  (skip-unless (equal
+                0
+                (call-process "aspell" nil nil nil "-vv")))
+  (skip-unless (equal
+                0
+                (with-temp-buffer
+                  (insert "test")
+                  (call-process-region
+                   nil
+                   nil
+                   "aspell" nil t nil "-a" "-denglish"))))
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (let ((default-directory temporary-file-directory))
+      (letopt ((ispell-program-name "aspell")
+               (ispell-dictionary "english"))
+        (ignore-errors (ispell-kill-ispell t t))
+        (with-temp-buffer
+          (insert
+           "hello\n")
+          (goto-char 0)
+          (ispell-change-dictionary "english")
+          (let ((debugmessage ""))
+            (ert-with-message-capture lres
+              (let ((ispell-check-only t))
+                (ispell-word)
+                (setf debugmessage lres)
+                ;;(should (string-match "is correct" lres))
+                ))
+            (message "lwf:lres=%s" debugmessage)))
+        'passed
+        )))
+  )
+
+(ert-deftest ispell/aspell/ispell-word/english/incorrect ()
+"This test checks that Russian spellchecking works for Aspell."
+  (skip-unless (executable-find "aspell"))
+  (skip-unless (equal
+                0
+                (call-process "aspell" nil nil nil "-vv")))
+  (skip-unless (equal
+                0
+                (with-temp-buffer
+                  (insert "test")
+                  (call-process-region
+                   nil
+                   nil
+                   "aspell" nil t nil "-a" "-denglish"))))
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (let ((default-directory temporary-file-directory))
+      (letopt ((ispell-program-name "aspell")
+               (ispell-dictionary "english"))
+        (ignore-errors (ispell-kill-ispell t t))
+        (with-temp-buffer
+          (insert
+           ;; there is no such a word in English, I swear.
+           "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+           )
+          (goto-char 0)
+          (ispell-change-dictionary "english")
+          (ert-with-message-capture lres
+            (let ((ispell-check-only t))
+              (ispell-word))
+            (should (string-match "is incorrect" lres))))
+        'passed
+        )))
+  )
+
+(ert-deftest ispell/aspell/ispell-word/english/wrong-language ()
+  "This test checks that Russian spellchecking works for Aspell."
+  :expected-result :failed
+  (skip-unless (executable-find "aspell"))
+  (skip-unless (equal
+                0
+                (call-process "aspell" nil nil nil "-vv")))
+  (skip-unless (equal
+                0
+                (with-temp-buffer
+                  (insert "test")
+                  (call-process-region nil nil "aspell" nil '("*scratch*" t) nil "-a" "-denglish"))))
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (let ((default-directory temporary-file-directory))
+      (letopt ((ispell-program-name "aspell"))
+        (ignore-errors (ispell-kill-ispell t t))
+        (with-temp-buffer
+          (insert
+           ;; giving Aspell a wrong language should not fail
+           "привет\n"
+           )
+          (goto-char 0)
+          (ispell-change-dictionary "english")
+          (ert-with-message-capture lres
+            (let ((ispell-check-only t))
+              (ispell-word))
+            (should (not (string-match "Error" lres)))))
+        'passed
+        )))
+  )
 
 (provide 'tests-ispell-aspell)
 ;;; tests-ispell-aspell.el ends here
diff --git a/test/lisp/textmodes/ispell-tests/ispell-hunspell-tests.el b/test/lisp/textmodes/ispell-tests/ispell-hunspell-tests.el
index ae3d6e303b3..ebdf10cc3f4 100644
--- a/test/lisp/textmodes/ispell-tests/ispell-hunspell-tests.el
+++ b/test/lisp/textmodes/ispell-tests/ispell-hunspell-tests.el
@@ -26,6 +26,11 @@
 
 (require 'ispell)
 
+(eval-when-compile
+  (defconst ispell-tests-lib (expand-file-name "test/lisp/textmodes/ispell-tests/ispell-tests-common.el" source-directory))
+  (load ispell-tests-lib))
+
+
 (load (expand-file-name "test/lisp/textmodes/ispell-tests/ispell-tests-common.el" source-directory))
 (ert-deftest ispell/hunspell/ispell-word/english/check-only ()
 "This test checks that Russian spellchecking works for Hunspell."
diff --git a/test/lisp/textmodes/ispell-tests/ispell-international-ispell-tests.el b/test/lisp/textmodes/ispell-tests/ispell-international-ispell-tests.el
index f232f26d10d..bcd19e105a3 100644
--- a/test/lisp/textmodes/ispell-tests/ispell-international-ispell-tests.el
+++ b/test/lisp/textmodes/ispell-tests/ispell-international-ispell-tests.el
@@ -25,6 +25,9 @@
 ;;; Code:
 
 (require 'ispell)
+(eval-when-compile
+  (defconst ispell-tests-lib (expand-file-name "test/lisp/textmodes/ispell-tests/ispell-tests-common.el" source-directory))
+  (load ispell-tests-lib))
 
 (load (expand-file-name "test/lisp/textmodes/ispell-tests/ispell-tests-common.el" source-directory))
 
diff --git a/test/lisp/textmodes/ispell-tests/ispell-tests-common.el b/test/lisp/textmodes/ispell-tests/ispell-tests-common.el
index a6c4f1247ee..e69e1a469e4 100644
--- a/test/lisp/textmodes/ispell-tests/ispell-tests-common.el
+++ b/test/lisp/textmodes/ispell-tests/ispell-tests-common.el
@@ -2,20 +2,35 @@
 
 (defvar tests-ispell-data-directory
   (expand-file-name "test/lisp/textmodes/ispell-resources/" source-directory))
+(defvar fake-aspell-path
+  (expand-file-name
+   "./fake-aspell-new.bash"
+   tests-ispell-data-directory))
 
-(let* ((backend-binaries (list "ispell" "aspell" "hunspell" "enchant-2"))
-       (filter-binaries (lambda ()
-                          (seq-filter
-                           #'executable-find
-                           backend-binaries))))
+
+(let* ((backend-binaries (list  "aspell"  fake-aspell-path  "hunspell"  "enchant-2")
+                         )
+       (filter-binaries (seq-filter
+                           (lambda (b)
+                             (and
+                              (executable-find b)
+                              ;; (equal 0
+                              ;;        (with-temp-buffer
+                              ;;          (call-process b nil t "-v")))
+                              ))
+                           backend-binaries)))
 
   (defun ispell-tests--some-backend-available-p ()
     (not
-     (null (funcall filter-binaries))))
+     (null filter-binaries)))
 
   (defun ispell-tests--some-backend ()
-    (car (funcall filter-binaries))))
+    (let ((retval (car filter-binaries)))
+      (message "available backend is:%s" retval)
+      retval)))
 
+(eval-when-compile
+  (require 'cl-macs))
 (cl-defmacro letopt (bindings &body body)
   (declare (indent 1))
   (let* ((binding-var (lambda (binding) (car binding)))
@@ -33,4 +48,16 @@ letopt
 			      ,@body)
 	 ,@(reverse restorebindings)))))
 
+(cl-defmacro with-ispell-global-dictionary (bindings &body body)
+  "This macro should not really be needed, but `ispell.el'.
+Sets up dictionaries in a stupid way."
+  (declare (indent 1))
+  (let* ((dictionary-val (car bindings))
+	 (temp-var (gensym 'old-dictionary)))
+    `(let ((,temp-var (symbol-value 'ispell-dictionary)))
+       (unwind-protect (progn (ispell-change-dictionary ,dictionary-val t)
+			      ,@body)
+	 (progn
+           (ispell-change-dictionary ,temp-var t))))))
+
 (provide 'ispell-tests-common)
diff --git a/test/lisp/textmodes/ispell-tests/ispell-tests.el b/test/lisp/textmodes/ispell-tests/ispell-tests.el
index 9e675443986..47816671475 100644
--- a/test/lisp/textmodes/ispell-tests/ispell-tests.el
+++ b/test/lisp/textmodes/ispell-tests/ispell-tests.el
@@ -24,9 +24,22 @@
 
 ;;; Code:
 
+(declare-function letopt ispell-tests-lib t t)
+(declare-function ispell-tests--some-backend ispell-tests-lib t t)
+(declare-function ispell-tests--some-backend-available-p ispell-tests-lib t t)
+
 (require 'ispell)
-(load (expand-file-name "test/lisp/textmodes/ispell-tests/ispell-tests-common.el" source-directory))
+(defconst ispell-tests-lib (expand-file-name "test/lisp/textmodes/ispell-tests/ispell-tests-common.el" source-directory))
+(eval-when-compile
+  (defconst ispell-tests-lib (expand-file-name "test/lisp/textmodes/ispell-tests/ispell-tests-common.el" source-directory))
+  (load ispell-tests-lib))
+(load ispell-tests-lib)
+
+(require 'ert)
+(require 'ert-x)
 
+(setopt ispell-program-name "hunspell")
+(setopt ispell-dictionary "fr_FR")
 
 (defun warnings-buffer-exists-p ()
   "Check if a buffer named \"*Warnings*\" exists."
@@ -450,18 +463,20 @@ ispell/ispell-buffer-local-words/ispell-words-keyword
 Should pass regardless of the backend and the dictionary, because
 presumably nobody will have `hellooooooo' in their dictionary."
   (skip-unless (ispell-tests--some-backend-available-p))
-  (letopt ((ispell-program-name (ispell-tests--some-backend)))
-          (with-temp-buffer
-            (nxml-mode)
-            (ignore-errors (ispell-kill-ispell))
-            (with-environment-variables (("HOME" temporary-file-directory))
-              (ispell-init-process)
-              (let ((test-output (ispell--run-on-word "hellooooooo")))
-                (should (listp test-output))
-                (should-not (equal t test-output)))
-              (ispell-add-per-file-word-list "hellooooooo")
-              (ispell-buffer-local-words)
-              (should (equal t (ispell--run-on-word "hellooooooo")))))))
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (with-ispell-global-dictionary nil
+      (letopt ((ispell-program-name (ispell-tests--some-backend)))
+        (with-temp-buffer
+          (nxml-mode)
+          (ignore-errors (ispell-kill-ispell))
+          (ispell-init-process)
+          (let ((test-output (ispell--run-on-word "hellooooooo")))
+            (should (listp test-output))
+            (should-not (equal t test-output)))
+          (ispell-add-per-file-word-list "hellooooooo")
+          (ispell-buffer-local-words)
+          (should (equal t (ispell--run-on-word "hellooooooo")))))))
+  )

 (ert-deftest
@@ -470,21 +485,24 @@ ispell/ispell-buffer-local-words/ispell-words-keyword
 Should pass regardless of the backend and the dictionary, because
 presumably nobody will have `hellooooooo' in their dictionary."
   (skip-unless (ispell-tests--some-backend-available-p))
-  (letopt ((ispell-program-name (ispell-tests--some-backend)))
-          (cd temporary-file-directory)
-          (with-temp-buffer
-            (nxml-mode)
-            (ignore-errors (ispell-kill-ispell))
-            (with-environment-variables (("HOME" temporary-file-directory))
-              (ispell-init-process)
-              (let ((test-output (ispell--run-on-word "hellooooooo")))
-                (should (listp test-output))
-                (should-not (equal t test-output)))
-              (let ((ispell-buffer-session-localwords (list "hellooooooo")))
-                (ispell-buffer-local-words)
-                (should (equal t (ispell--run-on-word "hellooooooo"))))))))
-
-(ert-deftest ispell/ispell-init-process/works-nohome ()
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (with-ispell-global-dictionary nil
+      (letopt ((ispell-program-name (ispell-tests--some-backend))
+               (ispell-dictionary nil))
+        (cd temporary-file-directory)
+        (with-temp-buffer
+          (nxml-mode)
+          (ignore-errors (ispell-kill-ispell))
+          (ispell-init-process)
+          (let ((test-output (ispell--run-on-word "hellooooooo")))
+            (should (listp test-output))
+            (should-not (equal t test-output)))
+          (let ((ispell-buffer-session-localwords (list "hellooooooo")))
+            (ispell-buffer-local-words)
+            (should (equal t (ispell--run-on-word "hellooooooo"))))))))
+  )
+
+(ert-deftest ispell/ispell-init-process/works-no-home ()
   "Simple test to check that ispell-init-process works."
   :expected-result :failed
   (skip-unless (ispell-tests--some-backend-available-p))
@@ -492,13 +510,14 @@ ispell/ispell-init-process/works-nohome
           (with-temp-buffer
             (ispell-init-process))))
 
-(ert-deftest ispell/ispell-init-process/works-withhome ()
+(ert-deftest ispell/ispell-init-process/works-with-home ()
   "Simple test to check that ispell-init-process works."
   (skip-unless (ispell-tests--some-backend-available-p))
-  (letopt ((ispell-program-name (ispell-tests--some-backend)))
-          (with-temp-buffer
-            (with-environment-variables (("HOME" temporary-file-directory))
-              (ispell-init-process)))))
+  (with-ispell-global-dictionary nil
+      (letopt ((ispell-program-name (ispell-tests--some-backend)))
+        (with-temp-buffer
+          (with-environment-variables (("HOME" temporary-file-directory))
+            (ispell-init-process))))))
 
 ;; Some more tests for buffer-local stuff.
 ;; `ispell-buffer-local-dict'
@@ -742,18 +761,17 @@ ispell/ispell-accept-buffer-local-defs/simple
 batch mode.
 1. local words
 2. dictionary and pdict
-3. parser and extcharmode"
-  (skip-unless (executable-find "ispell"))
-  (setq old-engine ispell-program-name)
-  (setopt ispell-program-name "ispell")
-  (ispell-check-version t)
-  (skip-unless (and (null ispell-really-aspell)
-                    (null ispell-really-hunspell)
-                    (null ispell-really-enchant)))
-  (setq ispell-program-name old-engine)
+3. parser and extcharmode.
+This does not work well on hunspell, because hunspell
+lies in their Man page, and in enchant-2 when it is using
+hunspell.  Hence skipping."
+  (skip-unless (not (or (equal (ispell-tests--some-backend)
+                               "hunspell")
+                        (equal (ispell-tests--some-backend)
+                               "enchant-2"))))
   (with-environment-variables (("HOME" temporary-file-directory))
     (with-temp-buffer
-      (letopt ((ispell-program-name "ispell"))
+      (letopt ((ispell-program-name (ispell-tests--some-backend)))
         (let ((test-dictname "english")
               (test-extcharmode "~latin3")
               (test-parser "~testparser")
@@ -806,9 +824,6 @@ ispell/ispell--run-on-word/default
   "`ispell--run-on-word' should be the simplest interface
 for checking a word."
   (skip-unless (ispell-tests--some-backend-available-p))
-  (skip-unless (equal
-                0
-                (call-process (ispell-tests--some-backend) nil nil nil "-vv")))
   (letopt ((ispell-program-name (ispell-tests--some-backend))
            (ispell-dictionary "default"))
     (let ((default-directory temporary-file-directory))
@@ -890,21 +905,18 @@ ispell/ispell-word/default/check-only/correct
                 (call-process (ispell-tests--some-backend) nil nil nil "-vv")))
   (with-environment-variables (("HOME" temporary-file-directory))
     (let ((default-directory temporary-file-directory))
-      (letopt ((ispell-program-name (ispell-tests--some-backend)))
+      (letopt ((ispell-program-name (ispell-tests--some-backend))
+               (ispell-dictionary nil))
         (ignore-errors (ispell-kill-ispell t t))
         (with-temp-buffer
           (insert
            "hello\n")
           (goto-char 0)
-          (let ((ispell-check-only t)
-                (current-point
-                 (with-current-buffer "*Messages*"
-                   (point))))
+          (ert-with-message-capture lres
             (ispell-word)
-            (with-current-buffer "*Messages*"
-              (goto-char (point-max))
-              (should ( > (search-backward "is correct" nil t)
-                        current-point)))))))))
+            (should (string-match "is correct" lres))))
+        'passed)))
+  )
 
 (ert-deftest ispell/ispell-word/default/check-only/correct/add-init ()
   "Check that `ispell-word' works with a default
@@ -920,23 +932,21 @@ ispell/ispell-word/default/check-only/correct/add-init
                 (call-process (ispell-tests--some-backend) nil nil nil "-vv")))
   (with-environment-variables (("HOME" temporary-file-directory))
     (let ((default-directory temporary-file-directory))
-      (letopt ((ispell-program-name (ispell-tests--some-backend)))
+      (letopt ((ispell-program-name (ispell-tests--some-backend))
+               (ispell-dictionary nil)
+               (ispell-check-only t))
         (ignore-errors (ispell-kill-ispell t t))
         (with-temp-buffer
           (ispell-init-process) ;; this is added
           (insert
            "hello\n")
           (goto-char 0)
-          (let ((ispell-check-only t)
-                (current-point
-                 (with-current-buffer "*Messages*"
-                   (point))))
+          (ert-with-message-capture lres
             (ispell-word)
-            (with-current-buffer "*Messages*"
-              (goto-char (point-max))
-              (should (> (search-backward "is correct" nil t)
-                         current-point)))
-            ))))))
+            (should (string-match "is correct" lres)))
+          'passed
+          ))))
+  )
 
 (ert-deftest ispell/ispell-word/default/check-only/incorrect ()
   "Check that `ispell-word' works with a default
@@ -945,75 +955,110 @@ ispell/ispell-word/default/check-only/incorrect
 be rewritten with a mock.
 This test gives it a word which does not exist."
   (skip-unless (ispell-tests--some-backend-available-p))
-  (skip-unless (equal
-                0
-                (call-process (ispell-tests--some-backend) nil nil nil "-vv")))
   (with-environment-variables (("HOME" temporary-file-directory))
     (let ((default-directory temporary-file-directory))
-      (letopt ((ispell-program-name (ispell-tests--some-backend)))
+      (letopt ((ispell-program-name (ispell-tests--some-backend))
+               (ispell-dictionary nil)
+               (ispell-check-only t))
         (ignore-errors (ispell-kill-ispell t t))
         (with-temp-buffer
           (insert
-           "helloooo\n")
+           "hellooooooo\n")
           (goto-char 0)
-          (let ((ispell-check-only t)
-                (current-point
-                 (with-current-buffer "*Messages*"
-                   (point))))
+          (ert-with-message-capture lres
             (ispell-word)
-            (with-current-buffer "*Messages*"
-              (goto-char (point-max))
-              (should (> (search-backward "is incorrect" nil t)
-                         current-point)))
-            ))))))
+            (should (string-match "is incorrect" lres))
+            'passed)))))
+  )
 
 (ert-deftest ispell/ispell-region/correct ()
   "The simplest test for `ispell-region'."
   (skip-unless (ispell-tests--some-backend-available-p))
-  (skip-unless (equal
-                0
-                (call-process (ispell-tests--some-backend) nil nil nil "-vv")))
   (with-environment-variables (("HOME" temporary-file-directory))
     (let* ((default-directory temporary-file-directory)
-           (fake-aspell-path (expand-file-name
-                                          "./fake-aspell-new.bash"
-                                          tests-ispell-data-directory))
            (words '("hello" "test" "test" "more" "obvious" "word"))
            (text (string-join words " ")))
-      (letopt ((ispell-program-name fake-aspell-path))
+      (letopt ((ispell-program-name (ispell-tests--some-backend))
+               (ispell-dictionary nil))
         (ignore-errors (ispell-kill-ispell t t))
         (with-temp-buffer
-          (insert
-           text)
+          (insert text)
+          (goto-char (length (nth 0 words)))
+          (ert-with-message-capture lres
+            (ispell-region (point) (point-max))
+            (should (string-match "^Spell-checking region using .* with .* dictionary...done" lres))
+            'passed)))))
+  )
+
+
+
+(ert-deftest ispell/ispell-region/incorrect ()
+  "The simplest test for `ispell-region'."
+  (skip-unless (ispell-tests--some-backend-available-p))
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (let* ((default-directory temporary-file-directory)
+           (words '("hello" "tarampampamtararam" "world"))
+           (text (string-join words " ")))
+      (letopt ((ispell-program-name (ispell-tests--some-backend))
+               (ispell-dictionary nil)
+               (ispell-check-only t))
+        (ignore-errors (ispell-kill-ispell t t))
+        (with-temp-buffer
+          (insert text)
           (goto-char (length (nth 0 words)))
-          (let (;(ispell-check-only t)
-                (current-point
+          (cl-labels ((checker ()
+                        (user-error "expected error")))
+            (unwind-protect
+                (progn
+                  (advice-add 'ispell-show-choices :override #'checker)
+                  (should-error (ispell-region (point) (point-max))))
+              (advice-remove 'ispell-show-choices #'checker))))
+        'passed)))
+  )
+
+(ert-deftest ispell/ispell-buffer/correct ()
+  "The simplest test for `ispell-buffer'.
+`ispell-buffer' is a very simple wrapper around `ispell-region',
+so this test virtually mirrors the previous one."
+  (skip-unless (ispell-tests--some-backend-available-p))
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (let* ((default-directory temporary-file-directory)
+           (words '("hello" "test" "test" "more" "obvious" "word"))
+           (text (string-join words " ")))
+      (letopt ((ispell-dictionary nil)
+               (ispell-program-name (ispell-tests--some-backend)))
+        (ignore-errors (ispell-kill-ispell t t))
+        (with-temp-buffer
+          (insert text)
+          (goto-char (length (nth 0 words)))
+          (let ((current-point
                  (with-current-buffer "*Messages*"
                    (point))))
-            (ispell-region (point) (point-max))
+            (ispell-buffer)
             (with-current-buffer "*Messages*"
               (goto-char (point-max))
-              (should (> (re-search-backward "Spell-checking region using .* with .* dictionary...done" nil t) current-point))
+              (should (> (re-search-backward "^Spell-checking .* using .* with .* dictionary...done" nil t) current-point))
               'passed)
             )))))
   )
 
-(ert-deftest ispell/ispell-region/incorrect ()
-  "The simplest test for `ispell-region'."
+(ert-deftest ispell/ispell-buffer/incorrect ()
+  "The simplest test for `ispell-buffer'.
+`ispell-buffer' is a very simple wrapper around `ispell-region',
+so this test virtually mirrors the previous one."
   (skip-unless (ispell-tests--some-backend-available-p))
-  (skip-unless (equal
-                0
-                (call-process (ispell-tests--some-backend) nil nil nil "-vv")))
   (with-environment-variables (("HOME" temporary-file-directory))
     (let* ((default-directory temporary-file-directory)
-           (fake-aspell-path "aspell")
-           (words '("hello" "tarampampamtararam" "world"))
+           (words '("tarampampamtararam" "test" "test" "more" "obvious" "word" "badworddd"))
            (text (string-join words " ")))
-      (letopt ((ispell-program-name fake-aspell-path))
+      (letopt ((ispell-dictionary nil)
+               (ispell-program-name (ispell-tests--some-backend)))
         (ignore-errors (ispell-kill-ispell t t))
         (with-temp-buffer
-          (insert
-           text)
+          (insert text)
+          ;; This is intentional. The incorrect word is not in the region,
+          ;; but `ispell-buffer' should move the point to the beginning
+          ;; of the buffer.
           (goto-char (length (nth 0 words)))
           (cl-labels ((checker ()
                         (user-error "expected error")))
@@ -1021,11 +1066,413 @@ ispell/ispell-region/incorrect
                 (progn
                   (advice-add 'ispell-show-choices :override
                               #'checker)
-                  (should-error (ispell-region (point) (point-max)))
+                  (should-error (ispell-buffer))
+                  (ispell-kill-ispell nil t)
                   'passed)
               (advice-remove 'ispell-show-choices #'checker)))
           ))))
   )
 
+(ert-deftest ispell/ispell-kill-ispell ()
+  "Test that killing ispell works."
+  (skip-unless (ispell-tests--some-backend-available-p))
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (let* ((default-directory temporary-file-directory)
+           (words '("tarampampamtararam" "test" "test" "more" "obvious" "word"))
+           (text (string-join words " ")))
+      (with-temp-buffer
+        (with-ispell-global-dictionary nil
+          (letopt ((ispell-program-name  (ispell-tests--some-backend)))
+            (insert text)
+            (ispell-init-process)
+            (should ispell-async-processp)
+            (should (eq (ispell-process-status) 'run))
+            (ispell-kill-ispell nil t)))
+        'passed
+        )))
+  (message "lwf:debug2:ispell-program-name=%s:ispell-dictionary=%s"
+           ispell-program-name ispell-dictionary)
+  )
+
+(ert-deftest ispell/ispell/buffer ()
+  "`ispell' is just a wrapper around `ispell-region'
+and `ispell-buffer', which is also a wrapper around
+`ispell-buffer'.
+This test might seem confusing, as it does not check
+for the availability of the backend, but this does
+not matter `ispell' function does not use the
+backend."
+  (let ((transient-mark-mode t))
+    (with-temp-buffer
+      (insert "hello world test test")
+      (goto-char 2)
+      (set-mark (point))
+      (goto-char (point-max))
+      (deactivate-mark)
+      (cl-labels ((checker-buffer ()
+                    t)
+                  (checker-region (_a _b)
+                    (user-error "test failed")))
+        (unwind-protect
+            (progn
+              (advice-add 'ispell-buffer :override #'checker-buffer)
+              (advice-add 'ispell-region :override #'checker-region)
+              (ispell)
+              )
+          (progn
+            (advice-remove 'ispell-buffer #'checker-buffer)
+            (advice-remove 'ispell-region #'checker-region))))
+      ))
+  )
+
+(ert-deftest ispell/ispell/region ()
+  "`ispell' is just a wrapper around `ispell-region'
+and `ispell-buffer', which is also a wrapper around
+`ispell-buffer'."
+  (let ((transient-mark-mode t))
+    (with-temp-buffer
+      (insert "hello world test test")
+      (goto-char 2)
+      (set-mark (point))
+      (goto-char (point-max))
+      (activate-mark)
+      (cl-labels ((checker-buffer ()
+                    (user-error "test failed"))
+                  (checker-region (_a _b)
+                    t))
+        (unwind-protect
+            (progn
+              (advice-add 'ispell-buffer :override #'checker-buffer)
+              (advice-add 'ispell-region :override #'checker-region)
+              (ispell)
+              )
+          (progn
+            (advice-remove 'ispell-buffer #'checker-buffer)
+            (advice-remove 'ispell-region #'checker-region))))
+      ))
+  )
+
+(ert-deftest ispell/ispell-change-dictionary ()
+  "Simple test for changing a dictionary"
+  (skip-unless (ispell-tests--some-backend-available-p))
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (let* ((default-directory temporary-file-directory))
+      (letopt ((ispell-program-name (ispell-tests--some-backend)))
+        (with-temp-buffer
+          (ispell-change-dictionary "english")
+          (should (equal ispell-local-dictionary "english"))
+          (ispell-change-dictionary "default")
+          (should (equal ispell-local-dictionary nil))
+          (ispell-change-dictionary "english")
+          (should (equal ispell-local-dictionary "english"))
+          'passed
+          ))))
+  )
+
+(ert-deftest ispell/ispell-comments-and-strings/correct ()
+  "Test that `ispell-comments-and-strings' does not err
+on a correct buffer."
+  (skip-unless (ispell-tests--some-backend-available-p))
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (let* ((default-directory temporary-file-directory))
+      (letopt ((ispell-dictionary nil)
+               (ispell-program-name (ispell-tests--some-backend)))
+        (with-temp-buffer
+          (ispell-kill-ispell t t)
+          (insert "#!/bin/bash\n"
+                  "echo \"string to check\"\n"
+                  "# commented line\n")
+          (sh-mode)
+          (ert-with-message-capture lres
+            (ispell-comments-and-strings)
+            (should (string-match "Spell-checking .* using .* with .* dictionary...done" lres))))
+          'passed
+          )))
+  )
+
+(ert-deftest ispell/ispell-comments-and-strings/incorrect ()
+  "Test that `ispell-comments-and-strings' errs
+on a correct buffer."
+  (skip-unless (ispell-tests--some-backend-available-p))
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (let* ((default-directory temporary-file-directory))
+      (letopt ((ispell-program-name (ispell-tests--some-backend)))
+        (with-temp-buffer
+          (insert "#!/bin/bash\n"
+                  "echo \"string to check\"\n"
+                  "# tarampampamtararam\n")
+          (sh-mode)
+          (ert-with-message-capture lres
+            (should-error (ispell-comments-and-strings)))
+          'passed
+          ))))
+  )
+
+(ert-deftest ispell/ispell-comment-or-string-at-point ()
+  "Test that `ispell-comment-or-string-at-point' runs two tests.
+One correct an one incorrect in the same buffer."
+  (skip-unless (ispell-tests--some-backend-available-p))
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (let* ((default-directory temporary-file-directory))
+      (letopt ((ispell-dictionary nil)
+               (ispell-program-name (ispell-tests--some-backend)))
+        (with-temp-buffer
+          (insert "#!/bin/bash\n"
+                  "echo \"string to check\"\n"
+                  "# tarampampamtararam\n")
+          (sh-mode)
+          (goto-char 25)
+          (ert-with-message-capture lres
+            (ispell-comment-or-string-at-point)
+            (should (string-match "Spell-checking .* using .* with .* dictionary...done" lres)))
+          (goto-char 47)
+          (should-error (ispell-comment-or-string-at-point))
+          'passed))))
+  )
+
+(ert-deftest ispell/ispell-pdict-save ()
+  "Simple `ispell-pdict-save' test."
+  (skip-unless (ispell-tests--some-backend-available-p))
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (let* ((default-directory temporary-file-directory))
+      (letopt ((ispell-program-name (ispell-tests--some-backend)))
+        (with-temp-buffer
+          (insert "test")
+          (ispell-kill-ispell t t)
+          (ispell-pdict-save t t)
+          'passed))))
+  )
+
+(ert-deftest ispell/ispell-pdict-save/force ()
+  "Simple `ispell-pdict-save' test."
+  (skip-unless (ispell-tests--some-backend-available-p))
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (let* ((default-directory temporary-file-directory))
+      (letopt ((ispell-program-name (ispell-tests--some-backend)))
+        (with-temp-buffer
+          (insert "testttttt")
+          (goto-char 1)
+          (ispell-kill-ispell t t)
+          (ispell-pdict-save t t)
+          'passed))))
+  )
+
+(ert-deftest ispell/ispell-pdict-save/modified ()
+  "Simple `ispell-pdict-save' test."
+  (skip-unless (ispell-tests--some-backend-available-p))
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (let* ((default-directory temporary-file-directory))
+      (letopt ((ispell-program-name (ispell-tests--some-backend-available-p)))
+        (with-temp-buffer
+          (insert "testttttt")
+          (goto-char 1)
+          (ispell-kill-ispell t t)
+          (cl-labels ((checker (s)
+                        (should (equal s "#\n"))))
+            (unwind-protect (progn
+                              (advice-add 'ispell-send-string :override
+                                          #'checker)
+                              (let ((ispell-pdict-modified-p t))
+                                (ispell-pdict-save t nil)))
+              (advice-remove 'ispell-send-string #'checker))))
+        'passed)))
+  )
+
+(ert-deftest ispell/ispell-pdict-save/unmodified ()
+  "Simple `ispell-pdict-save' test."
+  (skip-unless (ispell-tests--some-backend-available-p))
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (let* ((default-directory temporary-file-directory))
+      (letopt ((ispell-program-name (ispell-tests--some-backend)))
+        (with-temp-buffer
+          (insert "testttttt")
+          (goto-char 1)
+          (ispell-kill-ispell t t)
+          (cl-labels ((checker (_s)
+                        (user-error "test failed")))
+            (unwind-protect (progn
+                              (advice-add 'ispell-send-string :override
+                                          #'checker)
+                              (let ((ispell-pdict-modified-p nil))
+                                (ispell-pdict-save t nil)))
+              (advice-remove 'ispell-send-string #'checker))))
+        'passed)))
+  )
+
+(ert-deftest ispell/ispell-lookup-words/simple ()
+  "Test if `ispell-lookup-words' is runnable."
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (let* ((default-directory temporary-file-directory)
+           (tempfile (make-temp-file "emacs-ispell.el-test" nil nil "waveguides")))
+      (letopt ((ispell-complete-word-dict tempfile))
+        (with-temp-buffer
+          (insert "waveguid")
+          (unwind-protect
+                (progn
+                  (should (equal
+                           (ispell-lookup-words "waveguid")
+                           '("waveguides")))
+                  (should (equal
+                           (ispell-lookup-words "sdfsdfasdfsadfasdfasdf")
+                           nil)))
+              (delete-file tempfile)))
+        'passed)))
+  )
+
+(ert-deftest ispell/ispell-complete-word/ispell-completion-at-point ()
+  "Test if `ispell-complete-word' and `ispell-completion-at-point'
+are runnable."
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (let* ((default-directory temporary-file-directory)
+           (tempfile (make-temp-file "emacs-ispell.el-test" nil nil "waveguides")))
+      (ignore-errors (ispell-kill-ispell t t))
+      (with-ispell-global-dictionary nil
+        (letopt ((ispell-program-name (ispell-tests--some-backend))
+                 (ispell-complete-word-dict tempfile))
+          (with-temp-buffer
+            (insert "waveguid")
+            (cl-labels ((my-ispell-command-loop (_p _n _w _s _e)
+                          (car (nth 2 (ispell-completion-at-point)))))
+              (unwind-protect
+                  (progn
+                    (advice-add 'ispell-command-loop :override
+                                #'my-ispell-command-loop)
+                    (should (equal (car (nth 2 (ispell-completion-at-point)))
+                                   "waveguides"))
+                    (ispell-complete-word)
+                    (should (equal "waveguides" (buffer-string))))
+                (progn
+                  (delete-file tempfile)
+                  (advice-remove
+                   'ispell-command-loop
+                   #'my-ispell-command-loop)))))
+          'passed))))
+  )
+
+(ert-deftest ispell/ispell-complete-word-interior-frag/simple ()
+  "Test if `ispell-complete-word-interior-frag' is runnable."
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (let* ((default-directory temporary-file-directory)
+           (tempfile (make-temp-file "emacs-ispell.el-test" nil nil "waveguides")))
+      (with-ispell-global-dictionary nil
+        (letopt ((ispell-program-name (ispell-tests--some-backend))
+                 (ispell-complete-word-dict tempfile))
+          (with-temp-buffer
+            (insert "waveguid")
+            (cl-labels ((my-ispell-command-loop (_p _n _w _s _e)
+                          (car (nth 2 (ispell-completion-at-point)))))
+              (unwind-protect
+                  (progn
+                    (advice-add 'ispell-command-loop :override
+                                #'my-ispell-command-loop)
+                    (goto-char 4)
+                    (ispell-complete-word-interior-frag)
+                    (should (equal "waveguides" (buffer-string))))
+                (progn
+                  (delete-file tempfile)
+                  (advice-remove
+                   'ispell-command-loop
+                   #'my-ispell-command-loop)))))
+          'passed))))
+  )
+
+(ert-deftest ispell/ispell-minor-mode/simple ()
+  "Try enabling `ispell-minor-mode' and test
+one test file."
+  (skip-unless (ispell-tests--some-backend-available-p))
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (let* ((default-directory temporary-file-directory))
+      (letopt ((ispell-program-name (ispell-tests--some-backend))
+               (ispell-dictionary nil))
+        (with-temp-buffer
+          (text-mode)
+          (ispell-minor-mode)
+          (insert "tarampampamtararam")
+          (set--this-command-keys " ")
+          (ert-with-message-capture lres
+            (ispell-minor-check)
+            (should (string-match "TARAMPAMPAMTARARAM is incorrect" lres)))
+          )
+        'passed)))
+  )
+
+(ert-deftest ispell/ispell-message/correct ()
+  "Test that `ispell-message' works.
+`ispell-message' is intended to be run before
+a message is sent in `message-mode' or `mml-mode'."
+  (skip-unless (ispell-tests--some-backend-available-p))
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (let* ((default-directory temporary-file-directory))
+      (letopt ((ispell-program-name (ispell-tests--some-backend))
+               (ispell-dictionary nil))
+        (with-temp-buffer
+          (insert
+           "To:
+Subject:
+From: Anon <anon@anon>
+Fcc: /tmp/234234.cb022f1a625b65b2.mainframe:2,S
+User-Agent: mu4e 1.12.9; emacs 31.0.50
+Date: Tue, 09 Sep 2025 07:43:58 +0800
+Message-ID: <878qiov7b5.fsf@mainframe>
+--text follows this line--
+Hello World
+--
+signature
+")
+          (message-mode)
+          (ert-with-message-capture lres
+            (ispell-message)
+            (should (not (string-match "is incorrect" lres)))
+            )
+          (set-buffer-modified-p nil)
+          )
+        'passed)))
+  )
+(ert-deftest ispell/ispell-message/incorrect ()
+  "Test that `ispell-message' works.
+`ispell-message' is intended to be run before
+a message is sent in `message-mode' or `mml-mode'."
+  (skip-unless (ispell-tests--some-backend-available-p))
+  (with-environment-variables (("HOME" temporary-file-directory))
+    (let* ((default-directory temporary-file-directory))
+      (letopt ((ispell-program-name (ispell-tests--some-backend)))
+        (with-temp-buffer
+          (insert
+           "To:
+Subject:
+From: Anon <anon@anon>
+Fcc: /tmp/234234.cb022f1a625b65b2.mainframe:2,S
+User-Agent: mu4e 1.12.9; emacs 31.0.50
+Date: Tue, 09 Sep 2025 07:43:58 +0800
+Message-ID: <878qiov7b5.fsf@mainframe>
+--text follows this line--
+<#part sign=pgpmime>
+tarampampamtararam
+--
+signature
+")
+          (message-mode)
+          (cl-labels ((checker ()
+                        (user-error "expected error")))
+            (unwind-protect
+                (progn
+                  (advice-add 'ispell-show-choices :override #'checker)
+                  (should-error (ispell-message)))
+              (progn
+                (advice-remove 'ispell-show-choices #'checker)
+                (set-buffer-modified-p nil))))
+
+          )
+        'passed)))
+  )
+
+
+
+;;======================================================================
+;; On this "emacs page" I want to test that customise variables change
+;; function behavior in the way are intended to do.
+
+
+
 (provide 'tests-ispell)
 ;;; tests-ispell.el ends here
-- 
2.46.4

-- 
Your sincerely,
Vladimir Nikishkin (MiEr, lockywolf)
(Laptop)