use crate::suite::{TestEntry, FileReport, GLOBAL_SUITE, CURRENT_TEST_ARC};
use mumu::{
Interpreter,
Value,
parser::interpreter::apply_n_ary_function_value,
};
use std::sync::{Arc, Mutex};
use std::time::{SystemTime, UNIX_EPOCH};
use serde_json::to_string;
use std::thread;
use std::time::Duration;
pub fn describe_bridge_fn(interp: &mut Interpreter, mut args: Vec<Value>) -> Result<Value, String> {
if args.len() != 2 {
return Err(format!("describe => expected 2 args, got {}", args.len()));
}
let suite_name = match args.remove(0) {
Value::SingleString(s) => s,
Value::StrArray(a) if a.len() == 1 => a[0].clone(),
_ => return Err("describe => first arg must be single string".into()),
};
{
let mut gs = GLOBAL_SUITE.lock().unwrap();
gs.suite_name = Some(suite_name.clone());
gs.tests.clear();
}
let fn_val = match args.remove(0) {
Value::Function(fb) => fb,
_ => return Err("describe => second arg must be function".into()),
};
let ret = apply_n_ary_function_value(interp, fn_val.clone(), vec![])?;
if let Value::Function(f2) = ret {
let _ = apply_n_ary_function_value(interp, f2, vec![]);
}
loop {
let mut total_tasks = 0;
for poller_name in &["net:check_tasks", "sys:check_tasks", "process:check_tasks"] {
if let Some(dfn) = interp.get_dynamic_function(poller_name) {
if let Ok(val) = dfn.lock().unwrap()(interp, vec![]) {
if let Value::Int(n) = val {
total_tasks += n;
}
}
}
}
if total_tasks == 0 {
break;
}
thread::sleep(Duration::from_millis(30));
}
let report = {
let gs = GLOBAL_SUITE.lock().unwrap();
let mut out_tests = Vec::new();
for arc_test in &gs.tests {
let t = arc_test.lock().unwrap();
out_tests.push(t.clone());
}
FileReport {
suite: gs.suite_name.clone().unwrap_or_default(),
tests: out_tests,
}
};
let js = to_string(&report).map_err(|e| format!("describe => JSON err: {}", e))?;
println!("{}", js);
Ok(Value::Bool(true))
}
pub fn it_bridge_fn(interp: &mut Interpreter, mut args: Vec<Value>) -> Result<Value, String> {
if args.len() != 2 {
return Err(format!("it => expected 2 args, got {}", args.len()));
}
let test_name = match args.remove(0) {
Value::SingleString(s) => s,
Value::StrArray(a) if a.len()==1 => a[0].clone(),
_ => return Err("it => first arg must be single string".into()),
};
let fn_val = match args.remove(0) {
Value::Function(fb) => fb,
_ => return Err("it => second arg must be function".into()),
};
let start = current_time_micro();
let new_test = TestEntry {
name: test_name.clone(),
passed: true,
time_us: 0,
output: String::new(),
};
let arc_test = Arc::new(Mutex::new(new_test));
CURRENT_TEST_ARC.with(|cell| {
*cell.borrow_mut() = Some(arc_test.clone());
});
let ret = apply_n_ary_function_value(interp, fn_val.clone(), vec![])?;
if let Value::Function(f2) = ret {
let _ = apply_n_ary_function_value(interp, f2, vec![]);
}
let dur = current_time_micro() - start;
{
let mut lock_test = arc_test.lock().unwrap();
lock_test.time_us = dur;
}
{
let mut gs = GLOBAL_SUITE.lock().unwrap();
gs.tests.push(arc_test);
}
Ok(Value::Bool(true))
}
fn current_time_micro() -> i64 {
let now = SystemTime::now();
now.duration_since(UNIX_EPOCH).unwrap().as_micros() as i64
}