use crate::*;
#[test]
fn test_local_variable_scope() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local x = 10
do
local x = 20
assert(x == 20)
end
assert(x == 10)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_global_variable() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
globalVar = 42
assert(globalVar == 42)
assert(_G.globalVar == 42)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_multiple_assignment() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local a, b, c = 1, 2, 3
assert(a == 1 and b == 2 and c == 3)
local x, y = 10
assert(x == 10 and y == nil)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_swap_variables() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local a, b = 1, 2
a, b = b, a
assert(a == 2 and b == 1)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_vararg_function() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local function sum(...)
local total = 0
for _, v in ipairs({...}) do
total = total + v
end
return total
end
local result = sum(1, 2, 3, 4, 5)
assert(result == 15)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_table_constructor_array() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local t = {10, 20, 30}
assert(t[1] == 10 and t[2] == 20 and t[3] == 30)
assert(#t == 3)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_table_constructor_hash() {
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, z = 3}
assert(t.x == 1 and t.y == 2 and t.z == 3)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_table_constructor_mixed() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local t = {10, 20, x = "a", y = "b", 30}
assert(t[1] == 10 and t[2] == 20 and t[3] == 30)
assert(t.x == "a" and t.y == "b")
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_table_constructor_expression_key() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local key = "mykey"
local t = {[key] = 100, [1+1] = 200}
assert(t.mykey == 100 and t[2] == 200)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_simple_function() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local function add(a, b)
return a + b
end
local result = add(3, 5)
assert(result == 8)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_function_as_table_method() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local obj = {value = 10}
function obj:add(n)
self.value = self.value + n
end
obj:add(5)
assert(obj.value == 15)
"#,
);
if let Err(e) = &result {
eprintln!("Error: {}", e);
}
assert!(result.is_ok());
}
#[test]
fn test_while_loop() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local i = 0
local sum = 0
while i < 5 do
i = i + 1
sum = sum + i
end
assert(sum == 15)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_repeat_until() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local i = 0
local sum = 0
repeat
i = i + 1
sum = sum + i
until i >= 5
assert(sum == 15)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_numeric_for() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local sum = 0
for i = 1, 5 do
sum = sum + i
end
assert(sum == 15)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_numeric_for_with_step() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local sum = 0
for i = 0, 10, 2 do
sum = sum + i
end
assert(sum == 30) -- 0 + 2 + 4 + 6 + 8 + 10
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_break_statement() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local sum = 0
for i = 1, 10 do
if i > 5 then
break
end
sum = sum + i
end
assert(sum == 15)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_nested_loops() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local sum = 0
for i = 1, 3 do
for j = 1, 3 do
sum = sum + i * j
end
end
assert(sum == 36) -- (1+2+3)*1 + (1+2+3)*2 + (1+2+3)*3
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_if_elseif_else() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local function classify(n)
if n > 0 then
return "positive"
elseif n < 0 then
return "negative"
else
return "zero"
end
end
assert(classify(5) == "positive")
assert(classify(-3) == "negative")
assert(classify(0) == "zero")
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_truthiness() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
assert(true)
assert(not false)
assert(not nil)
assert(0) -- 0 is truthy in Lua
assert("") -- empty string is truthy
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_and_operator() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
assert((true and true) == true)
assert((true and false) == false)
assert((5 and 10) == 10)
assert((nil and 10) == nil)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_or_operator() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
assert((false or true) == true)
assert((nil or 10) == 10)
assert((5 or 10) == 5)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_not_operator() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
assert(not false)
assert(not nil)
assert(not (not true))
assert(not 0 == false) -- 0 is truthy
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_short_circuit_evaluation() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local called = false
local function f()
called = true
return true
end
local result = false and f()
assert(not called) -- f() should not be called
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_type_function() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
assert(type(nil) == "nil")
assert(type(true) == "boolean")
assert(type(42) == "number")
assert(type("hello") == "string")
assert(type({}) == "table")
assert(type(print) == "function")
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_pcall_success() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local function safe_func()
return 42
end
local success, result = pcall(safe_func)
assert(success == true)
assert(result == 42)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_pcall_error() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local function error_func()
error("oops")
end
local success, err = pcall(error_func)
assert(success == false)
assert(type(err) == "string")
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_ipairs() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local t = {10, 20, 30}
local sum = 0
for i, v in ipairs(t) do
sum = sum + v
end
assert(sum == 60)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_pairs() {
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}
local count = 0
for k, v in pairs(t) do
count = count + 1
end
assert(count == 3)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_tonumber() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
assert(tonumber("123") == 123)
assert(tonumber("3.14") == 3.14)
assert(tonumber("FF", 16) == 255)
assert(tonumber("invalid") == nil)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_tostring() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
assert(tostring(123) == "123")
assert(tostring(true) == "true")
assert(tostring(nil) == "nil")
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_string_concatenation() {
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 == "Hello World")
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_string_length() {
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 == 5)
assert(string.len(s) == 5)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_table_insert() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local t = {1, 2, 3}
table.insert(t, 4)
assert(#t == 4 and t[4] == 4)
table.insert(t, 2, 99)
assert(t[2] == 99)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_table_remove() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local t = {1, 2, 3, 4}
local v = table.remove(t)
assert(v == 4 and #t == 3)
v = table.remove(t, 2)
assert(v == 2)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_table_concat() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local t = {"a", "b", "c"}
assert(table.concat(t) == "abc")
assert(table.concat(t, ",") == "a,b,c")
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_simple_upvalue() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local x = 10
local function get_x()
return x
end
assert(get_x() == 10)
x = 20
assert(get_x() == 20)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_nil_in_table() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
local t = {1, 2, nil, 4}
assert(t[1] == 1)
assert(t[2] == 2)
assert(t[3] == nil)
assert(t[4] == 4)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_equality_comparison() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
assert(5 == 5)
assert(5 ~= 6)
assert("hello" == "hello")
local t1 = {}
local t2 = {}
assert(t1 == t1)
assert(t1 ~= t2)
"#,
);
assert!(result.is_ok());
}
#[test]
fn test_relational_comparison() {
let mut vm = LuaVM::new(SafeOption::default());
vm.open_stdlib(crate::stdlib::Stdlib::All).unwrap();
let result = vm.execute(
r#"
assert(5 < 10)
assert(10 > 5)
assert(5 <= 5)
assert(5 >= 5)
assert("a" < "b")
"#,
);
assert!(result.is_ok());
}