aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-17 09:02:12 +0200
committerDanilo M. <danix@danix.xyz>2026-09-17 09:02:12 +0200
commita9aa2ac3907cb24beae1ada6e58c59e61d16ece6 (patch)
tree997cfae1ab7434411ef260815c6ad6e57d8a3ead
parente6c5c5e6443345e019549d8b41ffa0c19d050c9f (diff)
downloadconky-theme-udt-a9aa2ac3907cb24beae1ada6e58c59e61d16ece6.tar.gz
conky-theme-udt-a9aa2ac3907cb24beae1ada6e58c59e61d16ece6.zip
fix: do not truncate a number in exponent form
The numeric patterns stopped at the 'e', so a temp of 1.8e1 parsed as 1.8 and the card would have drawn 2 degrees instead of 18. Wrong in the worst way available: silently, and still looking like weather. OWM has not been seen to emit exponent form, and sampling several cities near and below zero returned plain decimals throughout, so this was not reachable in practice. Fixed regardless, because two characters in a character class is cheaper than the reasoning required to be sure it stays unreachable, and unlike the NaN case noted in sun_t this one fails invisibly rather than leaving a mark. Tests now cover both a negative temperature, which is ordinary here for half the year, and the exponent form. Reverting the pattern fails them. Found by adversarial probing of the committed parser, not by the plan's own tests, which only exercise the fixture. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
-rw-r--r--docs/superpowers/plans/2026-09-17-weather-widget.md21
-rw-r--r--lib/weather.lua9
-rw-r--r--test/test_weather.lua12
3 files changed, 36 insertions, 6 deletions
diff --git a/docs/superpowers/plans/2026-09-17-weather-widget.md b/docs/superpowers/plans/2026-09-17-weather-widget.md
index c394943..c19b253 100644
--- a/docs/superpowers/plans/2026-09-17-weather-widget.md
+++ b/docs/superpowers/plans/2026-09-17-weather-widget.md
@@ -536,6 +536,18 @@ assert(weather.parse(nil) == nil, 'nil input gives nil')
-- An error body carries cod 401 and no weather. It must not parse as data.
assert(weather.parse('{"cod":401,"message":"Invalid API key."}') == nil,
'an API error body must give nil')
+
+-- Negative temperatures are ordinary here for half the year, and a number in
+-- exponent form must not be truncated at the 'e': reading 1.8e1 as 1.8 would
+-- draw 2 degrees instead of 18, wrong in a way that still looks like weather.
+local cold = weather.parse(
+ '{"weather":[{"id":600,"description":"snow"}],"main":{"temp":-12.5},' ..
+ '"sys":{"sunrise":100,"sunset":200},"name":"X","dt":150}')
+assert(cold and cold.temp == -12.5, 'a negative temp, got ' .. tostring(cold and cold.temp))
+local exp = weather.parse(
+ '{"weather":[{"id":800}],"main":{"temp":1.8e1},' ..
+ '"sys":{"sunrise":100,"sunset":200}}')
+assert(exp and exp.temp == 18, 'exponent form, got ' .. tostring(exp and exp.temp))
```
- [ ] **Step 3: Run test to verify it fails**
@@ -571,10 +583,13 @@ function M.parse(src)
local w = {
id = tonumber(cond:match('"id"%s*:%s*(%-?%d+)')),
description = cond:match('"description"%s*:%s*"([^"]*)"'),
- temp = tonumber(main:match('"temp"%s*:%s*(%-?[%d%.]+)')),
- feels_like = tonumber(main:match('"feels_like"%s*:%s*(%-?[%d%.]+)')),
+ -- The exponent is accepted although OWM has never been seen to emit one:
+ -- a pattern stopping at the 'e' would read 1.8e1 as 1.8 and draw 2 degrees
+ -- instead of 18, silently and plausibly. Cheaper to accept than to detect.
+ temp = tonumber(main:match('"temp"%s*:%s*(%-?[%d%.eE%+%-]+)')),
+ feels_like = tonumber(main:match('"feels_like"%s*:%s*(%-?[%d%.eE%+%-]+)')),
humidity = tonumber(main:match('"humidity"%s*:%s*(%d+)')),
- wind_speed = tonumber(wind:match('"speed"%s*:%s*([%d%.]+)')),
+ wind_speed = tonumber(wind:match('"speed"%s*:%s*([%d%.eE%+%-]+)')),
wind_deg = tonumber(wind:match('"deg"%s*:%s*(%d+)')),
sunrise = tonumber(sys:match('"sunrise"%s*:%s*(%d+)')),
sunset = tonumber(sys:match('"sunset"%s*:%s*(%d+)')),
diff --git a/lib/weather.lua b/lib/weather.lua
index a66d79a..d36bcf5 100644
--- a/lib/weather.lua
+++ b/lib/weather.lua
@@ -165,10 +165,13 @@ function M.parse(src)
local w = {
id = tonumber(cond:match('"id"%s*:%s*(%-?%d+)')),
description = cond:match('"description"%s*:%s*"([^"]*)"'),
- temp = tonumber(main:match('"temp"%s*:%s*(%-?[%d%.]+)')),
- feels_like = tonumber(main:match('"feels_like"%s*:%s*(%-?[%d%.]+)')),
+ -- The exponent is accepted although OWM has never been seen to emit one:
+ -- a pattern stopping at the 'e' would read 1.8e1 as 1.8 and draw 2 degrees
+ -- instead of 18, silently and plausibly. Cheaper to accept than to detect.
+ temp = tonumber(main:match('"temp"%s*:%s*(%-?[%d%.eE%+%-]+)')),
+ feels_like = tonumber(main:match('"feels_like"%s*:%s*(%-?[%d%.eE%+%-]+)')),
humidity = tonumber(main:match('"humidity"%s*:%s*(%d+)')),
- wind_speed = tonumber(wind:match('"speed"%s*:%s*([%d%.]+)')),
+ wind_speed = tonumber(wind:match('"speed"%s*:%s*([%d%.eE%+%-]+)')),
wind_deg = tonumber(wind:match('"deg"%s*:%s*(%d+)')),
sunrise = tonumber(sys:match('"sunrise"%s*:%s*(%d+)')),
sunset = tonumber(sys:match('"sunset"%s*:%s*(%d+)')),
diff --git a/test/test_weather.lua b/test/test_weather.lua
index 4ea953f..739161b 100644
--- a/test/test_weather.lua
+++ b/test/test_weather.lua
@@ -196,4 +196,16 @@ assert(weather.parse(nil) == nil, 'nil input gives nil')
assert(weather.parse('{"cod":401,"message":"Invalid API key."}') == nil,
'an API error body must give nil')
+-- Negative temperatures are ordinary here for half the year, and a number in
+-- exponent form must not be truncated at the 'e': reading 1.8e1 as 1.8 would
+-- draw 2 degrees instead of 18, wrong in a way that still looks like weather.
+local cold = weather.parse(
+ '{"weather":[{"id":600,"description":"snow"}],"main":{"temp":-12.5},' ..
+ '"sys":{"sunrise":100,"sunset":200},"name":"X","dt":150}')
+assert(cold and cold.temp == -12.5, 'a negative temp, got ' .. tostring(cold and cold.temp))
+local exp = weather.parse(
+ '{"weather":[{"id":800}],"main":{"temp":1.8e1},' ..
+ '"sys":{"sunrise":100,"sunset":200}}')
+assert(exp and exp.temp == 18, 'exponent form, got ' .. tostring(exp and exp.temp))
+
print('test_weather: all assertions passed')