diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test-wttrin--resolve-favorite-location.el | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/tests/test-wttrin--resolve-favorite-location.el b/tests/test-wttrin--resolve-favorite-location.el new file mode 100644 index 0000000..506c226 --- /dev/null +++ b/tests/test-wttrin--resolve-favorite-location.el @@ -0,0 +1,154 @@ +;;; test-wttrin--resolve-favorite-location.el --- Tests for wttrin--resolve-favorite-location -*- lexical-binding: t; -*- + +;; Copyright (C) 2026 Craig Jennings + +;;; Commentary: + +;; Unit tests for `wttrin--resolve-favorite-location' and its helpers. +;; The resolver maps the three modes of `wttrin-favorite-location' +;; (nil / string / t) onto a returned location string, kicking off an +;; async geolocation lookup the first time t is seen. + +;;; Code: + +(require 'ert) +(require 'cl-lib) +(require 'wttrin) +(require 'testutil-wttrin) + +;; Load wttrin-geolocation up front so cl-letf mocks of +;; `wttrin-geolocation-detect' aren't undone by the resolver's lazy +;; (require 'wttrin-geolocation) — which would otherwise re-evaluate +;; the defun and overwrite the mocked symbol-function. +(require 'wttrin-geolocation + (expand-file-name "wttrin-geolocation.el" + (file-name-directory (locate-library "wttrin")))) + +;;; Helpers + +(defmacro test-wttrin--resolve-with-geolocation-mock (returned-location &rest body) + "Run BODY with `wttrin-geolocation-detect' mocked to call back with +RETURNED-LOCATION synchronously. Resets resolver caches before BODY." + (declare (indent 1)) + `(let ((wttrin--resolved-favorite-location nil) + (wttrin--favorite-location-pending nil)) + (cl-letf (((symbol-function 'wttrin-geolocation-detect) + (lambda (callback) (funcall callback ,returned-location)))) + ,@body))) + +;;; Normal Cases + +(ert-deftest test-wttrin--resolve-favorite-location-normal-nil-returns-nil () + "Disabled mode (nil) resolves to nil." + (let ((wttrin-favorite-location nil) + (wttrin--resolved-favorite-location nil) + (wttrin--favorite-location-pending nil)) + (should-not (wttrin--resolve-favorite-location)))) + +(ert-deftest test-wttrin--resolve-favorite-location-normal-string-returns-itself () + "Explicit string resolves to itself." + (let ((wttrin-favorite-location "Berkeley, CA") + (wttrin--resolved-favorite-location nil) + (wttrin--favorite-location-pending nil)) + (should (string= "Berkeley, CA" (wttrin--resolve-favorite-location))))) + +(ert-deftest test-wttrin--resolve-favorite-location-normal-t-with-cache-returns-cached () + "When t and cache populated, resolver returns cached value without re-fetching." + (let ((wttrin-favorite-location t) + (wttrin--resolved-favorite-location "Cached, Place") + (wttrin--favorite-location-pending nil) + (detect-calls 0)) + (cl-letf (((symbol-function 'wttrin-geolocation-detect) + (lambda (_callback) (cl-incf detect-calls)))) + (should (string= "Cached, Place" (wttrin--resolve-favorite-location))) + (should (= 0 detect-calls))))) + +(ert-deftest test-wttrin--resolve-favorite-location-normal-t-detection-success-caches-result () + "t-mode detect callback populates the resolver cache." + (let ((wttrin-favorite-location t)) + (test-wttrin--resolve-with-geolocation-mock "Detected, City" + (wttrin--resolve-favorite-location) + (should (string= "Detected, City" wttrin--resolved-favorite-location)) + (should-not wttrin--favorite-location-pending)))) + +(ert-deftest test-wttrin--resolve-favorite-location-normal-second-call-returns-cached-from-first () + "After detection completes, the second call returns the cached string." + (let ((wttrin-favorite-location t)) + (test-wttrin--resolve-with-geolocation-mock "Detected, City" + (wttrin--resolve-favorite-location) + (should (string= "Detected, City" (wttrin--resolve-favorite-location)))))) + +;;; Boundary Cases + +(ert-deftest test-wttrin--resolve-favorite-location-boundary-t-without-cache-returns-nil () + "First call with t and empty cache returns nil while detection runs." + (let ((wttrin-favorite-location t) + (wttrin--resolved-favorite-location nil) + (wttrin--favorite-location-pending nil)) + (cl-letf (((symbol-function 'wttrin-geolocation-detect) + (lambda (_callback) + ;; Simulate an async lookup that has NOT called back yet. + (setq wttrin--favorite-location-pending t)))) + (should-not (wttrin--resolve-favorite-location))))) + +(ert-deftest test-wttrin--resolve-favorite-location-boundary-pending-suppresses-duplicate-detect () + "When a lookup is already pending, the resolver does not start another." + (let ((wttrin-favorite-location t) + (wttrin--resolved-favorite-location nil) + (wttrin--favorite-location-pending t) + (detect-calls 0)) + (cl-letf (((symbol-function 'wttrin-geolocation-detect) + (lambda (_callback) (cl-incf detect-calls)))) + (wttrin--resolve-favorite-location) + (should (= 0 detect-calls))))) + +;;; Error Cases + +(ert-deftest test-wttrin--resolve-favorite-location-error-detection-failure-leaves-cache-empty () + "When the detect callback returns nil, the cache stays empty and pending clears." + (let ((wttrin-favorite-location t)) + (test-wttrin--resolve-with-geolocation-mock nil + (wttrin--resolve-favorite-location) + (should-not wttrin--resolved-favorite-location) + (should-not wttrin--favorite-location-pending)))) + +(ert-deftest test-wttrin--resolve-favorite-location-error-detection-failure-allows-retry () + "After a failed detection, a subsequent resolve call kicks off a new lookup." + (let ((wttrin-favorite-location t) + (wttrin--resolved-favorite-location nil) + (wttrin--favorite-location-pending nil) + (detect-calls 0)) + (cl-letf (((symbol-function 'wttrin-geolocation-detect) + (lambda (callback) + (cl-incf detect-calls) + (funcall callback nil)))) + (wttrin--resolve-favorite-location) + (wttrin--resolve-favorite-location) + (should (= 2 detect-calls))))) + +;;; Display Name Helper + +(ert-deftest test-wttrin--favorite-location-display-name-resolved-string-returns-string () + "Display name returns the resolved string when available." + (let ((wttrin-favorite-location "Tokyo, JP") + (wttrin--resolved-favorite-location nil) + (wttrin--favorite-location-pending nil)) + (should (string= "Tokyo, JP" (wttrin--favorite-location-display-name))))) + +(ert-deftest test-wttrin--favorite-location-display-name-t-pending-returns-current-location-label () + "Display name returns \"current location\" when t-mode lookup is pending." + (let ((wttrin-favorite-location t) + (wttrin--resolved-favorite-location nil) + (wttrin--favorite-location-pending t)) + (should (string= "current location" + (wttrin--favorite-location-display-name))))) + +(ert-deftest test-wttrin--favorite-location-display-name-nil-returns-nil () + "Display name returns nil when feature is disabled." + (let ((wttrin-favorite-location nil) + (wttrin--resolved-favorite-location nil) + (wttrin--favorite-location-pending nil)) + (should-not (wttrin--favorite-location-display-name)))) + +(provide 'test-wttrin--resolve-favorite-location) +;;; test-wttrin--resolve-favorite-location.el ends here |
