diff options
| author | Craig Jennings <c@cjennings.net> | 2025-11-08 11:26:22 -0600 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2025-11-08 11:26:22 -0600 |
| commit | 47130cec2000f741bdcf61827c03226fd0301bc0 (patch) | |
| tree | b48ccf3a1969e6d7329c98f9b660e8a4b64fe0c0 /tests | |
| parent | 4309233e2bee1f56a8e41f3b49b1b564f6a09d21 (diff) | |
test: render: add comprehensive ERT tests for display helper functions
Add 34 new tests covering the three helper functions extracted from
wttrin--display-weather:
- test-wttrin--validate-weather-data.el (12 tests)
- test-wttrin--process-weather-content.el (12 tests)
- test-wttrin--add-buffer-instructions.el (10 tests)
Tests follow Normal/Boundary/Error pattern and all pass.
Co-Authored-By: Claude <noreply@anthropic.com>
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test-wttrin--add-buffer-instructions.el | 129 | ||||
| -rw-r--r-- | tests/test-wttrin--process-weather-content.el | 96 | ||||
| -rw-r--r-- | tests/test-wttrin--validate-weather-data.el | 73 |
3 files changed, 298 insertions, 0 deletions
diff --git a/tests/test-wttrin--add-buffer-instructions.el b/tests/test-wttrin--add-buffer-instructions.el new file mode 100644 index 0000000..d42d3a0 --- /dev/null +++ b/tests/test-wttrin--add-buffer-instructions.el @@ -0,0 +1,129 @@ +;;; test-wttrin--add-buffer-instructions.el --- Tests for wttrin--add-buffer-instructions -*- lexical-binding: t; -*- + +;; Copyright (C) 2024 Craig Jennings + +;;; Commentary: +;; Unit tests for wttrin--add-buffer-instructions function. +;; Tests adding user instructions to buffer content. + +;;; Code: + +(require 'ert) +(require 'wttrin) + +;;; Normal Cases + +(ert-deftest test-wttrin--add-buffer-instructions-normal-empty-buffer () + "Test adding instructions to empty buffer." + (with-temp-buffer + (wttrin--add-buffer-instructions) + (should (string= "\n\nPress: [a] for another location [g] to refresh [q] to quit" + (buffer-string))))) + +(ert-deftest test-wttrin--add-buffer-instructions-normal-with-existing-content () + "Test adding instructions to buffer with existing content." + (with-temp-buffer + (insert "Weather: Sunny\nTemperature: 20°C") + (wttrin--add-buffer-instructions) + (should (string= "Weather: Sunny\nTemperature: 20°C\n\nPress: [a] for another location [g] to refresh [q] to quit" + (buffer-string))))) + +(ert-deftest test-wttrin--add-buffer-instructions-normal-preserves-point () + "Test that point is moved to end after adding instructions." + (with-temp-buffer + (insert "Some content") + (goto-char (point-min)) + (wttrin--add-buffer-instructions) + (should (= (point) (point-max))))) + +(ert-deftest test-wttrin--add-buffer-instructions-normal-idempotent-check () + "Test that calling function twice adds instructions twice (not idempotent)." + (with-temp-buffer + (insert "Weather") + (wttrin--add-buffer-instructions) + (let ((first-result (buffer-string))) + (wttrin--add-buffer-instructions) + ;; Should add instructions again, not check if they already exist + (should-not (string= first-result (buffer-string))) + ;; Check for two occurrences of "Press:" by counting matches + (let ((count 0)) + (with-temp-buffer + (insert first-result) + (goto-char (point-min)) + (while (search-forward "Press:" nil t) + (setq count (1+ count)))) + ;; After first call, should have 1 occurrence + (should (= 1 count))) + ;; After second call, check for 2 occurrences + (let ((count 0)) + (save-excursion + (goto-char (point-min)) + (while (search-forward "Press:" nil t) + (setq count (1+ count)))) + (should (= 2 count)))))) + +;;; Boundary Cases + +(ert-deftest test-wttrin--add-buffer-instructions-boundary-point-at-beginning () + "Test adding instructions when point is at beginning of buffer." + (with-temp-buffer + (insert "Weather data here") + (goto-char (point-min)) + (wttrin--add-buffer-instructions) + (should (string-suffix-p "Press: [a] for another location [g] to refresh [q] to quit" + (buffer-string))))) + +(ert-deftest test-wttrin--add-buffer-instructions-boundary-point-in-middle () + "Test adding instructions when point is in middle of buffer." + (with-temp-buffer + (insert "Line 1\nLine 2\nLine 3") + (goto-char (point-min)) + (forward-line 1) + (wttrin--add-buffer-instructions) + (should (string-suffix-p "Press: [a] for another location [g] to refresh [q] to quit" + (buffer-string))))) + +(ert-deftest test-wttrin--add-buffer-instructions-boundary-buffer-with-trailing-newlines () + "Test adding instructions to buffer that already ends with newlines." + (with-temp-buffer + (insert "Weather\n\n\n") + (wttrin--add-buffer-instructions) + (should (string= "Weather\n\n\n\n\nPress: [a] for another location [g] to refresh [q] to quit" + (buffer-string))))) + +(ert-deftest test-wttrin--add-buffer-instructions-boundary-very-large-buffer () + "Test adding instructions to large buffer." + (with-temp-buffer + (insert (make-string 10000 ?x)) + (wttrin--add-buffer-instructions) + (goto-char (point-max)) + (should (looking-back "Press: \\[a\\] for another location \\[g\\] to refresh \\[q\\] to quit" nil)))) + +;;; Error Cases + +(ert-deftest test-wttrin--add-buffer-instructions-error-read-only-buffer () + "Test that function signals error when buffer is read-only." + (with-temp-buffer + (insert "Some content") + (read-only-mode 1) + (should-error (wttrin--add-buffer-instructions) + :type 'buffer-read-only))) + +(ert-deftest test-wttrin--add-buffer-instructions-error-narrowed-buffer () + "Test adding instructions to narrowed buffer adds at narrowed end." + (with-temp-buffer + (insert "Line 1\nLine 2\nLine 3\nLine 4") + (goto-char (point-min)) + (forward-line 1) + (let ((start (point))) + (forward-line 1) + (narrow-to-region start (point)) + (wttrin--add-buffer-instructions) + ;; Instructions should be added at end of narrowed region + (widen) + (goto-char start) + (forward-line 1) + (should (looking-at-p "\n\nPress:"))))) + +(provide 'test-wttrin--add-buffer-instructions) +;;; test-wttrin--add-buffer-instructions.el ends here diff --git a/tests/test-wttrin--process-weather-content.el b/tests/test-wttrin--process-weather-content.el new file mode 100644 index 0000000..a372f4c --- /dev/null +++ b/tests/test-wttrin--process-weather-content.el @@ -0,0 +1,96 @@ +;;; test-wttrin--process-weather-content.el --- Tests for wttrin--process-weather-content -*- lexical-binding: t; -*- + +;; Copyright (C) 2024 Craig Jennings + +;;; Commentary: +;; Unit tests for wttrin--process-weather-content function. +;; Tests ANSI filtering and removal of verbose Location lines. + +;;; Code: + +(require 'ert) +(require 'wttrin) +(require 'xterm-color) + +;;; Normal Cases + +(ert-deftest test-wttrin--process-weather-content-normal-plain-text () + "Test processing plain text without ANSI codes or Location lines." + (let ((input "Weather: Sunny\nTemperature: 20°C")) + (should (string= input (wttrin--process-weather-content input))))) + +(ert-deftest test-wttrin--process-weather-content-normal-removes-location-line () + "Test that Location line with coordinates is removed." + (let ((input "Weather: Sunny\n Location: Paris [48.8566, 2.3522]\nTemperature: 20°C") + (expected "Weather: Sunny\nTemperature: 20°C")) + (should (string= expected (wttrin--process-weather-content input))))) + +(ert-deftest test-wttrin--process-weather-content-normal-multiple-location-lines () + "Test that multiple Location lines are all removed." + (let ((input "Location: Paris [48.8566, 2.3522]\nWeather: Sunny\n Location: Test [0, 0]\nTemp: 20°C") + (expected "Weather: Sunny\nTemp: 20°C")) + (should (string= expected (wttrin--process-weather-content input))))) + +(ert-deftest test-wttrin--process-weather-content-normal-with-ansi-codes () + "Test that ANSI color codes are filtered by xterm-color-filter." + ;; xterm-color-filter should process ANSI codes + ;; We'll test that the function calls xterm-color-filter by checking + ;; that basic ANSI codes are handled (this depends on xterm-color behavior) + (let* ((input-with-ansi "\x1b[31mRed Text\x1b[0m\nNormal Text") + (result (wttrin--process-weather-content input-with-ansi))) + ;; xterm-color-filter adds text properties but returns the text content + (should (string-match-p "Red Text" result)) + (should (string-match-p "Normal Text" result)))) + +;;; Boundary Cases + +(ert-deftest test-wttrin--process-weather-content-boundary-empty-string () + "Test processing empty string." + (should (string= "" (wttrin--process-weather-content "")))) + +(ert-deftest test-wttrin--process-weather-content-boundary-only-location-line () + "Test processing string with only a Location line removes it." + (let ((input " Location: Test [0, 0]\n") + (expected "")) + ;; Input must have newline for delete-region to work correctly + (should (string= expected (wttrin--process-weather-content input))))) + +(ert-deftest test-wttrin--process-weather-content-boundary-location-without-brackets () + "Test that Location line without brackets is not removed (doesn't match pattern)." + (let ((input "Location: Paris\nWeather: Sunny")) + ;; Pattern requires [coordinates], so this line should remain + (should (string-match-p "Location: Paris" (wttrin--process-weather-content input))))) + +(ert-deftest test-wttrin--process-weather-content-boundary-location-case-insensitive () + "Test that 'location' (lowercase) IS removed due to case-insensitive regex." + (let ((input "location: test [0, 0]\nWeather: Sunny")) + ;; re-search-forward uses case-fold-search (defaults to t) + ;; so lowercase 'location' matches 'Location' pattern + (should-not (string-match-p "location:" (wttrin--process-weather-content input))))) + +(ert-deftest test-wttrin--process-weather-content-boundary-whitespace-variations () + "Test Location line with various whitespace patterns." + (let ((input " Location: Test [1, 2] \nWeather: Sunny") + (expected "Weather: Sunny")) + (should (string= expected (wttrin--process-weather-content input))))) + +(ert-deftest test-wttrin--process-weather-content-boundary-preserves-non-location-brackets () + "Test that lines with brackets but not Location pattern are preserved." + (let ((input "Weather: [Sunny] 20°C\nWind: [Strong]")) + (should (string= input (wttrin--process-weather-content input))))) + +;;; Error Cases + +(ert-deftest test-wttrin--process-weather-content-error-handles-malformed-ansi () + "Test that function handles malformed ANSI codes gracefully." + ;; xterm-color-filter should handle this, but we verify no errors occur + (let ((input "\x1b[9999mInvalid ANSI\nNormal text")) + (should (stringp (wttrin--process-weather-content input))))) + +(ert-deftest test-wttrin--process-weather-content-error-very-long-line () + "Test processing very long line without errors." + (let ((long-line (make-string 10000 ?x))) + (should (string= long-line (wttrin--process-weather-content long-line))))) + +(provide 'test-wttrin--process-weather-content) +;;; test-wttrin--process-weather-content.el ends here diff --git a/tests/test-wttrin--validate-weather-data.el b/tests/test-wttrin--validate-weather-data.el new file mode 100644 index 0000000..651fb5c --- /dev/null +++ b/tests/test-wttrin--validate-weather-data.el @@ -0,0 +1,73 @@ +;;; test-wttrin--validate-weather-data.el --- Tests for wttrin--validate-weather-data -*- lexical-binding: t; -*- + +;; Copyright (C) 2024 Craig Jennings + +;;; Commentary: +;; Unit tests for wttrin--validate-weather-data function. +;; Tests validation of weather data strings for errors and nil values. + +;;; Code: + +(require 'ert) +(require 'wttrin) + +;;; Normal Cases + +(ert-deftest test-wttrin--validate-weather-data-normal-valid-weather-string () + "Test that valid weather data string is accepted." + (let ((valid-weather "Weather: 20°C\nCondition: Sunny\nWind: 10 km/h")) + (should (wttrin--validate-weather-data valid-weather)))) + +(ert-deftest test-wttrin--validate-weather-data-normal-multiline-weather () + "Test that multiline weather data is accepted." + (let ((weather "┌─────────────┐\n│ Weather │\n│ 20°C │\n└─────────────┘")) + (should (wttrin--validate-weather-data weather)))) + +(ert-deftest test-wttrin--validate-weather-data-normal-weather-with-unicode () + "Test that weather data with Unicode characters is accepted." + (let ((weather "Temperature: 20°C ☀️\nWind: 15 km/h 💨")) + (should (wttrin--validate-weather-data weather)))) + +;;; Boundary Cases + +(ert-deftest test-wttrin--validate-weather-data-boundary-empty-string () + "Test that empty string is considered valid (though unusual)." + (should (wttrin--validate-weather-data ""))) + +(ert-deftest test-wttrin--validate-weather-data-boundary-whitespace-only () + "Test that whitespace-only string is considered valid." + (should (wttrin--validate-weather-data " \n \t "))) + +(ert-deftest test-wttrin--validate-weather-data-boundary-single-character () + "Test that single character string is valid." + (should (wttrin--validate-weather-data "x"))) + +(ert-deftest test-wttrin--validate-weather-data-boundary-error-lowercase () + "Test that lowercase 'error' is rejected (case-insensitive matching)." + ;; string-match uses case-fold-search which defaults to t in Emacs + (should-not (wttrin--validate-weather-data "error: connection failed"))) + +(ert-deftest test-wttrin--validate-weather-data-boundary-error-in-middle () + "Test that 'ERROR' anywhere in string causes rejection." + (should-not (wttrin--validate-weather-data "Weather: ERROR occurred while fetching"))) + +;;; Error Cases + +(ert-deftest test-wttrin--validate-weather-data-error-nil-string () + "Test that nil string is rejected." + (should-not (wttrin--validate-weather-data nil))) + +(ert-deftest test-wttrin--validate-weather-data-error-uppercase-error () + "Test that string containing 'ERROR' is rejected." + (should-not (wttrin--validate-weather-data "ERROR: Unable to fetch weather"))) + +(ert-deftest test-wttrin--validate-weather-data-error-error-at-start () + "Test that 'ERROR' at start of string causes rejection." + (should-not (wttrin--validate-weather-data "ERROR 404"))) + +(ert-deftest test-wttrin--validate-weather-data-error-error-at-end () + "Test that 'ERROR' at end of string causes rejection." + (should-not (wttrin--validate-weather-data "Network ERROR"))) + +(provide 'test-wttrin--validate-weather-data) +;;; test-wttrin--validate-weather-data.el ends here |
