summaryrefslogtreecommitdiff
path: root/tests/test-wttrin-query.el
blob: 396507b6a2ab5d8cfc99b7ead6a1ddd83867943b (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
;;; test-wttrin-query.el --- Tests for wttrin-query -*- lexical-binding: t; -*-

;; Copyright (C) 2025-2026 Craig Jennings

;;; Commentary:

;; Unit tests for wttrin-query function.
;; Tests the async weather query orchestration: buffer creation,
;; loading state, cache lookup, and display callback.

;;; Code:

(require 'ert)
(require 'wttrin)
(require 'testutil-wttrin)

;;; Setup and Teardown

(defun test-wttrin-query-setup ()
  "Setup for wttrin-query tests."
  (testutil-wttrin-setup)
  (when (get-buffer "*wttr.in*")
    (kill-buffer "*wttr.in*")))

(defun test-wttrin-query-teardown ()
  "Teardown for wttrin-query tests."
  (testutil-wttrin-teardown)
  (when (get-buffer "*wttr.in*")
    (kill-buffer "*wttr.in*")))

;;; Normal Cases

(ert-deftest test-wttrin-query-normal-creates-buffer ()
  "Calling query should create the *wttr.in* buffer."
  (test-wttrin-query-setup)
  (unwind-protect
      (cl-letf (((symbol-function 'wttrin--get-cached-or-fetch)
                 (lambda (_location _callback) nil)))
        (wttrin-query "Paris")
        (should (get-buffer "*wttr.in*")))
    (test-wttrin-query-teardown)))

(ert-deftest test-wttrin-query-normal-shows-loading-message ()
  "Buffer should show a loading message with the location name while fetching."
  (test-wttrin-query-setup)
  (unwind-protect
      (cl-letf (((symbol-function 'wttrin--get-cached-or-fetch)
                 (lambda (_location _callback) nil)))
        (wttrin-query "New Orleans, LA")
        (with-current-buffer "*wttr.in*"
          (let ((contents (buffer-string)))
            (should (string-match-p "Loading" contents))
            (should (string-match-p "New Orleans, LA" contents)))))
    (test-wttrin-query-teardown)))

(ert-deftest test-wttrin-query-normal-buffer-is-read-only-during-loading ()
  "The loading buffer should be read-only to prevent user edits."
  (test-wttrin-query-setup)
  (unwind-protect
      (cl-letf (((symbol-function 'wttrin--get-cached-or-fetch)
                 (lambda (_location _callback) nil)))
        (wttrin-query "Tokyo")
        (with-current-buffer "*wttr.in*"
          (should buffer-read-only)))
    (test-wttrin-query-teardown)))

(ert-deftest test-wttrin-query-normal-fetches-for-correct-location ()
  "Query should request weather for the specified location."
  (test-wttrin-query-setup)
  (unwind-protect
      (let ((fetched-location nil))
        (cl-letf (((symbol-function 'wttrin--get-cached-or-fetch)
                   (lambda (location _callback)
                     (setq fetched-location location))))
          (wttrin-query "Berlin, DE")
          (should (equal fetched-location "Berlin, DE"))))
    (test-wttrin-query-teardown)))

;;; Boundary Cases

(ert-deftest test-wttrin-query-boundary-dead-buffer-callback-is-safe ()
  "If the buffer is killed before the async callback fires, it should not error."
  (test-wttrin-query-setup)
  (unwind-protect
      (let ((saved-callback nil))
        (cl-letf (((symbol-function 'wttrin--get-cached-or-fetch)
                   (lambda (_location callback)
                     (setq saved-callback callback))))
          (wttrin-query "Paris")
          ;; Kill the buffer before callback fires
          (kill-buffer "*wttr.in*")
          ;; Invoke callback — should not error
          (should-not (get-buffer "*wttr.in*"))
          (funcall saved-callback "weather data")
          ;; Buffer should NOT be recreated
          (should-not (get-buffer "*wttr.in*"))))
    (test-wttrin-query-teardown)))

;;; Error Cases

(ert-deftest test-wttrin-query-error-nil-response-shows-error-message ()
  "When fetch returns nil, the user should see an error message, not a crash."
  (test-wttrin-query-setup)
  (unwind-protect
      (let ((saved-callback nil)
            (displayed-message nil))
        (cl-letf (((symbol-function 'wttrin--get-cached-or-fetch)
                   (lambda (_location callback)
                     (setq saved-callback callback)))
                  ((symbol-function 'message)
                   (lambda (fmt &rest args)
                     (setq displayed-message (apply #'format fmt args)))))
          (wttrin-query "BadLocation")
          ;; Simulate fetch returning nil
          (funcall saved-callback nil)
          ;; Should have shown error message (from wttrin--display-weather validation)
          (should displayed-message)
          (should (string-match-p "Cannot retrieve" displayed-message))))
    (test-wttrin-query-teardown)))

(provide 'test-wttrin-query)
;;; test-wttrin-query.el ends here