Files
plainleaf/client/space_lua/stdlib/global_test.lua
T
Matouš Jan Fialka 8cecd0985c [Space Lua] tostring() respects __tostring metamethod with live stack frame
`tostring()` was delegating to `luaToString()` which calls `__tostring`
with a dead stack frame, breaking metamethods that call back into
globals. Now `tostringFunction` receives the live stack frame, looks up
`__tostring` via `rawGet`, calls it through `luaCall` with the live
frame, and validates the return is a string.

Also add tests covering the basic case, the nested-call case, and the
error path for a non-string return.

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
2026-02-20 07:59:16 +01:00

55 lines
1.6 KiB
Lua

local function assertEqual(a, b)
if a ~= b then
error("Assertion failed: " .. a .. " is not equal to " .. b)
end
end
-- Logic values, shouldn't be affected
assertEqual(some(nil), nil)
assertEqual(some(true), true)
assertEqual(some(false), false)
-- Numbers
assertEqual(some(1), 1)
assertEqual(some(0), 0) -- 0 is not falsy unlike C
assertEqual(some(-1), -1)
assertEqual(some(1/0), nil) -- inf
assertEqual(some(0/0), nil) -- nan
-- Strings
assertEqual(some("foo bar"), "foo bar")
assertEqual(some(""), nil)
assertEqual(some(" \n"), nil)
-- Tables
assertEqual(some({}), nil)
assertEqual(some({"baz"})[1], "baz") -- compare an element to ensure passthrough
assertEqual(some({foo="bar"})["foo"], "bar")
-- tostring: primitives
assertEqual(tostring(nil), "nil")
assertEqual(tostring(true), "true")
assertEqual(tostring(false), "false")
assertEqual(tostring(42), "42")
assertEqual(tostring(3.14), "3.14")
-- tostring: `__tostring` metamethod is called with the live SF
local mt = { __tostring = function(t) return "custom:" .. t.name end }
local obj = setmetatable({ name = "lua" }, mt)
assertEqual(tostring(obj), "custom:lua")
-- tostring: `__tostring` returning non-string must error
local bad_mt = { __tostring = function(_) return 99 end }
local bad_obj = setmetatable({}, bad_mt)
local ok, err = pcall(tostring, bad_obj)
assertEqual(ok, false)
-- tostring: `__tostring` on a nested call (SF propagation via `luaCall`)
local inner_mt = {
__tostring = function(t)
return "inner:" .. tostring(t.val)
end
}
local inner = setmetatable({ val = 7 }, inner_mt)
assertEqual(tostring(inner), "inner:7")