use std::process::Command;
use crate::child_wrapper::ChildWrapper;
#[macro_export]
macro_rules! rusty_fork_test {
(#![rusty_fork(timeout_ms = $timeout:expr)]
$(
$(#[$meta:meta])*
fn $test_name:ident() $body:block
)*) => { $(
$(#[$meta])*
fn $test_name() {
fn body_fn() $body
let body: fn () = body_fn;
fn supervise_fn(child: &mut $crate::ChildWrapper,
_file: &mut ::std::fs::File) {
$crate::fork_test::supervise_child(child, $timeout)
}
let supervise:
fn (&mut $crate::ChildWrapper, &mut ::std::fs::File) =
supervise_fn;
$crate::fork(
$crate::rusty_fork_test_name!($test_name),
$crate::rusty_fork_id!(),
$crate::fork_test::no_configure_child,
supervise, body).expect("forking test failed")
}
)* };
($(
$(#[$meta:meta])*
fn $test_name:ident() $body:block
)*) => {
rusty_fork_test! {
#![rusty_fork(timeout_ms = 0)]
$($(#[$meta])* fn $test_name() $body)*
}
};
}
#[macro_export]
macro_rules! rusty_fork_test_name {
($function_name:ident) => {
$crate::fork_test::fix_module_path(
concat!(module_path!(), "::", stringify!($function_name)))
}
}
#[allow(missing_docs)]
#[doc(hidden)]
pub fn supervise_child(child: &mut ChildWrapper, timeout_ms: u64) {
if timeout_ms > 0 {
wait_timeout(child, timeout_ms)
} else {
let status = child.wait().expect("failed to wait for child");
assert!(status.success(),
"child exited unsuccessfully with {}", status);
}
}
#[allow(missing_docs)]
#[doc(hidden)]
pub fn no_configure_child(_child: &mut Command) { }
pub fn fix_module_path(path: &str) -> &str {
path.find("::").map(|ix| &path[ix+2..]).unwrap_or(path)
}
#[cfg(feature = "timeout")]
fn wait_timeout(child: &mut ChildWrapper, timeout_ms: u64) {
use std::time::Duration;
let timeout = Duration::from_millis(timeout_ms);
let status = child.wait_timeout(timeout).expect("failed to wait for child");
if let Some(status) = status {
assert!(status.success(),
"child exited unsuccessfully with {}", status);
} else {
panic!("child process exceeded {} ms timeout", timeout_ms);
}
}
#[cfg(not(feature = "timeout"))]
fn wait_timeout(_: &mut ChildWrapper, _: u64) {
panic!("Using the timeout feature of rusty_fork_test! requires \
enabling the `timeout` feature on the rusty-fork crate.");
}
#[cfg(test)]
mod test {
rusty_fork_test! {
#[test]
fn trivial() { }
#[test]
#[should_panic]
fn panicking_child() {
panic!("just testing a panic, nothing to see here");
}
#[test]
#[should_panic]
fn aborting_child() {
::std::process::abort();
}
}
rusty_fork_test! {
#![rusty_fork(timeout_ms = 1000)]
#[test]
#[cfg(feature = "timeout")]
fn timeout_passes() { }
#[test]
#[should_panic]
#[cfg(feature = "timeout")]
fn timeout_fails() {
println!("hello from child");
::std::thread::sleep(
::std::time::Duration::from_millis(10000));
println!("goodbye from child");
}
}
}