flesh/tests/test_func.rs

308 lines
11 KiB
Rust
Raw Normal View History

mod func_tests {
use relish::ast::lex;
use relish::ast::{SymTable, Type, UserFn};
use relish::ast::{Args, Symbol, Ctr, Seg, ValueType};
#[test]
fn decl_and_call_internal_func() {
let mut syms = SymTable::new();
let test_internal_func: Symbol = Symbol {
2022-01-16 22:02:40 -08:00
name: String::from("test_func_in"),
conditional_branches: false,
args: Args::Strict(vec![Type::Bool]),
value: ValueType::Internal(Box::new(
|a: &Seg, _: &mut SymTable| -> Ctr {
let inner = a;
let mut is_bool = false;
if let Ctr::Bool(_) = *inner.car {
is_bool = true;
}
Ctr::Bool(is_bool)
2022-01-16 22:02:40 -08:00
},
)),
};
let args = Seg::from(
Box::new(Ctr::Bool(true)),
Box::new(Ctr::None)
);
syms.insert(String::from("test_func_in"), test_internal_func);
if let Ok(ret) = syms.call_symbol(&"test_func_in".to_string(), &args, true) {
match *ret {
Ctr::Bool(b) => assert!(b),
_ => {
print!("invalid return from func!");
assert!(false);
}
}
} else {
print!("call to function failed!");
assert!(false);
}
}
2021-06-06 10:24:19 -07:00
#[test]
fn decl_and_call_external_func_singlet() {
let mut syms = SymTable::new();
match lex(&"input".to_string()) {
2021-11-02 20:12:14 -07:00
Err(e) => panic!("{}", e),
2021-07-19 23:59:03 -07:00
Ok(finner) => {
let test_external_func: Symbol = Symbol {
2021-07-19 23:59:03 -07:00
name: String::from("echo"),
conditional_branches: false,
2021-07-19 23:59:03 -07:00
args: Args::Lazy(1),
value: ValueType::FuncForm(UserFn{
2022-01-16 22:02:40 -08:00
arg_syms: vec!["input".to_string()],
ast: finner,
}),
2021-07-19 23:59:03 -07:00
};
2021-06-06 10:24:19 -07:00
let args = Seg::from(
Box::new(Ctr::String("test".to_string())),
Box::new(Ctr::None)
);
syms.insert(String::from("test_func_in"), test_external_func);
2021-06-06 10:24:19 -07:00
match syms.call_symbol(&"test_func_in".to_string(), &args, true) {
Ok(ret) => match *ret {
2022-01-16 22:02:40 -08:00
Ctr::String(b) => assert!(b == "test"),
_ => {
print!("Invalid return from func. Got {:?}\n", ret);
assert!(false);
2021-07-19 23:59:03 -07:00
}
},
Err(e) => {
print!("Call to function failed: {}\n", e);
2021-06-06 10:24:19 -07:00
assert!(false);
}
}
}
}
}
#[test]
2021-07-19 23:59:03 -07:00
fn decl_and_call_external_func_multi_body() {
let mut syms = SymTable::new();
match lex(&"(input input)".to_string()) {
2021-11-02 20:12:14 -07:00
Err(e) => panic!("{}", e),
2021-07-19 23:59:03 -07:00
Ok(finner) => {
let test_external_func: Symbol = Symbol{
2021-07-19 23:59:03 -07:00
name: String::from("echo_2"),
conditional_branches: false,
2021-07-19 23:59:03 -07:00
args: Args::Lazy(1),
value: ValueType::FuncForm(UserFn{
2022-01-16 22:02:40 -08:00
arg_syms: vec!["input".to_string()],
ast: finner,
}),
2021-07-19 23:59:03 -07:00
};
2021-06-06 10:24:19 -07:00
let args = Seg::from(
Box::new(Ctr::String("test".to_string())),
Box::new(Ctr::None)
);
syms.insert(String::from("echo_2"), test_external_func);
match syms.call_symbol(&"echo_2".to_string(), &args, true) {
Ok(ret) => assert_eq!(ret.to_string(), "'test'"),
2021-07-19 23:59:03 -07:00
Err(e) => {
print!("Call to function failed: {}\n", e);
2021-06-06 10:24:19 -07:00
assert!(false);
}
}
}
}
}
#[test]
fn decl_and_call_func_with_nested_call() {
let mut syms = SymTable::new();
let inner_func: Symbol = Symbol {
2021-06-06 10:24:19 -07:00
name: String::from("test_inner"),
conditional_branches: false,
2021-06-06 10:24:19 -07:00
args: Args::Strict(vec![Type::Bool]),
value: ValueType::Internal(Box::new(
|a: &Seg, _: &mut SymTable| -> Ctr {
let inner = a;
if let Ctr::Bool(b) = *inner.car {
if b {
2021-06-06 10:24:19 -07:00
Ctr::String("test".to_string())
} else {
Ctr::None
}
} else {
Ctr::None
}
2022-01-16 22:02:40 -08:00
},
)),
2021-06-06 10:24:19 -07:00
};
match lex(&"((test_inner true))".to_string()) {
2021-11-02 20:12:14 -07:00
Err(e) => panic!("{}", e),
2021-07-19 23:59:03 -07:00
Ok(finner) => {
let outer_func: Symbol = Symbol {
2021-07-19 23:59:03 -07:00
name: String::from("test_outer"),
conditional_branches: false,
2021-07-19 23:59:03 -07:00
args: Args::Lazy(1),
value: ValueType::FuncForm(UserFn{
2022-01-16 22:02:40 -08:00
arg_syms: vec!["input".to_string()],
ast: finner,
}),
2021-07-19 23:59:03 -07:00
};
2021-06-06 10:24:19 -07:00
let args = Seg::from(
Box::new(Ctr::Bool(true)),
Box::new(Ctr::None)
);
2021-06-06 10:24:19 -07:00
syms.insert(String::from("test_inner"), inner_func);
syms.insert(String::from("test_outer"), outer_func);
2021-06-06 10:24:19 -07:00
match syms.call_symbol(&"test_outer".to_string(), &args, true) {
Ok(ret) => match *ret {
2022-01-16 22:02:40 -08:00
Ctr::String(b) => assert!(b == "test"),
_ => {
print!("Invalid return from func. Got {:?}\n", ret);
assert!(false);
2021-07-19 23:59:03 -07:00
}
},
Err(e) => {
print!("Call to function failed: {}\n", e);
2021-06-06 10:24:19 -07:00
assert!(false);
}
}
}
}
}
#[test]
fn arg_type_mismatch() {
let mut syms = SymTable::new();
let test_internal_func: Symbol = Symbol {
name: String::from("test_func_in"),
conditional_branches: false,
args: Args::Strict(vec![Type::Bool]),
value: ValueType::Internal(Box::new(
|a: &Seg, _: &mut SymTable| -> Ctr {
let inner = a;
let mut is_bool = false;
if let Ctr::Bool(_) = *inner.car {
is_bool = true;
}
Ctr::Bool(is_bool)
},
)),
};
let args = Seg::from(
Box::new(Ctr::Integer(1)),
Box::new(Ctr::None)
);
syms.insert(String::from("test_func_in"), test_internal_func);
if let Err(s) = syms.call_symbol(&"test_func_in".to_string(), &args, true) {
assert_eq!(s, "failure to call test_func_in: arg 1 expected to be bool");
} else {
print!("call to function succeeded (shouldnt have)");
assert!(false);
}
}
#[test]
fn too_many_args() {
let mut syms = SymTable::new();
match lex(&"(input)".to_string()) {
Err(e) => panic!("{}", e),
Ok(finner) => {
let test_external_func: Symbol = Symbol {
name: String::from("echo"),
conditional_branches: false,
args: Args::Lazy(1),
value: ValueType::FuncForm(UserFn{
arg_syms: vec!["input".to_string()],
ast: finner,
}),
};
let args = Seg::from(
Box::new(Ctr::String("test".to_string())),
Box::new(Ctr::Seg(Seg::from_mono(Box::new(Ctr::Integer(1)))))
);
syms.insert(String::from("test_func_in"), test_external_func);
if let Err(s) = syms.call_symbol(&"test_func_in".to_string(), &args, true) {
assert_eq!(s, "failure to call echo: expected 1 args. Got 2.");
} else {
print!("call to function succeeded (shouldnt have)");
assert!(false);
}
}
}
}
#[test]
fn too_few_args() {
let mut syms = SymTable::new();
match lex(&"(input)".to_string()) {
Err(e) => panic!("{}", e),
Ok(finner) => {
let test_external_func: Symbol = Symbol {
name: String::from("echo"),
conditional_branches: false,
args: Args::Lazy(1),
value: ValueType::FuncForm(UserFn{
arg_syms: vec!["input".to_string()],
ast: finner,
}),
};
let args = Seg::new();
syms.insert(String::from("test_func_in"), test_external_func);
if let Err(s) = syms.call_symbol(&"test_func_in".to_string(), &args, true) {
assert_eq!(s, "failure to call echo: expected 1 args. Got 0.");
} else {
print!("call to function succeeded (shouldnt have)");
assert!(false);
}
}
}
}
#[test]
fn arg_cant_eval() {
let mut syms = SymTable::new();
let test_internal_func: Symbol = Symbol {
name: String::from("test_func_in"),
conditional_branches: false,
args: Args::Strict(vec![Type::Bool]),
value: ValueType::Internal(Box::new(
|a: &Seg, _: &mut SymTable| -> Ctr {
let inner = a;
let mut is_bool = false;
if let Ctr::Bool(_) = *inner.car {
is_bool = true;
}
Ctr::Bool(is_bool)
},
)),
};
let args = Seg::from(
Box::new(Ctr::Symbol("undefined-symbol".to_string())),
Box::new(Ctr::None)
);
syms.insert(String::from("test_func_in"), test_internal_func);
if let Err(s) = syms.call_symbol(&"test_func_in".to_string(), &args, true) {
assert_eq!(s, "error in call to undefined-symbol: undefined symbol: undefined-symbol");
} else {
print!("call to function succeeded (shouldnt have)");
assert!(false);
}
}
}