aboutsummaryrefslogtreecommitdiff
path: root/test/assert.lua
diff options
context:
space:
mode:
authorLewis Russell <lewis6991@gmail.com>2026-10-05 15:37:06 +0100
committerLewis Russell <me@lewisr.dev>2026-10-05 17:33:44 +0100
commit483815ab45cf8fc08804e0cfa95b126493a5dd1f (patch)
tree9bf9055171d9f16a8ebb9e7f5adf181949db35cc /test/assert.lua
parent7a8b7c04778d334f60766a0c83933b74e4e237b3 (diff)
downloadrneovim-483815ab45cf8fc08804e0cfa95b126493a5dd1f.tar.gz
rneovim-483815ab45cf8fc08804e0cfa95b126493a5dd1f.tar.bz2
rneovim-483815ab45cf8fc08804e0cfa95b126493a5dd1f.zip
test: simplify functional test expectations
Problem: Repeated default fields and field-by-field assertions obscure the values that each functional test is meant to check. Solution: Add eq_partial() to check selected record fields while preserving list length and order. Use local helpers to fill fixed expected defaults where tests need full equality. Keep explicit absence checks and test-specific values at the call sites. AI-assisted
Diffstat (limited to 'test/assert.lua')
-rw-r--r--test/assert.lua53
1 files changed, 53 insertions, 0 deletions
diff --git a/test/assert.lua b/test/assert.lua
index 5be7d21f00..8b26a7c327 100644
--- a/test/assert.lua
+++ b/test/assert.lua
@@ -54,6 +54,59 @@ function M.eq(expected, actual, context)
)
end
+--- Checks the supplied fields recursively, ignoring other record fields.
+--- Lists must have the same length and order; their records may have extra fields.
+--- Does not check the non-existence of a field.
+---
+--- Examples:
+--- ```lua
+--- local result = { id = 1, opts = { enabled = false, priority = 10 } }
+--- eq_partial({ opts = { enabled = false } }, result) -- Passes.
+--- eq(nil, result.missing) -- Check that a field is absent.
+---
+--- eq_partial({ { id = 1 } }, { { id = 1, name = 'test' } }) -- Passes.
+--- eq_partial({ { id = 1 } }, { { id = 1 }, { id = 2 } }) -- Fails: extra list item.
+--- ```
+---
+--- @param expected any
+--- @param actual any
+--- @param context? any
+--- @return any
+function M.eq_partial(expected, actual, context)
+ local seen = {} --- @type table<table, table<table, boolean>>
+ local prefix = context ~= nil and tostring(context) .. ': ' or ''
+
+ --- @param want any
+ --- @param got any
+ --- @param path string
+ local function compare(want, got, path)
+ if type(want) ~= 'table' or type(got) ~= 'table' or next(want) == nil then
+ M.eq(want, got, prefix .. path)
+ return
+ end
+
+ if vim.islist(want) then
+ assert_value(vim.islist(got), got, prefix .. path, 'Expected a list.\nActual:\n' .. fmt(got))
+ M.eq(#want, #got, prefix .. path .. ' (length)')
+ end
+
+ if seen[want] and seen[want][got] then
+ return
+ end
+ seen[want] = seen[want] or {}
+ seen[want][got] = true
+
+ for key, value in pairs(want) do
+ local field = type(key) == 'string' and key:match('^[%a_][%w_]*$') and '.' .. key
+ or '[' .. fmt(key) .. ']'
+ compare(value, got[key], path .. field)
+ end
+ end
+
+ compare(expected, actual, 'actual')
+ return actual
+end
+
--- @param expected any
--- @param actual any
--- @param context? any