use crate::{Result, prelude::*};
pub fn make_module() -> KMap {
let result = KMap::with_type("core.test");
result.add_fn("assert", |ctx| {
for value in ctx.args().iter() {
match value {
KValue::Bool(b) => {
if !b {
return runtime_error!("assertion failed");
}
}
unexpected => return unexpected_type("Bool", unexpected),
}
}
Ok(KValue::Null)
});
result.add_fn("assert_eq", |ctx| match ctx.args() {
[a, b] => {
let a = a.clone();
let b = b.clone();
let result = ctx.vm.run_binary_op(BinaryOp::Equal, a.clone(), b.clone());
match result {
Ok(KValue::Bool(true)) => Ok(KValue::Null),
Ok(KValue::Bool(false)) => {
runtime_error!(
"assertion failed, '{}' is not equal to '{}'",
ctx.vm.value_to_string(&a)?,
ctx.vm.value_to_string(&b)?,
)
}
Ok(unexpected) => unexpected_type("Bool from equality comparison", &unexpected),
Err(e) => Err(e),
}
}
unexpected => unexpected_args("|Any, Any|", unexpected),
});
result.add_fn("assert_ne", |ctx| match ctx.args() {
[a, b] => {
let a = a.clone();
let b = b.clone();
let result = ctx
.vm
.run_binary_op(BinaryOp::NotEqual, a.clone(), b.clone());
match result {
Ok(KValue::Bool(true)) => Ok(KValue::Null),
Ok(KValue::Bool(false)) => {
runtime_error!(
"assertion failed, '{}' should not be equal to '{}'",
ctx.vm.value_to_string(&a)?,
ctx.vm.value_to_string(&b)?
)
}
Ok(unexpected) => unexpected_type("Bool from equality comparison", &unexpected),
Err(e) => Err(e),
}
}
unexpected => unexpected_args("|Any, Any|", unexpected),
});
result.add_fn("assert_near", |ctx| match ctx.args() {
[KValue::Number(a), KValue::Number(b)] => number_near(*a, *b, 1.0e-12),
[
KValue::Number(a),
KValue::Number(b),
KValue::Number(allowed_diff),
] => number_near(*a, *b, allowed_diff.into()),
unexpected => unexpected_args("|Number, Number, Number|", unexpected),
});
result.add_fn("run_tests", |ctx| match ctx.args() {
[KValue::Map(tests)] => {
let tests = tests.clone();
ctx.vm.run_tests(tests)
}
unexpected => unexpected_args("|Map|", unexpected),
});
result
}
fn f64_near(a: f64, b: f64, allowed_diff: f64) -> bool {
(a - b).abs() <= allowed_diff
}
fn number_near(a: KNumber, b: KNumber, allowed_diff: f64) -> Result<KValue> {
if f64_near(a.into(), b.into(), allowed_diff) {
Ok(KValue::Null)
} else {
runtime_error!(
"assertion failed, '{a}' and '{b}' are not within {allowed_diff} of each other"
)
}
}