aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-06-30 01:00:33 -0400
committerCraig Jennings <c@cjennings.net>2026-06-30 01:00:33 -0400
commit6f43a260891deea175eeee83ec602f97a16c974e (patch)
tree858f4fa16ceee6097eb34966aa4cb77035c77864 /tests
parentdb903ea32b10ac2f8d10c7e718d81b68492225cc (diff)
downloaddotemacs-6f43a260891deea175eeee83ec602f97a16c974e.tar.gz
dotemacs-6f43a260891deea175eeee83ec602f97a16c974e.zip
feat(nov-reading): persist font size, add per-palette structural faces
Font size now carries across books and sessions. The +/-/= keys write the text-scale offset to data/nov-reading-text-scale and the offset is restored when a book opens, so a size I set sticks instead of resetting to the base height on every reopen. The = key returns to the base height and persists that reset. Each palette grows from a single bg/fg face into a bundle: :face plus optional :heading and :link. When a palette is active, its heading and link faces remap shr's h1-h6 and link faces buffer-local, so the EPUB hierarchy reads in the palette's accent. The remap stays buffer-local to the nov buffer, so HTML mail and eww keep the theme's normal shr colors.
Diffstat (limited to 'tests')
-rw-r--r--tests/test-nov-reading--palette.el42
-rw-r--r--tests/test-nov-reading--text-scale.el105
2 files changed, 142 insertions, 5 deletions
diff --git a/tests/test-nov-reading--palette.el b/tests/test-nov-reading--palette.el
index 164ec75f4..b34ea2cac 100644
--- a/tests/test-nov-reading--palette.el
+++ b/tests/test-nov-reading--palette.el
@@ -13,28 +13,60 @@
(require 'nov-reading)
(declare-function cj/nov--reading-palette-face "nov-reading" (name))
+(declare-function cj/nov--reading-palette-plist "nov-reading" (name))
(declare-function cj/nov--next-reading-palette "nov-reading" (current names))
(defvar cj/nov-reading-palettes)
+;; Each palette entry is a property list: :face supplies bg/fg, :heading and
+;; :link recolor shr's heading/link faces. Structural keys are optional.
+(defconst test-nov-reading--palettes
+ '(("sepia" :face cj/nov-reading-sepia
+ :heading cj/nov-reading-sepia-heading
+ :link cj/nov-reading-sepia-link)
+ ("dark" :face cj/nov-reading-dark))
+ "Bundle-shaped palette fixture: sepia carries structural faces, dark omits them.")
+
;;; ----------------------- cj/nov--reading-palette-face -----------------------
(ert-deftest test-nov-reading-palette-face-known ()
- "Normal: a known palette name resolves to its face."
- (let ((cj/nov-reading-palettes '(("sepia" . cj/nov-reading-sepia)
- ("dark" . cj/nov-reading-dark))))
+ "Normal: a known palette name resolves to its :face."
+ (let ((cj/nov-reading-palettes test-nov-reading--palettes))
(should (eq (cj/nov--reading-palette-face "sepia") 'cj/nov-reading-sepia))
(should (eq (cj/nov--reading-palette-face "dark") 'cj/nov-reading-dark))))
(ert-deftest test-nov-reading-palette-face-unknown ()
"Error: an unknown name resolves to nil."
- (let ((cj/nov-reading-palettes '(("sepia" . cj/nov-reading-sepia))))
+ (let ((cj/nov-reading-palettes test-nov-reading--palettes))
(should-not (cj/nov--reading-palette-face "nope"))))
(ert-deftest test-nov-reading-palette-face-nil ()
"Boundary: a nil name resolves to nil."
- (let ((cj/nov-reading-palettes '(("sepia" . cj/nov-reading-sepia))))
+ (let ((cj/nov-reading-palettes test-nov-reading--palettes))
(should-not (cj/nov--reading-palette-face nil))))
+;;; ---------------------- cj/nov--reading-palette-plist -----------------------
+
+(ert-deftest test-nov-reading-palette-plist-structural-faces ()
+ "Normal: a palette's :heading and :link faces are retrievable from its plist."
+ (let ((cj/nov-reading-palettes test-nov-reading--palettes))
+ (should (eq (plist-get (cj/nov--reading-palette-plist "sepia") :heading)
+ 'cj/nov-reading-sepia-heading))
+ (should (eq (plist-get (cj/nov--reading-palette-plist "sepia") :link)
+ 'cj/nov-reading-sepia-link))))
+
+(ert-deftest test-nov-reading-palette-plist-omitted-structural ()
+ "Boundary: a palette that omits structural keys yields nil for them."
+ (let ((cj/nov-reading-palettes test-nov-reading--palettes))
+ (should (eq (plist-get (cj/nov--reading-palette-plist "dark") :face)
+ 'cj/nov-reading-dark))
+ (should-not (plist-get (cj/nov--reading-palette-plist "dark") :heading))
+ (should-not (plist-get (cj/nov--reading-palette-plist "dark") :link))))
+
+(ert-deftest test-nov-reading-palette-plist-unknown ()
+ "Error: an unknown palette name yields a nil plist."
+ (let ((cj/nov-reading-palettes test-nov-reading--palettes))
+ (should-not (cj/nov--reading-palette-plist "nope"))))
+
;;; ----------------------- cj/nov--next-reading-palette -----------------------
(ert-deftest test-nov-reading-next-palette-advances ()
diff --git a/tests/test-nov-reading--text-scale.el b/tests/test-nov-reading--text-scale.el
new file mode 100644
index 000000000..8c2fed8b4
--- /dev/null
+++ b/tests/test-nov-reading--text-scale.el
@@ -0,0 +1,105 @@
+;;; test-nov-reading--text-scale.el --- nov reading text-scale persistence tests -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Tests for the persisted global reading text-scale offset: parsing the stored
+;; value (pure) and the save/load round-trip through the data file. The live
+;; text-scale application in the +/-/= commands is exercised live, not here.
+
+;;; Code:
+
+(require 'ert)
+(require 'cl-lib)
+(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
+(require 'nov-reading)
+
+(declare-function cj/nov-reading--parse-text-scale "nov-reading" (s))
+(declare-function cj/nov-reading--load-text-scale "nov-reading" ())
+(declare-function cj/nov-reading--save-text-scale "nov-reading" (amount))
+(defvar cj/nov-reading-text-scale-file)
+
+;;; --------------------- cj/nov-reading--parse-text-scale ----------------------
+
+(ert-deftest test-nov-reading-parse-text-scale-positive ()
+ "Normal: a positive integer string parses to that integer."
+ (should (= (cj/nov-reading--parse-text-scale "3") 3)))
+
+(ert-deftest test-nov-reading-parse-text-scale-negative ()
+ "Normal: a negative integer string parses to that integer."
+ (should (= (cj/nov-reading--parse-text-scale "-2") -2)))
+
+(ert-deftest test-nov-reading-parse-text-scale-trailing-newline ()
+ "Boundary: surrounding whitespace/newline is tolerated."
+ (should (= (cj/nov-reading--parse-text-scale "4\n") 4)))
+
+(ert-deftest test-nov-reading-parse-text-scale-zero ()
+ "Boundary: \"0\" parses to 0."
+ (should (= (cj/nov-reading--parse-text-scale "0") 0)))
+
+(ert-deftest test-nov-reading-parse-text-scale-nil ()
+ "Boundary: nil parses to 0."
+ (should (= (cj/nov-reading--parse-text-scale nil) 0)))
+
+(ert-deftest test-nov-reading-parse-text-scale-empty ()
+ "Boundary: an empty string parses to 0."
+ (should (= (cj/nov-reading--parse-text-scale "") 0)))
+
+(ert-deftest test-nov-reading-parse-text-scale-garbage ()
+ "Error: non-numeric content parses to 0."
+ (should (= (cj/nov-reading--parse-text-scale "garbage") 0)))
+
+(ert-deftest test-nov-reading-parse-text-scale-float-rejected ()
+ "Error: a non-integer numeric string parses to 0 (offsets are integers)."
+ (should (= (cj/nov-reading--parse-text-scale "3.5") 0)))
+
+;;; ------------------ cj/nov-reading--save/load round-trip ---------------------
+
+(ert-deftest test-nov-reading-save-load-roundtrip-positive ()
+ "Normal: a saved positive offset loads back unchanged."
+ (let ((cj/nov-reading-text-scale-file (make-temp-file "nov-scale-")))
+ (unwind-protect
+ (progn
+ (cj/nov-reading--save-text-scale 4)
+ (should (= (cj/nov-reading--load-text-scale) 4)))
+ (delete-file cj/nov-reading-text-scale-file))))
+
+(ert-deftest test-nov-reading-save-load-roundtrip-negative ()
+ "Normal: a saved negative offset loads back unchanged."
+ (let ((cj/nov-reading-text-scale-file (make-temp-file "nov-scale-")))
+ (unwind-protect
+ (progn
+ (cj/nov-reading--save-text-scale -3)
+ (should (= (cj/nov-reading--load-text-scale) -3)))
+ (delete-file cj/nov-reading-text-scale-file))))
+
+(ert-deftest test-nov-reading-save-load-roundtrip-zero ()
+ "Boundary: a saved 0 offset loads back as 0."
+ (let ((cj/nov-reading-text-scale-file (make-temp-file "nov-scale-")))
+ (unwind-protect
+ (progn
+ (cj/nov-reading--save-text-scale 0)
+ (should (= (cj/nov-reading--load-text-scale) 0)))
+ (delete-file cj/nov-reading-text-scale-file))))
+
+(ert-deftest test-nov-reading-load-missing-file-defaults-zero ()
+ "Boundary: loading when no file exists yet returns 0."
+ (let ((cj/nov-reading-text-scale-file
+ (expand-file-name "nov-scale-absent"
+ (make-temp-file "nov-scale-dir-" t))))
+ (unwind-protect
+ (should (= (cj/nov-reading--load-text-scale) 0))
+ (delete-directory (file-name-directory cj/nov-reading-text-scale-file) t))))
+
+(ert-deftest test-nov-reading-save-creates-missing-directory ()
+ "Boundary: save creates the data directory when it is absent."
+ (let* ((dir (make-temp-file "nov-scale-dir-" t))
+ (cj/nov-reading-text-scale-file
+ (expand-file-name "sub/nov-reading-text-scale" dir)))
+ (unwind-protect
+ (progn
+ (cj/nov-reading--save-text-scale 2)
+ (should (file-readable-p cj/nov-reading-text-scale-file))
+ (should (= (cj/nov-reading--load-text-scale) 2)))
+ (delete-directory dir t))))
+
+(provide 'test-nov-reading--text-scale)
+;;; test-nov-reading--text-scale.el ends here