blob: 408711bc1c4bf2d4a57cb1d0c25d2898539f35f8 (
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
|
;;; test-wttrin--mode-line-helpers.el --- Tests for mode-line helper functions -*- lexical-binding: t; -*-
;; Copyright (C) 2025-2026 Craig Jennings
;;; Commentary:
;; Unit tests for wttrin--make-emoji-icon and wttrin--set-mode-line-string.
;; These helpers extract the common mode-line icon creation and string
;; assignment pattern used by placeholder, error, and display functions.
;;; Code:
(require 'ert)
(require 'wttrin)
(require 'testutil-wttrin)
;;; Setup and Teardown
(defun test-wttrin--mode-line-helpers-setup ()
"Setup for mode-line helper tests."
(testutil-wttrin-setup)
(setq wttrin-mode-line-string nil))
(defun test-wttrin--mode-line-helpers-teardown ()
"Teardown for mode-line helper tests."
(testutil-wttrin-teardown)
(setq wttrin-mode-line-string nil))
;;; --------------------------------------------------------------------------
;;; wttrin--make-emoji-icon
;;; --------------------------------------------------------------------------
;;; Normal Cases
(ert-deftest test-wttrin--make-emoji-icon-normal-without-font ()
"Without emoji font configured, should return the plain emoji string."
(let ((wttrin-mode-line-emoji-font nil))
(should (equal (wttrin--make-emoji-icon "☀") "☀"))))
(ert-deftest test-wttrin--make-emoji-icon-normal-with-font ()
"With emoji font configured, should apply font family face property."
(let ((wttrin-mode-line-emoji-font "Noto Color Emoji"))
(let ((result (wttrin--make-emoji-icon "☀")))
(should (stringp result))
(let ((face (get-text-property 0 'face result)))
(should (equal (plist-get face :family) "Noto Color Emoji"))
(should (equal (plist-get face :height) 1.0))))))
(ert-deftest test-wttrin--make-emoji-icon-normal-with-foreground ()
"Foreground color should be applied when specified."
(let ((wttrin-mode-line-emoji-font nil))
(let ((result (wttrin--make-emoji-icon "☀" "gray60")))
(let ((face (get-text-property 0 'face result)))
(should (equal (plist-get face :foreground) "gray60"))))))
(ert-deftest test-wttrin--make-emoji-icon-normal-with-font-and-foreground ()
"Both font and foreground should be applied together."
(let ((wttrin-mode-line-emoji-font "Noto Color Emoji"))
(let ((result (wttrin--make-emoji-icon "⏳" "gray60")))
(let ((face (get-text-property 0 'face result)))
(should (equal (plist-get face :family) "Noto Color Emoji"))
(should (equal (plist-get face :foreground) "gray60"))))))
;;; Boundary Cases
(ert-deftest test-wttrin--make-emoji-icon-boundary-nil-foreground-no-color ()
"Nil foreground should not add any :foreground property when no font."
(let ((wttrin-mode-line-emoji-font nil))
(let ((result (wttrin--make-emoji-icon "☀" nil)))
;; Without font or foreground, should be plain string
(should (equal result "☀")))))
(ert-deftest test-wttrin--make-emoji-icon-boundary-nil-foreground-with-font ()
"With font set and nil foreground, the face plist must omit :foreground entirely.
A literal `:foreground nil' entry triggers \"Invalid face attribute\" warnings on
every redisplay. `plist-member' (not `plist-get') is required: `plist-get' can't
distinguish a missing key from a present key bound to nil."
(let ((wttrin-mode-line-emoji-font "Noto Color Emoji"))
(let* ((result (wttrin--make-emoji-icon "☀" nil))
(face (get-text-property 0 'face result)))
(should (equal (plist-get face :family) "Noto Color Emoji"))
(should-not (plist-member face :foreground)))))
;;; --------------------------------------------------------------------------
;;; wttrin--set-mode-line-string
;;; --------------------------------------------------------------------------
;;; Normal Cases
(ert-deftest test-wttrin--set-mode-line-string-normal-sets-string ()
"Should set wttrin-mode-line-string to a non-nil propertized value."
(test-wttrin--mode-line-helpers-setup)
(unwind-protect
(progn
(wttrin--set-mode-line-string "X" "tooltip text")
(should wttrin-mode-line-string))
(test-wttrin--mode-line-helpers-teardown)))
(ert-deftest test-wttrin--set-mode-line-string-normal-includes-icon ()
"The icon text should appear in the mode-line string."
(test-wttrin--mode-line-helpers-setup)
(unwind-protect
(progn
(wttrin--set-mode-line-string "⏳" "tip")
(should (string-match-p "⏳" (substring-no-properties wttrin-mode-line-string))))
(test-wttrin--mode-line-helpers-teardown)))
(ert-deftest test-wttrin--set-mode-line-string-normal-has-tooltip ()
"The help-echo property should contain the tooltip text."
(test-wttrin--mode-line-helpers-setup)
(unwind-protect
(progn
(wttrin--set-mode-line-string "X" "Weather is sunny")
(should (equal (get-text-property 0 'help-echo wttrin-mode-line-string)
"Weather is sunny")))
(test-wttrin--mode-line-helpers-teardown)))
(ert-deftest test-wttrin--set-mode-line-string-normal-has-keymap ()
"The local-map property should be the mode-line keymap."
(test-wttrin--mode-line-helpers-setup)
(unwind-protect
(progn
(wttrin--set-mode-line-string "X" "tip")
(should (eq (get-text-property 0 'local-map wttrin-mode-line-string)
wttrin--mode-line-map)))
(test-wttrin--mode-line-helpers-teardown)))
(ert-deftest test-wttrin--set-mode-line-string-normal-has-mouse-face ()
"The mouse-face property should highlight on hover."
(test-wttrin--mode-line-helpers-setup)
(unwind-protect
(progn
(wttrin--set-mode-line-string "X" "tip")
(should (equal (get-text-property 0 'mouse-face wttrin-mode-line-string)
'mode-line-highlight)))
(test-wttrin--mode-line-helpers-teardown)))
;;; --------------------------------------------------------------------------
;;; wttrin--mode-line-stale-p
;;; --------------------------------------------------------------------------
;;; Normal Cases
(ert-deftest test-wttrin--mode-line-stale-p-normal-fresh-cache-returns-nil ()
"Cache entry well within the refresh window is not stale."
(let ((wttrin-mode-line-refresh-interval 100))
(let ((entry (cons (- (float-time) 50) "data")))
(should-not (wttrin--mode-line-stale-p entry)))))
(ert-deftest test-wttrin--mode-line-stale-p-normal-stale-cache-returns-t ()
"Cache entry older than 2× refresh-interval is stale."
(let ((wttrin-mode-line-refresh-interval 100))
(let ((entry (cons (- (float-time) 500) "data")))
(should (wttrin--mode-line-stale-p entry)))))
;;; Boundary Cases
(ert-deftest test-wttrin--mode-line-stale-p-boundary-just-below-threshold ()
"Age 1s below the 2× threshold is not stale (strict >)."
(let ((wttrin-mode-line-refresh-interval 100))
(let ((entry (cons (- (float-time) 199) "data")))
(should-not (wttrin--mode-line-stale-p entry)))))
(ert-deftest test-wttrin--mode-line-stale-p-boundary-just-past-threshold ()
"Age 1s past the 2× threshold is stale."
(let ((wttrin-mode-line-refresh-interval 100))
(let ((entry (cons (- (float-time) 201) "data")))
(should (wttrin--mode-line-stale-p entry)))))
(ert-deftest test-wttrin--mode-line-stale-p-boundary-nil-cache-returns-nil ()
"Nil cache-entry returns nil with no signal."
(should-not (wttrin--mode-line-stale-p nil)))
;;; --------------------------------------------------------------------------
;;; wttrin--mode-line-extract-emoji
;;; --------------------------------------------------------------------------
;;; Normal Cases
(ert-deftest test-wttrin--mode-line-extract-emoji-normal-typical-response ()
"Typical response \"Location: emoji rest\" returns the emoji."
(should (equal (wttrin--mode-line-extract-emoji "Paris: ☀ +72°F Clear")
"☀")))
(ert-deftest test-wttrin--mode-line-extract-emoji-normal-different-emoji ()
"Different emoji is returned correctly (no hardcoded match)."
(should (equal (wttrin--mode-line-extract-emoji "London: ⛅ +15°C Cloudy")
"⛅")))
;;; Boundary Cases
(ert-deftest test-wttrin--mode-line-extract-emoji-boundary-no-whitespace-after-colon ()
"Colon with no whitespace before the emoji still extracts."
(should (equal (wttrin--mode-line-extract-emoji "X:Y rest")
"Y")))
(ert-deftest test-wttrin--mode-line-extract-emoji-boundary-multiple-whitespace ()
"Multiple whitespace chars between colon and emoji are skipped."
(should (equal (wttrin--mode-line-extract-emoji "X: Z rest")
"Z")))
;;; Error Cases
(ert-deftest test-wttrin--mode-line-extract-emoji-error-no-colon ()
"String with no colon returns the placeholder \"?\"."
(should (equal (wttrin--mode-line-extract-emoji "no colon here")
"?")))
(ert-deftest test-wttrin--mode-line-extract-emoji-error-empty-string ()
"Empty string returns the placeholder \"?\"."
(should (equal (wttrin--mode-line-extract-emoji "")
"?")))
(provide 'test-wttrin--mode-line-helpers)
;;; test-wttrin--mode-line-helpers.el ends here
|