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
|
;;; test-wttrin-set-location-from-geolocation.el --- Tests for wttrin-set-location-from-geolocation -*- lexical-binding: t; -*-
;; Copyright (C) 2026 Craig Jennings
;;; Commentary:
;; Unit tests for the interactive `wttrin-set-location-from-geolocation'
;; command. Mocks `wttrin-geolocation-detect' (to invoke the callback
;; synchronously with a chosen value) and `yes-or-no-p' (to simulate
;; user consent). Does not hit the network and does not prompt.
;;; Code:
(require 'ert)
(require 'cl-lib)
(require 'wttrin)
(require 'wttrin-geolocation)
;;; Setup and Teardown
(defvar test-wttrin-set-location-from-geolocation--saved-favorite nil
"Snapshot of `wttrin-favorite-location' restored in teardown.")
(defvar test-wttrin-set-location-from-geolocation--saved-override nil
"Snapshot of `wttrin--favorite-override' restored in teardown.")
(defun test-wttrin-set-location-from-geolocation-setup ()
"Snapshot the configured favorite and runtime override, clearing both."
(setq test-wttrin-set-location-from-geolocation--saved-favorite
wttrin-favorite-location)
(setq test-wttrin-set-location-from-geolocation--saved-override
wttrin--favorite-override)
(setq wttrin-favorite-location nil)
(setq wttrin--favorite-override nil))
(defun test-wttrin-set-location-from-geolocation-teardown ()
"Restore the configured favorite and runtime override to pre-test values."
(setq wttrin-favorite-location
test-wttrin-set-location-from-geolocation--saved-favorite)
(setq wttrin--favorite-override
test-wttrin-set-location-from-geolocation--saved-override))
;;; Helpers
(defmacro test-wttrin-set-location--with-detected (location confirm &rest body)
"Run BODY with `wttrin-geolocation-detect' returning LOCATION and `yes-or-no-p' returning CONFIRM."
(declare (indent 2))
`(cl-letf (((symbol-function 'wttrin-geolocation-detect)
(lambda (callback) (funcall callback ,location)))
((symbol-function 'yes-or-no-p)
(lambda (&rest _) ,confirm)))
,@body))
;;; Normal Cases
(ert-deftest test-wttrin-set-location-from-geolocation-normal-confirm-sets-variable ()
"Successful detection followed by user confirmation sets the favorite."
(test-wttrin-set-location-from-geolocation-setup)
(unwind-protect
(progn
(test-wttrin-set-location--with-detected "Berkeley, California" t
(wttrin-set-location-from-geolocation))
(should (string= "Berkeley, California" (wttrin--favorite-location))))
(test-wttrin-set-location-from-geolocation-teardown)))
(ert-deftest test-wttrin-set-location-from-geolocation-normal-decline-leaves-variable-unchanged ()
"Successful detection followed by user declining leaves the favorite untouched."
(test-wttrin-set-location-from-geolocation-setup)
(setq wttrin-favorite-location "Pre-existing, Place")
(unwind-protect
(progn
(test-wttrin-set-location--with-detected "Berkeley, California" nil
(wttrin-set-location-from-geolocation))
(should (string= "Pre-existing, Place" wttrin-favorite-location)))
(test-wttrin-set-location-from-geolocation-teardown)))
(ert-deftest test-wttrin-set-location-from-geolocation-normal-confirm-refreshes-mode-line ()
"Normal: a confirmed detection refreshes the mode-line so it tracks the new
favorite immediately instead of at the next scheduled fetch."
(test-wttrin-set-location-from-geolocation-setup)
(setq wttrin-favorite-location "Pre-existing, Place")
(unwind-protect
(let ((wttrin-geolocation-enabled t)
(wttrin-mode-line-mode t)
(wttrin--location-history nil)
(fetched nil))
(cl-letf (((symbol-function 'wttrin-geolocation-detect)
(lambda (callback) (funcall callback "Berkeley, California")))
((symbol-function 'yes-or-no-p) (lambda (&rest _) t))
((symbol-function 'message) (lambda (&rest _) nil))
((symbol-function 'wttrin--mode-line-fetch-weather)
(lambda () (setq fetched t)))
((symbol-function 'wttrin--mode-line-set-placeholder)
(lambda () nil)))
(wttrin-set-location-from-geolocation))
(should (string= "Berkeley, California" (wttrin--favorite-location)))
(should fetched))
(test-wttrin-set-location-from-geolocation-teardown)))
;;; Boundary Cases
(ert-deftest test-wttrin-set-location-from-geolocation-boundary-unicode-location ()
"A Unicode location string round-trips into the favorite variable."
(test-wttrin-set-location-from-geolocation-setup)
(unwind-protect
(progn
(test-wttrin-set-location--with-detected "München, Bayern" t
(wttrin-set-location-from-geolocation))
(should (string= "München, Bayern" (wttrin--favorite-location))))
(test-wttrin-set-location-from-geolocation-teardown)))
;;; Error Cases
(ert-deftest test-wttrin-set-location-from-geolocation-error-nil-detection-leaves-variable-unchanged ()
"When detection returns nil, the favorite variable is not modified."
(test-wttrin-set-location-from-geolocation-setup)
(setq wttrin-favorite-location "Pre-existing, Place")
(unwind-protect
(progn
(test-wttrin-set-location--with-detected nil t
(wttrin-set-location-from-geolocation))
(should (string= "Pre-existing, Place" wttrin-favorite-location)))
(test-wttrin-set-location-from-geolocation-teardown)))
(ert-deftest test-wttrin-set-location-from-geolocation-error-nil-detection-does-not-prompt ()
"When detection returns nil, the user is not prompted for confirmation."
(test-wttrin-set-location-from-geolocation-setup)
(unwind-protect
(let ((prompt-called nil))
(cl-letf (((symbol-function 'wttrin-geolocation-detect)
(lambda (callback) (funcall callback nil)))
((symbol-function 'yes-or-no-p)
(lambda (&rest _) (setq prompt-called t) t)))
(wttrin-set-location-from-geolocation))
(should-not prompt-called))
(test-wttrin-set-location-from-geolocation-teardown)))
(ert-deftest test-wttrin-set-location-from-geolocation-error-detection-failure-shows-message ()
"When detection returns nil, the user sees a diagnostic message."
(test-wttrin-set-location-from-geolocation-setup)
(unwind-protect
(let ((messages nil))
(cl-letf (((symbol-function 'wttrin-geolocation-detect)
(lambda (callback) (funcall callback nil)))
((symbol-function 'message)
(lambda (fmt &rest args)
(push (apply #'format fmt args) messages))))
(wttrin-set-location-from-geolocation))
(should (cl-some (lambda (m) (string-match-p "[Cc]ould not detect" m))
messages)))
(test-wttrin-set-location-from-geolocation-teardown)))
;;; Opt-out
(ert-deftest test-wttrin-set-location-from-geolocation-boundary-disabled-no-detect ()
"Boundary: with geolocation disabled, the command neither detects nor sets."
(test-wttrin-set-location-from-geolocation-setup)
(setq wttrin-favorite-location "Pre-existing, Place")
(unwind-protect
(let ((detected nil)
(wttrin-geolocation-enabled nil))
(cl-letf (((symbol-function 'wttrin-geolocation-detect)
(lambda (_cb) (setq detected t)))
((symbol-function 'message) (lambda (&rest _) nil)))
(wttrin-set-location-from-geolocation))
(should-not detected)
(should (string= "Pre-existing, Place" wttrin-favorite-location)))
(test-wttrin-set-location-from-geolocation-teardown)))
;;; Deprecation
(ert-deftest test-wttrin-set-location-from-geolocation-normal-marked-obsolete ()
"Normal: the command is marked obsolete with a steering message.
The favorite-setting behavior is preserved (see the Normal cases above);
this only asserts the obsolescence marker so callers get a deprecation
notice steering them to the picker."
(let ((info (get 'wttrin-set-location-from-geolocation 'byte-obsolete-info)))
(should info)
;; Option 1: a steering string, not an alias to another function.
(should (stringp (nth 0 info)))))
(provide 'test-wttrin-set-location-from-geolocation)
;;; test-wttrin-set-location-from-geolocation.el ends here
|