use super::*;
use crate::ffi::OsStr;
use crate::mem;
use crate::ptr;
use crate::sys::{cvt, cvt_nz};
macro_rules! t {
($e:expr) => {
match $e {
Ok(t) => t,
Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
}
};
}
#[test]
#[cfg_attr(
any(
// See #14232 for more information, but it appears that signal delivery to a
// newly spawned process may just be raced in the macOS, so to prevent this
// test from being flaky we ignore it on macOS.
target_os = "macos",
// When run under our current QEMU emulation test suite this test fails,
// although the reason isn't very clear as to why. For now this test is
// ignored there.
target_arch = "arm",
target_arch = "aarch64",
target_arch = "riscv64",
),
ignore
)]
fn test_process_mask() {
fn test_inner(mut cmd: Command) {
unsafe {
let mut set = mem::MaybeUninit::<libc::sigset_t>::uninit();
let mut old_set = mem::MaybeUninit::<libc::sigset_t>::uninit();
t!(cvt(sigemptyset(set.as_mut_ptr())));
t!(cvt(sigaddset(set.as_mut_ptr(), libc::SIGINT)));
t!(cvt_nz(libc::pthread_sigmask(
libc::SIG_SETMASK,
set.as_ptr(),
old_set.as_mut_ptr()
)));
cmd.stdin(Stdio::MakePipe);
cmd.stdout(Stdio::MakePipe);
let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true));
let stdin_write = pipes.stdin.take().unwrap();
let stdout_read = pipes.stdout.take().unwrap();
t!(cvt_nz(libc::pthread_sigmask(libc::SIG_SETMASK, old_set.as_ptr(), ptr::null_mut())));
t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT)));
let _ = stdin_write.write(b"Hello");
drop(stdin_write);
let mut buf = [0; 5];
let ret = t!(stdout_read.read(&mut buf));
assert_eq!(ret, 5);
assert_eq!(&buf, b"Hello");
t!(cat.wait());
}
}
let cmd = Command::new(OsStr::new("cat"));
test_inner(cmd);
let mut cmd = Command::new(OsStr::new("cat"));
unsafe { cmd.pre_exec(Box::new(|| Ok(()))) };
test_inner(cmd);
}
#[test]
#[cfg_attr(
any(
// See test_process_mask
target_os = "macos",
target_arch = "arm",
target_arch = "aarch64",
target_arch = "riscv64",
),
ignore
)]
fn test_process_group_posix_spawn() {
unsafe {
let mut cmd = Command::new(OsStr::new("cat"));
cmd.pgroup(0);
cmd.stdin(Stdio::MakePipe);
cmd.stdout(Stdio::MakePipe);
let (mut cat, _pipes) = t!(cmd.spawn(Stdio::Null, true));
t!(cvt(libc::kill(-(cat.id() as libc::pid_t), libc::SIGINT)));
t!(cat.wait());
}
}
#[test]
#[cfg_attr(
any(
// See test_process_mask
target_os = "macos",
target_arch = "arm",
target_arch = "aarch64",
target_arch = "riscv64",
),
ignore
)]
fn test_process_group_no_posix_spawn() {
unsafe {
let mut cmd = Command::new(OsStr::new("cat"));
cmd.pgroup(0);
cmd.pre_exec(Box::new(|| Ok(()))); cmd.stdin(Stdio::MakePipe);
cmd.stdout(Stdio::MakePipe);
let (mut cat, _pipes) = t!(cmd.spawn(Stdio::Null, true));
t!(cvt(libc::kill(-(cat.id() as libc::pid_t), libc::SIGINT)));
t!(cat.wait());
}
}
#[test]
fn test_program_kind() {
let vectors = &[
("foo", ProgramKind::PathLookup),
("foo.out", ProgramKind::PathLookup),
("./foo", ProgramKind::Relative),
("../foo", ProgramKind::Relative),
("dir/foo", ProgramKind::Relative),
("fo\\/o", ProgramKind::Relative),
("/foo", ProgramKind::Absolute),
("/dir/../foo", ProgramKind::Absolute),
];
for (program, expected_kind) in vectors {
assert_eq!(
ProgramKind::new(program.as_ref()),
*expected_kind,
"actual != expected program kind for input {program}",
);
}
}