#![allow(clippy::expect_used)]
#![allow(clippy::unwrap_used)]
#![allow(clippy::panic)]
#![allow(clippy::match_wild_err_arm)]
use std::process::exit;
use fork::{Fork, WEXITSTATUS, WIFEXITED, WIFSIGNALED, WTERMSIG, fork, waitpid};
#[test]
fn test_wifexited_macro_works() {
match fork() {
Ok(Fork::Parent(child_pid)) => {
let status = waitpid(child_pid).expect("waitpid failed");
assert!(WIFEXITED(status), "Child should exit normally");
}
Ok(Fork::Child) => {
exit(0);
}
Err(_) => panic!("Fork failed"),
}
}
#[test]
fn test_wexitstatus_macro_works() {
match fork() {
Ok(Fork::Parent(child_pid)) => {
let status = waitpid(child_pid).expect("waitpid failed");
assert!(WIFEXITED(status), "Child should exit normally");
let exit_code = WEXITSTATUS(status);
assert_eq!(exit_code, 42, "Exit code should be 42");
}
Ok(Fork::Child) => {
exit(42);
}
Err(_) => panic!("Fork failed"),
}
}
#[test]
fn test_wifsignaled_macro_works() {
match fork() {
Ok(Fork::Parent(child_pid)) => {
let status = waitpid(child_pid).expect("waitpid failed");
assert!(WIFSIGNALED(status), "Child should be terminated by signal");
}
Ok(Fork::Child) => {
unsafe {
libc::raise(libc::SIGKILL);
}
exit(0); }
Err(_) => panic!("Fork failed"),
}
}
#[test]
fn test_wtermsig_macro_works() {
match fork() {
Ok(Fork::Parent(child_pid)) => {
let status = waitpid(child_pid).expect("waitpid failed");
assert!(WIFSIGNALED(status), "Child should be terminated by signal");
let signal = WTERMSIG(status);
assert_eq!(signal, libc::SIGTERM, "Signal should be SIGTERM");
}
Ok(Fork::Child) => {
unsafe {
libc::raise(libc::SIGTERM);
}
exit(0); }
Err(_) => panic!("Fork failed"),
}
}
#[test]
fn test_all_macros_together() {
match fork() {
Ok(Fork::Parent(child_pid)) => {
let status = waitpid(child_pid).expect("waitpid failed");
if WIFEXITED(status) {
let code = WEXITSTATUS(status);
assert_eq!(code, 7, "Exit code should be 7");
} else if WIFSIGNALED(status) {
let signal = WTERMSIG(status);
panic!("Child unexpectedly terminated by signal {signal}");
} else {
panic!("Child in unexpected state");
}
}
Ok(Fork::Child) => {
exit(7);
}
Err(_) => panic!("Fork failed"),
}
}
#[test]
fn test_macros_with_multiple_exit_codes() {
let exit_codes = [0, 1, 42, 127, 255];
for expected_code in exit_codes {
match fork() {
Ok(Fork::Parent(child_pid)) => {
let status = waitpid(child_pid).expect("waitpid failed");
assert!(
WIFEXITED(status),
"Child should exit normally with code {expected_code}"
);
let actual_code = WEXITSTATUS(status);
assert_eq!(
actual_code, expected_code,
"Exit code should be {expected_code}"
);
}
Ok(Fork::Child) => {
exit(expected_code);
}
Err(_) => panic!("Fork failed"),
}
}
}
#[test]
fn test_macros_distinguish_exit_vs_signal() {
match fork() {
Ok(Fork::Parent(child_pid)) => {
let status = waitpid(child_pid).expect("waitpid failed");
assert!(WIFEXITED(status), "First child should exit normally");
assert!(!WIFSIGNALED(status), "First child should not be signaled");
assert_eq!(WEXITSTATUS(status), 0, "Exit code should be 0");
}
Ok(Fork::Child) => {
exit(0);
}
Err(_) => panic!("Fork failed"),
}
match fork() {
Ok(Fork::Parent(child_pid)) => {
let status = waitpid(child_pid).expect("waitpid failed");
assert!(
WIFSIGNALED(status),
"Second child should be terminated by signal"
);
assert!(!WIFEXITED(status), "Second child should not exit normally");
assert_eq!(WTERMSIG(status), libc::SIGABRT, "Signal should be SIGABRT");
}
Ok(Fork::Child) => {
unsafe {
libc::raise(libc::SIGABRT);
}
exit(0); }
Err(_) => panic!("Fork failed"),
}
}
#[test]
fn test_no_libc_import_needed() {
match fork() {
Ok(Fork::Parent(child_pid)) => {
let status = waitpid(child_pid).expect("waitpid failed");
assert!(WIFEXITED(status));
assert_eq!(WEXITSTATUS(status), 13);
}
Ok(Fork::Child) => {
exit(13);
}
Err(_) => panic!("Fork failed"),
}
}