test-mumu 0.1.8

Test suite plugin for the Lava language
Documentation
use mumu::parser::types::{Value, FunctionValue};
use std::fs;
use std::path::{Path};

/// Accepts an array of folders to scan for test files (.mu), defaulting to ["./tests"].
/// Returns full relative file paths as strings.
pub fn runner_list_in_folders(folders: &[String]) -> Result<Vec<String>, String> {
    let mut all_names = Vec::new();
    for folder in folders {
        let folder_path = Path::new(folder);
        let mut names: Vec<String> = match fs::read_dir(folder_path) {
            Ok(rd) => rd.filter_map(|entry_res| {
                let entry = entry_res.ok()?;
                let fname = entry.file_name().to_string_lossy().into_owned();
                if fname.starts_with('.') || !fname.ends_with(".mu") {
                    return None;
                }
                // Full relative path for each test file
                Some(format!("{}/{}", folder.trim_end_matches('/'), fname))
            }).collect(),
            Err(e) => return Err(format!("test:list => cannot read folder '{}': {}", folder, e)),
        };
        all_names.append(&mut names);
    }
    all_names.sort();
    Ok(all_names)
}

pub fn runner_list_bridge(_interp: &mut mumu::parser::interpreter::Interpreter, args: Vec<Value>) -> Result<Value, String> {
    if !args.is_empty() {
        return Err(format!("test:list => expected 0 args, got {}", args.len()));
    }
    // By default, scan ./tests
    let files = runner_list_in_folders(&["./tests".to_string()])?;
    Ok(Value::StrArray(files))
}

// Used by test:all to support folders option
pub fn runner_list_for_folders_option(folders_opt: Option<&Value>) -> Result<Vec<String>, String> {
    if let Some(Value::StrArray(folders)) = folders_opt {
        if !folders.is_empty() {
            return runner_list_in_folders(folders);
        }
    }
    runner_list_in_folders(&["./tests".to_string()])
}

pub const HRULE: &str = "\x1b[1;30m----------------------------------\x1b[0m";
pub const HRULE_PLAIN: &str = "----------------------------------";

use arboard::Clipboard;

pub fn copy_to_clipboard(s: &str) {
    if let Ok(mut clipboard) = Clipboard::new() {
        let _ = clipboard.set_text(s);
    }
}

pub trait CloneFunction {
    fn clone_function(&self) -> Option<Box<FunctionValue>>;
}
impl CloneFunction for Value {
    fn clone_function(&self) -> Option<Box<FunctionValue>> {
        if let Value::Function(fb) = self {
            Some(Box::new((**fb).clone()))
        } else {
            None
        }
    }
}