procspawn/
testsupport.rs

1#![cfg(feature = "test-support")]
2use std::env;
3use std::process::Command;
4use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
5
6use crate::core::mark_initialized;
7
8static TEST_MODE: AtomicBool = AtomicBool::new(false);
9static TEST_MODULE: AtomicPtr<String> = AtomicPtr::new(std::ptr::null_mut());
10
11// we need this.
12pub use small_ctor::ctor;
13
14/// Supports the use of procspawn in tests.
15///
16/// Due to limitations in rusttest it's currently not easily possible to use
17/// procspawn with rusttest.  The workaround is to call use this macro toplevel
18/// which will define a dummy test which is used to invoke all subprocesses.
19///
20/// ```rust,no_run
21/// procspawn::enable_test_support!();
22/// ```
23///
24/// Requires the `test-support` feature.
25#[macro_export]
26macro_rules! enable_test_support {
27    () => {
28        #[$crate::testsupport::ctor]
29        unsafe fn __procspawn_test_support_init() {
30            // strip the crate name from the module path
31            let module_path = std::module_path!().splitn(2, "::").nth(1);
32            $crate::testsupport::enable(module_path);
33        }
34
35        #[test]
36        fn procspawn_test_helper() {
37            $crate::init();
38        }
39    };
40}
41
42pub fn enable(module: Option<&str>) {
43    if TEST_MODE.swap(true, Ordering::SeqCst) {
44        panic!("procspawn testmode can only be enabled once");
45    }
46
47    if let Some(module) = module {
48        let ptr = Box::into_raw(Box::new(module.to_string()));
49        TEST_MODULE.store(ptr, Ordering::SeqCst);
50    }
51
52    mark_initialized();
53}
54
55pub struct TestMode {
56    pub can_pass_args: bool,
57    pub should_silence_stdout: bool,
58}
59
60fn test_helper_path() -> String {
61    match unsafe { TEST_MODULE.load(Ordering::SeqCst).as_ref() } {
62        Some(module) => format!("{}::procspawn_test_helper", module),
63        None => "procspawn_test_helper".to_string(),
64    }
65}
66
67pub fn update_command_for_tests(cmd: &mut Command) -> Option<TestMode> {
68    if TEST_MODE.load(Ordering::SeqCst) {
69        cmd.arg(test_helper_path());
70        cmd.arg("--exact");
71        cmd.arg("--test-threads=1");
72        cmd.arg("-q");
73        Some(TestMode {
74            can_pass_args: false,
75            should_silence_stdout: !env::args().any(|x| x == "--show-output" || x == "--nocapture"),
76        })
77    } else {
78        None
79    }
80}