use std::collections::HashMap;
use anyhow::{anyhow, Result};
use rquickjs::{Context, Function, Persistent, Promise};
use tanoshi_vm::{
api::{BytesToString, Console, Fetch, Print},
vm::create_runtime,
};
use tokio::io::AsyncReadExt;
pub async fn test(filename: Option<String>) -> Result<()> {
let rt = create_runtime(".")?;
let ctx = Context::full(&rt)?;
let source = if let Some(filename) = filename {
tokio::fs::read_to_string(filename)
.await?
.as_bytes()
.to_vec()
} else {
let mut buf = vec![];
let mut stdin = tokio::io::stdin();
stdin.read_to_end(&mut buf).await?;
buf
};
let mut tests = HashMap::new();
ctx.with(|ctx| -> Result<_> {
let global = ctx.globals();
global.init_def::<Print>()?;
global.init_def::<Console>()?;
global.init_def::<Fetch>()?;
global.init_def::<BytesToString>()?;
let module = ctx.compile("run", source)?;
for entry in module.entries::<String, Function>() {
if let Ok((name, test)) = entry {
tests.insert(name, Persistent::save(ctx, test));
}
}
Ok(())
})?;
let test_len = tests.len();
eprintln!("running {} test", test_len);
let mut failures = HashMap::new();
for (name, test) in tests {
eprint!("test {} ... ", name);
let func: Promise<()> = ctx.with(|ctx| test.restore(ctx)?.call(()))?;
if let Err(e) = func.await {
eprint!("FAILED");
failures.insert(name.clone(), e.to_string());
} else {
eprint!("ok");
}
eprintln!("");
}
let failures_len = failures.len();
if failures_len > 0 {
eprintln!("---failures---");
}
for (name, failure) in failures {
eprintln!("{}", name);
eprintln!("\t{}", failure);
}
eprintln!(
"test result: {}. {} passed; {} failed",
if failures_len == 0 { "ok" } else { "FAILED" },
test_len - failures_len,
failures_len
);
if failures_len > 0 {
return Err(anyhow!("{}", failures_len));
}
Ok(())
}