use std::sync::{Arc, Mutex};
use expy::{Context, EvalError, Value, eval_in};
#[test]
fn function_constant() {
let mut ctx = Context::new();
ctx.set("foo", |_: &mut Context, _: &_| Ok(Value::Integer(42)));
assert_eq!(eval_in(&mut ctx, "foo()").unwrap().unwrap_integer(), 42);
}
#[test]
fn function_pure() {
let mut ctx = Context::new();
ctx.set("foo", |_: &mut Context, args: &[Value]| {
let Some(&Value::Integer(x)) = args.get(0) else {
return Err(EvalError::custom("wrong arguments"));
};
Ok(Value::Integer(x * 2 + 1))
});
assert_eq!(eval_in(&mut ctx, "foo(3)").unwrap().unwrap_integer(), 7);
assert_eq!(eval_in(&mut ctx, "foo(11)").unwrap().unwrap_integer(), 23);
}
#[test]
fn function_pure_external() {
fn foo(_: &mut Context, args: &[Value]) -> Result<Value, EvalError> {
let Some(&Value::Integer(x)) = args.get(0) else {
return Err(EvalError::custom("wrong arguments"));
};
Ok(Value::Integer(x * 2 + 1))
}
let mut ctx = Context::new();
ctx.set("foo", foo);
assert_eq!(eval_in(&mut ctx, "foo(3)").unwrap().unwrap_integer(), 7);
assert_eq!(eval_in(&mut ctx, "foo(11)").unwrap().unwrap_integer(), 23);
}
#[test]
fn function_stateful() {
let mut ctx = Context::new();
ctx.set("inc", |ctx: &mut Context, _: &_| {
let mut c = ctx.get("counter").and_then(Value::as_integer).copied().unwrap_or_default();
c += 1;
ctx.set("counter", c);
Ok(Value::Integer(c))
});
for c in 1..=100 {
assert_eq!(eval_in(&mut ctx, "inc()").unwrap().unwrap_integer(), c);
}
}
#[test]
fn function_local() {
let mut ctx = Context::new();
let counter = Arc::new(Mutex::new(0));
ctx.set("inc", {
let counter = counter.clone();
move |_: &mut Context, _: &_| {
let mut c = counter.lock().unwrap();
*c += 1;
Ok(Value::Integer(*c))
}
});
for c in 1..=100 {
assert_eq!(eval_in(&mut ctx, "inc()").unwrap().unwrap_integer(), c);
}
}