mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-27 06:02:51 +08:00
141 lines
4.7 KiB
Lua
141 lines
4.7 KiB
Lua
-- util_json_test.lua — JSON 编解码保真与错误上报单元测试
|
|
-- 用法:lua5.1 tests/util_json_test.lua
|
|
--
|
|
-- 覆盖审计表 M13(null / 空对象往返被改写)与 M14(json_decode 永不返回错误串)。
|
|
|
|
package.path = "./root/usr/share/?.lua;" .. package.path
|
|
|
|
local util = require("substore.util")
|
|
|
|
local passed, failed = 0, 0
|
|
local function check(name, cond)
|
|
if cond then
|
|
passed = passed + 1
|
|
else
|
|
failed = failed + 1
|
|
print("FAIL: " .. name)
|
|
end
|
|
end
|
|
|
|
local function rt(s) -- 解码再编码,返回编码结果与错误
|
|
local v, err = util.json_decode(s)
|
|
if err then return nil, err end
|
|
return util.json_encode(v)
|
|
end
|
|
|
|
-- ---------- M14:错误必须上报 ----------
|
|
do
|
|
local _, err = util.json_decode("{")
|
|
check("M14 unterminated object reports error", type(err) == "string")
|
|
|
|
local _, err2 = util.json_decode("[1,2")
|
|
check("M14 unterminated array reports error", type(err2) == "string")
|
|
|
|
local _, err3 = util.json_decode('{"a":}')
|
|
check("M14 missing value reports error", type(err3) == "string")
|
|
|
|
local _, err4 = util.json_decode("[1,]")
|
|
check("M14 trailing comma in array rejected", type(err4) == "string")
|
|
|
|
local _, err5 = util.json_decode('{"a":1,}')
|
|
check("M14 trailing comma in object rejected", type(err5) == "string")
|
|
|
|
-- 合法输入不得被误判
|
|
local v, e = util.json_decode('{"a":1}')
|
|
check("M14 valid object still parses", type(v) == "table" and v.a == 1 and e == nil)
|
|
|
|
local arr, e2 = util.json_decode("[1,2,3]")
|
|
check("M14 valid array still parses", type(arr) == "table" and #arr == 3 and e2 == nil)
|
|
|
|
-- 顶层 null 是合法 JSON,必须与「解析失败」区分开
|
|
local n, e3 = util.json_decode("null")
|
|
check("M14 top-level null is valid, not an error", n == nil and e3 == nil)
|
|
end
|
|
|
|
-- ---------- M14:尾部脏数据必须拒绝 ----------
|
|
do
|
|
local _, err = util.json_decode("1 2")
|
|
check("M14 trailing content after number rejected", type(err) == "string")
|
|
|
|
local _, err2 = util.json_decode("[1] junk")
|
|
check("M14 trailing content after array rejected", type(err2) == "string")
|
|
|
|
local _, err3 = util.json_decode('{"a":1}{"b":2}')
|
|
check("M14 two concatenated objects rejected", type(err3) == "string")
|
|
|
|
local _, err4 = util.json_decode("1.2.3")
|
|
check("M14 malformed number rejected", type(err4) == "string")
|
|
|
|
-- 尾随空白是合法的
|
|
local v, e = util.json_decode("[1] \n\t ")
|
|
check("M14 trailing whitespace allowed", type(v) == "table" and v[1] == 1 and e == nil)
|
|
end
|
|
|
|
-- ---------- M13:数组中的 null 往返保持 null ----------
|
|
do
|
|
local out = rt("[null,1]")
|
|
check("M13 null in array round-trips to null", out == "[null,1]")
|
|
|
|
local out2 = rt("[null,null]")
|
|
check("M13 multiple nulls round-trip", out2 == "[null,null]")
|
|
|
|
local out3 = rt('{"a":[1,null,2]}')
|
|
check("M13 nested null in object array round-trips", out3 == '{"a":[1,null,2]}')
|
|
|
|
-- 编码侧直接喂 null 占位符
|
|
local decoded = util.json_decode("[null]")
|
|
check("M13 decoded null slot is a table placeholder", type(decoded) == "table" and type(decoded[1]) == "table")
|
|
end
|
|
|
|
-- ---------- M13:空对象往返保持对象 ----------
|
|
do
|
|
local out = rt('{"tls":{}}')
|
|
check("M13 empty object round-trips as object", out == '{"tls":{}}')
|
|
|
|
local out2 = rt('{"settings":{},"x":1}')
|
|
check("M13 empty object among other keys round-trips", out2 == '{"settings":{},"x":1}')
|
|
|
|
-- 空数组仍须保持数组
|
|
local out3 = rt("[]")
|
|
check("M13 empty array still round-trips as array", out3 == "[]")
|
|
|
|
local out4 = rt('{"a":[]}')
|
|
check("M13 empty array value round-trips", out4 == '{"a":[]}')
|
|
|
|
-- 显式常量仍然有效
|
|
check("M13 JSON_EMPTY_OBJECT still encodes to {}", util.json_encode(util.JSON_EMPTY_OBJECT) == "{}")
|
|
end
|
|
|
|
-- ---------- 回归:既有行为不得被破坏 ----------
|
|
do
|
|
local out = rt('{"a":1,"b":"x","c":true,"d":false}')
|
|
check("regression object scalars", out ~= nil and out:find('"a":1', 1, true) ~= nil
|
|
and out:find('"b":"x"', 1, true) ~= nil and out:find('"c":true', 1, true) ~= nil)
|
|
|
|
local out2 = rt('[1,2,3]')
|
|
check("regression plain array", out2 == "[1,2,3]")
|
|
|
|
local out3 = rt('"hello"')
|
|
check("regression plain string", out3 == '"hello"')
|
|
|
|
local out4 = rt("42")
|
|
check("regression plain number", out4 == "42")
|
|
|
|
-- 转义序列
|
|
local s = util.json_decode('"a\\nb\\tc\\"d"')
|
|
check("regression escape sequences", s == 'a\nb\tc"d')
|
|
|
|
-- unicode 转义
|
|
local u = util.json_decode('"\\u4e2d"')
|
|
check("regression unicode escape", u == "中")
|
|
|
|
-- 空对象解码后仍是 table 且可被 pairs 遍历(调用方普遍这么用)
|
|
local o = util.json_decode("{}")
|
|
local cnt = 0
|
|
for _ in pairs(o) do cnt = cnt + 1 end
|
|
check("regression decoded empty object iterable", type(o) == "table" and cnt == 0)
|
|
end
|
|
|
|
print(string.format("\n%d passed, %d failed", passed, failed))
|
|
os.exit(failed == 0 and 0 or 1)
|