aboutsummaryrefslogtreecommitdiff
path: root/scripts/theme-studio
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-06-20 03:26:28 -0400
committerCraig Jennings <c@cjennings.net>2026-06-20 03:26:28 -0400
commit1c62e02962d679f2dc7361d9fb6b4d3286e47707 (patch)
tree8fa67384344112b02da01bcf93297c2770c85428 /scripts/theme-studio
parent350ccfa05732066baaa577bf05c98f2ac60dc2d3 (diff)
downloaddotemacs-1c62e02962d679f2dc7361d9fb6b4d3286e47707.tar.gz
dotemacs-1c62e02962d679f2dc7361d9fb6b4d3286e47707.zip
test(theme-studio): cover the face-docs dump helper and syntax map
I added ERT tests for face-docs-dump.el: the pure first-line extractor across Normal/Boundary/Error inputs (multi-line, leading blanks, whitespace collapse, empty, whitespace-only, nil/non-string), and the syntax-category resolution (kw to the keyword-face doc, bg and p to default, the faceless dec absent). run-tests.sh loads the new file alongside the build-theme tests in the same batch.
Diffstat (limited to 'scripts/theme-studio')
-rwxr-xr-xscripts/theme-studio/run-tests.sh16
-rw-r--r--scripts/theme-studio/test-face-docs-dump.el78
2 files changed, 87 insertions, 7 deletions
diff --git a/scripts/theme-studio/run-tests.sh b/scripts/theme-studio/run-tests.sh
index ab9c351ad..6107287d7 100755
--- a/scripts/theme-studio/run-tests.sh
+++ b/scripts/theme-studio/run-tests.sh
@@ -41,18 +41,20 @@ if node --test ./*.mjs >/tmp/ts-node.log 2>&1; then
pass_msg "Node unit tests ($(grep -E '^. tests' /tmp/ts-node.log | grep -oE '[0-9]+' | head -1) tests)"
else fail_msg "Node unit tests"; grep -E 'not ok|AssertionError|Error' /tmp/ts-node.log | sed 's/^/ /' | head -20; fi
-# 3b. ERT tests for build-theme.el (the theme.json -> deftheme emitter). The
-# tests live in the repo's tests/ dir; run them headless. Skip cleanly if no
-# emacs is on PATH (the JS/Python gates still run).
+# 3b. ERT tests for the theme-studio Emacs code: build-theme.el (the theme.json
+# -> deftheme emitter, tests under the repo's tests/ dir) and face-docs-dump.el
+# (the hover-docstring asset generator, test alongside it here). Run them in one
+# headless batch. Skip cleanly if no emacs is on PATH (JS/Python gates still run).
BT_TESTS="$HERE/../../tests/test-build-theme.el"
+FD_TESTS="$HERE/test-face-docs-dump.el"
if command -v emacs >/dev/null 2>&1 && [ -f "$BT_TESTS" ]; then
if emacs --batch --no-site-file --no-site-lisp \
-L "$HERE/../.." -L "$HERE/../../modules" -L "$HERE/../../tests" -L "$HERE/../../themes" \
- -l "$BT_TESTS" -f ert-run-tests-batch-and-exit >/tmp/ts-bt.log 2>&1; then
- pass_msg "build-theme.el ERT tests ($(grep -oE 'Ran [0-9]+' /tmp/ts-bt.log | awk '{print $2}') tests)"
- else fail_msg "build-theme.el ERT tests"; grep -E 'FAILED|Error' /tmp/ts-bt.log | sed 's/^/ /' | head -20; fi
+ -l "$BT_TESTS" -l "$FD_TESTS" -f ert-run-tests-batch-and-exit >/tmp/ts-bt.log 2>&1; then
+ pass_msg "theme-studio ERT tests ($(grep -oE 'Ran [0-9]+' /tmp/ts-bt.log | awk '{print $2}') tests)"
+ else fail_msg "theme-studio ERT tests"; grep -E 'FAILED|Error' /tmp/ts-bt.log | sed 's/^/ /' | head -20; fi
else
- skip_msg "build-theme.el ERT tests (no emacs on PATH)"
+ skip_msg "theme-studio ERT tests (no emacs on PATH)"
fi
# 4. Syntax-check the inlined page script.
diff --git a/scripts/theme-studio/test-face-docs-dump.el b/scripts/theme-studio/test-face-docs-dump.el
new file mode 100644
index 000000000..c77417708
--- /dev/null
+++ b/scripts/theme-studio/test-face-docs-dump.el
@@ -0,0 +1,78 @@
+;;; test-face-docs-dump.el --- ERT tests for face-docs-dump.el -*- lexical-binding: t -*-
+
+;;; Commentary:
+;; Tests the pure docstring-extraction helper (`face-docs--first-line') and the
+;; syntax-category resolution (`face-docs--syntax-map') in face-docs-dump.el, the
+;; asset generator behind theme-studio's element hovers. The faces map is a
+;; thin `face-list' walk over `face-docs--first-line', so testing the helper and
+;; the syntax resolution covers the logic that can actually be wrong.
+;;
+;; Self-locating: loads face-docs-dump.el and build-theme.el (for the
+;; category->face map) from this file's own directory, so the runner only needs
+;; to `-l' this file.
+
+;;; Code:
+
+(require 'ert)
+
+(let ((dir (file-name-directory
+ (or load-file-name buffer-file-name default-directory))))
+ (load (expand-file-name "face-docs-dump.el" dir) nil t)
+ (load (expand-file-name "build-theme.el" dir) nil t))
+
+;;; --- face-docs--first-line ---
+
+(ert-deftest test-face-docs-first-line-normal-multiline ()
+ "Normal: returns the first line of a multi-line docstring."
+ (should (equal (face-docs--first-line "First line.\nSecond line.")
+ "First line.")))
+
+(ert-deftest test-face-docs-first-line-single-line ()
+ "Normal: a single-line docstring returns unchanged."
+ (should (equal (face-docs--first-line "Just one.") "Just one.")))
+
+(ert-deftest test-face-docs-first-line-skips-leading-blank-lines ()
+ "Boundary: leading blank lines are skipped to the first real line, trimmed."
+ (should (equal (face-docs--first-line "\n\n Real line.\nrest")
+ "Real line.")))
+
+(ert-deftest test-face-docs-first-line-collapses-internal-whitespace ()
+ "Boundary: runs of spaces and tabs inside the line collapse to one space."
+ (should (equal (face-docs--first-line "A B\tC") "A B C")))
+
+(ert-deftest test-face-docs-first-line-empty-is-nil ()
+ "Boundary: an empty string yields nil."
+ (should (null (face-docs--first-line ""))))
+
+(ert-deftest test-face-docs-first-line-whitespace-only-is-nil ()
+ "Boundary: a blank/whitespace-only docstring yields nil."
+ (should (null (face-docs--first-line " \n\t ")))
+ (should (null (face-docs--first-line " "))))
+
+(ert-deftest test-face-docs-first-line-non-string-is-nil ()
+ "Error: nil, a number, or the :null sentinel yields nil."
+ (should (null (face-docs--first-line nil)))
+ (should (null (face-docs--first-line 42)))
+ (should (null (face-docs--first-line :null))))
+
+;;; --- face-docs--syntax-map ---
+
+(ert-deftest test-face-docs-syntax-map-resolves-category-to-face-doc ()
+ "Normal: kw resolves to font-lock-keyword-face's first docstring line."
+ (let ((m (face-docs--syntax-map)))
+ (should (stringp (gethash "kw" m)))
+ (should (string-match-p "keyword" (downcase (gethash "kw" m))))))
+
+(ert-deftest test-face-docs-syntax-map-bg-and-p-are-default ()
+ "Boundary: bg and p resolve to the default face's docstring."
+ (let ((m (face-docs--syntax-map))
+ (def (face-docs--first-line (face-documentation 'default))))
+ (should (equal (gethash "bg" m) def))
+ (should (equal (gethash "p" m) def))))
+
+(ert-deftest test-face-docs-syntax-map-omits-faceless-category ()
+ "Boundary: dec (Emacs has no dedicated decorator face) is absent."
+ (should (null (gethash "dec" (face-docs--syntax-map)))))
+
+(provide 'test-face-docs-dump)
+;;; test-face-docs-dump.el ends here