aboutsummaryrefslogtreecommitdiff
path: root/tests/gallery-widgets/test-gallery-widget.el
blob: 166cd5955ad128fee67e322c6d83767037281142 (plain)
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