summaryrefslogtreecommitdiff
path: root/tests/test-wttrin--fetch-url.el
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test-wttrin--fetch-url.el')
-rw-r--r--tests/test-wttrin--fetch-url.el205
1 files changed, 205 insertions, 0 deletions
diff --git a/tests/test-wttrin--fetch-url.el b/tests/test-wttrin--fetch-url.el
new file mode 100644
index 0000000..bbec115
--- /dev/null
+++ b/tests/test-wttrin--fetch-url.el
@@ -0,0 +1,205 @@
+;;; test-wttrin--fetch-url.el --- Tests for wttrin--fetch-url -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2024 Craig Jennings
+
+;;; Commentary:
+;; Unit tests for wttrin--fetch-url function.
+;; Tests the common async URL fetching logic extracted during refactoring.
+
+;;; Code:
+
+(require 'ert)
+(require 'wttrin)
+
+;;; Normal Cases
+
+(ert-deftest test-wttrin--fetch-url-normal-success-calls-callback-with-data ()
+ "Test that successful fetch calls callback with decoded data."
+ (let ((callback-called nil)
+ (callback-data nil))
+ ;; Mock url-retrieve to simulate successful response
+ (cl-letf (((symbol-function 'url-retrieve)
+ (lambda (url callback)
+ ;; Simulate successful HTTP response
+ (with-temp-buffer
+ (insert "HTTP/1.1 200 OK\r\n")
+ (insert "Content-Type: text/plain\r\n")
+ (insert "\r\n")
+ (insert "Weather data here")
+ (funcall callback nil)))))
+
+ (wttrin--fetch-url
+ "http://example.com/weather"
+ (lambda (data)
+ (setq callback-called t)
+ (setq callback-data data)))
+
+ ;; Verify callback was called with correct data
+ (should callback-called)
+ (should (string= "Weather data here" callback-data)))))
+
+(ert-deftest test-wttrin--fetch-url-normal-utf8-decoding ()
+ "Test that UTF-8 content is properly decoded."
+ (let ((callback-data nil))
+ (cl-letf (((symbol-function 'url-retrieve)
+ (lambda (url callback)
+ (with-temp-buffer
+ (insert "HTTP/1.1 200 OK\r\n\r\n")
+ (insert "Weather: ☀️ Sunny 中文")
+ (funcall callback nil)))))
+
+ (wttrin--fetch-url
+ "http://example.com/weather"
+ (lambda (data)
+ (setq callback-data data)))
+
+ (should (string-match-p "☀️" callback-data))
+ (should (string-match-p "中文" callback-data)))))
+
+(ert-deftest test-wttrin--fetch-url-normal-headers-stripped ()
+ "Test that HTTP headers are correctly stripped from response."
+ (let ((callback-data nil))
+ (cl-letf (((symbol-function 'url-retrieve)
+ (lambda (url callback)
+ (with-temp-buffer
+ (insert "HTTP/1.1 200 OK\r\n")
+ (insert "Content-Type: text/plain\r\n")
+ (insert "Content-Length: 17\r\n")
+ (insert "\r\n")
+ (insert "Weather data here")
+ (funcall callback nil)))))
+
+ (wttrin--fetch-url
+ "http://example.com/weather"
+ (lambda (data)
+ (setq callback-data data)))
+
+ ;; Headers should not be in the data
+ (should-not (string-match-p "HTTP/1.1" callback-data))
+ (should-not (string-match-p "Content-Type" callback-data))
+ (should (string= "Weather data here" callback-data)))))
+
+;;; Boundary Cases
+
+(ert-deftest test-wttrin--fetch-url-boundary-empty-response ()
+ "Test handling of empty response body."
+ (let ((callback-data nil))
+ (cl-letf (((symbol-function 'url-retrieve)
+ (lambda (url callback)
+ (with-temp-buffer
+ (insert "HTTP/1.1 200 OK\r\n\r\n")
+ ;; Empty body
+ (funcall callback nil)))))
+
+ (wttrin--fetch-url
+ "http://example.com/weather"
+ (lambda (data)
+ (setq callback-data data)))
+
+ (should (string= "" callback-data)))))
+
+(ert-deftest test-wttrin--fetch-url-boundary-large-response ()
+ "Test handling of large response body."
+ (let ((callback-data nil)
+ (large-body (make-string 10000 ?x)))
+ (cl-letf (((symbol-function 'url-retrieve)
+ (lambda (url callback)
+ (with-temp-buffer
+ (insert "HTTP/1.1 200 OK\r\n\r\n")
+ (insert large-body)
+ (funcall callback nil)))))
+
+ (wttrin--fetch-url
+ "http://example.com/weather"
+ (lambda (data)
+ (setq callback-data data)))
+
+ (should (= 10000 (length callback-data))))))
+
+(ert-deftest test-wttrin--fetch-url-boundary-unix-line-endings ()
+ "Test handling of Unix-style line endings (LF only)."
+ (let ((callback-data nil))
+ (cl-letf (((symbol-function 'url-retrieve)
+ (lambda (url callback)
+ (with-temp-buffer
+ (insert "HTTP/1.1 200 OK\n")
+ (insert "Content-Type: text/plain\n")
+ (insert "\n")
+ (insert "Weather data")
+ (funcall callback nil)))))
+
+ (wttrin--fetch-url
+ "http://example.com/weather"
+ (lambda (data)
+ (setq callback-data data)))
+
+ (should (string= "Weather data" callback-data)))))
+
+;;; Error Cases
+
+(ert-deftest test-wttrin--fetch-url-error-network-error-calls-callback-with-nil ()
+ "Test that network errors result in callback being called with nil."
+ (let ((callback-called nil)
+ (callback-data 'not-nil))
+ (cl-letf (((symbol-function 'url-retrieve)
+ (lambda (url callback)
+ ;; Simulate network error
+ (with-temp-buffer
+ (funcall callback '(:error (error "Network unreachable")))))))
+
+ (wttrin--fetch-url
+ "http://example.com/weather"
+ (lambda (data)
+ (setq callback-called t)
+ (setq callback-data data)))
+
+ (should callback-called)
+ (should (null callback-data)))))
+
+(ert-deftest test-wttrin--fetch-url-error-processing-error-calls-callback-with-nil ()
+ "Test that processing errors result in callback being called with nil."
+ (let ((callback-called nil)
+ (callback-data 'not-nil))
+ (cl-letf (((symbol-function 'url-retrieve)
+ (lambda (url callback)
+ (with-temp-buffer
+ ;; Simulate a real error by having decode-coding-string fail
+ ;; Make buffer-substring-no-properties return invalid data
+ (cl-letf (((symbol-function 'decode-coding-string)
+ (lambda (string coding-system)
+ (error "Decoding error"))))
+ (insert "HTTP/1.1 200 OK\r\n\r\ndata")
+ (funcall callback nil))))))
+
+ (wttrin--fetch-url
+ "http://example.com/weather"
+ (lambda (data)
+ (setq callback-called t)
+ (setq callback-data data)))
+
+ ;; Should still call callback even on error
+ (should callback-called)
+ ;; But data should be nil due to error
+ (should (null callback-data)))))
+
+(ert-deftest test-wttrin--fetch-url-error-buffer-killed-after-processing ()
+ "Test that response buffer is properly killed after processing."
+ (let ((buffers-before (buffer-list))
+ (callback-called nil))
+ (cl-letf (((symbol-function 'url-retrieve)
+ (lambda (url callback)
+ (with-temp-buffer
+ (insert "HTTP/1.1 200 OK\r\n\r\ndata")
+ (funcall callback nil)))))
+
+ (wttrin--fetch-url
+ "http://example.com/weather"
+ (lambda (data)
+ (setq callback-called t)))
+
+ (should callback-called)
+ ;; Buffer list should be the same (no leaked buffers)
+ (should (= (length buffers-before) (length (buffer-list)))))))
+
+(provide 'test-wttrin--fetch-url)
+;;; test-wttrin--fetch-url.el ends here