use kernal_api::platform::process::{foreground_output, foreground_status};
use std::process::{Command, Stdio};
const PROBE: &str = "KERNAL_FOREGROUND_PROBE";
#[test]
fn child_probe() {
let Ok(mode) = std::env::var(PROBE) else {
return;
};
if mode == "exit-3" {
std::process::exit(3);
}
if mode == "speak" {
use std::io::Write as _;
let mut stdout = std::io::stdout();
let mut stderr = std::io::stderr();
stdout.write_all(b"to stdout\n").expect("write stdout");
stderr.write_all(b"to stderr\n").expect("write stderr");
stdout.flush().expect("flush stdout");
stderr.flush().expect("flush stderr");
std::process::exit(0);
}
let expected = std::path::PathBuf::from(mode);
let sentinel_seen = std::env::args().any(|argument| argument == "kernal-sentinel");
let working_directory_matches = std::env::current_dir()
.and_then(|directory| directory.canonicalize())
.map(|directory| directory == expected)
.unwrap_or(false);
std::process::exit(if sentinel_seen && working_directory_matches {
0
} else {
9
});
}
#[test]
fn the_command_s_own_exit_status_is_reported() {
let mut fails = probe();
fails.env(PROBE, "exit-3");
let mut plain = probe();
plain.env_remove(PROBE);
let success = foreground_status(&mut plain).expect("run the passing helper");
let failure = foreground_status(&mut fails).expect("run the failing helper");
assert!(success.success());
assert!(!failure.success());
assert_eq!(failure.code(), Some(3));
}
#[test]
fn the_caller_s_command_configuration_is_left_alone() {
let directory = tempfile::tempdir().expect("probe directory");
let expected = directory
.path()
.canonicalize()
.expect("canonical probe directory");
let mut command = probe();
command
.arg("kernal-sentinel")
.current_dir(&expected)
.env(PROBE, &expected);
let status = foreground_status(&mut command).expect("run the probe");
assert!(
status.success(),
"argv, cwd and env reached the child unchanged (exit {:?})",
status.code()
);
}
#[test]
fn captured_output_carries_both_streams_and_the_status() {
let mut command = Command::new(std::env::current_exe().expect("test binary path"));
command
.arg("--exact")
.arg("foreground_command::child_probe")
.env(PROBE, "speak");
let output = foreground_output(&mut command).expect("run the speaking helper");
assert!(output.status.success());
assert!(
String::from_utf8_lossy(&output.stdout).contains("to stdout"),
"stdout was captured"
);
assert!(
String::from_utf8_lossy(&output.stderr).contains("to stderr"),
"stderr was captured separately from stdout"
);
}
#[test]
fn a_command_that_cannot_start_reports_an_error() {
let mut missing = Command::new("kernal-api-no-such-program-xyz");
missing.stdout(Stdio::null()).stderr(Stdio::null());
let error = foreground_status(&mut missing).expect_err("no such program");
assert_eq!(error.kind(), std::io::ErrorKind::NotFound);
}
fn probe() -> Command {
let mut command = Command::new(std::env::current_exe().expect("test binary path"));
command
.arg("--exact")
.arg("foreground_command::child_probe")
.stdout(Stdio::null())
.stderr(Stdio::null());
command
}