mumu-test 0.1.2

Test suite plugin for the Lava language
Documentation
// test/src/file_asserts.rs

use crate::mark_fail;
use mumu::{
    parser::interpreter::Interpreter,
    parser::types::Value,
};

use std::{
    fs,
    sync::{Arc, Mutex},
};

/// file_contents_equal => fail the test if file contents differ or if the file cannot be read.
fn file_contents_equal_bridge_fn(
    _interp: &mut Interpreter,
    mut args: Vec<Value>
) -> Result<Value, String> {
    if args.len() != 2 {
        return Err(format!(
            "file_contents_equal => expected 2 arguments => (filename, string), got {}",
            args.len()
        ));
    }

    // 1) Filename
    let filename_val = args.remove(0);
    let filename_str = match filename_val {
        Value::SingleString(s) => s,
        Value::StrArray(a) if a.len() == 1 => a[0].clone(),
        other => {
            mark_fail(&format!(
                "file_contents_equal => first argument must be a single string (filename), got {:?}",
                other
            ));
            return Ok(Value::Bool(true));
        }
    };

    // 2) Expected content
    let expected_val = args.remove(0);
    let expected_str = match expected_val {
        Value::SingleString(s) => s,
        Value::StrArray(a) if a.len() == 1 => a[0].clone(),
        other => {
            mark_fail(&format!(
                "file_contents_equal => second argument must be single string, got {:?}",
                other
            ));
            return Ok(Value::Bool(true));
        }
    };

    // 3) Try reading the file
    match fs::read_to_string(&filename_str) {
        Ok(file_str) => {
            if file_str != expected_str {
                // Show your new, single-line “fail:” format:
                mark_fail(&format!(
                    "file_contents_equal fail: file='{}', actual=SingleString({}), expected=SingleString({})",
                    filename_str,
                    file_str,
                    expected_str
                ));
            }
        }
        Err(e) => {
            mark_fail(&format!(
                "file_contents_equal => cannot read '{}': {}",
                filename_str,
                e
            ));
        }
    }

    Ok(Value::Bool(true))
}

/// file_contents_not_equal => fail the test if file contents match or if file cannot be read.
fn file_contents_not_equal_bridge_fn(
    _interp: &mut Interpreter,
    mut args: Vec<Value>
) -> Result<Value, String> {
    if args.len() != 2 {
        return Err(format!(
            "file_contents_not_equal => expected 2 arguments => (filename, string), got {}",
            args.len()
        ));
    }

    // 1) Filename
    let filename_val = args.remove(0);
    let filename_str = match filename_val {
        Value::SingleString(s) => s,
        Value::StrArray(a) if a.len() == 1 => a[0].clone(),
        other => {
            mark_fail(&format!(
                "file_contents_not_equal => first argument must be single string (filename), got {:?}",
                other
            ));
            return Ok(Value::Bool(true));
        }
    };

    // 2) Compare content
    let compare_val = args.remove(0);
    let compare_str = match compare_val {
        Value::SingleString(s) => s,
        Value::StrArray(a) if a.len() == 1 => a[0].clone(),
        other => {
            mark_fail(&format!(
                "file_contents_not_equal => second argument must be single string, got {:?}",
                other
            ));
            return Ok(Value::Bool(true));
        }
    };

    // 3) Try reading the file
    match fs::read_to_string(&filename_str) {
        Ok(file_str) => {
            if file_str == compare_str {
                mark_fail(&format!(
                    "file_contents_not_equal fail: file='{}', actual=SingleString({}), not_expected=SingleString({})",
                    filename_str,
                    file_str,
                    compare_str
                ));
            }
        }
        Err(e) => {
            mark_fail(&format!(
                "file_contents_not_equal => cannot read '{}': {}",
                filename_str, e
            ));
        }
    }

    Ok(Value::Bool(true))
}

/// file_contents_length_equal => fail the test if the file's length
/// does not equal the given integer or if the file cannot be read.
fn file_contents_length_equal_bridge_fn(
    _interp: &mut Interpreter,
    mut args: Vec<Value>
) -> Result<Value, String> {
    if args.len() != 2 {
        return Err(format!(
            "file_contents_length_equal => expected 2 arguments => (filename, length), got {}",
            args.len()
        ));
    }

    // 1) Filename
    let filename_val = args.remove(0);
    let filename_str = match filename_val {
        Value::SingleString(s) => s,
        Value::StrArray(a) if a.len() == 1 => a[0].clone(),
        other => {
            mark_fail(&format!(
                "file_contents_length_equal => first argument must be single string (filename), got {:?}",
                other
            ));
            return Ok(Value::Bool(true));
        }
    };

    // 2) Expected length
    let length_val = args.remove(0);
    let expected_len = match length_val {
        Value::Int(n) if n >= 0 => n as usize,
        Value::IntArray(a) if a.len() == 1 && a[0] >= 0 => a[0] as usize,
        other => {
            mark_fail(&format!(
                "file_contents_length_equal => second argument must be a non-negative int, got {:?}",
                other
            ));
            return Ok(Value::Bool(true));
        }
    };

    // 3) Try reading the file
    match fs::read_to_string(&filename_str) {
        Ok(file_str) => {
            let actual_len = file_str.len();
            if actual_len != expected_len {
                mark_fail(&format!(
                    "file_contents_length_equal => file='{}' => length mismatch => actual={}, expected={}",
                    filename_str,
                    actual_len,
                    expected_len
                ));
            }
        }
        Err(e) => {
            mark_fail(&format!(
                "file_contents_length_equal => cannot read '{}': {}",
                filename_str,
                e
            ));
        }
    }

    Ok(Value::Bool(true))
}

/// A helper to register bridging functions in the interpreter:
///   - file_contents_equal
///   - file_contents_not_equal
///   - file_contents_length_equal
pub fn register_file_asserts(interp: &mut Interpreter) {
    use mumu::parser::interpreter::DynamicFn;
    use mumu::parser::types::FunctionValue;

    // file_contents_equal
    let eq_fn: DynamicFn = Arc::new(Mutex::new(file_contents_equal_bridge_fn));
    interp.register_dynamic_function("file_contents_equal", eq_fn);
    interp.set_variable(
        "file_contents_equal",
        Value::Function(Box::new(FunctionValue::Named("file_contents_equal".to_string())))
    );

    // file_contents_not_equal
    let neq_fn: DynamicFn = Arc::new(Mutex::new(file_contents_not_equal_bridge_fn));
    interp.register_dynamic_function("file_contents_not_equal", neq_fn);
    interp.set_variable(
        "file_contents_not_equal",
        Value::Function(Box::new(FunctionValue::Named("file_contents_not_equal".to_string())))
    );

    // file_contents_length_equal
    let len_eq_fn: DynamicFn = Arc::new(Mutex::new(file_contents_length_equal_bridge_fn));
    interp.register_dynamic_function("file_contents_length_equal", len_eq_fn);
    interp.set_variable(
        "file_contents_length_equal",
        Value::Function(Box::new(FunctionValue::Named("file_contents_length_equal".to_string())))
    );
}