* Align `#` operator and `__len` metamethod with Lua and add `rawlen` function Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
107 lines
1.8 KiB
Lua
107 lines
1.8 KiB
Lua
local function assert_eq(actual, expected, msg)
|
|
if actual ~= expected then
|
|
error('assert_eq failed: ' .. msg)
|
|
end
|
|
end
|
|
|
|
local function assert_throws(substr, fn)
|
|
local ok, err = pcall(fn)
|
|
if ok then
|
|
error("expected error containing: " .. substr)
|
|
end
|
|
|
|
err = tostring(err)
|
|
if not string.find(err, substr, 1, true) then
|
|
error("error message mismatch: got: " .. err)
|
|
end
|
|
end
|
|
|
|
-- 1. Strings: raw length, ignore metamethods
|
|
assert_eq(#"", 0, "empty string length")
|
|
assert_eq(#"abc", 3, "string length")
|
|
|
|
-- 2. Tables (raw length for sequence or `__len`)
|
|
assert_eq(#{}, 0, "empty table length")
|
|
assert_eq(#{1,2,3}, 3, "array length")
|
|
|
|
do
|
|
local t = {}
|
|
|
|
setmetatable(t,
|
|
{
|
|
__len = function(_)
|
|
return 42
|
|
end,
|
|
})
|
|
|
|
assert_eq(#t, 42, "__len should override raw table length")
|
|
end
|
|
|
|
-- 2.1. Metamethod result handling
|
|
do
|
|
local t = {}
|
|
|
|
setmetatable(t,
|
|
{
|
|
__len = function(_)
|
|
return 42, 1, 2, 3
|
|
end,
|
|
})
|
|
|
|
assert_eq(#t, 42, "__len must use only first return value")
|
|
end
|
|
|
|
-- 2.2. Raw length when no array part
|
|
do
|
|
local t = {
|
|
a = 1,
|
|
b = 2,
|
|
}
|
|
|
|
assert_eq(#t, 0, "table with only non-integer keys has length 0")
|
|
end
|
|
|
|
-- 2.3. Length when both array and key-value parts
|
|
do
|
|
local t = {
|
|
a = 1,
|
|
b = 2,
|
|
1,
|
|
2,
|
|
c = 3,
|
|
3,
|
|
}
|
|
|
|
assert_eq(#t, 3, "table with mixed non-integer and integer keys")
|
|
end
|
|
|
|
-- 3. Non-strings and non-tables
|
|
assert_throws(
|
|
"attempt to get length of a nil value",
|
|
function()
|
|
return #nil
|
|
end
|
|
)
|
|
|
|
assert_throws(
|
|
"attempt to get length of a number value",
|
|
function()
|
|
return #1
|
|
end
|
|
)
|
|
|
|
assert_throws(
|
|
"attempt to get length of a boolean value",
|
|
function()
|
|
return #false
|
|
end
|
|
)
|
|
|
|
assert_throws(
|
|
"attempt to get length of a function value",
|
|
function()
|
|
local f = function() end
|
|
return #f
|
|
end
|
|
)
|