about summary refs log tree commit diff
path: root/library/test/src/helpers
diff options
context:
space:
mode:
Diffstat (limited to 'library/test/src/helpers')
-rw-r--r--library/test/src/helpers/concurrency.rs117
-rw-r--r--library/test/src/helpers/exit_code.rs20
-rw-r--r--library/test/src/helpers/isatty.rs32
-rw-r--r--library/test/src/helpers/metrics.rs50
-rw-r--r--library/test/src/helpers/mod.rs8
-rw-r--r--library/test/src/helpers/sink.rs24
6 files changed, 251 insertions, 0 deletions
diff --git a/library/test/src/helpers/concurrency.rs b/library/test/src/helpers/concurrency.rs
new file mode 100644
index 00000000000..2fe87247e3a
--- /dev/null
+++ b/library/test/src/helpers/concurrency.rs
@@ -0,0 +1,117 @@
+//! Helper module which helps to determine amount of threads to be used
+//! during tests execution.
+use std::env;
+
+#[allow(deprecated)]
+pub fn get_concurrency() -> usize {
+    return match env::var("RUST_TEST_THREADS") {
+        Ok(s) => {
+            let opt_n: Option<usize> = s.parse().ok();
+            match opt_n {
+                Some(n) if n > 0 => n,
+                _ => panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.", s),
+            }
+        }
+        Err(..) => num_cpus(),
+    };
+}
+
+cfg_if::cfg_if! {
+    if #[cfg(windows)] {
+        #[allow(nonstandard_style)]
+        fn num_cpus() -> usize {
+            #[repr(C)]
+            struct SYSTEM_INFO {
+                wProcessorArchitecture: u16,
+                wReserved: u16,
+                dwPageSize: u32,
+                lpMinimumApplicationAddress: *mut u8,
+                lpMaximumApplicationAddress: *mut u8,
+                dwActiveProcessorMask: *mut u8,
+                dwNumberOfProcessors: u32,
+                dwProcessorType: u32,
+                dwAllocationGranularity: u32,
+                wProcessorLevel: u16,
+                wProcessorRevision: u16,
+            }
+            extern "system" {
+                fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32;
+            }
+            unsafe {
+                let mut sysinfo = std::mem::zeroed();
+                GetSystemInfo(&mut sysinfo);
+                sysinfo.dwNumberOfProcessors as usize
+            }
+        }
+    } else if #[cfg(any(
+        target_os = "android",
+        target_os = "cloudabi",
+        target_os = "emscripten",
+        target_os = "fuchsia",
+        target_os = "ios",
+        target_os = "linux",
+        target_os = "macos",
+        target_os = "solaris",
+        target_os = "illumos",
+    ))] {
+        fn num_cpus() -> usize {
+            unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize }
+        }
+    } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] {
+        fn num_cpus() -> usize {
+            use std::ptr;
+
+            let mut cpus: libc::c_uint = 0;
+            let mut cpus_size = std::mem::size_of_val(&cpus);
+
+            unsafe {
+                cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint;
+            }
+            if cpus < 1 {
+                let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
+                unsafe {
+                    libc::sysctl(
+                        mib.as_mut_ptr(),
+                        2,
+                        &mut cpus as *mut _ as *mut _,
+                        &mut cpus_size as *mut _ as *mut _,
+                        ptr::null_mut(),
+                        0,
+                    );
+                }
+                if cpus < 1 {
+                    cpus = 1;
+                }
+            }
+            cpus as usize
+        }
+    } else if #[cfg(target_os = "openbsd")] {
+        fn num_cpus() -> usize {
+            use std::ptr;
+
+            let mut cpus: libc::c_uint = 0;
+            let mut cpus_size = std::mem::size_of_val(&cpus);
+            let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
+
+            unsafe {
+                libc::sysctl(
+                    mib.as_mut_ptr(),
+                    2,
+                    &mut cpus as *mut _ as *mut _,
+                    &mut cpus_size as *mut _ as *mut _,
+                    ptr::null_mut(),
+                    0,
+                );
+            }
+            if cpus < 1 {
+                cpus = 1;
+            }
+            cpus as usize
+        }
+    } else {
+        // FIXME: implement on vxWorks, Redox, HermitCore, Haiku, l4re
+        fn num_cpus() -> usize {
+            1
+        }
+    }
+}
diff --git a/library/test/src/helpers/exit_code.rs b/library/test/src/helpers/exit_code.rs
new file mode 100644
index 00000000000..31e234d9818
--- /dev/null
+++ b/library/test/src/helpers/exit_code.rs
@@ -0,0 +1,20 @@
+//! Helper module to detect subprocess exit code.
+
+use std::process::ExitStatus;
+
+#[cfg(not(unix))]
+pub fn get_exit_code(status: ExitStatus) -> Result<i32, String> {
+    status.code().ok_or("received no exit code from child process".into())
+}
+
+#[cfg(unix)]
+pub fn get_exit_code(status: ExitStatus) -> Result<i32, String> {
+    use std::os::unix::process::ExitStatusExt;
+    match status.code() {
+        Some(code) => Ok(code),
+        None => match status.signal() {
+            Some(signal) => Err(format!("child process exited with signal {}", signal)),
+            None => Err("child process exited with unknown signal".into()),
+        },
+    }
+}
diff --git a/library/test/src/helpers/isatty.rs b/library/test/src/helpers/isatty.rs
new file mode 100644
index 00000000000..874ecc37645
--- /dev/null
+++ b/library/test/src/helpers/isatty.rs
@@ -0,0 +1,32 @@
+//! Helper module which provides a function to test
+//! if stdout is a tty.
+
+cfg_if::cfg_if! {
+    if #[cfg(unix)] {
+        pub fn stdout_isatty() -> bool {
+            unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
+        }
+    } else if #[cfg(windows)] {
+        pub fn stdout_isatty() -> bool {
+            type DWORD = u32;
+            type BOOL = i32;
+            type HANDLE = *mut u8;
+            type LPDWORD = *mut u32;
+            const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD;
+            extern "system" {
+                fn GetStdHandle(which: DWORD) -> HANDLE;
+                fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL;
+            }
+            unsafe {
+                let handle = GetStdHandle(STD_OUTPUT_HANDLE);
+                let mut out = 0;
+                GetConsoleMode(handle, &mut out) != 0
+            }
+        }
+    } else {
+        // FIXME: Implement isatty on SGX
+        pub fn stdout_isatty() -> bool {
+            false
+        }
+    }
+}
diff --git a/library/test/src/helpers/metrics.rs b/library/test/src/helpers/metrics.rs
new file mode 100644
index 00000000000..f77a23e6875
--- /dev/null
+++ b/library/test/src/helpers/metrics.rs
@@ -0,0 +1,50 @@
+//! Benchmark metrics.
+use std::collections::BTreeMap;
+
+#[derive(Clone, PartialEq, Debug, Copy)]
+pub struct Metric {
+    value: f64,
+    noise: f64,
+}
+
+impl Metric {
+    pub fn new(value: f64, noise: f64) -> Metric {
+        Metric { value, noise }
+    }
+}
+
+#[derive(Clone, PartialEq)]
+pub struct MetricMap(BTreeMap<String, Metric>);
+
+impl MetricMap {
+    pub fn new() -> MetricMap {
+        MetricMap(BTreeMap::new())
+    }
+
+    /// Insert a named `value` (+/- `noise`) metric into the map. The value
+    /// must be non-negative. The `noise` indicates the uncertainty of the
+    /// metric, which doubles as the "noise range" of acceptable
+    /// pairwise-regressions on this named value, when comparing from one
+    /// metric to the next using `compare_to_old`.
+    ///
+    /// If `noise` is positive, then it means this metric is of a value
+    /// you want to see grow smaller, so a change larger than `noise` in the
+    /// positive direction represents a regression.
+    ///
+    /// If `noise` is negative, then it means this metric is of a value
+    /// you want to see grow larger, so a change larger than `noise` in the
+    /// negative direction represents a regression.
+    pub fn insert_metric(&mut self, name: &str, value: f64, noise: f64) {
+        let m = Metric { value, noise };
+        self.0.insert(name.to_owned(), m);
+    }
+
+    pub fn fmt_metrics(&self) -> String {
+        let v = self
+            .0
+            .iter()
+            .map(|(k, v)| format!("{}: {} (+/- {})", *k, v.value, v.noise))
+            .collect::<Vec<_>>();
+        v.join(", ")
+    }
+}
diff --git a/library/test/src/helpers/mod.rs b/library/test/src/helpers/mod.rs
new file mode 100644
index 00000000000..eb416b10150
--- /dev/null
+++ b/library/test/src/helpers/mod.rs
@@ -0,0 +1,8 @@
+//! Module with common helpers not directly related to tests
+//! but used in `libtest`.
+
+pub mod concurrency;
+pub mod exit_code;
+pub mod isatty;
+pub mod metrics;
+pub mod sink;
diff --git a/library/test/src/helpers/sink.rs b/library/test/src/helpers/sink.rs
new file mode 100644
index 00000000000..aa7fe248773
--- /dev/null
+++ b/library/test/src/helpers/sink.rs
@@ -0,0 +1,24 @@
+//! Module providing a helper structure to capture output in subprocesses.
+
+use std::{
+    io,
+    io::prelude::Write,
+    sync::{Arc, Mutex},
+};
+
+pub struct Sink(Arc<Mutex<Vec<u8>>>);
+
+impl Sink {
+    pub fn new_boxed(data: &Arc<Mutex<Vec<u8>>>) -> Box<Self> {
+        Box::new(Self(data.clone()))
+    }
+}
+
+impl Write for Sink {
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+        Write::write(&mut *self.0.lock().unwrap(), data)
+    }
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}