diff options
| author | Danilo M. <danix@danix.xyz> | 2026-09-17 08:52:14 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-09-17 08:52:14 +0200 |
| commit | 6832a816f9965e273c104f7641c662d6d5d57ced (patch) | |
| tree | 02a25a3cff9b9ca5734ac51d8744e94bec11c7bd | |
| parent | 159fabf66ca1b7e0a745165de0ef56e2631f79b8 (diff) | |
| download | conky-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.md | 6 | ||||
| -rw-r--r-- | lib/weather.lua | 6 | ||||
| -rw-r--r-- | test/test_weather.lua | 15 |
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') |
