use crate::{list::Styles, runner::AbortStatus};
use camino::{Utf8Path, Utf8PathBuf};
use owo_colors::OwoColorize;
use std::{
fmt,
io::{self, Write},
path::PathBuf,
process::ExitStatus,
time::Duration,
};
pub(crate) fn write_test_name(
name: &str,
style: &Styles,
mut writer: impl Write,
) -> io::Result<()> {
let mut splits = name.rsplitn(2, "::");
let trailing = splits.next().expect("test should have at least 1 element");
if let Some(rest) = splits.next() {
write!(
writer,
"{}{}",
rest.style(style.module_path),
"::".style(style.module_path)
)?;
}
write!(writer, "{}", trailing.style(style.test_name))?;
Ok(())
}
pub(crate) fn convert_build_platform(
platform: nextest_metadata::BuildPlatform,
) -> guppy::graph::cargo::BuildPlatform {
match platform {
nextest_metadata::BuildPlatform::Target => guppy::graph::cargo::BuildPlatform::Target,
nextest_metadata::BuildPlatform::Host => guppy::graph::cargo::BuildPlatform::Host,
}
}
pub(crate) fn dylib_path_envvar() -> &'static str {
if cfg!(windows) {
"PATH"
} else if cfg!(target_os = "macos") {
"DYLD_FALLBACK_LIBRARY_PATH"
} else {
"LD_LIBRARY_PATH"
}
}
pub(crate) fn dylib_path() -> Vec<PathBuf> {
match std::env::var_os(dylib_path_envvar()) {
Some(var) => std::env::split_paths(&var).collect(),
None => Vec::new(),
}
}
#[cfg(windows)]
pub(crate) fn convert_rel_path_to_forward_slash(rel_path: &Utf8Path) -> Utf8PathBuf {
if !rel_path.is_relative() {
panic!(
"path for conversion to forward slash '{}' is not relative",
rel_path
);
}
rel_path.as_str().replace('\\', "/").into()
}
#[cfg(not(windows))]
pub(crate) fn convert_rel_path_to_forward_slash(rel_path: &Utf8Path) -> Utf8PathBuf {
rel_path.to_path_buf()
}
#[cfg(windows)]
pub(crate) fn convert_rel_path_to_main_sep(rel_path: &Utf8Path) -> Utf8PathBuf {
if !rel_path.is_relative() {
panic!(
"path for conversion to backslash '{}' is not relative",
rel_path
);
}
rel_path.as_str().replace('/', "\\").into()
}
#[cfg(not(windows))]
pub(crate) fn convert_rel_path_to_main_sep(rel_path: &Utf8Path) -> Utf8PathBuf {
rel_path.to_path_buf()
}
pub(crate) fn format_duration(duration: Duration) -> String {
let duration = duration.as_secs_f64();
if duration > 60.0 {
format!("{}m {:.2}s", duration as u32 / 60, duration % 60.0)
} else {
format!("{duration:.2}s")
}
}
pub(crate) fn extract_abort_status(exit_status: ExitStatus) -> Option<AbortStatus> {
cfg_if::cfg_if! {
if #[cfg(unix)] {
use std::os::unix::process::ExitStatusExt;
exit_status.signal().map(AbortStatus::UnixSignal)
} else if #[cfg(windows)] {
exit_status.code().and_then(|code| {
let exception = windows::Win32::Foundation::NTSTATUS(code);
exception.is_err().then(|| AbortStatus::WindowsNtStatus(exception))
})
} else {
None
}
}
}
#[cfg(unix)]
pub(crate) fn signal_str(signal: i32) -> Option<&'static str> {
match signal {
1 => Some("HUP"),
2 => Some("INT"),
5 => Some("TRAP"),
6 => Some("ABRT"),
8 => Some("FPE"),
9 => Some("KILL"),
11 => Some("SEGV"),
13 => Some("PIPE"),
14 => Some("ALRM"),
15 => Some("TERM"),
24 => Some("XCPU"),
25 => Some("XFSZ"),
26 => Some("VTALRM"),
27 => Some("PROF"),
_ => None,
}
}
#[cfg(windows)]
pub(crate) fn display_nt_status(nt_status: windows::Win32::Foundation::NTSTATUS) -> String {
let win32_code = unsafe { windows::Win32::Foundation::RtlNtStatusToDosError(nt_status) };
if win32_code == windows::Win32::Foundation::ERROR_MR_MID_NOT_FOUND.0 {
let nt_status = nt_status.0;
return format!("{nt_status:#x} ({nt_status})");
}
return format!(
"{:#x}: {}",
nt_status.0,
io::Error::from_raw_os_error(win32_code as i32)
);
}
#[derive(Copy, Clone, Debug)]
pub(crate) struct QuotedDisplay<'a, T: ?Sized>(pub(crate) &'a T);
impl<'a, T: ?Sized> fmt::Display for QuotedDisplay<'a, T>
where
T: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "'{}'", self.0)
}
}
extern "C" {
fn __nextest_external_symbol_that_does_not_exist();
}
#[inline]
#[allow(dead_code)]
pub(crate) fn statically_unreachable() -> ! {
unsafe {
__nextest_external_symbol_that_does_not_exist();
}
unreachable!("linker symbol above cannot be resolved")
}