use crate::value::*;
use std::fs::File;
use std::io::{Read, Write}; use std::process::{Command, Stdio};
pub(crate) fn identifier_is_consumable(ident: &str) -> bool {
let ch = ident.chars().next().unwrap();
ch.is_uppercase() || ch == '_'
}
#[allow(dead_code)]
pub(crate) fn testcase(code: &str) {
let (filename, code) = match File::open(code) {
Ok(mut file) => {
let mut content = String::new();
file.read_to_string(&mut content).unwrap();
(code, content)
}
Err(_) => ("--", code.to_owned()),
};
let repl_mode = code.starts_with("#testmode:repl\n");
if let Some((code, data)) = code.split_once("#---\n") {
let mut lines = code.matches("\n").count() + 1;
let program = if cfg!(test) {
"target/debug/tokay".to_string()
} else {
std::env::current_exe()
.unwrap()
.to_str()
.unwrap()
.to_owned()
};
let mut cmd = Command::new(&program);
if repl_mode {
cmd.arg("-q");
cmd.env("TOKAY_HISTORY_SAVE", "0");
cmd.stdin(Stdio::piped());
} else {
cmd.arg("-e");
cmd.arg(code);
}
let mut result = data;
let tmp;
if let Some((input, output)) = data.split_once("#---\n") {
let input: Vec<&str> = input
.split("\n")
.map(|line| line.trim_start())
.filter(|line| line.starts_with("#"))
.map(|line| &line[1..])
.collect();
tmp = input.join("\n");
lines += tmp.matches("\n").count() + 1 + 1;
cmd.arg("--").arg(&tmp);
result = output;
}
let mut process = cmd
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.expect(&format!(
"{} failed to run using {}; You need to run `cargo build` first!",
filename, &program
));
if repl_mode {
process
.stdin
.as_mut()
.unwrap()
.write(code.as_bytes())
.unwrap();
}
let output = process.wait_with_output().unwrap();
let out = String::from_utf8(output.stdout).expect("stdout is not UTF-8");
let err = String::from_utf8(output.stderr).expect("stderr is not UTF-8");
let mut out: Vec<String> = if out.is_empty() {
Vec::new()
} else {
out.trim_end()
.split("\n")
.map(|line| line.to_string())
.collect()
};
let mut err: Vec<String> = if err.is_empty() {
Vec::new()
} else {
err.trim_end()
.split("\n")
.map(|line| line.to_string())
.collect()
};
for (row, line) in result.split("\n").into_iter().enumerate() {
let line = line.trim_start();
if line.is_empty() {
continue;
}
assert!(
line.starts_with("#"),
"{}:{} Result must start with a #-comment, got {:?}",
filename,
lines + row + 1,
line
);
if line.starts_with("#ERR:") {
let exp = &line[5..];
let line = err
.get(0)
.expect("Expecting stderr but nothing was emitted");
if exp != "SKIP" {
assert_eq!(
line,
exp,
"{}:{} stderr expects {:?} but got {:?}",
filename,
lines + row + 1,
exp,
line
);
}
err.remove(0);
} else {
let exp = &line[1..];
let line = out
.get(0)
.expect("Expecting stdout but nothing was emitted");
if exp != "SKIP" {
assert_eq!(
line,
exp,
"{}:{} stdout expects {:?} but got {:?}",
filename,
lines + row + 1,
exp,
line
);
}
out.remove(0);
}
}
assert!(
out.is_empty(),
"{} some output not consumed: {:#?}",
filename,
out
);
assert!(
err.is_empty(),
"{} Some errors not consumed: {:#?}",
filename,
err
);
} else {
panic!(
"{} invalid testcase, at least one '#---' delimiter required",
filename
)
}
}