use crate::*;
#[test]
fn test_add_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local a = {val = 5}
local b = {val = 3}
setmetatable(a, {__add = function(x, y) return {val = x.val + y.val} end})
setmetatable(b, {__add = function(x, y) return {val = x.val + y.val} end})
local c = a + b
assert(c.val == 8)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_add_metamethod_with_number() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local a = {val = 5}
setmetatable(a, {__add = function(x, y)
if type(y) == "number" then
return {val = x.val + y}
else
return {val = x.val + y.val}
end
end})
local c = a + 10
assert(c.val == 15)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_sub_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local a = {val = 10}
local b = {val = 3}
setmetatable(a, {__sub = function(x, y) return {val = x.val - y.val} end})
setmetatable(b, {__sub = function(x, y) return {val = x.val - y.val} end})
local c = a - b
assert(c.val == 7)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_mul_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local a = {val = 5}
setmetatable(a, {__mul = function(x, y) return {val = x.val * y} end})
local c = a * 3
assert(c.val == 15)
"#,
);
if let Err(e) = &result {
eprintln!("Error: {}", e);
}
assert!(result.is_ok());
}
#[test]
fn test_div_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local a = {val = 20}
setmetatable(a, {__div = function(x, y) return {val = x.val / y} end})
local c = a / 4
assert(c.val == 5)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_mod_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local a = {val = 17}
setmetatable(a, {__mod = function(x, y) return {val = x.val % y} end})
local c = a % 5
assert(c.val == 2)
"#,
);
if let Err(e) = &result {
eprintln!("test_index_metamethod_table error: {:?}", e);
}
assert!(result.is_ok());
}
#[test]
fn test_pow_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local a = {val = 2}
setmetatable(a, {__pow = function(x, y) return {val = x.val ^ y} end})
local c = a ^ 4
assert(c.val == 16)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_unm_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local a = {val = 10}
setmetatable(a, {__unm = function(x) return {val = -x.val} end})
local c = -a
assert(c.val == -10)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_idiv_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local a = {val = 17}
setmetatable(a, {__idiv = function(x, y) return {val = x.val // y} end})
local c = a // 5
assert(c.val == 3)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_band_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local a = {val = 5} -- 101
local b = {val = 3} -- 011
setmetatable(a, {__band = function(x, y) return {val = x.val & y.val} end})
setmetatable(b, {__band = function(x, y) return {val = x.val & y.val} end})
local c = a & b -- 001 = 1
assert(c.val == 1)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_bor_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local a = {val = 5} -- 101
local b = {val = 3} -- 011
setmetatable(a, {__bor = function(x, y) return {val = x.val | y.val} end})
setmetatable(b, {__bor = function(x, y) return {val = x.val | y.val} end})
local c = a | b -- 111 = 7
assert(c.val == 7)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_bxor_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local a = {val = 5} -- 101
local b = {val = 3} -- 011
setmetatable(a, {__bxor = function(x, y) return {val = x.val ~ y.val} end})
setmetatable(b, {__bxor = function(x, y) return {val = x.val ~ y.val} end})
local c = a ~ b -- 110 = 6
assert(c.val == 6)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_bnot_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local a = {val = 5}
setmetatable(a, {__bnot = function(x) return {val = ~x.val} end})
local c = ~a
assert(c.val == ~5)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_shl_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local a = {val = 5}
setmetatable(a, {__shl = function(x, n) return {val = x.val << n} end})
local c = a << 2
assert(c.val == 20)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_shr_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local a = {val = 20}
setmetatable(a, {__shr = function(x, n) return {val = x.val >> n} end})
local c = a >> 2
assert(c.val == 5)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_index_metamethod_function() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local t = {}
setmetatable(t, {
__index = function(tbl, key)
return "value_" .. key
end
})
assert(t.foo == "value_foo")
"#,
);
if let Err(e) = &result {
eprintln!("test_index_metamethod_function error: {:?}", e);
}
assert!(result.is_ok());
}
#[test]
fn test_index_metamethod_table() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local defaults = {x = 10, y = 20}
local t = {}
setmetatable(t, {__index = defaults})
assert(t.x == 10 and t.y == 20)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_newindex_metamethod_function() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local storage = {}
local t = {}
local mt = {
__newindex = function(tbl, key, value)
print("__newindex called with", key, value)
storage[key] = value * 2
end,
__index = storage
}
setmetatable(t, mt)
print("Metatable set:", getmetatable(t) == mt)
print("About to set t.val = 5")
t.val = 5
print("storage.val =", storage.val)
assert(storage.val == 10)
"#,
);
if let Err(e) = &result {
eprintln!("Error: {:?}", e);
}
assert!(result.is_ok());
}
#[test]
fn test_newindex_metamethod_table() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local storage = {}
local t = {}
setmetatable(t, {__newindex = storage, __index = storage})
t.name = "test"
assert(storage.name == "test")
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_call_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local t = {}
setmetatable(t, {
__call = function(tbl, a, b)
return a + b
end
})
local result = t(3, 5)
assert(result == 8)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_tostring_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local t = {x = 1, y = 2}
setmetatable(t, {
__tostring = function(tbl)
return "Point(" .. tbl.x .. "," .. tbl.y .. ")"
end
})
assert(tostring(t) == "Point(1,2)")
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_len_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local t = {a = 1, b = 2, c = 3}
setmetatable(t, {
__len = function(tbl)
local count = 0
for _ in pairs(tbl) do
count = count + 1
end
return count
end
})
assert(#t == 3)
"#,
);
if result.is_err() {
eprintln!("test_len_metamethod error: {:?}", result.as_ref().err());
}
assert!(result.is_ok());
}
#[test]
fn test_eq_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local a = {val = 5}
local b = {val = 5}
local mt = {__eq = function(x, y) return x.val == y.val end}
setmetatable(a, mt)
setmetatable(b, mt)
local result = (a == b)
-- Don't use assert to avoid potential issue with print/assert
if not result then
error("Expected a == b to be true")
end
"#,
);
if let Err(e) = &result {
println!("ERROR in test_eq_metamethod: {:?}", e);
}
assert!(result.is_ok());
}
#[test]
fn test_lt_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local a = {val = 3}
local b = {val = 5}
setmetatable(a, {__lt = function(x, y) return x.val < y.val end})
setmetatable(b, {__lt = function(x, y) return x.val < y.val end})
assert(a < b)
"#,
);
if let Err(e) = &result {
eprintln!("test_lt_metamethod error: {:?}", e);
}
assert!(result.is_ok());
}
#[test]
fn test_le_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local a = {val = 3}
local b = {val = 3}
setmetatable(a, {__le = function(x, y) return x.val <= y.val end})
setmetatable(b, {__le = function(x, y) return x.val <= y.val end})
assert(a <= b)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_concat_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local a = {str = "Hello"}
local b = {str = "World"}
setmetatable(a, {__concat = function(x, y) return {str = x.str .. " " .. y.str} end})
setmetatable(b, {__concat = function(x, y) return {str = x.str .. " " .. y.str} end})
local c = a .. b
assert(c.str == "Hello World")
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_nested_index_chain() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local level1 = {a = 1}
local level2 = {}
local level3 = {}
setmetatable(level2, {__index = level1})
setmetatable(level3, {__index = level2})
assert(level3.a == 1)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_multiple_metamethods_same_object() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local mt = {
__add = function(a, b)
local result = {x = a.x + 5}
setmetatable(result, mt)
return result
end,
__sub = function(a, b)
local result = {x = a.x - 3}
setmetatable(result, mt)
return result
end,
__tostring = function(o) return "Obj(" .. o.x .. ")" end
}
local obj = {x = 10}
setmetatable(obj, mt)
local r1 = obj + obj
local r2 = obj - obj
local s = tostring(obj)
assert(r1.x == 15 and r2.x == 7 and s == "Obj(10)")
"#,
);
if let Err(e) = &result {
eprintln!("Error: {:?}", e);
}
assert!(result.is_ok());
}
#[test]
fn test_string_metatable_len() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local s = "hello"
assert(s:len() == 5)
assert(#s == 5)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_string_metatable_upper() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local s = "hello"
assert(s:upper() == "HELLO")
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_string_metatable_lower() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local s = "HELLO"
assert(s:lower() == "hello")
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_string_metatable_sub() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local s = "hello world"
assert(s:sub(1, 5) == "hello")
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_getmetatable_table() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local t = {}
local mt = {__index = {x = 1}}
setmetatable(t, mt)
assert(getmetatable(t) == mt)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_getmetatable_string() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local s = "hello"
local mt = getmetatable(s)
assert(mt ~= nil)
assert(mt.__index == string)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_arithmetic_metamethod_chain() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local mt = {
__add = function(a, b)
local result = {n = a.n + b.n}
setmetatable(result, getmetatable(a))
return result
end,
__mul = function(a, b)
local result = {n = a.n * b.n}
setmetatable(result, getmetatable(a))
return result
end
}
local t = {n = 2}
setmetatable(t, mt)
local r = (t + t) * t
assert(r.n == 8) -- (2 + 2) * 2
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_index_with_rawget() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local t = {real = 1}
setmetatable(t, {
__index = function(tbl, key)
return "meta_" .. key
end
})
assert(t.real == 1)
assert(t.fake == "meta_fake")
assert(rawget(t, "real") == 1)
assert(rawget(t, "fake") == nil)
"#,
);
if let Err(e) = &result {
eprintln!("Error: {}", e);
}
assert!(result.is_ok());
}
#[test]
fn test_newindex_with_rawset() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local storage = {}
local t = {}
setmetatable(t, {
__newindex = function(tbl, key, value)
storage[key] = value
end
})
t.a = 1
rawset(t, "b", 2)
assert(storage.a == 1)
assert(storage.b == nil)
assert(rawget(t, "b") == 2)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_mode_weak_tables() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local t = {}
setmetatable(t, {__mode = "k"})
local key = {}
t[key] = "value"
assert(t[key] == "value")
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_ipairs_with_index_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
-- ipairs should trigger __index metamethod
local a = {n = 10}
setmetatable(a, {
__index = function(t, k)
if k <= t.n then return k * 10 end
end
})
local count = 0
for k, v in ipairs(a) do
count = count + 1
assert(k == count, "ipairs key mismatch")
assert(v == count * 10, "ipairs value mismatch")
end
assert(count == a.n, "ipairs should iterate " .. a.n .. " times, got " .. count)
"#,
);
assert!(result.is_ok(), "ipairs with __index failed: {:?}", result);
}
#[test]
fn test_ipairs_with_index_table() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
-- ipairs with __index pointing to another table
local backing = {100, 200, 300, 400, 500}
local proxy = setmetatable({}, { __index = backing })
local sum = 0
local count = 0
for _, v in ipairs(proxy) do
sum = sum + v
count = count + 1
end
assert(count == 5, "expected 5 iterations, got " .. count)
assert(sum == 1500, "expected sum 1500, got " .. sum)
"#,
);
assert!(
result.is_ok(),
"ipairs with __index table failed: {:?}",
result
);
}
#[test]
fn test_ipairs_stops_at_nil() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
-- ipairs with __index that returns nil at index 4
local a = setmetatable({}, {
__index = function(_, k)
if k <= 3 then return k * 100 end
-- returns nil for k > 3
end
})
local count = 0
for k, v in ipairs(a) do
count = count + 1
end
assert(count == 3, "ipairs should stop at nil, got " .. count)
"#,
);
assert!(result.is_ok(), "ipairs stops at nil failed: {:?}", result);
}
#[test]
fn test_pairs_with_pairs_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
-- Custom iterator via __pairs
local data = {10, 20, 30}
local t = setmetatable({}, {
__pairs = function(self)
local i = 0
return function()
i = i + 1
if i <= #data then return i, data[i] end
end, self, nil
end
})
local sum = 0
local count = 0
for k, v in pairs(t) do
sum = sum + v
count = count + 1
end
assert(count == 3, "pairs metamethod: expected 3, got " .. count)
assert(sum == 60, "pairs metamethod: expected sum 60, got " .. sum)
"#,
);
assert!(result.is_ok(), "pairs with __pairs failed: {:?}", result);
}
#[test]
fn test_pairs_with_tbc_variable() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
-- __pairs returns a to-be-closed variable (4th return value)
local closed = false
local t = setmetatable({}, {
__pairs = function(self)
local tbc = setmetatable({}, {
__close = function() closed = true end
})
local i = 0
return function()
i = i + 1
if i <= 3 then return i, i * 10 end
end, self, nil, tbc
end
})
for k, v in pairs(t) do end
assert(closed, "to-be-closed variable should have been closed")
"#,
);
assert!(
result.is_ok(),
"pairs with TBC variable failed: {:?}",
result
);
}
#[test]
fn test_pairs_without_metamethod_returns_4_values() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
-- pairs without __pairs should still work (returns next, t, nil, nil)
local t = {a = 1, b = 2}
local x, y, z = pairs(t)
assert(type(x) == "function", "pairs should return function as 1st value")
assert(y == t, "pairs should return table as 2nd value")
assert(z == nil, "pairs should return nil as 3rd value")
-- Verify standard iteration still works
local keys = {}
for k, v in pairs(t) do
keys[k] = v
end
assert(keys.a == 1 and keys.b == 2)
"#,
);
assert!(
result.is_ok(),
"pairs without metamethod failed: {:?}",
result
);
}
#[test]
fn test_pairs_yield_inside_pairs_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
-- __pairs metamethod that yields before returning the iterator
local t = setmetatable({10, 20, 30}, {__pairs = function(t)
local inc = coroutine.yield() -- yield inside __pairs!
return function(t, i)
if i > 1 then return i - inc, t[i - inc] else return nil end
end, t, #t + 1
end})
local res = {}
local co = coroutine.wrap(function()
for i, p in pairs(t) do res[#res + 1] = p end
end)
co() -- start: __pairs runs, hits yield
co(1) -- resume with inc=1, iteration proceeds
assert(res[1] == 30, "expected 30, got " .. tostring(res[1]))
assert(res[2] == 20, "expected 20, got " .. tostring(res[2]))
assert(res[3] == 10, "expected 10, got " .. tostring(res[3]))
assert(#res == 3, "expected 3 results, got " .. #res)
"#,
);
assert!(result.is_ok(), "yield inside __pairs failed: {:?}", result);
}
#[test]
fn test_pairs_yield_multiple_times_in_pairs_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
-- __pairs yields twice: once to get the step, once to get the start
local t = setmetatable({100, 200, 300}, {__pairs = function(t)
local step = coroutine.yield("need step")
local start = coroutine.yield("need start")
local i = start
return function()
if i >= 1 then
local idx = i
i = i - step
return idx, t[idx]
end
end, t, nil
end})
local res = {}
local co = coroutine.create(function()
for k, v in pairs(t) do res[#res + 1] = v end
end)
local ok, msg = coroutine.resume(co) -- start
assert(ok and msg == "need step")
ok, msg = coroutine.resume(co, 1) -- provide step=1
assert(ok and msg == "need start")
ok = coroutine.resume(co, 3) -- provide start=3
assert(ok)
assert(#res == 3, "expected 3, got " .. #res)
assert(res[1] == 300 and res[2] == 200 and res[3] == 100)
"#,
);
assert!(
result.is_ok(),
"multiple yields inside __pairs failed: {:?}",
result
);
}