Files
wadamesh/deploy/apps/sdktest/1.2/sdktest.lua
T
Kaj SchittecatandClaude Opus 5 25c76a3798 i18n: the audit could not see strings reached through a table, and one was missing
pisti87 asked whether the obsolete entries in the language files will be removed
(#262). Measuring it first was the right move, because the tool that would have
driven that cleanup was wrong.

source_keys() only ever matched TR("literal"). Strings reached indirectly, as in
TR(kSettingsCats[c].label), were invisible to it, so every settings-category name
looked unreferenced: About, Backups, Language, MQTT bridge, App permissions and
the rest. Anyone pruning the .lang files on that output would have deleted live
translations for some of the most visible labels in the UI.

The audit now also pulls literals out of any table whose name appears inside a
TR(...) subscript. Deliberately greedy: over-collecting keeps a translation alive,
under-collecting deletes one.

That immediately found a real gap it had been hiding. "App permissions", the
settings category added with the permissions page, was missing from all 13
languages and the old audit reported everything as covered. Added, builtin
regenerated, published as language v15.

Also adds --obsolete, the reverse check pisti87 actually needs: rows in each .lang
file that no TR() key matches. It reports and never deletes, and says plainly that
these are candidates to check rather than a delete list, for the reason above.
Numbers now: 950 keys reachable, hu.lang carries 1044 rows, 94 unreferenced. The
earlier figure was 119, so 25 of those were the false positives just fixed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 19:19:21 +02:00

116 lines
4.5 KiB
Lua

-- SDK self-test. Exercises the extended SDK so the results can be read off the
-- screen instead of inferred from a build log. Published to the store as a
-- developer/bench tool.
--
-- 1.2 adds wada.crypto (checked against published RFC vectors, so a PASS here is
-- real evidence and not just "it returned something"), wada.mesh.channels, and
-- wada.mesh.send_dm.
local ui, sys, store, timer = wada.ui, wada.sys, wada.store, wada.timer
local C = ui.colors
local app = {}
local rows, keyline, sendline, dmline, msgline = {}, nil, nil, nil, nil
local W = 300
local function row(y, text, color)
local l = ui.label(text, 6, y, 12, color or C.text)
l:width(W - 12)
rows[#rows + 1] = l
return l
end
local function yn(v) return v and "yes" or "NO" end
function app.on_open(w, h)
W = w or 300
ui.scroll(true)
local y = 4
local c = sys.caps()
row(y, "caps: sdk_ext=" .. yn(c.sdk_ext) .. " kbd=" .. yn(c.keyboard) ..
" touch=" .. yn(c.touch) .. " sd=" .. yn(c.sd), C.accent); y = y + 16
-- crypto: published test vectors, so this is checkable rather than merely alive
if wada.crypto then
local hex = wada.crypto.hex
local k20 = string.rep(string.char(0x0b), 20)
local checks = {
{ "sha256('abc')", hex(wada.crypto.sha256("abc")),
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" },
{ "sha1('abc')", hex(wada.crypto.sha1("abc")),
"a9993e364706816aba3e25717850c26c9cd0d89d" },
{ "hmac_sha1 RFC2202#1", hex(wada.crypto.hmac_sha1(k20, "Hi There")),
"b617318655057264e28bc0b6fb378c8ef146be00" },
{ "hmac_sha256 RFC4231#1", hex(wada.crypto.hmac_sha256(k20, "Hi There")),
"b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7" },
}
local allok = true
for _, t in ipairs(checks) do
local ok = (t[2] == t[3])
if not ok then allok = false end
row(y, "crypto " .. t[1] .. ": " .. (ok and "PASS" or ("FAIL got " .. tostring(t[2]):sub(1, 16))),
ok and C.good or C.bad); y = y + 16
end
-- The point of having it in C: this loop would blow the instruction budget in Lua.
local t0 = sys.millis()
for _ = 1, 200 do wada.crypto.hmac_sha1(k20, "Hi There") end
row(y, string.format("crypto: 200 x hmac_sha1 in %d ms%s", sys.millis() - t0,
allok and "" or " (VECTORS FAILED)"), allok and C.good or C.bad); y = y + 20
else
row(y, "wada.crypto: MISSING", C.bad); y = y + 20
end
-- channel discovery
local chans = wada.mesh.channels and wada.mesh.channels() or nil
if chans then
local names = table.concat(chans, ", ")
row(y, "channels(): " .. #chans .. " " .. names:sub(1, 60), C.text); y = y + 20
else
row(y, "wada.mesh.channels: MISSING", C.bad); y = y + 20
end
if not c.sdk_ext then
row(y, "extended SDK is OFF on this board - stopping here.", C.sub)
return
end
-- contacts, so send_dm has a target to name
local cts = wada.mesh.contacts()
local first = cts[1] and cts[1].name or nil
row(y, "contacts: " .. #cts .. (first and (" first=" .. first) or ""), C.text); y = y + 20
sendline = row(y, "mesh.send: not tried yet", C.sub); y = y + 18
dmline = row(y, "mesh.send_dm: not tried yet", C.sub); y = y + 18
msgline = row(y, "on_message: waiting (needs the read permissions)", C.sub); y = y + 22
ui.button("Send to Public", 6, y, 120, 30, function()
local ok, err = wada.mesh.send("Public", "wadamesh SDK self-test")
sendline:set("mesh.send: " .. tostring(ok) .. " " .. tostring(err))
sendline:color(ok and C.good or C.bad)
end)
ui.button("DM first contact", 132, y, 130, 30, function()
if not first then dmline:set("mesh.send_dm: no contacts to target"); dmline:color(C.bad); return end
local ok, err = wada.mesh.send_dm(first, "wadamesh SDK self-test (DM)")
dmline:set("mesh.send_dm -> " .. first .. ": " .. tostring(ok) .. " " .. tostring(err))
dmline:color(ok and C.good or C.bad)
end)
y = y + 34
ui.button("Beep", 6, y, 70, 30, function() sys.beep() end)
end
function app.on_input(ev)
if ev.type == "key" and keyline then
keyline:set("keys: got '" .. tostring(ev.key) .. "'")
keyline:color(C.good)
end
end
-- Proves the kind field and that DMs/rooms reach an app at all, not just channels.
function app.on_message(m)
if not msgline then return end
msgline:set("on_message: kind=" .. tostring(m.kind) .. " from=" .. tostring(m.sender) ..
" ch=" .. tostring(m.channel) .. " text=" .. tostring(m.text):sub(1, 20))
msgline:color(C.good)
end
return app