use luna_core::runtime::Value;
use luna_core::version::LuaVersion;
use luna_core::vm::Vm;
#[test]
fn sandbox_builder_roundtrip() {
let mut vm = Vm::sandbox(LuaVersion::Lua54)
.open_base()
.open_math()
.with_instr_budget(1_000_000)
.build();
let r = vm.eval("return 1 + 2").unwrap();
assert_eq!(r.len(), 1);
match r[0] {
Value::Int(3) => {}
Value::Float(f) if (f - 3.0).abs() < 1e-9 => {}
other => panic!("unexpected: {other:?}"),
}
}
#[test]
fn sandbox_builder_no_base_means_no_print() {
let mut vm = Vm::sandbox(LuaVersion::Lua55).build();
let err = vm
.eval("print('hello')")
.expect_err("print should be undefined without open_base");
let msg = vm.error_text(&err);
assert!(
msg.contains("nil") || msg.contains("global 'print'") || msg.contains("attempt to call"),
"got: {msg}"
);
}
#[test]
fn sandbox_builder_instr_budget_trips() {
let mut vm = Vm::sandbox(LuaVersion::Lua55)
.open_base()
.with_instr_budget(500)
.build();
let err = vm.eval("while true do end").expect_err("budget must trip");
let msg = vm.error_text(&err);
assert!(msg.contains("instruction budget"), "got: {msg}");
}
#[test]
fn eval_returns_multi_value() {
let mut vm = Vm::sandbox(LuaVersion::Lua55).open_base().build();
let r = vm.eval("return 1, 'two', true").unwrap();
assert_eq!(r.len(), 3);
}
#[test]
fn eval_chunk_uses_chunk_name() {
let mut vm = Vm::sandbox(LuaVersion::Lua55).open_base().build();
let err = vm
.eval_chunk("not lua syntax !@#", "myscript.lua")
.expect_err("must be a syntax error");
let msg = vm.error_text(&err);
assert!(!msg.is_empty(), "syntax error message must be non-empty");
}
#[test]
fn intern_str_is_idempotent() {
let mut vm = Vm::sandbox(LuaVersion::Lua55).build();
let s1 = vm.intern_str("hello");
let s2 = vm.intern_str("hello");
assert!(s1.ptr_eq(s2));
}
#[test]
fn try_as_str_utf8_only() {
let mut vm = Vm::sandbox(LuaVersion::Lua55).build();
let s = vm.intern_str("café");
let v = Value::Str(s);
assert_eq!(v.try_as_str(), Some("café"));
let bytes = b"\xff\xfe\x00binary";
let s_bin = vm.heap.intern(bytes);
let v_bin = Value::Str(s_bin);
assert_eq!(v_bin.try_as_str(), None);
assert_eq!(v_bin.as_bytes(), Some(&bytes[..]));
}
#[test]
fn as_bytes_on_non_string_is_none() {
assert_eq!(Value::Int(42).as_bytes(), None);
assert_eq!(Value::Nil.as_bytes(), None);
assert_eq!(Value::Bool(true).as_bytes(), None);
}