Acord/core/src/interp/tests/embedding.rs

99 lines
3.4 KiB
Rust

use crate::interp::*;
#[allow(unused_imports)]
use super::helpers::*;
#[test]
fn extern_handle_round_trips() {
let mut i = Interpreter::new();
let h = Value::Extern(ExternHandle { kind: "toroid".into(), id: 42 });
i.set_var("t", h);
let back = i.eval("t").unwrap();
match back {
Value::Extern(h) => {
assert_eq!(h.kind, "toroid");
assert_eq!(h.id, 42);
}
_ => panic!("expected Extern"),
}
}
#[test]
fn custom_builtin_invoked_from_cordial() {
use std::cell::Cell;
use std::rc::Rc;
let calls = Rc::new(Cell::new(0));
let calls_h = Rc::clone(&calls);
let mut i = Interpreter::new();
i.register_builtin("scene_update", move |_interp, args| {
calls_h.set(calls_h.get() + 1);
match args {
[Value::Extern(h)] => Ok(Value::Str(format!("updated {}#{}", h.kind, h.id))),
_ => Err("scene_update(extern)".into()),
}
});
i.set_var("t1", Value::Extern(ExternHandle { kind: "node".into(), id: 7 }));
let r = i.eval("scene_update(t1)").unwrap();
assert_eq!(r.display(), "updated node#7");
assert_eq!(calls.get(), 1);
}
#[test]
fn custom_builtin_overrides_hardcoded() {
let mut i = Interpreter::new();
i.register_builtin("sin", |_interp, _args| Ok(Value::Number(42.0)));
assert_eq!(i.eval("sin(0)").unwrap().display(), "42");
}
#[test]
fn unregister_restores_hardcoded() {
let mut i = Interpreter::new();
i.register_builtin("sin", |_interp, _args| Ok(Value::Number(42.0)));
i.unregister_builtin("sin");
let r = i.eval("sin(0)").unwrap();
assert!(matches!(r, Value::Number(n) if n.abs() < 1e-9));
}
#[test]
fn call_invokes_user_fn_by_name_with_values() {
let mut i = Interpreter::new();
i.exec("fn add(a, b) {\n return a + b\n}").unwrap();
let r = i.call("add", &[Value::Number(3.0), Value::Number(4.0)]).unwrap();
assert_eq!(r.display(), "7");
}
#[test]
fn call_passes_extern_through_user_fn() {
let mut i = Interpreter::new();
i.exec("fn pass(x) {\n return x\n}").unwrap();
let h = Value::Extern(ExternHandle { kind: "anchor".into(), id: 9 });
let r = i.call("pass", &[h]).unwrap();
match r {
Value::Extern(h) => { assert_eq!(h.kind, "anchor"); assert_eq!(h.id, 9); }
_ => panic!("expected Extern back"),
}
}
#[test]
fn host_driven_loop_round_trip() {
use std::cell::RefCell;
use std::rc::Rc;
let scene_log: Rc<RefCell<Vec<u64>>> = Rc::new(RefCell::new(Vec::new()));
let log_h = Rc::clone(&scene_log);
let mut i = Interpreter::new();
i.register_builtin("emit", move |_interp, args| {
if let [Value::Extern(h)] = args {
log_h.borrow_mut().push(h.id);
Ok(Value::Void)
} else {
Err("emit(extern)".into())
}
});
i.exec("fn step(handle) {\n emit(handle)\n return handle\n}").unwrap();
for id in 0..3u64 {
let h = Value::Extern(ExternHandle { kind: "node".into(), id });
i.call("step", &[h]).unwrap();
}
assert_eq!(*scene_log.borrow(), vec![0, 1, 2]);
}