TradeSkillMaster/External/EmbeddedLibs/LibSerialize/tests.lua

302 lines
9.4 KiB
Lua
Raw Permalink Normal View History

2020-11-13 14:13:12 -05:00
local LibSerialize = require("LibSerialize")
local pairs = pairs
local type = type
local tostring = tostring
local assert = assert
local unpack = unpack
local pcall = pcall
--[[---------------------------------------------------------------------------
Examples from the top of LibSerialize.lua
--]]---------------------------------------------------------------------------
do
local t = { "test", [false] = {} }
t[ t[false] ] = "hello"
local serialized = LibSerialize:Serialize(t, "extra")
local success, tab, str = LibSerialize:Deserialize(serialized)
assert(success)
assert(tab[1] == "test")
assert(tab[ tab[false] ] == "hello")
assert(str == "extra")
end
do
local serialized = LibSerialize:SerializeEx(
{ errorOnUnserializableType = false },
print, { a = 1, b = print })
local success, fn, tab = LibSerialize:Deserialize(serialized)
assert(success)
assert(fn == nil)
assert(tab.a == 1)
assert(tab.b == nil)
end
do
local t = { a = 1 }
t.t = t
t[t] = "test"
local serialized = LibSerialize:Serialize(t)
local success, tab = LibSerialize:Deserialize(serialized)
assert(success)
assert(tab.t.t.t.t.t.t.a == 1)
assert(tab[tab.t] == "test")
end
do
local t = { a = 1, b = print, c = 3 }
local nested = { a = 1, b = print, c = 3 }
t.nested = nested
setmetatable(nested, { __LibSerialize = {
filter = function(t, k, v) return k ~= "c" end
}})
local opts = {
filter = function(t, k, v) return LibSerialize:IsSerializableType(k, v) end
}
local serialized = LibSerialize:SerializeEx(opts, t)
local success, tab = LibSerialize:Deserialize(serialized)
assert(success)
assert(tab.a == 1)
assert(tab.b == nil)
assert(tab.c == 3)
assert(tab.nested.a == 1)
assert(tab.nested.b == nil)
assert(tab.nested.c == nil)
end
--[[---------------------------------------------------------------------------
Test of stable serialization
--]]---------------------------------------------------------------------------
do
local t = { a = 1, b = print, c = 3 }
local nested = { a = 1, b = print, c = 3 }
t.nested = nested
setmetatable(nested, { __LibSerialize = {
filter = function(t, k, v) return k ~= "c" end
}})
local opts = {
filter = function(t, k, v) return LibSerialize:IsSerializableType(k, v) end,
stable = true
}
local serialized = LibSerialize:SerializeEx(opts, t)
local success, tab = LibSerialize:Deserialize(serialized)
assert(success)
assert(tab.a == 1)
assert(tab.b == nil)
assert(tab.c == 3)
assert(tab.nested.a == 1)
assert(tab.nested.b == nil)
assert(tab.nested.c == nil)
end
do
local t1 = { x = "y", "test", [false] = { 1, 2, 3, a = "b" } }
local opts = {
stable = true,
filter = function(t, k, v) return not tonumber(k) or tonumber(k) < 100 end
}
local serialized1 = LibSerialize:SerializeEx(opts, t1)
local success1, tab1 = LibSerialize:Deserialize(serialized1)
assert(success1)
assert(tab1[1] == "test")
assert(tab1.x == "y")
assert(tab1[false][1] == 1)
assert(tab1[false][2] == 2)
assert(tab1[false][3] == 3)
assert(tab1[false].a == "b")
-- make a copy of the original table, but first insert a bunch of extra keys (which we'll
-- filter out) to force the order of the hashes to be different (tested with lua 5.1 and 5.2)
local t2 = {}
for i = 100, 10000 do
t2[tostring(i)] = i
end
t2.x = "y"
t2[1] = "test"
t2[false] = { 1, 2, 3, a = "b" }
-- ensure the iteration order is different
local isDifferent = false
local k1, k2 = nil, nil
while true do
k1 = next(t1, k1)
-- get the next key from t2 that's not going to be filtered
while true do
k2 = next(t2, k2)
if k2 == nil or not tonumber(k2) or tonumber(k2) < 100 then
break
end
end
if k1 == nil and k2 == nil then
break
end
assert(k1 ~= nil and k2 ~= nil)
isDifferent = isDifferent or k1 ~= k2
end
assert(isDifferent)
-- serialize the copy and ensure the result is the same
local serialized2 = LibSerialize:SerializeEx(opts, t2)
assert(serialized2 == serialized1)
end
--[[---------------------------------------------------------------------------
Utilities
--]]---------------------------------------------------------------------------
local function tCompare(lhsTable, rhsTable, depth)
depth = depth or 1
for key, value in pairs(lhsTable) do
if type(value) == "table" then
local rhsValue = rhsTable[key]
if type(rhsValue) ~= "table" then
return false
end
if depth > 1 then
if not tCompare(value, rhsValue, depth - 1) then
return false
end
end
elseif value ~= rhsTable[key] then
-- print("mismatched value: " .. key .. ": " .. tostring(value) .. ", " .. tostring(rhsTable[key]))
return false
end
end
-- Check for any keys that are in rhsTable and not lhsTable.
for key, value in pairs(rhsTable) do
if lhsTable[key] == nil then
-- print("mismatched key: " .. key)
return false
end
end
return true
end
--[[---------------------------------------------------------------------------
Test cases for serialization
--]]---------------------------------------------------------------------------
local function fail(value, desc)
assert(false, ("Test failed (%s): %s"):format(tostring(value), desc))
end
local function testfilter(t, k, v)
return k ~= "banned" and v ~= "banned"
end
local function check(value, bytelen, cmp)
local serialized = LibSerialize:SerializeEx({ errorOnUnserializableType = false, filter = testfilter }, value)
if #serialized ~= bytelen then
fail(value, ("Unexpected serialized length (%d, expected %d)"):format(#serialized, bytelen))
end
local success, deserialized = LibSerialize:Deserialize(serialized)
if not success then
fail(value, ("Deserialization failed: %s"):format(deserialized))
end
local typ = type(value)
if typ == "table" and not tCompare(cmp or value, deserialized) then
fail(value, "Non-matching deserialization result")
elseif typ ~= "table" and value ~= deserialized then
fail(value, ("Non-matching deserialization result: %s"):format(tostring(deserialized)))
end
end
-- Format: each test case is { value, bytelen, cmp }. The value will be serialized
-- and then deserialized, checking for success and equality, and the length of
-- the serialized string will be compared against bytelen. If `cmp` is provided,
-- it will be used for comparison against the deserialized result instead of `value`.
-- Note that the length always contains one extra byte for the version number.
local testCases = {
{ nil, 2 },
{ true, 2 },
{ false, 2 },
{ 0, 2 },
{ 1, 2 },
{ 127, 2 },
{ 128, 3 },
{ 4095, 3 },
{ 4096, 4 },
{ 65535, 4 },
{ 65536, 5 },
{ 16777215, 5 },
{ 16777216, 6 },
{ 4294967295, 6 },
{ 4294967296, 9 },
{ 9007199254740992, 9 },
{ 1.5, 6 },
{ 27.32, 8 },
{ 123.45678901235, 10 },
{ 148921291233.23, 10 },
{ -1, 3 },
{ -4095, 3 },
{ -4096, 4 },
{ -65535, 4 },
{ -65536, 5 },
{ -16777215, 5 },
{ -16777216, 6 },
{ -4294967295, 6 },
{ -4294967296, 9 },
{ -9007199254740992, 9 },
{ -1.5, 6 },
{ -123.45678901235, 10 },
{ -148921291233.23, 10 },
{ "", 2 },
{ "a", 3 },
{ "abcdefghijklmno", 17 },
{ "abcdefghijklmnop", 19 },
{ ("1234567890"):rep(30), 304 },
{ {}, 2 },
{ { 1 }, 3 },
{ { 1, 2, 3, 4, 5 }, 7 },
{ { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, 17 },
{ { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, 19 },
{ { 1, 2, 3, 4, a = 1, b = 2, [true] = 3, d = 4 }, 17 },
{ { 1, 2, 3, 4, 5, a = 1, b = 2, c = true, d = 4 }, 21 },
{ { 1, 2, 3, 4, 5, a = 1, b = 2, c = 3, d = 4, e = false }, 24 },
{ { a = 1, b = 2, c = 3 }, 11 },
{ { "aa", "bb", "aa", "bb" }, 14 },
{ { "aa1", "bb2", "aa3", "bb4" }, 18 },
{ { "aa1", "bb2", "aa1", "bb2" }, 14 },
{ { "aa1", "bb2", "bb2", "aa1" }, 14 },
{ { "abcdefghijklmno", "abcdefghijklmno", "abcdefghijklmno", "abcdefghijklmno" }, 24 },
{ { "abcdefghijklmno", "abcdefghijklmno", "abcdefghijklmno", "abcdefghijklmnop" }, 40 },
{ { 1, 2, 3, print, print, 6 }, 7, { 1, 2, 3, nil, nil, 6 } },
{ { 1, 2, 3, print, 5, 6 }, 8, { 1, 2, 3, nil, 5, 6 } },
{ { a = print, b = 1, c = print }, 5, { b = 1 } },
{ { a = print, [print] = "a" }, 2, {} },
{ { "banned", 1, 2, 3, banned = 4, test = "banned", a = 1 }, 9, { nil, 1, 2, 3, a = 1 } },
}
do
local t = { a = 1, b = 2 }
table.insert(testCases, { { t, t, t }, 13 })
table.insert(testCases, { { { a = 1, b = 2 }, { a = 1, b = 2 }, { a = 1, b = 2 } }, 23 })
end
for _, testCase in ipairs(testCases) do
check(unpack(testCase))
end
-- Since all the above tests assume serialization success, try some failures now.
local failCases = {
{ print },
{ [print] = true },
{ [true] = print },
print,
}
for _, testCase in ipairs(failCases) do
local success = pcall(LibSerialize.Serialize, LibSerialize, testCase)
assert(success == false)
end
print("All tests passed!")