|
| 1 | +local M = {} |
| 2 | + |
| 3 | +--- Recursively convert a table to a formatted string with indentation. |
| 4 | +---@param value any |
| 5 | +---@param indent? integer |
| 6 | +---@return string |
| 7 | +local function pretty(value, indent) |
| 8 | + indent = indent or 0 |
| 9 | + local t = type(value) |
| 10 | + |
| 11 | + if t == "table" then |
| 12 | + local pad = string.rep(" ", indent) |
| 13 | + local buf = { "{" } |
| 14 | + for k, v in pairs(value) do |
| 15 | + local key_str = tostring(k) |
| 16 | + local val_str = pretty(v, indent + 1) |
| 17 | + table.insert(buf, string.format("\n%s [%s] = %s", pad, key_str, val_str)) |
| 18 | + end |
| 19 | + table.insert(buf, "\n" .. pad .. "}") |
| 20 | + return table.concat(buf, "") |
| 21 | + elseif t == "string" then |
| 22 | + return string.format("%q", value) |
| 23 | + else |
| 24 | + return tostring(value) |
| 25 | + end |
| 26 | +end |
| 27 | + |
| 28 | +--- Deep equality comparison |
| 29 | +---@param a any |
| 30 | +---@param b any |
| 31 | +---@return boolean |
| 32 | +local function deep_equal(a, b) |
| 33 | + if a == b then |
| 34 | + return true |
| 35 | + end |
| 36 | + if type(a) ~= type(b) then |
| 37 | + return false |
| 38 | + end |
| 39 | + if type(a) ~= "table" then |
| 40 | + return false |
| 41 | + end |
| 42 | + |
| 43 | + local seen = {} |
| 44 | + for k in pairs(a) do |
| 45 | + seen[k] = true |
| 46 | + if not deep_equal(a[k], b[k]) then |
| 47 | + return false |
| 48 | + end |
| 49 | + end |
| 50 | + for k in pairs(b) do |
| 51 | + if not seen[k] then |
| 52 | + return false |
| 53 | + end |
| 54 | + end |
| 55 | + return true |
| 56 | +end |
| 57 | + |
| 58 | +--- Assert that two values are deeply equal, printing full diff if not. |
| 59 | +---@param expected any |
| 60 | +---@param actual any |
| 61 | +---@param msg? string |
| 62 | +function M.eq(expected, actual, msg) |
| 63 | + if not deep_equal(expected, actual) then |
| 64 | + local err = string.format( |
| 65 | + "%s\nExpected:\n%s\n\nGot:\n%s", |
| 66 | + msg or "Assertion failed (tables not equal):", |
| 67 | + pretty(expected), |
| 68 | + pretty(actual) |
| 69 | + ) |
| 70 | + error(err, 2) |
| 71 | + end |
| 72 | +end |
| 73 | + |
| 74 | +return M |
0 commit comments