1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
;;; test-gallery-widget.el --- ERT tests for gallery-widget.el -*- lexical-binding: t; -*-
;;; Commentary:
;; Tests for the svg.el proof-of-concept renderer in docs/prototypes/.
;; gallery-widget.el reads the generated gallery-tokens.el (same source of truth as
;; the web gallery and the waybar CSS) and renders gallery widgets as SVG.
;; These tests exercise the REAL module (loaded by path, not a copy):
;; token resolution, needle-angle math (normal/boundary/error), and the
;; rendered SVG document's structure.
;;
;; Run from repo root:
;; make test-elisp
;; (or emacs --batch -l ert -l tests/gallery-widgets/test-gallery-widget.el \
;; -f ert-run-tests-batch-and-exit)
;;; Code:
(require 'ert)
(require 'cl-lib)
(defvar test-gallery-widget--root
(expand-file-name "../.." (file-name-directory (or load-file-name buffer-file-name)))
"Repo root, derived from this test file's location.")
(load (expand-file-name "docs/prototypes/gallery-widget.el" test-gallery-widget--root))
;;; --- token access ---
(ert-deftest gallery-widget-token-resolves-hex ()
"Known tokens resolve to hex color strings from the generated alist."
(should (string-match-p "\\`#[0-9a-f]\\{6\\}\\'" (gallery-widget-token 'gold)))
(should (string-match-p "\\`#[0-9a-f]\\{6\\}\\'" (gallery-widget-token 'glow-hi)))
(should (string-match-p "\\`#[0-9a-f]\\{6\\}\\'" (gallery-widget-token 'wash))))
(ert-deftest gallery-widget-token-missing-errors ()
"An unknown token name signals an error rather than returning nil."
(should-error (gallery-widget-token 'no-such-token)))
;;; --- needle angle math ---
(ert-deftest gallery-widget-needle-angle-normal ()
"0..100 maps linearly onto -60..+60 degrees."
(should (= (gallery-widget--needle-angle 0) -60.0))
(should (= (gallery-widget--needle-angle 50) 0.0))
(should (= (gallery-widget--needle-angle 100) 60.0)))
(ert-deftest gallery-widget-needle-angle-boundary-clamps ()
"Out-of-range values clamp to the dial's ends instead of overswinging."
(should (= (gallery-widget--needle-angle -5) -60.0))
(should (= (gallery-widget--needle-angle 150) 60.0)))
(ert-deftest gallery-widget-needle-angle-error-non-number ()
"A non-numeric value signals an error."
(should-error (gallery-widget--needle-angle "fifty"))
(should-error (gallery-widget--needle-angle nil)))
;;; --- rendered SVG structure ---
(defun test-gallery-widget--svg-string (value)
"Render the needle gauge at VALUE and return its XML string."
(gallery-widget-svg-string (gallery-widget-needle-gauge value)))
(ert-deftest gallery-widget-gauge-renders-svg-document ()
"The gauge renders to a parseable SVG document."
(let ((xml (test-gallery-widget--svg-string 42)))
(should (string-match-p "\\`<svg" xml))
(should (with-temp-buffer
(insert xml)
(libxml-parse-xml-region (point-min) (point-max))))))
(ert-deftest gallery-widget-gauge-has-expected-parts ()
"Arc, three ticks, needle, hub, and value text are all present."
(let ((xml (test-gallery-widget--svg-string 42)))
;; arc path stroked in the wash token
(should (string-match-p (format "path[^>]*stroke=\"%s\"" (gallery-widget-token 'wash)) xml))
;; exactly three ticks
(should (= 3 (cl-count-if (lambda (_) t)
(split-string xml "class=\"tick\"" t)
:start 1)))
;; needle + hub in the amber tokens
(should (string-match-p (format "class=\"needle\"[^>]*stroke=\"%s\""
(gallery-widget-token 'gold-hi))
xml))
;; hub is a half-dome sitting on the dial's bottom edge, like the web card
(should (string-match-p (format "class=\"hub\"[^>]*fill=\"%s\""
(gallery-widget-token 'gold))
xml))
(should (string-match-p "class=\"hub\"[^>]*d=\"M 44 48 A 4 4 0 0 1 52 48 Z\"" xml))
;; value readout
(should (string-match-p ">42%<" xml))))
(ert-deftest gallery-widget-gauge-has-glow-filter ()
"The needle glow is a real SVG blur filter, not a dropped effect."
(let ((xml (test-gallery-widget--svg-string 42)))
(should (string-match-p "feGaussianBlur" xml))
(should (string-match-p "filter=\"url(#" xml))))
(ert-deftest gallery-widget-gauge-needle-tracks-value ()
"The needle endpoint lands where the angle math says: left at 0, up at 50, right at 100."
;; value 50 -> vertical: x2 = pivot x (48), y2 = 48 - 40 = 8
(let ((xml (test-gallery-widget--svg-string 50)))
(should (string-match-p "class=\"needle\"[^>]*x2=\"48.0+\"" xml))
(should (string-match-p "class=\"needle\"[^>]*y2=\"8.0+\"" xml)))
;; value 100 -> +60 deg: x2 = 48 + 40*sin60 ~ 82.64
(should (string-match-p "x2=\"82.6" (test-gallery-widget--svg-string 100)))
;; value 0 -> -60 deg: x2 = 48 - 40*sin60 ~ 13.36
(should (string-match-p "x2=\"13.3" (test-gallery-widget--svg-string 0))))
(ert-deftest gallery-widget-gauge-integer-percent-in-readout ()
"The readout shows a rounded integer percent, matching the web card."
(should (string-match-p ">67%<" (test-gallery-widget--svg-string 66.6))))
(provide 'test-gallery-widget)
;;; test-gallery-widget.el ends here
|