From b74b98f177d92d50ddbede900ba41212e07c5f63 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sat, 21 Feb 2026 07:06:50 -0600 Subject: feat: unified cache and staleness handling for mode-line and buffer Replace TTL-based cache invalidation with proactive scheduled refresh. Both mode-line and buffer systems now follow: timer refreshes cache, display reads from cache, staleness indicated when data is old. Phase 1 - Mode-line cache formalization + staleness display: - Replace wttrin--mode-line-tooltip-data with wttrin--mode-line-cache as (timestamp . data) cons cell matching buffer cache pattern - Add wttrin--format-age helper for human-readable age strings - Rewrite wttrin--mode-line-update-display to take no arguments, read from cache, compute staleness (age > 2x refresh interval), dim emoji gray when stale, show staleness info in tooltip - Rewrite wttrin--mode-line-fetch-weather to write cache on success, show stale display on failure with cache, error placeholder without - Add wttrin--mode-line-update-placeholder-error for first-launch failure Phase 2 - Remove TTL, add proactive buffer refresh: - Rename wttrin-cache-ttl to wttrin-refresh-interval (default 3600s) with define-obsolete-variable-alias for backward compatibility - Change wttrin-mode-line-refresh-interval default from 900 to 3600 - Remove TTL check from wttrin--get-cached-or-fetch; serve cached data regardless of age, background timer keeps it fresh - Add buffer refresh timer (wttrin--buffer-cache-refresh) Phase 3 - Buffer staleness display: - Add wttrin--format-staleness-header for buffer age display - Insert staleness line in wttrin--display-weather before instructions Phase 4 - Cleanup: - Remove all references to wttrin--mode-line-tooltip-data - Update README.org cache settings and mode-line documentation - Update tests for new API (198 tests across 21 files, all passing) --- tests/test-wttrin--format-staleness-header.el | 80 +++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 tests/test-wttrin--format-staleness-header.el (limited to 'tests/test-wttrin--format-staleness-header.el') diff --git a/tests/test-wttrin--format-staleness-header.el b/tests/test-wttrin--format-staleness-header.el new file mode 100644 index 0000000..ef8882f --- /dev/null +++ b/tests/test-wttrin--format-staleness-header.el @@ -0,0 +1,80 @@ +;;; test-wttrin--format-staleness-header.el --- Tests for staleness header -*- lexical-binding: t; -*- + +;; Copyright (C) 2025 Craig Jennings + +;;; Commentary: + +;; Unit tests for wttrin--format-staleness-header function. +;; Tests that buffer staleness information is formatted correctly. + +;;; Code: + +(require 'ert) +(require 'wttrin) +(require 'testutil-wttrin) + +;;; Setup and Teardown + +(defun test-wttrin--format-staleness-header-setup () + "Setup for staleness header tests." + (testutil-wttrin-setup)) + +(defun test-wttrin--format-staleness-header-teardown () + "Teardown for staleness header tests." + (testutil-wttrin-teardown)) + +;;; Normal Cases + +(ert-deftest test-wttrin--format-staleness-header-normal-returns-formatted-string () + "Staleness header includes time and age when cache exists." + (test-wttrin--format-staleness-header-setup) + (unwind-protect + (let ((now 1000000.0)) + (cl-letf (((symbol-function 'float-time) (lambda () now))) + ;; Add data cached 5 minutes ago + (testutil-wttrin-add-to-cache "Paris" "weather data" 300) + (let ((header (wttrin--format-staleness-header "Paris"))) + (should header) + (should (string-match-p "Last updated:" header)) + (should (string-match-p "5 minutes ago" header))))) + (test-wttrin--format-staleness-header-teardown))) + +(ert-deftest test-wttrin--format-staleness-header-normal-just-now () + "Staleness header shows 'just now' for very recent data." + (test-wttrin--format-staleness-header-setup) + (unwind-protect + (let ((now 1000000.0)) + (cl-letf (((symbol-function 'float-time) (lambda () now))) + (testutil-wttrin-add-to-cache "Paris" "weather data" 10) + (let ((header (wttrin--format-staleness-header "Paris"))) + (should (string-match-p "just now" header))))) + (test-wttrin--format-staleness-header-teardown))) + +;;; Boundary Cases + +(ert-deftest test-wttrin--format-staleness-header-boundary-no-cache-returns-nil () + "Returns nil when no cache entry exists for location." + (test-wttrin--format-staleness-header-setup) + (unwind-protect + (should-not (wttrin--format-staleness-header "Unknown City")) + (test-wttrin--format-staleness-header-teardown))) + +(ert-deftest test-wttrin--format-staleness-header-boundary-different-unit-system () + "Cache lookup respects current unit system setting." + (test-wttrin--format-staleness-header-setup) + (unwind-protect + (let ((now 1000000.0)) + (cl-letf (((symbol-function 'float-time) (lambda () now))) + ;; Add data under metric unit system + (let ((wttrin-unit-system "m")) + (testutil-wttrin-add-to-cache "Paris" "metric data" 300)) + ;; Query under imperial unit system — should find nothing + (let ((wttrin-unit-system "u")) + (should-not (wttrin--format-staleness-header "Paris"))) + ;; Query under metric — should find it + (let ((wttrin-unit-system "m")) + (should (wttrin--format-staleness-header "Paris"))))) + (test-wttrin--format-staleness-header-teardown))) + +(provide 'test-wttrin--format-staleness-header) +;;; test-wttrin--format-staleness-header.el ends here -- cgit v1.2.3