use pty::run_with_pty;
use std::os::unix::process::CommandExt as _;
use std::path::Path;
use std::process::Command;
use std::process::Stdio;
mod pty;
const BIN: &str = env!("CARGO_BIN_EXE_yash3");
const TMPDIR: &str = env!("CARGO_TARGET_TMPDIR");
unsafe fn run_with_preexec<F>(name: &str, pre_exec: F)
where
F: FnMut() -> std::io::Result<()> + Send + Sync + 'static,
{
let mut log_file = Path::new(TMPDIR).join(name);
log_file.set_extension("log");
let mut command = Command::new("sh");
command
.env("TMPDIR", TMPDIR)
.current_dir("tests/scripted_test")
.stdin(Stdio::null())
.arg("./run-test.sh")
.arg(BIN)
.arg(name)
.arg(&log_file);
unsafe {
command.pre_exec(pre_exec);
}
let result = command.output().unwrap();
assert!(result.status.success(), "{result:?}");
let log = std::fs::read_to_string(&log_file).unwrap();
let failures = failures(&log);
assert!(failures.is_empty(), "{failures}");
}
fn run(name: &str) {
unsafe { run_with_preexec(name, || Ok(())) }
}
fn failures(log: &str) -> String {
let mut lines = log.lines();
let mut test_case = Vec::new();
let mut result = String::new();
while let Some(start) = lines.find(|line| line.starts_with("%%% START: ")) {
test_case.clear();
test_case.push(start);
for line in lines.by_ref() {
if line.starts_with("%%% OK[") || line.starts_with("%%% SKIPPED: ") {
break;
} else if line.starts_with("%%% ERROR[") {
test_case.push(line);
for line in test_case.drain(..) {
result.push_str(line);
result.push('\n');
}
result.push('\n');
break;
} else {
test_case.push(line);
}
}
}
result
}
#[test]
fn alias() {
run("alias-p.sh")
}
#[test]
fn alias_ex() {
run("alias-y.sh")
}
#[test]
fn and_or_list() {
run("andor-p.sh")
}
#[test]
fn arithmetic_expansion() {
run("arith-p.sh")
}
#[test]
fn arithmetic_expansion_ex() {
run("arith-y.sh")
}
#[test]
fn asynchronous_list() {
run("async-p.sh")
}
#[test]
fn bg_builtin() {
run_with_pty("bg-p.sh")
}
#[test]
fn bracket_ex() {
run("bracket-y.sh")
}
#[test]
fn break_builtin() {
run("break-p.sh")
}
#[test]
fn builtins() {
run("builtins-p.sh")
}
#[test]
fn case_command() {
run("case-p.sh")
}
#[test]
fn case_command_ex() {
run("case-y.sh");
}
#[test]
fn cd_builtin() {
run("cd-p.sh")
}
#[test]
fn cd_builtin_ex() {
run("cd-y.sh");
}
#[test]
fn command_builtin() {
run("command-p.sh")
}
#[test]
fn command_builtin_ex() {
run("command-y.sh")
}
#[test]
fn command_substitution() {
run("cmdsub-p.sh")
}
#[test]
fn comment() {
run("comment-p.sh")
}
#[test]
fn continue_builtin() {
run("continue-p.sh")
}
#[test]
fn declaration_utilities() {
run("declutil-p.sh")
}
#[test]
fn declaration_utilities_ex() {
run("declutil-y.sh")
}
#[test]
fn errexit_option() {
run("errexit-p.sh")
}
#[test]
fn error_consequences() {
run("error-p.sh")
}
#[test]
fn error_consequences_ex() {
run("error-y.sh")
}
#[test]
fn eval_builtin() {
run("eval-p.sh")
}
#[test]
fn exec_builtin() {
run("exec-p.sh")
}
#[test]
fn exit_builtin() {
run("exit-p.sh")
}
#[test]
fn export_builtin() {
run("export-p.sh")
}
#[test]
fn export_builtin_ex() {
run("export-y.sh")
}
#[test]
fn false_builtin() {
run("false-p.sh")
}
#[test]
fn fg_builtin() {
run_with_pty("fg-p.sh")
}
#[test]
fn fnmatch() {
run("fnmatch-p.sh")
}
#[test]
fn field_splitting() {
run("fsplit-p.sh")
}
#[test]
fn for_loop() {
run("for-p.sh")
}
#[test]
fn for_loop_ex() {
run("for-y.sh");
}
#[test]
fn function() {
run("function-p.sh")
}
#[test]
fn function_ex() {
run("function-y.sh");
}
#[test]
fn getopts_builtin() {
run("getopts-p.sh")
}
#[test]
fn getopts_builtin_ex() {
run("getopts-y.sh");
}
#[test]
fn grouping() {
run("grouping-p.sh")
}
#[test]
fn grouping_ex() {
run("grouping-y.sh")
}
#[test]
fn if_command() {
run("if-p.sh")
}
#[test]
fn input() {
run("input-p.sh")
}
#[test]
fn intr() {
run_with_pty("intr-y.sh")
}
#[test]
fn job_control() {
run_with_pty("job-p.sh")
}
#[test]
fn job_control_ex() {
run_with_pty("job-y.sh")
}
#[test]
fn kill_builtin_1() {
run("kill1-p.sh")
}
#[test]
fn kill_builtin_2() {
run("kill2-p.sh")
}
#[test]
fn kill_builtin_3() {
run("kill3-p.sh")
}
#[test]
fn kill_builtin_4() {
run_with_pty("kill4-p.sh")
}
#[test]
fn lineno() {
run("lineno-p.sh")
}
#[test]
fn nop_builtins() {
run("nop-p.sh")
}
#[test]
fn options() {
run("option-p.sh")
}
#[test]
fn options_ex() {
run("option-y.sh")
}
#[test]
fn parameter_expansion() {
run("param-p.sh")
}
#[test]
fn parameter_expansion_ex() {
run("param-y.sh")
}
#[test]
fn pathname_expansion() {
run("path-p.sh")
}
#[test]
fn pathname_expansion_ex() {
run("path-y.sh");
}
#[test]
fn pipeline() {
run("pipeline-p.sh")
}
#[test]
fn ppid_variable() {
run("ppid-p.sh")
}
#[test]
fn quotation() {
run("quote-p.sh")
}
#[test]
fn quotation_ex() {
run("quote-y.sh");
}
#[test]
fn read_builtin() {
run("read-p.sh")
}
#[test]
fn read_builtin_ex() {
run("read-y.sh");
}
#[test]
fn readonly_builtin() {
run("readonly-p.sh")
}
#[test]
fn readonly_builtin_ex() {
run("readonly-y.sh");
}
#[test]
fn redirection() {
run("redir-p.sh")
}
#[test]
fn redirection_ex() {
run("redir-y.sh")
}
#[test]
fn return_builtin() {
run("return-p.sh")
}
#[test]
fn set_builtin() {
run("set-p.sh")
}
#[test]
fn shift_builtin() {
run("shift-p.sh")
}
#[test]
fn simple_command() {
run("simple-p.sh")
}
#[test]
fn simple_command_ex() {
run("simple-y.sh")
}
#[test]
fn source_builtin() {
run("source-p.sh")
}
#[test]
fn startup() {
run("startup-p.sh")
}
#[test]
fn startup_ex() {
run("startup-y.sh")
}
#[test]
fn tilde_expansion() {
run("tilde-p.sh")
}
#[test]
fn trap_builtin() {
run("trap-p.sh")
}
#[test]
fn trap_ex() {
run("trap-y.sh");
}
#[test]
fn trap_ex_2() {
run_with_pty("trap2-y.sh")
}
#[test]
fn true_builtin() {
run("true-p.sh")
}
#[test]
fn type_builtin() {
run("type-y.sh");
}
#[test]
fn typeset_builtin() {
run("typeset-y.sh")
}
#[test]
fn ulimit_builtin() {
run("ulimit-y.sh")
}
#[test]
fn umask_builtin() {
run("umask-p.sh")
}
#[test]
fn unset_builtin() {
run("unset-p.sh")
}
#[test]
fn until_loop() {
run("until-p.sh")
}
#[test]
fn wait_builtin() {
run_with_pty("wait-p.sh")
}
#[test]
fn while_loop() {
run("while-p.sh")
}