aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-17 08:52:14 +0200
committerDanilo M. <danix@danix.xyz>2026-09-17 08:52:14 +0200
commit6832a816f9965e273c104f7641c662d6d5d57ced (patch)
tree02a25a3cff9b9ca5734ac51d8744e94bec11c7bd
parent159fabf66ca1b7e0a745165de0ef56e2631f79b8 (diff)
downloadconky-theme-udt-6832a816f9965e273c104f7641c662d6d5d57ced.tar.gz
conky-theme-udt-6832a816f9965e273c104f7641c662d6d5d57ced.zip
fix: guard a nil timestamp in the icon lookup
icon(800, nil, 1500, 1900) compared nil against a number and raised, which in this project is a blank dashboard with no message. The module's own header promises nothing raises, and is_day() already guards the same case, so the inconsistency was the bug. Not reachable from the widget as written: it passes os.time(), and parse() refuses a response without sunrise and sunset, so no caller can currently produce the failing combination. Fixed anyway, because the contract is what future callers will rely on and the fix is one word. The test file also now says why the codepoint VALUES carry no assertion: comparing M.ICON.snow against a literal would only prove the escape was typed twice. Whether E31A draws a snow cloud is what the glyph sheet is for, and mutation testing confirms the assertions cannot see it. Found by code review. The same fix is applied to the plan, so Tasks 2-5 inherit the guarded version. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
-rw-r--r--docs/superpowers/plans/2026-09-17-weather-widget.md6
-rw-r--r--lib/weather.lua6
-rw-r--r--test/test_weather.lua15
3 files changed, 25 insertions, 2 deletions
diff --git a/docs/superpowers/plans/2026-09-17-weather-widget.md b/docs/superpowers/plans/2026-09-17-weather-widget.md
index 853e08c..a7c9ef3 100644
--- a/docs/superpowers/plans/2026-09-17-weather-widget.md
+++ b/docs/superpowers/plans/2026-09-17-weather-widget.md
@@ -174,8 +174,12 @@ M.ICON = {
-- face for the conditions that have both.
function M.icon(id, now, sunrise, sunset)
if type(id) ~= 'number' then return M.ICON.unknown end
+ -- `now` is guarded alongside sunrise and sunset, not just them: comparing a
+ -- nil now against a number raises, and a raise here is a blank dashboard.
+ -- Missing any of the three means the sun is unknown, so the day face is
+ -- drawn, which is what is_day() falls back to as well.
local day = true
- if sunrise and sunset then day = (now >= sunrise and now <= sunset) end
+ if now and sunrise and sunset then day = (now >= sunrise and now <= sunset) end
local function pick(d, n) return day and d or n end
if id <= 232 then return pick(M.ICON.thunder_day, M.ICON.thunder_night)
diff --git a/lib/weather.lua b/lib/weather.lua
index 4eab3ac..0b4b1b7 100644
--- a/lib/weather.lua
+++ b/lib/weather.lua
@@ -41,8 +41,12 @@ M.ICON = {
-- face for the conditions that have both.
function M.icon(id, now, sunrise, sunset)
if type(id) ~= 'number' then return M.ICON.unknown end
+ -- `now` is guarded alongside sunrise and sunset, not just them: comparing a
+ -- nil now against a number raises, and a raise here is a blank dashboard.
+ -- Missing any of the three means the sun is unknown, so the day face is
+ -- drawn, which is what is_day() falls back to as well.
local day = true
- if sunrise and sunset then day = (now >= sunrise and now <= sunset) end
+ if now and sunrise and sunset then day = (now >= sunrise and now <= sunset) end
local function pick(d, n) return day and d or n end
if id <= 232 then return pick(M.ICON.thunder_day, M.ICON.thunder_night)
diff --git a/test/test_weather.lua b/test/test_weather.lua
index 87e787a..f61fa22 100644
--- a/test/test_weather.lua
+++ b/test/test_weather.lua
@@ -62,4 +62,19 @@ assert(icon(804, DAY) == weather.ICON.overcast, 'id 804 is overcast')
assert(icon(999, DAY) == weather.ICON.unknown, 'unknown id gets the error glyph')
assert(weather.icon(nil, DAY, 1500, 1900) == weather.ICON.unknown, 'nil id')
+-- Nothing may raise. A missing timestamp with a known sun, or a known
+-- timestamp with no sun, both have to return a glyph rather than an error,
+-- because an error here is a blank dashboard with no message.
+assert(weather.icon(800, nil, 1500, 1900) == weather.ICON.clear_day,
+ 'a nil now must not raise, and falls back to the day face')
+assert(weather.icon(800, DAY, nil, nil) == weather.ICON.clear_day,
+ 'no sun times must not raise')
+
+-- The codepoint VALUES are deliberately not asserted. A test comparing
+-- M.ICON.snow against a literal would only prove the same escape was typed
+-- twice; whether E31A actually draws a snow cloud in the target font is not
+-- something an assertion can see. That check is the glyph sheet rendered in
+-- the plan's Step 5, and it is how a wrong-but-present codepoint was caught
+-- before this file existed.
+
print('test_weather: all assertions passed')