branch: externals/hyperbole
commit 223496edb9a05b4bc9dddad53167131bd33f7235
Merge: 9c27bc9787 402317d48c
Author: bw <r...@gnu.org>
Commit: bw <r...@gnu.org>

    Merge branch 'master' into rsw
---
 .github/workflows/main.yml |    2 +-
 ChangeLog                  |  107 ++++
 Makefile                   |   16 +-
 hpath.el                   |    4 +-
 hywiki.el                  |   12 +-
 test/hactypes-tests.el     |   10 +-
 test/hpath-tests.el        |   28 +-
 test/hproperty-tests.el    |   10 +-
 test/hui-mini-tests.el     |   10 +-
 test/hycontrol-tests.el    |   10 +-
 test/hywiki-tests.el       | 1284 ++++++++++++++++++++++++++++++--------------
 11 files changed, 1081 insertions(+), 412 deletions(-)

diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index fe453264eb..102d10f761 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -14,7 +14,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        version: [27.2, 28.2, 29.4, master]
+        version: [28.2, 29.4, 30.1, master]
     container: silex/emacs:${{ matrix.version }}-ci
 
     steps:
diff --git a/ChangeLog b/ChangeLog
index edafff7245..b95eca3ae9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,44 @@
+2025-03-23  Mats Lidell  <ma...@gnu.org>
+
+* test/hywiki-tests.el (hywiki-tests--run-test-case): Run DSL for testing
+    Hywiki words.
+    (hywiki-tests--lorem-ipsum): Surrounding test text.
+    (hywiki-tests--verify-hywiki-word): DSL verification helper.
+    (hywiki-tests--wikiword-step-check-verification)
+    (hywiki-tests--wikiword-step-check-verification-with-surrounding-text):
+    DSL based tests of WikiWords.
+
+2025-03-20  Mats Lidell  <ma...@gnu.org>
+
+* Makefile (DOCKER_VERSIONS): Include 30.1.
+    (docker-run): Use a volume for the elpa folder to reuse between docker
+    runs.
+    (recompile-docker-elpa): Recompile elpa folder to ensure files are
+    compiled with the same Emacs as used.
+    (docker-clean): Remove the elpa volume, useful for starting with a
+    fresh download of the required packages.
+
+2025-03-18  Mats Lidell  <ma...@gnu.org>
+
+* test/hywiki-tests.el
+    (hywiki-tests--published-html-links-to-word-and-section): Fix should
+    check.
+
+2025-03-17  Mats Lidell  <ma...@gnu.org>
+
+* test/hywiki-tests.el (hywiki-tests--add-hywiki-hooks)
+    (hywiki-tests--remove-hywiki-hooks, with-hywiki-buttonize-hooks)
+    (with-hywiki-buttonize-and-insert-hooks): Remove helpers for running
+    hooks, replaced by hywiki-tests--command-execute.
+    (hywiki-tests--preserve-hywiki-mode): Macro that restores the current
+    state of hywiki-mode so test case will not change users setting. Use
+    it for all tests setting hywiki-mode.
+    (hywiki-tests--verify-preserve-hywiki-mode): Unit test of the macro.
+
+* test/hywiki-tests.el (hywiki-tests--command-execute): Function that runs
+    command while also executing the pre and post command hooks. Use it
+    instead of the with-hywiki-buttonize macros.
+
 2025-03-17  Bob Weiner  <r...@gnu.org>
 
 * hywiki.el (hywiki-maybe-dehighlight-between-page-names): Fix to dehighlight
@@ -119,6 +160,72 @@ value to be [[WikiWord]] not 
[[file:WikiWord.org][WikiWord]].
     'post-self-insert-hook'.
             (hywiki-non-hook-context-p): Add.
 
+2025-03-07  Mats Lidell  <ma...@gnu.org>
+
+* hywiki.el (hywiki-convert-words-to-org-links)
+    (hywiki--org-export-get-reference): Fix docstrings.
+
+* hui-select.el (hbut:syntax-table): Public declare var.
+
+* test/hpath-tests.el (hpath--spaces-to-dashes-markup-anchor)
+    (hpath--dashes-to-spaces-markup-anchor): Add tests.
+
+2025-03-04  Mats Lidell  <ma...@gnu.org>
+
+* test/hywiki-tests.el:
+  test/hycontrol-tests.el:
+  test/hui-mini-tests.el:
+  test/hproperty-tests.el:
+  test/hactypes-tests.el: Add local-variable section disabling
+    byte-compilation to avoid error message during user
+    installation. The message comes from these files depend on el-mock
+    which is not a package dependency.
+
+* .github/workflows/main.yml (jobs): Add 30.1 to CI
+
+2025-03-03  Mats Lidell  <ma...@gnu.org>
+
+* Makefile (DOCKER_VERSIONS): Remove 27.2.
+
+* test/hywiki-tests.el (hywiki-tests--word-face-at-p): Add unit test.
+    (with-hywiki-buttonize-and-insert-hooks): Move debuttonize before body.
+
+* hywiki.el (hywiki-word-face-at-p): Add predicate for hywiki-word-face
+    and use it in hywiki-tests.
+
+2025-03-02  Mats Lidell  <ma...@gnu.org>
+
+* test/hywiki-tests.el (hywiki-tests--referent-test): Add macro with
+    boiler plate code for the reference save and restore tests.
+    (hywiki-tests--save-referent-keyseries)
+    (hywiki-tests--save-referent-keyseries-use-menu)
+    (hywiki-tests--save-referent-bookmark)
+    (hywiki-tests--save-referent-bookmark-use-menu)
+    (hywiki-tests--save-referent-find)
+    (hywiki-tests--save-referent-global-button)
+    (hywiki-tests--save-referent-global-button-use-menu)
+    (hywiki-tests--save-referent-hyrolo)
+    (hywiki-tests--save-referent-info-index)
+    (hywiki-tests--save-referent-info-node)
+    (hywiki-tests--save-referent-info-node-use-menu)
+    (hywiki-tests--save-referent-path-link)
+    (hywiki-tests--save-referent-org-id)
+    (hywiki-tests--save-referent-org-roam-node)
+    (hywiki-tests--save-referent-org-roam-node-use-menu): Save and restore
+    referent tests.
+
+2025-02-28  Mats Lidell  <ma...@gnu.org>
+
+* .github/workflows/main.yml (jobs): Remove 27.2 from the versions to
+    test in the CI.
+
+2025-02-24  Mats Lidell  <ma...@gnu.org>
+
+* test/hywiki-tests.el (hywiki-tests--action-key-moves-to-word-and-section):
+    Test action-key on WikiWords with section and line info.
+    (hywiki-tests--published-html-links-to-word-and-section): Verify html
+    links to sections are generated.
+
 2025-02-23  Bob Weiner  <r...@gnu.org>
 
 * hywiki.el (hywiki-referent-menu): Re-add accidentally deleted "Keys" key
diff --git a/Makefile b/Makefile
index 15e2d16bef..b56b4a368a 100644
--- a/Makefile
+++ b/Makefile
@@ -3,9 +3,9 @@
 # Author:       Bob Weiner
 #
 # Orig-Date:    15-Jun-94 at 03:42:38
-# Last-Mod:     16-Mar-25 at 10:20:44 by Bob Weiner
+# Last-Mod:     30-Mar-25 at 10:36:42 by Bob Weiner
 #
-# Copyright (C) 1994-2023  Free Software Foundation, Inc.
+# Copyright (C) 1994-2025  Free Software Foundation, Inc.
 # See the file HY-COPY for license information.
 #
 # This file is part of GNU Hyperbole.
@@ -637,11 +637,16 @@ else
 DOCKER_VERSION = master-ci
 endif
 
+recompile-docker-elpa:
+       $(EMACS_BATCH) --eval "(byte-recompile-directory 
\"/root/.emacs.d/elpa\" 0 'force)"
+
 docker: docker-update
-       docker run -v $$(pwd):/hypb -v /tmp:/hypb-tmp -it --rm 
silex/emacs:${DOCKER_VERSION} bash -c "cp -a /hypb /hyperbole && make -C 
hyperbole ${DOCKER_TARGETS}"
+       docker run --mount type=volume,src=elpa-local,dst=/root/.emacs.d/elpa \
+       -v $$(pwd):/hypb -v /tmp:/hypb-tmp -it --rm 
silex/emacs:${DOCKER_VERSION} bash -c "cp -a /hypb /hyperbole && make -C 
hyperbole recompile-docker-elpa ${DOCKER_TARGETS}"
 
 docker-run: docker-update
-       docker run -v $$(pwd):/hypb -v /tmp:/hypb-tmp -it --rm 
silex/emacs:${DOCKER_VERSION}
+       docker run --mount type=volume,src=elpa-local,dst=/root/.emacs.d/elpa \
+       -v $$(pwd):/hypb -v /tmp:/hypb-tmp -it --rm 
silex/emacs:${DOCKER_VERSION}
 
 # Update the docker image for the specified version of Emacs
 docker-update:
@@ -652,6 +657,9 @@ docker-update:
 run-emacs:
        emacs --eval "(progn (add-to-list 'load-path \"/hyperbole\") (require 
'hyperbole) (hyperbole-mode 1))"
 
+docker-clean:
+       docker rm elpa-local
+
 # Run with coverage. Run tests given by testspec and monitor the
 # coverage for the specified file.
 #
diff --git a/hpath.el b/hpath.el
index 0b9a54822d..f35f004b85 100644
--- a/hpath.el
+++ b/hpath.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:     1-Nov-91 at 00:44:23
-;; Last-Mod:     16-Feb-25 at 10:04:57 by Bob Weiner
+;; Last-Mod:      7-Mar-25 at 00:22:47 by Mats Lidell
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -1623,7 +1623,7 @@ but locational suffixes within the file are utilized."
     (subst-char-in-string ?\  ?- anchor)))
 
 (defun hpath:dashes-to-spaces-markup-anchor (anchor)
-  "Replace spaces with dashes with spaces in ANCHOR if not a prog mode and no 
existing dashes."
+  "Replace dashes with spaces in ANCHOR if not a prog mode and no existing 
dashes."
   (if (or (derived-mode-p 'prog-mode)
          (string-match-p "-.* \\| .*-" anchor))
       anchor
diff --git a/hywiki.el b/hywiki.el
index 2eadbb84de..877b7e8a6f 100644
--- a/hywiki.el
+++ b/hywiki.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    21-Acpr-24 at 22:41:13
-;; Last-Mod:     17-Mar-25 at 23:13:09 by Bob Weiner
+;; Last-Mod:     30-Mar-25 at 10:39:00 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -3088,6 +3088,10 @@ A call to `hywiki-active-in-current-buffer-p' at point 
must return non-nil
 or this will return nil."
   (hywiki-get-singular-wikiword (hywiki-word-strip-suffix (hywiki-word-at))))
 
+(defun hywiki-word-face-at-p ()
+  "Non-nil if but at point has `hywiki-word-face' property."
+  (hproperty:but-get (point) 'face hywiki-word-face))
+
 ;;;###autoload
 (defun hywiki-word-consult-grep (word)
   "Use `hywiki-consult-grep' to show occurrences of a prompted for HyWikiWord.
@@ -3370,17 +3374,17 @@ DATUM is either an element or an object.  INFO is the 
current
 export state, as a plist.
 
 References for the current document are stored in
-‘:internal-references’ property.  Its value is an alist with
+`:internal-references' property.  Its value is an alist with
 associations of the following types:
 
   (REFERENCE . DATUM) and (SEARCH-CELL . ID)
 
 REFERENCE is the reference string to be used for object or
 element DATUM.  SEARCH-CELL is a search cell, as returned by
-‘org-export-search-cells’.  ID is a number or a string uniquely
+`org-export-search-cells'.  ID is a number or a string uniquely
 identifying DATUM within the document.
 
-This function also checks ‘:crossrefs’ property for search cells
+This function also checks `:crossrefs' property for search cells
 matching DATUM before creating a new reference."
   (let ((cache (plist-get info :internal-references)))
     (or (car (rassq datum cache))
diff --git a/test/hactypes-tests.el b/test/hactypes-tests.el
index 97cd64f2df..304d342039 100644
--- a/test/hactypes-tests.el
+++ b/test/hactypes-tests.el
@@ -3,7 +3,7 @@
 ;; Author:       Mats Lidell <ma...@gnu.org>
 ;;
 ;; Orig-Date:    30-Jan-21 at 12:00:00
-;; Last-Mod:      3-Jan-25 at 23:52:37 by Mats Lidell
+;; Last-Mod:      4-Mar-25 at 17:05:59 by Mats Lidell
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -49,4 +49,12 @@
     (kill-matching-buffers "^\\*info\\*" nil t)))
 
 (provide 'hactypes-tests)
+
+;; This file can't be byte-compiled without the `el-mock' package
+;; which is not a dependency of Hyperbole.
+;;
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
+
 ;;; hactypes-tests.el ends here
diff --git a/test/hpath-tests.el b/test/hpath-tests.el
index b8fb6753f3..462b2b3fa2 100644
--- a/test/hpath-tests.el
+++ b/test/hpath-tests.el
@@ -3,7 +3,7 @@
 ;; Author:       Mats Lidell <ma...@gnu.org>
 ;;
 ;; Orig-Date:    28-Feb-21 at 23:26:00
-;; Last-Mod:     15-Jul-24 at 00:07:11 by Mats Lidell
+;; Last-Mod:      7-Mar-25 at 10:21:48 by Mats Lidell
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -463,6 +463,32 @@ dir/subdir:
       (should (= (line-number-at-pos) 1))
       (should (= (current-column) 0)))))
 
+(ert-deftest hpath--spaces-to-dashes-markup-anchor ()
+  "Verify `hpath:spaces-to-dashes-markup-anchor'."
+  (with-temp-buffer
+    ;; Normal case: Replace space wih dash.
+    (should (string= "a-b-c" (hpath:spaces-to-dashes-markup-anchor "a b c")))
+    ;; Mixed case: No conversion.
+    (should (string= "a b-c" (hpath:spaces-to-dashes-markup-anchor "a b-c")))
+    ;; Prog-mode: No conversion.
+    (prog-mode)
+    (should (string= "a b c" (hpath:spaces-to-dashes-markup-anchor "a b c")))
+    (should (string= "a-b-c" (hpath:spaces-to-dashes-markup-anchor "a-b-c")))
+    (should (string= "a b-c" (hpath:spaces-to-dashes-markup-anchor "a b-c")))))
+
+(ert-deftest hpath--dashes-to-spaces-markup-anchor ()
+  "Verify `hpath:dashes-to-spaces-markup-anchor'."
+  (with-temp-buffer
+    ;; Normal case: Replace dash with space.
+    (should (string= "a b c" (hpath:dashes-to-spaces-markup-anchor "a-b-c")))
+    ;; Mixed case: No conversion.
+    (should (string= "a b-c" (hpath:dashes-to-spaces-markup-anchor "a b-c")))
+    ;; Prog-mode: No conversion.
+    (prog-mode)
+    (should (string= "a b c" (hpath:spaces-to-dashes-markup-anchor "a b c")))
+    (should (string= "a-b-c" (hpath:dashes-to-spaces-markup-anchor "a-b-c")))
+    (should (string= "a b-c" (hpath:dashes-to-spaces-markup-anchor "a b-c")))))
+
 (provide 'hpath-tests)
 
 :; This file can't be byte-compiled without the `el-mock' package
diff --git a/test/hproperty-tests.el b/test/hproperty-tests.el
index bc8c04e243..65e38e28c1 100644
--- a/test/hproperty-tests.el
+++ b/test/hproperty-tests.el
@@ -3,7 +3,7 @@
 ;; Author:       Mats Lidell
 ;;
 ;; Orig-Date:     6-Aug-24 at 20:32:51
-;; Last-Mod:      6-Aug-24 at 21:59:39 by Mats Lidell
+;; Last-Mod:      4-Mar-25 at 17:04:46 by Mats Lidell
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -37,4 +37,12 @@
       (should (hproperty:but-p)))))
 
 (provide 'hproperty-tests)
+
+;; This file can't be byte-compiled without the `el-mock' package
+;; which is not a dependency of Hyperbole.
+;;
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
+
 ;;; hproperty-tests.el ends here
diff --git a/test/hui-mini-tests.el b/test/hui-mini-tests.el
index 6bd0230ea5..b6981ffba0 100644
--- a/test/hui-mini-tests.el
+++ b/test/hui-mini-tests.el
@@ -3,7 +3,7 @@
 ;; Author:       Mats Lidell
 ;;
 ;; Orig-Date:    30-Jan-25 at 22:39:37
-;; Last-Mod:     30-Jan-25 at 23:28:18 by Mats Lidell
+;; Last-Mod:      4-Mar-25 at 17:06:50 by Mats Lidell
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -33,4 +33,12 @@
         (should (hui:menu-read-from-minibuffer "" (format "Org M-RET %s" 
menu-string) hui:menu-mode-map nil t))))))
 
 (provide 'hui-mini-tests)
+
+;; This file can't be byte-compiled without the `el-mock' package
+;; which is not a dependency of Hyperbole.
+;;
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
+
 ;;; hui-mini-tests.el ends here
diff --git a/test/hycontrol-tests.el b/test/hycontrol-tests.el
index 799482cd63..24bc44c14b 100644
--- a/test/hycontrol-tests.el
+++ b/test/hycontrol-tests.el
@@ -3,7 +3,7 @@
 ;; Author:       Mats Lidell
 ;;
 ;; Orig-Date:     8-Jan-25 at 22:52:00
-;; Last-Mod:     21-Jan-25 at 17:03:54 by Mats Lidell
+;; Last-Mod:      4-Mar-25 at 17:06:26 by Mats Lidell
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -30,4 +30,12 @@
       (should (string-match "Requires manual installation" (cadr err))))))
 
 (provide 'hycontrol-tests)
+
+;; This file can't be byte-compiled without the `el-mock' package
+;; which is not a dependency of Hyperbole.
+;;
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
+
 ;;; hycontrol-tests.el ends here
diff --git a/test/hywiki-tests.el b/test/hywiki-tests.el
index 0984235223..2b23aebdff 100644
--- a/test/hywiki-tests.el
+++ b/test/hywiki-tests.el
@@ -3,7 +3,7 @@
 ;; Author:       Mats Lidell
 ;;
 ;; Orig-Date:    18-May-24 at 23:59:48
-;; Last-Mod:     14-Mar-25 at 17:35:00 by Bob Weiner
+;; Last-Mod:     30-Mar-25 at 10:45:03 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -25,6 +25,35 @@
 (require 'hsys-org)
 (require 'ox-publish)
 
+(defun hywiki-tests--command-execute (cmd &rest rest)
+  "Run CMD, with optional REST params, between calls to pre and post hooks.
+This is for simulating the command loop."
+  (setq last-command this-command)
+  (setq this-command cmd)
+  (run-hooks 'pre-command-hook)
+  (if rest
+      (apply cmd rest)
+    (command-execute cmd))
+  (run-hooks 'post-command-hook))
+
+(defmacro hywiki-tests--preserve-hywiki-mode (&rest body)
+  "Restore hywiki-mode after running BODY."
+  (declare (indent 0) (debug t))
+  `(let ((current-hywiki-mode hywiki-mode))
+     (unwind-protect
+        (progn ,@body)
+       (hywiki-mode (if current-hywiki-mode 1 0)))))
+
+(ert-deftest hywiki-tests--verify-preserve-hywiki-mode ()
+  "Verify `hywiki-tests--preserve-hywiki-mode' restores `hywiki-mode'."
+  (hywiki-tests--preserve-hywiki-mode
+    (hywiki-mode 1)
+    (hywiki-tests--preserve-hywiki-mode
+      (should hywiki-mode)
+      (hywiki-mode 0)
+      (should-not hywiki-mode))
+    (should hywiki-mode)))
+
 (ert-deftest hywiki-tests--hywiki-create-page--adds-file-in-wiki-folder ()
   "Verify add page creates file in wiki folder and sets hash table."
   (let* ((hsys-org-enable-smart-keys t)
@@ -55,150 +84,155 @@
 
 (ert-deftest hywiki-tests--action-key-on-hywikiword-displays-page ()
   "Verify `action-key' on a prefixed WikiWord, outside of hywiki-directory, 
creates a new page."
-  (let ((hsys-org-enable-smart-keys t)
-        (hywiki-directory (make-temp-file "hywiki" t))
-        (wikifile "WikiWord.org"))
-    (unwind-protect
-        (with-temp-buffer
-         (hywiki-mode 1)
-          (insert "[[hy:WikiWord]]")
-          (goto-char 4)
-          (action-key)
-         (should (equal (cons 'page wikifile) (hywiki-get-referent 
"WikiWord"))))
-      (hy-delete-file-and-buffer (expand-file-name wikifile hywiki-directory))
-      (hy-delete-dir-and-buffer hywiki-directory))))
+  (hywiki-tests--preserve-hywiki-mode
+    (let ((hsys-org-enable-smart-keys t)
+          (hywiki-directory (make-temp-file "hywiki" t))
+          (wikifile "WikiWord.org"))
+      (unwind-protect
+          (with-temp-buffer
+           (hywiki-mode 1)
+            (insert "[[hy:WikiWord]]")
+            (goto-char 4)
+            (action-key)
+           (should (equal (cons 'page wikifile) (hywiki-get-referent 
"WikiWord"))))
+        (hy-delete-file-and-buffer (expand-file-name wikifile 
hywiki-directory))
+        (hy-delete-dir-and-buffer hywiki-directory)))))
 
 (ert-deftest hywiki-tests--assist-key-on-hywikiword-displays-help ()
   "Verify `assist-key' on a prefixed WikiWord, outside of hywiki-directory, 
displays help for the WikiWord link."
-  (let ((hsys-org-enable-smart-keys t)
-        (hywiki-directory (make-temp-file "hywiki" t)))
-    (unwind-protect
-        (with-temp-buffer
-         (hywiki-mode 1)
-          (insert "[[hy:WikiWord]]")
-          (goto-char 6)
-          (should (string= "WikiWord" (hywiki-word-at)))
-          (delete-other-windows)
-          (assist-key)
-          (other-window 1)
-          (should (string-prefix-p "*Help: Hyperbole " (buffer-name))))
-      (hy-delete-dir-and-buffer hywiki-directory))))
+  (hywiki-tests--preserve-hywiki-mode
+    (let ((hsys-org-enable-smart-keys t)
+          (hywiki-directory (make-temp-file "hywiki" t)))
+      (unwind-protect
+          (with-temp-buffer
+           (hywiki-mode 1)
+            (insert "[[hy:WikiWord]]")
+            (goto-char 6)
+            (should (string= "WikiWord" (hywiki-word-at)))
+            (delete-other-windows)
+            (assist-key)
+            (other-window 1)
+            (should (string-prefix-p "*Help: Hyperbole " (buffer-name))))
+        (hy-delete-dir-and-buffer hywiki-directory)))))
 
 (ert-deftest hywiki-tests--action-key-on-wikiword-displays-page ()
   "Verify `action-key' on a WikiWord, outside of hywiki-directory, creates a 
new page."
-  (let* ((hsys-org-enable-smart-keys t)
-         (hywiki-directory (make-temp-file "hywiki" t))
-         (hywiki-page-file (expand-file-name "WikiWord.org" hywiki-directory)))
-    (unwind-protect
-        (dolist (v '(nil t)) ;; Verify the file exists the second time
-          (if v
-              (should (file-exists-p hywiki-page-file))
-            (should-not (file-exists-p hywiki-page-file)))
-          (with-temp-buffer
-           (hywiki-mode 1)
-            (insert "WikiWord\n")
-            (goto-char 4)
-            (action-key)
-            (should (string= hywiki-page-file (buffer-file-name)))
-            (should (equal (cons 'page (file-name-nondirectory 
hywiki-page-file))
-                           (hywiki-get-referent "WikiWord")))
+  (hywiki-tests--preserve-hywiki-mode
+    (let* ((hsys-org-enable-smart-keys t)
+           (hywiki-directory (make-temp-file "hywiki" t))
+           (hywiki-page-file (expand-file-name "WikiWord.org" 
hywiki-directory)))
+      (unwind-protect
+          (dolist (v '(nil t)) ;; Verify the file exists the second time
             (if v
-                (should (looking-at-p "WikiWord page"))
-              (insert "WikiWord page")
-              (goto-char (point-min)))))
-      (hy-delete-file-and-buffer hywiki-page-file)
-      (hy-delete-dir-and-buffer hywiki-directory))))
-
-(ert-deftest hywiki-tests--action-key-on-wikiword-and-section-displays-page ()
-  "Verify `action-key' on a WikiWord with section moves to the section."
-  (let* ((hsys-org-enable-smart-keys t)
-         (hywiki-directory (make-temp-file "hywiki" t))
-        (hywiki-page-file (expand-file-name "WikiWord.org" hywiki-directory))
-         (sections '("* Header" "** SubHeader" "*** SubSubHeader")))
-    (unwind-protect
-        (progn
-          (find-file hywiki-page-file)
-          (dolist (v sections)
-            (insert (format "%s\nbody\n" v)))
-          (save-buffer)
-         (hywiki-mode 1)
-          (dolist (v sections)
+                (should (file-exists-p hywiki-page-file))
+              (should-not (file-exists-p hywiki-page-file)))
             (with-temp-buffer
-              (insert "WikiWord#" (cadr (split-string v " ")))
+             (hywiki-mode 1)
+              (insert "WikiWord\n")
               (goto-char 4)
               (action-key)
               (should (string= hywiki-page-file (buffer-file-name)))
-             (should (looking-at-p (regexp-quote v))))))
-      (hywiki-mode 0)
-      (hy-delete-file-and-buffer hywiki-page-file)
-      (hy-delete-dir-and-buffer hywiki-directory))))
+              (should (equal (cons 'page (file-name-nondirectory 
hywiki-page-file))
+                             (hywiki-get-referent "WikiWord")))
+              (if v
+                  (should (looking-at-p "WikiWord page"))
+                (insert "WikiWord page")
+                (goto-char (point-min)))))
+        (hy-delete-file-and-buffer hywiki-page-file)
+        (hy-delete-dir-and-buffer hywiki-directory)))))
+
+(ert-deftest hywiki-tests--action-key-on-wikiword-and-section-displays-page ()
+  "Verify `action-key' on a WikiWord with section moves to the section."
+  (hywiki-tests--preserve-hywiki-mode
+    (let* ((hsys-org-enable-smart-keys t)
+           (hywiki-directory (make-temp-file "hywiki" t))
+          (hywiki-page-file (expand-file-name "WikiWord.org" hywiki-directory))
+           (sections '("* Header" "** SubHeader" "*** SubSubHeader")))
+      (unwind-protect
+          (progn
+            (find-file hywiki-page-file)
+            (dolist (v sections)
+              (insert (format "%s\nbody\n" v)))
+            (save-buffer)
+           (hywiki-mode 1)
+            (dolist (v sections)
+              (with-temp-buffer
+                (insert "WikiWord#" (cadr (split-string v " ")))
+                (goto-char 4)
+                (action-key)
+                (should (string= hywiki-page-file (buffer-file-name)))
+               (should (looking-at-p (regexp-quote v))))))
+        (hy-delete-file-and-buffer hywiki-page-file)
+        (hy-delete-dir-and-buffer hywiki-directory)))))
 
 (ert-deftest 
hywiki-tests--action-key-on-wikiword-and-line-column-displays-page ()
   "Verify `action-key' on a WikiWord with line and column specifications goes 
to expected point."
-  (let* ((hsys-org-enable-smart-keys t)
-         (hywiki-directory (make-temp-file "hywiki" t))
-        (hywiki-page-file (expand-file-name "WikiWord.org" hywiki-directory)))
-    (unwind-protect
-        (progn
-          (find-file hywiki-page-file)
-          (insert "\
+  (hywiki-tests--preserve-hywiki-mode
+    (let* ((hsys-org-enable-smart-keys t)
+           (hywiki-directory (make-temp-file "hywiki" t))
+          (hywiki-page-file (expand-file-name "WikiWord.org" 
hywiki-directory)))
+      (unwind-protect
+          (progn
+            (find-file hywiki-page-file)
+            (insert "\
 line 1
 line 2
 ")
-          (save-buffer)
-         (hywiki-mode 1)
-          (dolist (l '(1 2))
-            (dolist (c '("" ":C0" ":C5"))
-              (with-temp-buffer
-                (insert (format "WikiWord:L%s%s" l c))
-                (goto-char 4)
-                (action-key)
-                (should (string= hywiki-page-file (buffer-file-name)))
-                (if (string= c ":C5")
-                   (should (looking-at-p (format "%s$" l)))
-                 (should (looking-at-p (format "line %s$" l))))))))
-      (hywiki-mode 0)
-      (hy-delete-file-and-buffer hywiki-page-file)
-      (hy-delete-dir-and-buffer hywiki-directory))))
+            (save-buffer)
+           (hywiki-mode 1)
+            (dolist (l '(1 2))
+              (dolist (c '("" ":C0" ":C5"))
+                (with-temp-buffer
+                  (insert (format "WikiWord:L%s%s" l c))
+                  (goto-char 4)
+                  (action-key)
+                  (should (string= hywiki-page-file (buffer-file-name)))
+                  (if (string= c ":C5")
+                     (should (looking-at-p (format "%s$" l)))
+                   (should (looking-at-p (format "line %s$" l))))))))
+        (hy-delete-file-and-buffer hywiki-page-file)
+        (hy-delete-dir-and-buffer hywiki-directory)))))
 
 (ert-deftest hywiki-tests--not-a-wikiword-unless-in-hywiki-mode ()
   "Verify WikiWord is not a WikiWord unless in `hywiki-mode'."
-  (let ((hsys-org-enable-smart-keys t)
-        (hywiki-directory (make-temp-file "hywiki" t)))
-    (unwind-protect
-        (with-temp-buffer
-          (hywiki-mode 0)
-          (insert "WikiWord")
-          (goto-char 4)
-          (should-not (hywiki-word-at))
-          (hywiki-mode 1)
-          (should (string= "WikiWord" (hywiki-word-at))))
-      (hywiki-mode 0)
-      (hy-delete-dir-and-buffer hywiki-directory))))
+  (hywiki-tests--preserve-hywiki-mode
+    (let ((hsys-org-enable-smart-keys t)
+          (hywiki-directory (make-temp-file "hywiki" t)))
+      (unwind-protect
+          (with-temp-buffer
+            (hywiki-mode 0)
+            (insert "WikiWord")
+            (goto-char 4)
+            (should-not (hywiki-word-at))
+            (hywiki-mode 1)
+            (should (string= "WikiWord" (hywiki-word-at))))
+        (hy-delete-dir-and-buffer hywiki-directory)))))
 
 (ert-deftest hywiki-tests--a-wikiword-in-hywiki-directory ()
   "Verify WikiWord is identified if in `hywiki-directory'."
-  (let* ((hsys-org-enable-smart-keys t)
-         (hywiki-directory (make-temp-file "hywiki" t))
-         (referent (hywiki-add-page "WikiWord"))
-        (wiki-page (cdr referent)))
-    (unwind-protect
-        (with-current-buffer (find-file-noselect wiki-page)
-          (hywiki-mode 0)
-          (insert "AnotherWikiWord")
-         (newline nil t)
-          (goto-char 4)
-          (should (hywiki-word-at)))
-      (hy-delete-file-and-buffer wiki-page)
-      (hy-delete-dir-and-buffer hywiki-directory))))
+  (hywiki-tests--preserve-hywiki-mode
+    (let* ((hsys-org-enable-smart-keys t)
+           (hywiki-directory (make-temp-file "hywiki" t))
+           (referent (hywiki-add-page "WikiWord"))
+          (wiki-page (cdr referent)))
+      (unwind-protect
+          (with-current-buffer (find-file-noselect wiki-page)
+            (hywiki-mode 0)
+            (insert "AnotherWikiWord")
+           (newline nil t)
+            (goto-char 4)
+            (should (hywiki-word-at)))
+        (hy-delete-file-and-buffer wiki-page)
+        (hy-delete-dir-and-buffer hywiki-directory)))))
 
 (ert-deftest hywiki-tests--wikiword-identified-with-delimiters ()
   "Verify WikiWord is identified when surrounded by delimiters."
-  (let ((hsys-org-enable-smart-keys t)
-        (hywiki-directory (make-temp-file "hywiki" t)))
-    (unwind-protect
-        (progn
-          (hywiki-mode 1)
+  (hywiki-tests--preserve-hywiki-mode
+    (let ((hsys-org-enable-smart-keys t)
+          (hywiki-directory (make-temp-file "hywiki" t)))
+      (unwind-protect
+          (progn
+            (hywiki-mode 1)
 
           ;; Matches a WikiWord
           (dolist (v '("WikiWord" "[WikiWord]" "[[WikiWord]]" "{WikiWord}" 
"(WikiWord)"
@@ -253,56 +287,51 @@ line 2
                  (should-not v)
                (should t)))))
       (hywiki-mode 0)
-      (hy-delete-dir-and-buffer hywiki-directory))))
+      (hy-delete-dir-and-buffer hywiki-directory)))))
 
 (ert-deftest hywiki-tests--at-wikiword-finds-word-and-section ()
   "Verify `hywiki-word-at' finds WikiWord and section if available."
-  (let ((hywiki-directory (make-temp-file "hywiki" t)))
-    (unwind-protect
-        (with-temp-buffer
-          (hywiki-mode)
-          (insert "WikiWord")
-          (goto-char 4)
-          (should (string= "WikiWord" (hywiki-word-at)))
-
-          ;; Section
-          (goto-char (point-max))
-          (insert "#section")
-          (goto-char 4)
-          (should (string= "WikiWord#section" (hywiki-word-at)))
-
-          ;; Section with dash
-          (goto-char (point-max))
-          (insert "-subsection")
-          (goto-char 4)
-          (should (string= "WikiWord#section-subsection" (hywiki-word-at))))
-      (hywiki-mode -1)
-      (hy-delete-dir-and-buffer hywiki-directory))))
+  (hywiki-tests--preserve-hywiki-mode
+    (let ((hywiki-directory (make-temp-file "hywiki" t))
+          (words '("WikiWord" "WikiWord:L1" "WikiWord:L1:C2"
+                   "WikiWord#section" "WikiWord#section:L1" 
"WikiWord#section:L1:C2"
+                   "WikiWord#section-subsection" 
"WikiWord#section-subsection:L1" "WikiWord#section-subsection:L1:C2"
+                   ;; !! FIXME: Uncomment when implemented.
+                   ;; ("(WikiWord#section with spaces)" . "WikiWord#section 
with spaces")
+                   ;; ("(WikiWord#section)" . "WikiWord#section")
+                   )))
+      (unwind-protect
+          (with-temp-buffer
+            (hywiki-mode 1)
+            (dolist (w words)
+              (let ((in (if (stringp w) w (car w)))
+                    (expect (if (stringp w) w (cdr w))))
+                (erase-buffer)
+                (insert in)
+                (goto-char 4)
+                (should (string= expect (hywiki-word-at))))))
+        (hy-delete-dir-and-buffer hywiki-directory)))))
 
 (ert-deftest hywiki-tests--sections-with-dash-space ()
   "Verify `hywiki-word-at' finds sections with dash and space."
-  (let ((hywiki-directory (make-temp-file "hywiki" t)))
-    (unwind-protect
-        (progn
-          (with-temp-buffer
-            (hywiki-mode)
-            (insert "WikiWord#section rest is ignored")
-            (goto-char 4)
-            (should (string= "WikiWord#section" (hywiki-word-at))))
-
-          (with-temp-buffer
-            (hywiki-mode)
-            (insert "WikiWord#section-with-dash")
-            (goto-char 4)
-            (should (string= "WikiWord#section-with-dash" (hywiki-word-at))))
-
-          (with-temp-buffer
-            (hywiki-mode)
-            (insert "WikiWord#\"section-within-quotes\"")
-            (goto-char 4)
-            (should (string= "WikiWord#\"section-within-quotes\"" 
(hywiki-word-at)))))
-      (hywiki-mode -1)
-      (hy-delete-dir-and-buffer hywiki-directory))))
+  (hywiki-tests--preserve-hywiki-mode
+    (let ((hywiki-directory (make-temp-file "hywiki" t)))
+      (unwind-protect
+          (progn
+            (hywiki-mode 1)
+            (with-temp-buffer
+              (insert "WikiWord#section rest is ignored")
+              (goto-char 4)
+              (should (string= "WikiWord#section" (hywiki-word-at))))
+            (with-temp-buffer
+              (insert "WikiWord#section-with-dash")
+              (goto-char 4)
+              (should (string= "WikiWord#section-with-dash" (hywiki-word-at))))
+            (with-temp-buffer
+              (insert "WikiWord#\"section-within-quotes\"")
+              (goto-char 4)
+              (should (string= "WikiWord#\"section-within-quotes\"" 
(hywiki-word-at)))))
+        (hy-delete-dir-and-buffer hywiki-directory)))))
 
 (ert-deftest hywiki-tests--word-is-p ()
   "Verify `hywiki-word-is-p' identifies WikiWords."
@@ -474,183 +503,127 @@ Both mod-time and checksum must be changed for a test 
to return true."
               (hy-delete-dir-and-buffer hywiki-directory))))
       (hy-delete-dir-and-buffer hywiki-directory))))
 
-;; Following three test cases for verifying proper face is some what
+;; Following test cases for verifying proper face is some what
 ;; experimental. They need to be run in interactive mode.
 
-(defun hywiki-tests--add-hywiki-hooks ()
-  "Enable all hywiki hook functions."
-  (add-hook 'pre-command-hook      'hywiki-debuttonize-non-character-commands 
95)
-  (add-hook 'post-command-hook     'hywiki-buttonize-non-character-commands 95)
-  (add-hook 'post-self-insert-hook 'hywiki-buttonize-character-commands)
-  (add-hook 'window-buffer-change-functions
-           'hywiki-maybe-highlight-wikiwords-in-frame)
-  (add-to-list 'yank-handled-properties
-              '(hywiki-word-face . hywiki-highlight-on-yank)))
-
-(defun hywiki-tests--remove-hywiki-hooks ()
-  "Disable all hywiki hook functions."
-  (remove-hook 'pre-command-hook      
'hywiki-debuttonize-non-character-commands)
-  (remove-hook 'post-command-hook     'hywiki-buttonize-non-character-commands)
-  (remove-hook 'post-self-insert-hook 'hywiki-buttonize-character-commands)
-  (remove-hook 'window-buffer-change-functions
-              'hywiki-maybe-highlight-wikiwords-in-frame)
-  (setq yank-handled-properties
-       (delete '(hywiki-word-face . hywiki-highlight-on-yank)
-               yank-handled-properties)))
-
-(defmacro with-hywiki-buttonize-hooks (&rest body)
-  "Call BODY wrapped in hywiki hooks to simulate Emacs redisplay."
-  (declare (indent 0) (debug t))
-  `(progn
-     (funcall 'hywiki-debuttonize-non-character-commands)
-     (progn ,@body)
-     (funcall 'hywiki-buttonize-non-character-commands)))
-
-(defmacro with-hywiki-buttonize-and-insert-hooks (&rest body)
-  "Call BODY wrapped in hywiki hooks to simulate Emacs redisplay."
-  (declare (indent 0) (debug t))
-  `(progn
-     (progn ,@body)
-     (setq this-command 'org-return)
-     (funcall 'hywiki-debuttonize-non-character-commands)
-     (funcall 'hywiki-buttonize-character-commands)
-     (funcall 'hywiki-buttonize-non-character-commands)))
-
 (ert-deftest hywiki-tests--face-property-for-wikiword-with-wikipage ()
   "Verify WikiWord for a wiki page gets face property hywiki-word-face."
   (skip-unless (not noninteractive))
-  (let* ((hsys-org-enable-smart-keys t)
-         (hywiki-directory (make-temp-file "hywiki" t))
-         (wikipage (cdr (hywiki-add-page "WikiWord"))))
-    (unwind-protect
-        (progn
-          (hywiki-tests--remove-hywiki-hooks)
-          (with-temp-buffer
-            (hywiki-mode 1)
-            (with-hywiki-buttonize-and-insert-hooks (insert "WikiWord "))
-            (goto-char 4)
-            (should (hproperty:but-get (point) 'face hywiki-word-face)))
-          (with-temp-buffer
+  (hywiki-tests--preserve-hywiki-mode
+    (let* ((hsys-org-enable-smart-keys t)
+           (hywiki-directory (make-temp-file "hywiki" t))
+           (wikipage (cdr (hywiki-add-page "WikiWord"))))
+      (unwind-protect
+          (progn
             (hywiki-mode 1)
-            (with-hywiki-buttonize-and-insert-hooks
+            (with-temp-buffer
+              (insert "WikiWor")
+             (hywiki-tests--command-execute #'self-insert-command 1 ?d)
+              (goto-char 4)
+              (should (hywiki-word-face-at-p)))
+            (with-temp-buffer
               (insert "WikiWord")
-             (command-execute #'newline))
-            (goto-char 4)
-            (should (hproperty:but-get (point) 'face hywiki-word-face))))
-      (hywiki-tests--add-hywiki-hooks)
-      (hywiki-mode 0)
-      (hy-delete-file-and-buffer wikipage)
-      (hy-delete-dir-and-buffer hywiki-directory))))
+             (hywiki-tests--command-execute #'newline 1 'interactive)
+              (goto-char 4)
+              (should (hywiki-word-face-at-p))))
+        (hy-delete-file-and-buffer wikipage)
+        (hy-delete-dir-and-buffer hywiki-directory)))))
 
 (ert-deftest hywiki-tests--no-face-property-for-no-wikipage ()
   "Verify WikiWord for no wiki page does not get face property 
hywiki-word-face."
   (skip-unless (not noninteractive))
-  (let* ((hsys-org-enable-smart-keys t)
-         (hywiki-directory (make-temp-file "hywiki" t)))
-    (unwind-protect
-        (progn
-          (hywiki-tests--remove-hywiki-hooks)
-          (with-temp-buffer
-            (hywiki-mode 0)
-            (with-hywiki-buttonize-and-insert-hooks
-              (insert "WikiWord")
-             (newline nil t))
-            (goto-char 4)
-            (should-not (hproperty:but-get (point) 'face hywiki-word-face))))
-      (hywiki-tests--add-hywiki-hooks)
-      (hy-delete-dir-and-buffer hywiki-directory))))
+  (hywiki-tests--preserve-hywiki-mode
+    (let* ((hsys-org-enable-smart-keys t)
+           (hywiki-directory (make-temp-file "hywiki" t)))
+      (unwind-protect
+          (progn
+            (with-temp-buffer
+              (hywiki-mode 0)
+              (insert "WikiWor")
+             (hywiki-tests--command-execute #'self-insert-command 1 ?d)
+              (goto-char 4)
+              (should-not (hywiki-word-face-at-p))))
+        (hy-delete-dir-and-buffer hywiki-directory)))))
 
 (ert-deftest hywiki-tests--verify-face-property-when-editing-wikiword ()
   "Verify face property changes when WikiWord is edited."
   (skip-unless (not noninteractive))
-  (let* ((hywiki-directory (make-temp-file "hywiki" t))
-         (wikipage (cdr (hywiki-add-page "WikiWord"))))
-    (unwind-protect
-        (progn
-          (hywiki-tests--remove-hywiki-hooks)
-          (with-temp-buffer
-            (hywiki-mode 1)
-            (with-hywiki-buttonize-and-insert-hooks
-             (insert "Wikiord ")
-              (goto-char 5))
-            (should (looking-at-p "ord"))
-            (should-not (hproperty:but-get (point) 'face hywiki-word-face))
-
-            (with-hywiki-buttonize-and-insert-hooks
-             (insert "W")
-              (goto-char 5))
-            (should (looking-at-p "Word"))
-            (should (hproperty:but-get (point) 'face hywiki-word-face))
-
-            (with-hywiki-buttonize-and-insert-hooks
-             (delete-char 1))
-            (should (looking-at-p "ord"))
-            (should-not (hproperty:but-get (point) 'face hywiki-word-face))))
-      (hywiki-tests--add-hywiki-hooks)
-      (hywiki-mode 0)
-      (hy-delete-files-and-buffers (list wikipage))
-      (hy-delete-dir-and-buffer hywiki-directory))))
+  (hywiki-tests--preserve-hywiki-mode
+    (let* ((hywiki-directory (make-temp-file "hywiki" t))
+           (wikipage (cdr (hywiki-add-page "WikiWord"))))
+      (unwind-protect
+          (progn
+            (with-temp-buffer
+              (hywiki-mode 1)
+              (insert "Wikiord")
+              (hywiki-tests--command-execute #'self-insert-command 1 ? )
+              (goto-char 5)
+              (should (looking-at-p "ord "))
+              (should-not (hywiki-word-face-at-p))
+
+              (hywiki-tests--command-execute #'self-insert-command 1 ?W)
+              (goto-char 5)
+              (should (looking-at-p "Word "))
+              (should (hywiki-word-face-at-p))
+
+              (hywiki-tests--command-execute #'delete-char 1)
+              (should (looking-at-p "ord "))
+              (should-not (hywiki-word-face-at-p))))
+        (hy-delete-files-and-buffers (list wikipage))
+        (hy-delete-dir-and-buffer hywiki-directory)))))
 
 (ert-deftest 
hywiki-tests--verify-face-property-when-editing-wikiword-first-char ()
   "Verify face property changes when WikiWord is edited in the first char 
position."
   (skip-unless (not noninteractive))
-  (with-temp-buffer
+  (hywiki-tests--preserve-hywiki-mode
     (let* ((hywiki-directory (make-temp-file "hywiki" t))
            (wikipage (cdr (hywiki-add-page "WikiWord"))))
       (unwind-protect
           (progn
-            (hywiki-tests--remove-hywiki-hooks)
-            (hywiki-mode 1)
-            (with-hywiki-buttonize-and-insert-hooks (insert "WikiWord "))
-            (goto-char 1)
-            (should (looking-at-p "Wiki"))
-            (should (hproperty:but-get (point) 'face hywiki-word-face))
-
-            (with-hywiki-buttonize-and-insert-hooks
-             (delete-char 1))
-            (should (looking-at-p "iki"))
-            (should-not (hproperty:but-get (point) 'face hywiki-word-face))
-
-            (with-hywiki-buttonize-and-insert-hooks
-             (insert "W")
-              (goto-char 1))
-            (should (looking-at-p "Wiki"))
-            (should (hproperty:but-get (point) 'face hywiki-word-face)))
-       ;; !! FIXME: Uncomment these lines.
-       ;; (hywiki-tests--add-hywiki-hooks)
-       ;; (hywiki-mode 0)
-       ;; (hy-delete-files-and-buffers (list wikipage))
-       ;; (hy-delete-dir-and-buffer hywiki-directory)
-       ))))
+            (with-temp-buffer
+              (hywiki-mode 1)
+              (insert "WikiWord")
+              (hywiki-tests--command-execute #'self-insert-command 1 ? )
+              (goto-char 1)
+              (should (looking-at-p "WikiWord"))
+              (should (hywiki-word-face-at-p))
+
+             (hywiki-tests--command-execute #'delete-char 1)
+              (should (looking-at-p "ikiWord"))
+              (should-not (hywiki-word-face-at-p))
+
+              (hywiki-tests--command-execute #'self-insert-command 1 ?W)
+              (goto-char 1)
+              (should (looking-at-p "WikiWord"))
+              (should (hywiki-word-face-at-p))))
+        (hy-delete-files-and-buffers (list wikipage))
+        (hy-delete-dir-and-buffer hywiki-directory)))))
 
 (ert-deftest hywiki-tests--convert-words-to-org-link ()
   "Verify `hywiki-convert-words-to-org-links' converts WikiWords to org links."
   (skip-unless (not noninteractive))
-  (let* ((hywiki-directory (make-temp-file "hywiki" t))
-         (wikipage (cdr (hywiki-add-page "WikiWord"))))
-    (unwind-protect
-        (progn
-          (hywiki-tests--remove-hywiki-hooks)
-          (with-temp-buffer
-            (hywiki-mode 1)
-            (with-hywiki-buttonize-and-insert-hooks (insert "WikiWord "))
-            (goto-char 4)
-            (hywiki-convert-words-to-org-links)
-            (should (string= "[[WikiWord]] "
-                             (buffer-substring-no-properties (point-min) 
(point-max)))))
-          (with-temp-buffer
+  (hywiki-tests--preserve-hywiki-mode
+    (let* ((hywiki-directory (make-temp-file "hywiki" t))
+           (wikipage (cdr (hywiki-add-page "WikiWord"))))
+      (unwind-protect
+          (progn
             (hywiki-mode 1)
-            (with-hywiki-buttonize-and-insert-hooks
+            (with-temp-buffer
               (insert "WikiWord")
-             (newline nil t))
-            (goto-char 4)
-            (hywiki-convert-words-to-org-links)
-            (should (string= "[[WikiWord]]\n"
-                             (buffer-substring-no-properties (point-min) 
(point-max))))))
-      (hywiki-tests--add-hywiki-hooks)
-      (hywiki-mode 0)
-      (hy-delete-file-and-buffer wikipage)
-      (hy-delete-dir-and-buffer hywiki-directory))))
+              (hywiki-tests--command-execute #'self-insert-command 1 ? )
+              (goto-char 4)
+              (hywiki-convert-words-to-org-links)
+              (should (string= "[[WikiWord]] "
+                               (buffer-substring-no-properties (point-min) 
(point-max)))))
+            (with-temp-buffer
+              (insert "WikiWor")
+             (hywiki-tests--command-execute #'self-insert-command 1 ?d)
+              (goto-char 4)
+              (hywiki-convert-words-to-org-links)
+              (should (string= "[[WikiWord]]"
+                               (buffer-substring-no-properties (point-min) 
(point-max))))))
+        (hy-delete-file-and-buffer wikipage)
+        (hy-delete-dir-and-buffer hywiki-directory)))))
 
 (ert-deftest hywiki-tests--at-tags-p ()
   "Verify `hywiki-at-tags-p'."
@@ -735,6 +708,112 @@ Both mod-time and checksum must be changed for a test to 
return true."
       (hy-delete-file-and-buffer wikipage)
       (hy-delete-dir-and-buffer hywiki-directory))))
 
+(ert-deftest hywiki-tests--action-key-moves-to-word-and-section ()
+  "Verify action key on a WikiWord with section, line and column works."
+  (hywiki-tests--preserve-hywiki-mode
+    (let* ((hywiki-directory (make-temp-file "hywiki" t))
+           (wikipage (cdr (hywiki-add-page "WikiWord")))
+           (words '(("WikiWord:L1" . "First line")
+                    ("WikiWord:L1:C2" . "rst line")
+                    ("WikiWord#Asection" . "* Asection")
+                    ("WikiWord#Asection:L1" . "* Asection")
+                    ("WikiWord#Asection:L2" . "body A")
+                    ("WikiWord#Asection:L2:C2" . "dy A")
+                    ("WikiWord#Bsection-subsection" . "** Bsection subsection")
+                    ("WikiWord#Bsection-subsection:L2" . "body B")
+                    ("WikiWord#Bsection-subsection:L2:C2" . "dy B")
+                    ;; FIXME: Uncomment when implemented.
+                    ;; ("(WikiWord#Bsection subsection)" . "** Bsection 
subsection")
+                    ;; ("(WikiWord#Asection)" . "* Asection")
+                    )))
+      (unwind-protect
+          (progn
+            ;; Setup target WikiWord
+            (with-current-buffer (find-file-noselect wikipage)
+              (insert "\
+First line
+* Asection
+body A
+** Bsection subsection
+body B
+")
+              (save-buffer))
+            ;; Create temp buffers with WikiWord links to the target
+            ;; WikiWord page and verify they work.
+            (with-temp-buffer
+              (hywiki-mode 1)
+              (dolist (w words)
+                (let ((wiki-link (car w))
+                      (expected-str-at-pos (cdr w)))
+                  (erase-buffer)
+                  (insert wiki-link)
+                  (goto-char 4)
+                  (save-excursion
+                    (action-key)
+                    ;; (should (string-prefix-p "WikiWord.org" (buffer-name)))
+                    (should (looking-at-p expected-str-at-pos)))))))
+        (hy-delete-file-and-buffer wikipage)
+        (hy-delete-dir-and-buffer hywiki-directory)))))
+
+(ert-deftest hywiki-tests--published-html-links-to-word-and-section ()
+  "Verify published html links to WikiWord and section."
+  :expected-result :failed
+  (let* ((hywiki-directory (make-temp-file "hywiki_" t))
+         (hywiki-org-publishing-directory (make-temp-file "public_html_" t))
+         (wikipage (cdr (hywiki-add-page "WikiPage")))
+         (wikipage-html (expand-file-name "WikiPage.html" 
hywiki-org-publishing-directory))
+         (wikiword (cdr (hywiki-add-page "WikiWord")))
+         (wikiword-html (expand-file-name "WikiWord.html" 
hywiki-org-publishing-directory)))
+    (unwind-protect
+        (progn
+          (hywiki-org-set-publish-project)
+          (should (file-exists-p hywiki-directory))
+          (should (file-exists-p wikipage))
+          (should (file-exists-p wikiword))
+
+          ;; Setup wiki pages for WikiWord and WikiPage.
+          (with-current-buffer (find-file-noselect wikiword)
+            (insert "\
+First line
+* Asection
+body A
+** Bsection subsection
+body B
+")
+            (save-buffer))
+          (with-current-buffer (find-file-noselect wikipage)
+            (insert "\
+WikiWord
+WikiWord#Asection
+WikiWord#Bsection-subsection
+")
+            (save-buffer))
+
+          ;; Export the wiki
+          (hywiki-publish-to-html t)
+
+          ;; Verify files and folder are generated
+          (should (file-exists-p hywiki-org-publishing-directory))
+          (should (file-exists-p wikipage-html))
+          (should (file-exists-p wikiword-html))
+
+          ;; Verify links are generated
+          (with-current-buffer (find-file-noselect wikipage-html)
+            ;; (First check we even get the wikipage with sections)
+            (should (<= 1 (count-matches (regexp-quote "WikiWord") (point-min) 
(point-max))))
+            (should (= 1 (count-matches (regexp-quote "WikiWord#Asection") 
(point-min) (point-max))))
+            (should (= 1 (count-matches (regexp-quote 
"WikiWord#Bsection-subsection") (point-min) (point-max))))
+
+            ;; Then verify the href links are generated
+            (should (= 1 (count-matches (regexp-quote "<a 
href=\"WikiWord.html\">WikiWord</a>") (point-min) (point-max))))
+            (should (= 1 (count-matches (regexp-quote "<a 
href=\"WikiWord.html#Asection\">WikiWord#ASection</a>") (point-min) 
(point-max))))
+            (should (= 1 (count-matches (regexp-quote "<a 
href=\"WikiWord.html#Bsection-subsection\">WikiWord#Bsection-subsection</a>") 
(point-min) (point-max))))))
+      (hy-delete-files-and-buffers (list wikipage wikiword wikipage-html 
wikiword-html
+                                         (expand-file-name "index.org" 
hywiki-directory)
+                                         (expand-file-name "index.html" 
hywiki-org-publishing-directory)))
+      (hy-delete-dir-and-buffer hywiki-org-publishing-directory)
+      (hy-delete-dir-and-buffer hywiki-directory))))
+
 (ert-deftest hywiki-tests--get-singular-wikiword ()
   "Verify plural WikiWord is converted to singular.
 Note special meaning of `hywiki-allow-plurals-flag'."
@@ -809,8 +888,9 @@ Note special meaning of `hywiki-allow-plurals-flag'."
 
 (ert-deftest hywiki-tests--add-find ()
   "Verify `hywiki-add-find'."
-  (let* ((wikiword "WikiWord")
-        (referent '(find . hywiki-word-grep)))
+  (let ((hywiki-directory (make-temp-file "hywiki" t))
+        (wikiword "WikiWord")
+       (referent '(find . hywiki-word-grep)))
     (hywiki-add-find wikiword)
     (should (equal referent (hywiki-get-referent wikiword)))))
 
@@ -876,33 +956,36 @@ Note special meaning of `hywiki-allow-plurals-flag'."
 (ert-deftest hywiki-tests--add-org-id ()
   "Verify `hywiki-add-org-id'."
   ;; Error case - Non org-mode buffer
-  (let ((wikiword "WikiWord"))
-    (let ((filea (make-temp-file "hypb" nil ".txt")))
-      (unwind-protect
-          (with-current-buffer (find-file filea)
-            (mocklet (((hmouse-choose-link-and-referent-windows) => (list nil 
(get-buffer-window))))
-              (should-error (hywiki-add-org-id wikiword) :type '(error))))
-       (hy-delete-file-and-buffer filea)))
-
-    (let ((filea (make-temp-file "hypb" nil ".org")))
-      (unwind-protect
-          (with-current-buffer (find-file filea)
-            (insert "* header\n")
-
-            ;; Error-case - No Org ID and read only
-            (setq buffer-read-only t)
-            (mocklet (((hmouse-choose-link-and-referent-windows) => (list nil 
(get-buffer-window))))
-             (should-error (hywiki-add-org-id wikiword) :type '(error))
+  (let ((wikiword "WikiWord")
+        (hywiki-directory (make-temp-file "hywiki" t)))
+    (unwind-protect
+        (progn
+          (let ((filea (make-temp-file "hypb" nil ".txt")))
+            (unwind-protect
+                (with-current-buffer (find-file filea)
+                  (mocklet (((hmouse-choose-link-and-referent-windows) => 
(list nil (get-buffer-window))))
+                    (should-error (hywiki-add-org-id wikiword) :type 
'(error))))
+             (hy-delete-file-and-buffer filea)))
 
-              ;; Normal case - Org-mode with Org ID
-              (goto-char (point-max))
-              (setq buffer-read-only nil)
-              (defvar hywiki-test--org-id)
-             (let ((referent-value (cdr (hywiki-add-org-id wikiword))))
-               (if (stringp referent-value)
-                   (should (string-prefix-p "ID: " referent-value))
-                 (error "(hywiki-tests--add-org-id): referent value is a 
non-string: %s" referent-value)))))
-       (hy-delete-file-and-buffer filea)))))
+          (let ((filea (make-temp-file "hypb" nil ".org")))
+            (unwind-protect
+                (with-current-buffer (find-file filea)
+                  (insert "* header\n")
+
+                  ;; Error-case - No Org ID and read only
+                  (setq buffer-read-only t)
+                  (mocklet (((hmouse-choose-link-and-referent-windows) => 
(list nil (get-buffer-window))))
+                   (should-error (hywiki-add-org-id wikiword) :type '(error))
+
+                    ;; Normal case - Org-mode with Org ID
+                    (goto-char (point-max))
+                    (setq buffer-read-only nil)
+                   (let ((referent-value (cdr (hywiki-add-org-id wikiword))))
+                     (if (stringp referent-value)
+                         (should (string-prefix-p "ID: " referent-value))
+                       (error "(hywiki-tests--add-org-id): referent value is a 
non-string: %s" referent-value)))))
+             (hy-delete-file-and-buffer filea))))
+      (hy-delete-dir-and-buffer hywiki-directory))))
 
 (ert-deftest hywiki-tests--add-org-roam-node ()
   "Verify `hywiki-add-org-roam-node'."
@@ -936,62 +1019,327 @@ Note special meaning of `hywiki-allow-plurals-flag'."
 ;;                      (hywiki-get-referent wikiword))))
 ;;       (hy-delete-dir-and-buffer hywiki-directory))))
 
-(ert-deftest hywiki-tests--save-referent ()
-  "Verify saving and loading a referent works."
-  (let* ((hywiki-directory (make-temp-file "hywiki" t))
-         (wiki-page (cdr (hywiki-add-page "WikiPage" )))
-        (wiki-referent "WikiReferent"))
-    (unwind-protect
-        (progn
-          (find-file wiki-page)
-          (insert wiki-referent)
-          (goto-char 4)
-          (with-simulated-input "ABC RET"
-           (hywiki-add-key-series wiki-referent))
-         (should (equal '(key-series . "{ABC}") (hywiki-get-referent 
wiki-referent)))
-          (should (string= wiki-referent (buffer-string)))
-          (should (file-exists-p (hywiki-cache-default-file)))
-
-          ;; Simulate reload from cache
-          (setq hywiki--referent-hasht nil)
-          (hywiki-make-referent-hasht)
-          (should (equal '(key-series . "{ABC}") (hywiki-get-referent 
wiki-referent))))
-      (hy-delete-files-and-buffers (list wiki-page 
(hywiki-cache-default-file)))
-      (hy-delete-dir-and-buffer hywiki-directory))))
-
-(ert-deftest hywiki-tests--save-referent-use-hyperbole-menu ()
-  "Verify saving and loading a referent works when using Hyperbole's menu."
+(defmacro hywiki-tests--referent-test (expected &rest prepare)
+  "Referent test boilerplate code.
+EXPECTED is the result expected from hywiki-get-referent.  PREPARE sets
+up the test."
+  (declare (indent 0) (debug t))
+  `(let* ((hywiki-directory (make-temp-file "hywiki" t))
+          (wiki-page (cdr (hywiki-add-page "WikiPage" )))
+         (wiki-referent "WikiReferent")
+          (mode-require-final-newline nil))
+     (unwind-protect
+         (progn
+           (should (equal '("WikiPage") (hywiki-get-wikiword-list)))
+           (find-file wiki-page)
+           (insert wiki-referent)
+           (save-buffer)
+           (goto-char 4)
+
+           ,@prepare
+
+           (should (equal ,expected (hywiki-get-referent wiki-referent)))
+
+           (should (string= wiki-referent (buffer-string)))
+           (should (file-exists-p (hywiki-cache-default-file)))
+
+           ;; Simulate reload from cache
+           (hywiki-cache-save)
+           (setq hywiki--referent-hasht nil)
+           (hywiki-make-referent-hasht)
+
+           (should (equal ,expected (hywiki-get-referent wiki-referent))))
+
+       (hy-delete-files-and-buffers (list wiki-page 
(hywiki-cache-default-file)))
+       (hy-delete-dir-and-buffer hywiki-directory))))
+
+(ert-deftest hywiki-tests--save-referent-keyseries ()
+  "Verify saving and loading a referent keyseries works ."
+  (hywiki-tests--referent-test
+   (cons 'key-series "{ABC}")
+   (with-simulated-input "ABC RET"
+     (hywiki-add-key-series wiki-referent))))
+
+;; FIXME: Not stable. Can sometimes succeed.
+(ert-deftest hywiki-tests--save-referent-keyseries-use-menu ()
+  "Verify saving and loading a referent keyseries works using Hyperbole's 
menu."
   :expected-result :failed
-  ;; The entered key series is inserted into the WikiWord file. See
-  ;; comment below.
+  ; The failure is intermittent. See expanded test case below.
   (skip-unless (not noninteractive))
-  (let* ((hywiki-directory (make-temp-file "hywiki" t))
-         (wiki-page (cdr (hywiki-add-page "WikiPage" )))
-        (wiki-referent "WikiReferent"))
-    (unwind-protect
-        (progn
-          (find-file wiki-page)
-          (insert wiki-referent)
-          (goto-char 4)
-
-          (kbd-key:act "C-u C-h h h c")
-          ;; (hy-test-helpers:consume-input-events)
-         (sit-for 0.1)
-          (kbd-key:act "k {ABC} RET")
-          ;; (hy-test-helpers:consume-input-events)
-
-          ;; The expected behavior here is no change in the WikiPage buffer
-          (should (string= wiki-referent (buffer-substring-no-properties 
(point-min) (point-max))))
-
-          (should (file-exists-p (hywiki-cache-default-file)))
-         (should (equal '(key-series . "{ABC}") (hywiki-get-referent 
wiki-referent)))
-
-          ;; Simulate reload from cache
-          (setq hywiki--referent-hasht nil)
-          (hywiki-make-referent-hasht)
-          (should (equal '(key-series . "{ABC}") (hywiki-get-referent 
wiki-referent))))
-      (hy-delete-files-and-buffers (list wiki-page 
(hywiki-cache-default-file)))
-      (hy-delete-dir-and-buffer hywiki-directory))))
+  (hywiki-tests--referent-test
+   (cons 'key-series "{ABC}")
+   (should (hact 'kbd-key "C-u C-h hhck{ABC} RET"))
+   (hy-test-helpers:consume-input-events)))
+
+;; !! TODO: Have to make this work or remove it.
+;; Expanded for easier debugging
+;; (ert-deftest hywiki-tests--save-referent-keyseries-use--menu-expanded ()
+;;   "Verify saving and loading a referent works when using Hyperbole's menu."
+;;   :expected-result :failed
+;;   ;; The entered key series is inserted into the WikiWord file. See
+;;   ;; comment below. The failure is intermittent.
+;;   (skip-unless (not noninteractive))
+;;   (let* ((hywiki-directory (make-temp-file "hywiki" t))
+;;          (wiki-page (cdr (hywiki-add-page "WikiPage" )))
+;;      (wiki-referent "WikiReferent")
+;;          (mode-require-final-newline nil))
+;;     (unwind-protect
+;;         (progn
+;;           (find-file wiki-page)
+;;           (insert wiki-referent)
+;;           (save-buffer)
+;;           (goto-char 4)
+
+;;           (should (hact 'kbd-key "C-u C-h hhck{ABC} RET"))
+;;           (hy-test-helpers:consume-input-events)
+
+;;           ;; The buffer contents is changed and now reads
+;;           ;; "Wik{ABC}iReferent" as the next should verifies. The
+;;           ;; second should is the expected behavior. No change in the
+;;           ;; WikiPage buffer.
+;;           (should (string= "Wik{ABC}iReferent" 
(buffer-substring-no-properties (point-min) (point-max))))
+;;           (should (string= wiki-referent (buffer-substring-no-properties 
(point-min) (point-max))))
+
+;;           (should (file-exists-p (hywiki-cache-default-file)))
+;;       (should (equal '(key-series . "{ABC}") (hywiki-get-referent 
wiki-referent)))
+
+;;           ;; Simulate reload from cache
+;;           (hywiki-cache-save)
+;;           (setq hywiki--referent-hasht nil)
+;;           (hywiki-make-referent-hasht)
+
+;;           (should (equal '(key-series . "{ABC}") (hywiki-get-referent 
wiki-referent))))
+;;       (hy-delete-files-and-buffers (list wiki-page 
(hywiki-cache-default-file)))
+;;       (hy-delete-dir-and-buffer hywiki-directory))))
+
+;; Bookmark
+(ert-deftest hywiki-tests--save-referent-bookmark ()
+  "Verify saving and loading a referent bookmark works."
+  (hywiki-tests--referent-test
+   (cons 'bookmark "bmark")
+   (bookmark-set "bmark")
+   (with-simulated-input "bmark RET"
+     (hywiki-add-bookmark wiki-referent))))
+
+(ert-deftest hywiki-tests--save-referent-bookmark-use-menu ()
+  "Verify saving and loading a referent bookmark works using Hyperbole's menu."
+  (skip-unless (not noninteractive))
+  (hywiki-tests--referent-test
+   (cons 'bookmark "bmark")
+   (bookmark-set "bmark")
+   (should (hact 'kbd-key "C-u C-h hhcb bmark RET"))
+   (hy-test-helpers:consume-input-events)))
+
+;; Command
+
+;; (defun hywiki-tests--command (_wikiword)
+;;   "Test command."
+;;   (interactive)
+;;   t)
+
+;; ;; FIXME: Command get the referent as argument which is not useful.
+;; (ert-deftest hywiki-tests--save-referent-command ()
+;;   "Verify saving and loading a referent command works."
+;;   (hywiki-tests--referent-test
+;;    (cons 'command #'hywiki-tests--command)
+;;    (with-simulated-input "hywiki-tests--command RET"
+;;      (hywiki-add-command wiki-referent))))
+
+;; (ert-deftest hywiki-tests--save-referent-command-use-menu ()
+;;   "Verify saving and loading a referent command works using Hyperbole's 
menu.."
+;;   (skip-unless (not noninteractive))
+;;   (hywiki-tests--referent-test
+;;    (cons 'command #'hpath:find)
+;;    (should (hact 'kbd-key "C-u C-h hhcc hpath:find RET"))
+;;    (hy-test-helpers:consume-input-events)))
+
+;; Expanded for debugging
+;; FIXME: There is a race here. It mostly fails but on rerun it can be
+;; made to work.
+;; (ert-deftest hywiki-tests--save-referent-command-use-menu-expanded ()
+;;   "Verify saving and loading a referent bookmark works using Hyperbole's 
menu.."
+;;   (skip-unless (not noninteractive))
+;;   (let* ((hywiki-directory (make-temp-file "hywiki" t))
+;;          (wiki-page (cdr (hywiki-add-page "WikiPage" )))
+;;      (wiki-referent "WikiReferent")
+;;          (mode-require-final-newline nil))
+;;     (unwind-protect
+;;         (progn
+;;           (find-file wiki-page)
+;;           (insert wiki-referent)
+;;           (save-buffer)
+;;           (goto-char 4)
+
+;;           (should (hact 'kbd-key "C-u C-h hhcc hpath:find RET"))
+;;           (hy-test-helpers:consume-input-events)
+
+;;           (should (string= wiki-referent (buffer-substring-no-properties 
(point-min) (point-max))))
+;;           (should (file-exists-p (hywiki-cache-default-file)))
+;;       (should (equal (cons 'command #'hpath:find) (hywiki-get-referent 
wiki-referent)))
+
+;;           ;; Simulate reload from cache
+;;           (hywiki-cache-save)
+;;           (setq hywiki--referent-hasht nil)
+;;           (hywiki-make-referent-hasht)
+
+;;       (should (equal (cons 'command #'hpath:find) (hywiki-get-referent 
wiki-referent))))
+;;       (hy-delete-files-and-buffers (list wiki-page 
(hywiki-cache-default-file)))
+;;       (hy-delete-dir-and-buffer hywiki-directory))))
+
+;; Find
+(ert-deftest hywiki-tests--save-referent-find ()
+  "Verify saving and loading a referent find works."
+  (hywiki-tests--referent-test
+   (cons 'find #'hywiki-word-grep)
+   (hywiki-add-find wiki-referent)))
+
+;; FIXME - Find defaults to search the referent which is not a likely
+;; use case. Should it not prompt user for the search string and
+;; not assume the referent is what you want to search for?
+
+;; FIXME - fails on 28.2 if executed with other test case!?
+;; (ert-deftest hywiki-tests--save-referent-find-use-menu ()
+;;   "Verify saving and loading a referent find works using Hyperbole's menu.."
+;;   (skip-unless (not noninteractive))
+;;   (hywiki-tests--referent-test
+;;    (cons 'find #'hywiki-word-grep)
+;;    (with-mock
+;;     (mock (hywiki-word-grep "WikiReferent") => t)
+;;     (should (hact 'kbd-key "C-u C-h hhcf"))
+;;     (hy-test-helpers:consume-input-events))))
+
+;; Global-button
+(ert-deftest hywiki-tests--save-referent-global-button ()
+  "Verify saving and loading a referent global-button works."
+  (hywiki-tests--referent-test
+   (cons 'global-button "gbtn")
+   (mocklet ((hargs:read-match => "gbtn"))
+     (hywiki-add-global-button wiki-referent))))
+
+(ert-deftest hywiki-tests--save-referent-global-button-use-menu ()
+  "Verify saving and loading a referent global-button works using Hyperbole's 
menu."
+  (skip-unless (not noninteractive))
+  (hywiki-tests--referent-test
+   (cons 'global-button "global")
+
+   (defvar test-buffer)
+   (let* ((test-file (make-temp-file "gbut" nil ".txt"))
+          (test-buffer (find-file-noselect test-file)))
+     (unwind-protect
+         (with-mock
+           (mock (hpath:find-noselect (expand-file-name hbmap:filename 
hbmap:dir-user)) => test-buffer)
+           (stub gbut:label-list => (list "global"))
+           (mock (gbut:act "global") => t)
+           (gbut:ebut-program "global" 'link-to-file test-file)
+           (should (hact 'kbd-key "C-u C-h hhcg global RET"))
+           (hy-test-helpers:consume-input-events))
+       (hy-delete-file-and-buffer test-file)))))
+
+;; HyRolo
+;; FIXME: The search is over the name of the WikiWord which is likely
+;; not what was intended. Test below is for completeness.
+(ert-deftest hywiki-tests--save-referent-hyrolo ()
+  "Verify saving and loading a referent hyrolo works."
+  (hywiki-tests--referent-test
+   (cons 'hyrolo #'hyrolo-fgrep)
+   (hywiki-add-hyrolo wiki-referent)))
+
+;; Info index
+(ert-deftest hywiki-tests--save-referent-info-index ()
+  "Verify saving and loading a referent info index works."
+  (hywiki-tests--referent-test
+   (cons 'info-index "(emacs)files")
+   (save-excursion
+     (with-simulated-input "files RET"
+       (info "emacs")
+       (hywiki-add-info-index wiki-referent)))))
+
+;; FIXME: Does not work properly. Ends prematurely on reading in index
+;; item, at least if starting from scratch, i.e., no *info* buffer
+;; already created.
+;; --
+;; (ert-deftest hywiki-tests--save-referent-info-index-use-menu ()
+;;   "Verify saving and loading a referent info index works using Hyperbole's 
menu."
+;;   (skip-unless (not noninteractive))
+;;   (hywiki-tests--referent-test
+;;    (cons 'info-index "(emacs)files")
+;;    (save-excursion
+;;      (unwind-protect
+;;          (progn
+;;            (should (hact 'kbd-key "C-u C-h hhcim emacs RET i files RET"))
+;;            (hy-test-helpers:consume-input-events))
+;;        (kill-buffer "*info*")))))
+
+;; Info node
+(ert-deftest hywiki-tests--save-referent-info-node ()
+  "Verify saving and loading a referent info node works."
+  (hywiki-tests--referent-test
+   (cons 'info-node "(emacs)")
+   (save-excursion
+     (unwind-protect
+         (with-simulated-input "(emacs) RET"
+           (hywiki-add-info-node wiki-referent))
+       (kill-buffer "*info*")))))
+
+(ert-deftest hywiki-tests--save-referent-info-node-use-menu ()
+  "Verify saving and loading a referent info node works using Hyperbole's 
menu."
+  (skip-unless (not noninteractive))
+  (hywiki-tests--referent-test
+   (cons 'info-node "(emacs)")
+   (save-excursion
+     (unwind-protect
+         (progn
+           (should (hact 'kbd-key "C-u C-h hhcn (emacs) RET"))
+           (hy-test-helpers:consume-input-events))
+       (kill-buffer "*info*")))))
+
+;; Path link
+(ert-deftest hywiki-tests--save-referent-path-link ()
+  "Verify saving and loading a referent path link works."
+  (hywiki-tests--referent-test
+   (cons 'path-link "file:L1")
+   (hywiki-add-path-link wiki-referent "file" 1)))
+
+;; Org id
+(ert-deftest hywiki-tests--save-referent-org-id ()
+  "Verify saving and loading a referent org id works."
+  (hywiki-tests--referent-test
+   (cons 'org-id "ID: generated-org-id")
+   (save-excursion
+     (let ((filea (make-temp-file "hypb" nil ".org")))
+      (unwind-protect
+          (with-current-buffer (find-file filea)
+            (insert "* header\n")
+            (mocklet (((hmouse-choose-link-and-referent-windows) => (list nil 
(get-buffer-window)))
+                      ((org-id-get-create) => "generated-org-id"))
+              (goto-char (point-max))
+             (hywiki-add-org-id wiki-referent)))
+       (hy-delete-file-and-buffer filea))))))
+
+;; FIXME: Org-id links does not seem to work.
+;; FIXME: Add test using Hyperbole's menu.
+
+;; Org roam
+(ert-deftest hywiki-tests--save-referent-org-roam-node ()
+  "Verify saving and loading a referent org roam node works."
+  (hywiki-tests--referent-test
+   (cons 'org-roam-node "node-title")
+   (mocklet (((hypb:require-package 'org-roam) => t)
+            ((org-roam-node-read) => "node")
+            ((org-roam-node-title "node") => "node-title"))
+     (hywiki-add-org-roam-node wiki-referent))))
+
+(ert-deftest hywiki-tests--save-referent-org-roam-node-use-menu ()
+  "Verify saving and loading a referent org roam node works using Hyperbole's 
menu."
+  (skip-unless (not noninteractive))
+  (hywiki-tests--referent-test
+   (cons 'org-roam-node "node-title")
+   (mocklet (((hypb:require-package 'org-roam) => t)
+            ((org-roam-node-read) => "node")
+            ((org-roam-node-title "node") => "node-title")
+             (hywiki-display-org-roam-node => t))
+     (should (hact 'kbd-key "C-u C-h hhcr"))
+     (hy-test-helpers:consume-input-events))))
 
 (ert-deftest hywiki-tests--delete-parenthesised-char ()
   "Verify removing a char between parentheses only removes the char.
@@ -999,10 +1347,154 @@ See gh#rswgnu/hyperbole/669."
   (with-temp-buffer
     (insert "(a)")
     (goto-char 2)
-    (let ((this-command #'delete-char))
-      (with-hywiki-buttonize-hooks
-        (delete-char 1)))
+    (hywiki-tests--command-execute #'delete-char 1)
     (should (string= "()" (buffer-substring-no-properties (point-min) 
(point-max))))))
 
+(ert-deftest hywiki-tests--word-face-at-p ()
+  "Verify `hywiki-word-face-at-p'."
+  (skip-unless (not noninteractive))
+  (hywiki-tests--preserve-hywiki-mode
+    (let* ((hywiki-directory (make-temp-file "hywiki" t))
+           (wiki-page (cdr (hywiki-add-page "WikiWord"))))
+      (with-temp-buffer
+        (hywiki-mode 0)
+        (insert "WikiWor")
+        (hywiki-tests--command-execute #'self-insert-command 1 ?d)
+        (goto-char 4)
+        (should-not (hywiki-word-face-at-p)))
+      (unwind-protect
+          (progn
+            (with-temp-buffer
+              (hywiki-mode 1)
+              (insert "WikiWor")
+             (hywiki-tests--command-execute #'self-insert-command 1 ?d)
+              (goto-char 4)
+              (should (hywiki-word-face-at-p))))
+        (hy-delete-file-and-buffer wiki-page)
+        (hy-delete-dir-and-buffer hywiki-directory)))))
+
+(defun hywiki-tests--verify-hywiki-word (expected)
+  "Verify that `hywiki-word-at' returns t if a wikiword is EXPECTED.
+If EXPECTED is a string also verify that the wikiword matches the
+string."
+  (if (not expected)
+      (should-not (hywiki-word-at))
+    (if (stringp expected)
+        (should (string= expected (hywiki-word-at)))
+      (should (hywiki-word-at)))))
+
+(defun hywiki-tests--run-test-case (test-case)
+  "Run the TEST-CASE from point.
+Each test case consists of cons cells with an operation and the expected
+state of the WikiWord being constructed.  Operations are either a string
+to be inserted, a number of chars to be deleted or a symbol p<number>
+for where to move point.  The expected state is either nil for not a
+wikiword or non-nil for a wikiword.  If equal to a string it is checked
+for match with the wikiword.  Movement of point is relative to point
+when the function is called."
+  (let ((origin (point)))
+    (should (listp test-case))           ; For traceability
+    (dolist (steps test-case)
+      (let ((step (car steps))
+            (vfy (cdr steps)))
+        (cond ((stringp step)
+               (dolist (ch (string-to-list step))
+                 (hywiki-tests--command-execute #'self-insert-command 1 ch)
+                 (save-excursion
+                   (goto-char (1- (point)))
+                   (hywiki-tests--verify-hywiki-word vfy))))
+              ((integerp step)
+               (let ((forward (> step 0)))
+                 (dotimes (_ (abs step))
+                   (if forward
+                       (hywiki-tests--command-execute #'delete-forward-char 1)
+                     (hywiki-tests--command-execute #'backward-delete-char 1))
+                   (hywiki-tests--verify-hywiki-word vfy))))
+              ((and (symbolp step) (string-prefix-p "p" (symbol-name step)))
+               (let* ((pos (string-to-number (substring (symbol-name step) 1)))
+                      (newpos (+ origin (1- pos))))
+                 (when (or (> 0 newpos) (< (point-max) newpos))
+                   (ert-fail (format "New point: '%s' is outside of buffer" 
newpos)))
+                 (goto-char newpos))
+               (hywiki-tests--verify-hywiki-word vfy))
+              (t (ert-fail (format "Unknown step: '%s' in WikiWord 
verification" step))))))))
+
+(defconst hywiki-tests--wikiword-step-check
+  '(
+    (("H") ("i" . "Hi"))
+    (("H") ("iHo" . t) ("#") ("s " . "HiHo#s"))
+    (("H") ("iHo" . t) ("#") ("s" . t) (-1) (-1 . "HiHo"))
+    (("H") ("iHo" . t) ("#") ("s" . t) (-1) (-3 . t) (-1) ("i" . "Hi"))
+    (("H") ("iHo" . t) ("#") ("s " . t) ("n"))
+    (("H") ("iHo" . t) ("#") ("s " . t) (" n"))
+    ;; With delimiters
+    (("(H") ("iHo" . t) ("#") ("s" . "HiHo#s") (" " . "HiHo#s"))
+    (("(H") ("iHo" . t) ("#") ("s" . "HiHo#s") (")" . "HiHo#s)")) ; Delimiter 
part of WikiWord. See below too.
+    (("(H") ("iHo" . t) ("#") ("s" . "HiHo#s") ("-" . "HiHo#s-") ("n" . 
"HiHo#s-n") (")" . "HiHo#s-n)"))
+    ;; Insert and delete between WikiWords
+    (("H") ("iHo" . t) (p3 . t) (" " . "Hi") (p4 . "Ho") (-1 . "HiHo"))
+    (("H") ("iho" . t) (p3 . t) (" " . "Hi") (p4) (-1 . "Hiho"))
+    )
+  "List of test cases for WikiWords.")
+
+(ert-deftest hywiki-tests--wikiword-step-check-verification ()
+  "Run the step check to verify WikiWord is identified under change.
+Performs each operation from the step check and verifies if the
+resulting state at point is a WikiWord or not."
+  (hywiki-tests--preserve-hywiki-mode
+   (let* ((hywiki-directory (make-temp-file "hywiki" t)))
+    (unwind-protect
+        (progn
+          (hywiki-mode 1)
+          (dolist (testcase hywiki-tests--wikiword-step-check)
+            (with-temp-buffer
+              (hywiki-tests--run-test-case testcase))))
+      (hy-delete-dir-and-buffer hywiki-directory)))))
+
+(defconst hywiki-tests--lorem-ipsum "\
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse
+aliquet diam euismod turpis ultricies, et porta sem blandit. Sed vitae."
+  "Bulk text for in the middle of text tests.")
+
+(ert-deftest 
hywiki-tests--wikiword-step-check-verification-with-surrounding-text ()
+  "Run the step check to verify WikiWord is identified under change.
+Insert test in the middle of other text."
+  (hywiki-tests--preserve-hywiki-mode
+   (let* ((hywiki-directory (make-temp-file "hywiki" t)))
+     (unwind-protect
+         (progn
+           (hywiki-mode 1)
+           (with-temp-buffer
+             (insert hywiki-tests--lorem-ipsum)
+             (goto-char (/ (point-max) 2))
+             (let ((pos (point)))
+               (insert " HiHo ")
+               (goto-char (1+ pos))
+               (should (looking-at-p "HiHo ")))
+             (hywiki-tests--run-test-case
+              '((p3 . t)
+                (" " . "Hi")
+                (p1 . t) (p4 . t) (-1 . t))))
+           (with-temp-buffer
+             (insert hywiki-tests--lorem-ipsum)
+             (goto-char (/ (point-max) 2))
+             (let ((pos (point)))
+               (insert " Hiho ")
+               (goto-char (1+ pos))
+               (should (looking-at-p "Hiho ")))
+             (hywiki-tests--run-test-case
+              '((p3 . t)
+                (" " . "Hi")
+                (p1 . t) (p4) (-1 . "Hiho")))))
+       (hy-delete-dir-and-buffer hywiki-directory)))))
+
 (provide 'hywiki-tests)
+
+;; This file can't be byte-compiled without the `el-mock' package
+;; which is not a dependency of Hyperbole.
+;;
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
+
 ;;; hywiki-tests.el ends here

Reply via email to