test-mumu 0.1.8

Test suite plugin for the Lava language
Documentation
// src/expect_error.rs
use crate::suite::mark_fail;
use mumu::{
    parser::interpreter::Interpreter,
    parser::types::{FunctionValue, Value},
};

/// Invoke **any** function value (Named or inline lambda).
/// If a Named function is not a dynamic one, we fallback to the general apply().
fn call_any_function(
    interp: &mut Interpreter,
    func: Box<FunctionValue>,
    args: Vec<Value>,
) -> Result<Value, String> {
    match *func {
        FunctionValue::Named(ref name) => {
            if let Some(df) = interp.get_dynamic_function(name) {
                (df.lock().unwrap())(interp, args)
            } else {
                // Fallback to generic apply for user-defined functions
                mumu::parser::interpreter::apply::apply_function_value(
                    interp,
                    Box::new(FunctionValue::Named(name.clone())),
                    args,
                )
            }
        }
        other => {
            mumu::parser::interpreter::apply::apply_function_value(
                interp,
                Box::new(other),
                args,
            )
        }
    }
}

pub fn expect_error_bridge_fn(
    interp: &mut Interpreter,
    mut args: Vec<Value>,
) -> Result<Value, String> {
    if args.is_empty() || args.len() > 2 {
        return Err(format!(
            "test:expect_error => expected 1 or 2 args (function, optional string), got {}",
            args.len()
        ));
    }

    let user_fn_value = args.remove(0);
    let user_fn = match user_fn_value {
        Value::Function(fb) => fb,
        other => {
            mark_fail(&format!(
                "test:expect_error => first arg must be a function, got {:?}",
                other
            ));
            return Ok(Value::Bool(true));
        }
    };

    let mut expected_substring: Option<String> = None;
    if !args.is_empty() {
        let maybe_str = args.remove(0);
        match maybe_str {
            Value::SingleString(s) => expected_substring = Some(s),
            Value::StrArray(arr) if arr.len() == 1 => expected_substring = Some(arr[0].clone()),
            other => {
                mark_fail(&format!(
                    "test:expect_error => second arg must be a single string, got {:?}",
                    other
                ));
                return Ok(Value::Bool(true));
            }
        }
    }

    match call_any_function(interp, user_fn, vec![]) {
        Ok(_val) => {
            mark_fail("test:expect_error => function did NOT raise an error");
        }
        Err(e) => {
            if let Some(sub) = expected_substring {
                if !e.contains(&sub) {
                    mark_fail(&format!(
                        "test:expect_error => error found, but it does not contain {:?}. Full error => {}",
                        sub, e
                    ));
                }
            }
        }
    }

    Ok(Value::Bool(true))
}