aboutsummaryrefslogtreecommitdiff
path: root/tests/test-wttrin-geolocation-sentinel.el
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test-wttrin-geolocation-sentinel.el')
-rw-r--r--tests/test-wttrin-geolocation-sentinel.el212
1 files changed, 212 insertions, 0 deletions
diff --git a/tests/test-wttrin-geolocation-sentinel.el b/tests/test-wttrin-geolocation-sentinel.el
new file mode 100644
index 0000000..169761b
--- /dev/null
+++ b/tests/test-wttrin-geolocation-sentinel.el
@@ -0,0 +1,212 @@
+;;; test-wttrin-geolocation-sentinel.el --- Tests for the picker geolocation sentinel -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2024-2026 Craig Jennings
+
+;;; Commentary:
+;; Unit tests for the "Current location (detect)" picker sentinel: its presence
+;; and position in `wttrin--completion-candidates', the selection routing in
+;; `wttrin--query-selection' (literal vs detect-then-query), and the guard that
+;; keeps the sentinel out of location history.
+
+;;; Code:
+
+(require 'ert)
+(require 'cl-lib)
+(require 'wttrin)
+(require 'wttrin-geolocation)
+(require 'testutil-wttrin)
+
+;;; wttrin--completion-candidates — sentinel presence and position
+
+(ert-deftest test-wttrin-geolocation-sentinel-normal-first-candidate ()
+ "Normal: the sentinel is the first completion candidate."
+ (testutil-wttrin-setup)
+ (unwind-protect
+ (let ((wttrin-favorite-location nil)
+ (wttrin-default-locations '("Honolulu, HI"))
+ (wttrin--location-history '("Tokyo")))
+ (should (equal wttrin--geolocation-sentinel
+ (car (wttrin--completion-candidates)))))
+ (testutil-wttrin-teardown)))
+
+(ert-deftest test-wttrin-geolocation-sentinel-normal-first-even-with-favorite ()
+ "Normal: the sentinel precedes a string favorite in the candidate list."
+ (testutil-wttrin-setup)
+ (unwind-protect
+ (let ((wttrin-favorite-location "New Orleans, LA")
+ (wttrin-default-locations '("Honolulu, HI"))
+ (wttrin--location-history nil))
+ (should (equal (list wttrin--geolocation-sentinel
+ "New Orleans, LA" "Honolulu, HI")
+ (wttrin--completion-candidates))))
+ (testutil-wttrin-teardown)))
+
+;;; wttrin--sort-completions — pin the sentinel first
+
+(ert-deftest test-wttrin-geolocation-sentinel-normal-sort-pins-first ()
+ "Normal: the sentinel is moved to the front, the rest keep their order.
+Sorting completion UIs (vertico, icomplete) call the metadata
+display-sort-function, so this is what keeps the sentinel pinned."
+ (should (equal (list wttrin--geolocation-sentinel "Honolulu, HI" "Tokyo")
+ (wttrin--sort-completions
+ (list "Honolulu, HI" wttrin--geolocation-sentinel "Tokyo")))))
+
+(ert-deftest test-wttrin-geolocation-sentinel-boundary-sort-no-sentinel-unchanged ()
+ "Boundary: a list without the sentinel is returned in its original order."
+ (should (equal '("Honolulu, HI" "Tokyo")
+ (wttrin--sort-completions '("Honolulu, HI" "Tokyo")))))
+
+(ert-deftest test-wttrin-geolocation-sentinel-boundary-sort-empty ()
+ "Boundary: an empty candidate list sorts to empty."
+ (should (null (wttrin--sort-completions nil))))
+
+;;; wttrin--completion-table — metadata + completion
+
+(ert-deftest test-wttrin-geolocation-sentinel-normal-table-metadata-sort-fn ()
+ "Normal: the table advertises the pin-first display-sort-function."
+ (let* ((table (wttrin--completion-table
+ (list wttrin--geolocation-sentinel "Tokyo")))
+ (meta (funcall table "" nil 'metadata)))
+ (should (eq #'wttrin--sort-completions
+ (cdr (assq 'display-sort-function (cdr meta)))))))
+
+(ert-deftest test-wttrin-geolocation-sentinel-normal-table-completes-candidates ()
+ "Normal: the table completes over the candidates it was given."
+ (let ((table (wttrin--completion-table
+ (list wttrin--geolocation-sentinel "Tokyo" "Paris"))))
+ (should (equal (sort (list wttrin--geolocation-sentinel "Tokyo" "Paris")
+ #'string-lessp)
+ (sort (all-completions "" table) #'string-lessp)))))
+
+;;; wttrin interactive entry — delegates to routing
+
+(ert-deftest test-wttrin-geolocation-sentinel-normal-entry-delegates-to-query-selection ()
+ "Normal: the interactive `wttrin' command routes its picker selection
+through `wttrin--query-selection' (smoke test of the entry wrapper)."
+ (testutil-wttrin-setup)
+ (unwind-protect
+ (let ((routed nil))
+ (cl-letf (((symbol-function 'completing-read)
+ (lambda (&rest _) "London, GB"))
+ ((symbol-function 'wttrin--query-selection)
+ (lambda (loc) (setq routed loc))))
+ (call-interactively 'wttrin))
+ (should (equal "London, GB" routed)))
+ (testutil-wttrin-teardown)))
+
+;;; wttrin--query-selection — routing
+
+(ert-deftest test-wttrin-geolocation-sentinel-normal-typed-location-queries-literally ()
+ "Normal: a typed location is passed straight to `wttrin-query'."
+ (testutil-wttrin-setup)
+ (unwind-protect
+ (let ((captured nil))
+ (cl-letf (((symbol-function 'wttrin-query)
+ (lambda (loc &rest _) (setq captured loc))))
+ (wttrin--query-selection "Paris"))
+ (should (equal "Paris" captured)))
+ (testutil-wttrin-teardown)))
+
+(ert-deftest test-wttrin-geolocation-sentinel-normal-routes-to-detect-then-query ()
+ "Normal: selecting the sentinel detects, then queries the resolved city."
+ (testutil-wttrin-setup)
+ (unwind-protect
+ (let ((captured nil))
+ (cl-letf (((symbol-function 'wttrin-geolocation-detect)
+ (lambda (callback) (funcall callback "Austin, TX")))
+ ((symbol-function 'wttrin-query)
+ (lambda (loc &rest _) (setq captured loc)))
+ ((symbol-function 'message) (lambda (&rest _) nil)))
+ (wttrin--query-selection wttrin--geolocation-sentinel))
+ (should (equal "Austin, TX" captured)))
+ (testutil-wttrin-teardown)))
+
+(ert-deftest test-wttrin-geolocation-sentinel-error-detect-failure-no-query ()
+ "Error: a failed detection does not query and does not mutate the favorite."
+ (testutil-wttrin-setup)
+ (unwind-protect
+ (let ((queried nil)
+ (wttrin-favorite-location "New Orleans, LA"))
+ (cl-letf (((symbol-function 'wttrin-geolocation-detect)
+ (lambda (callback) (funcall callback nil)))
+ ((symbol-function 'wttrin-query)
+ (lambda (_loc) (setq queried t)))
+ ((symbol-function 'message) (lambda (&rest _) nil)))
+ (wttrin--query-selection wttrin--geolocation-sentinel))
+ (should-not queried)
+ (should (equal "New Orleans, LA" wttrin-favorite-location)))
+ (testutil-wttrin-teardown)))
+
+;;; sentinel never enters history
+
+(ert-deftest test-wttrin-geolocation-sentinel-boundary-never-added-to-history ()
+ "Boundary: the sentinel string is never recorded in location history."
+ (testutil-wttrin-setup)
+ (unwind-protect
+ (let ((wttrin-default-locations '())
+ (wttrin--location-history nil))
+ (wttrin--add-to-location-history wttrin--geolocation-sentinel)
+ (should (null wttrin--location-history)))
+ (testutil-wttrin-teardown)))
+
+;;; wttrin-geolocation-enabled — opt-out switch
+
+(ert-deftest test-wttrin-geolocation-sentinel-normal-disabled-hides-sentinel ()
+ "Normal: with geolocation disabled, the sentinel is not offered."
+ (testutil-wttrin-setup)
+ (unwind-protect
+ (let ((wttrin-geolocation-enabled nil)
+ (wttrin-favorite-location nil)
+ (wttrin-default-locations '("Honolulu, HI"))
+ (wttrin--location-history '("Tokyo")))
+ (should-not (member wttrin--geolocation-sentinel
+ (wttrin--completion-candidates)))
+ (should (equal '("Honolulu, HI" "Tokyo")
+ (wttrin--completion-candidates))))
+ (testutil-wttrin-teardown)))
+
+(ert-deftest test-wttrin-geolocation-sentinel-boundary-enabled-shows-sentinel ()
+ "Boundary: with geolocation enabled (default), the sentinel is offered first."
+ (testutil-wttrin-setup)
+ (unwind-protect
+ (let ((wttrin-geolocation-enabled t)
+ (wttrin-favorite-location nil)
+ (wttrin-default-locations '("Honolulu, HI"))
+ (wttrin--location-history nil))
+ (should (equal wttrin--geolocation-sentinel
+ (car (wttrin--completion-candidates)))))
+ (testutil-wttrin-teardown)))
+
+(ert-deftest test-wttrin-geolocation-sentinel-error-disabled-detect-then-query-no-detect ()
+ "Error: with geolocation disabled, detect-then-query does not detect or query."
+ (testutil-wttrin-setup)
+ (unwind-protect
+ (let ((detected nil)
+ (queried nil)
+ (wttrin-geolocation-enabled nil))
+ (cl-letf (((symbol-function 'wttrin-geolocation-detect)
+ (lambda (_cb) (setq detected t)))
+ ((symbol-function 'wttrin-query)
+ (lambda (_loc) (setq queried t)))
+ ((symbol-function 'message) (lambda (&rest _) nil)))
+ (wttrin--detect-then-query))
+ (should-not detected)
+ (should-not queried))
+ (testutil-wttrin-teardown)))
+
+(ert-deftest test-wttrin-geolocation-sentinel-boundary-disabled-favorite-no-autodetect ()
+ "Boundary: with geolocation disabled, the t-favorite auto-detect does not fire."
+ (testutil-wttrin-setup)
+ (unwind-protect
+ (let ((detected nil)
+ (wttrin-geolocation-enabled nil)
+ (wttrin--favorite-location-pending nil))
+ (cl-letf (((symbol-function 'wttrin-geolocation-detect)
+ (lambda (_cb) (setq detected t))))
+ (wttrin--start-favorite-location-detect))
+ (should-not detected)
+ (should-not wttrin--favorite-location-pending))
+ (testutil-wttrin-teardown)))
+
+(provide 'test-wttrin-geolocation-sentinel)
+;;; test-wttrin-geolocation-sentinel.el ends here