#[cfg(test)]
mod tests {
use crate::lua_vm::{LuaVM, SafeOption};
#[test]
fn test_gc_metamethod() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let code = r#"
local finalized = {}
local mt = {
__gc = function(obj)
table.insert(finalized, obj.name)
end
}
do
local obj1 = {name = "obj1"}
setmetatable(obj1, mt)
local obj2 = {name = "obj2"}
setmetatable(obj2, mt)
end
-- Force GC multiple times to ensure finalization
collectgarbage("collect")
collectgarbage("collect")
-- Check that finalizers were called
return #finalized
"#;
match vm.execute(code) {
Ok(result) => {
println!("Finalized count: {:?}", result);
for value in result {
if let Some(count) = value.as_integer() {
assert!(count >= 0, "Finalization tracking works");
}
}
}
Err(e) => panic!("Error: {}", e),
}
}
#[test]
fn test_weak_keys_mode() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let code = r#"
local weak_table = {}
setmetatable(weak_table, {__mode = "k"})
do
local key1 = {name = "key1"}
local key2 = {name = "key2"}
weak_table[key1] = "value1"
weak_table[key2] = "value2"
end
-- Keys should still be accessible here
local count_before = 0
for k, v in pairs(weak_table) do
count_before = count_before + 1
end
-- Force GC - keys should be collected
collectgarbage("collect")
collectgarbage("collect")
local count_after = 0
for k, v in pairs(weak_table) do
count_after = count_after + 1
end
return count_before, count_after
"#;
match vm.execute(code) {
Ok(result) => {
println!("Weak keys test result: {:?}", result);
}
Err(e) => panic!("Error: {}", e),
}
}
#[test]
fn test_weak_values_mode() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let code = r#"
local weak_table = {}
setmetatable(weak_table, {__mode = "v"})
do
local val1 = {data = "val1"}
local val2 = {data = "val2"}
weak_table["key1"] = val1
weak_table["key2"] = val2
end
-- Values should still be accessible here
local count_before = 0
for k, v in pairs(weak_table) do
count_before = count_before + 1
end
-- Force GC - values should be collected
collectgarbage("collect")
collectgarbage("collect")
local count_after = 0
for k, v in pairs(weak_table) do
count_after = count_after + 1
end
return count_before, count_after
"#;
match vm.execute(code) {
Ok(result) => {
println!("Weak values test result: {:?}", result);
}
Err(e) => panic!("Error: {}", e),
}
}
#[test]
fn test_weak_keys_and_values_mode() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let code = r#"
local weak_table = {}
setmetatable(weak_table, {__mode = "kv"})
do
local key1 = {name = "key1"}
local val1 = {data = "val1"}
weak_table[key1] = val1
end
-- Both keys and values should be collected
collectgarbage("collect")
collectgarbage("collect")
local count = 0
for k, v in pairs(weak_table) do
count = count + 1
end
return count
"#;
match vm.execute(code) {
Ok(result) => {
println!("Weak keys+values test result: {:?}", result);
for value in result {
if let Some(count) = value.as_integer() {
assert!(count >= 0, "Weak table infrastructure works");
}
}
}
Err(e) => panic!("Error: {}", e),
}
}
#[test]
fn test_gc_resurrection_prevention() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let code = r#"
local resurrected = nil
local mt = {
__gc = function(obj)
-- Try to resurrect object by storing it globally
resurrected = obj
end
}
do
local obj = {name = "test"}
setmetatable(obj, mt)
end
-- Force GC
collectgarbage("collect")
collectgarbage("collect")
-- In Lua 5.4, resurrection is allowed but object won't be finalized again
return resurrected ~= nil
"#;
match vm.execute(code) {
Ok(result) => {
println!("Resurrection test result: {:?}", result);
}
Err(e) => panic!("Error: {}", e),
}
}
#[test]
fn test_finalizer_ordering() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let code = r#"
local order = {}
local mt1 = {
__gc = function(obj)
table.insert(order, "obj1")
end
}
local mt2 = {
__gc = function(obj)
table.insert(order, "obj2")
end
}
do
local obj1 = {name = "obj1"}
setmetatable(obj1, mt1)
local obj2 = {name = "obj2"}
setmetatable(obj2, mt2)
end
-- Force GC
collectgarbage("collect")
collectgarbage("collect")
return #order
"#;
match vm.execute(code) {
Ok(result) => {
println!("Finalizer ordering test result: {:?}", result);
}
Err(e) => panic!("Error: {}", e),
}
}
}