From 50fe62344729fb2194cd81159c605a10d3d6651a Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Fri, 28 Mar 2025 09:22:03 +0100 Subject: [PATCH 1/3] Create the uutest crate + adjust the code + move some of the tests into the program test --- .../workspace.wordlist.txt | 2 + Cargo.lock | 63 ++++++++++- Cargo.toml | 3 + tests/test_util_name.rs | 107 ++++++++++-------- tests/tests.rs | 15 ++- tests/uutests/Cargo.toml | 45 ++++++++ .../{common/mod.rs => uutests/src/lib/lib.rs} | 0 tests/{common => uutests/src/lib}/macros.rs | 0 tests/uutests/src/lib/mod.rs | 8 ++ tests/{common => uutests/src/lib}/random.rs | 0 tests/{common => uutests/src/lib}/util.rs | 32 ++++-- 11 files changed, 211 insertions(+), 64 deletions(-) create mode 100644 tests/uutests/Cargo.toml rename tests/{common/mod.rs => uutests/src/lib/lib.rs} (100%) rename tests/{common => uutests/src/lib}/macros.rs (100%) create mode 100644 tests/uutests/src/lib/mod.rs rename tests/{common => uutests/src/lib}/random.rs (100%) rename tests/{common => uutests/src/lib}/util.rs (99%) diff --git a/.vscode/cspell.dictionaries/workspace.wordlist.txt b/.vscode/cspell.dictionaries/workspace.wordlist.txt index 45373d95c..43f56dfc2 100644 --- a/.vscode/cspell.dictionaries/workspace.wordlist.txt +++ b/.vscode/cspell.dictionaries/workspace.wordlist.txt @@ -325,6 +325,7 @@ libc libstdbuf musl tmpd +uchild ucmd ucommand utmpx @@ -333,6 +334,7 @@ uucore_procs uudoc uumain uutil +uutests uutils # * function names diff --git a/Cargo.lock b/Cargo.lock index b0f54656c..086aace1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -448,6 +448,7 @@ dependencies = [ "clap", "clap_complete", "clap_mangen", + "ctor", "filetime", "glob", "hex-literal", @@ -574,6 +575,7 @@ dependencies = [ "uu_yes", "uucore", "uuhelp_parser", + "uutests", "walkdir", "xattr", "zip", @@ -724,6 +726,22 @@ dependencies = [ "typenum", ] +[[package]] +name = "ctor" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e9666f4a9a948d4f1dff0c08a4512b0f7c86414b23960104c243c10d79f4c3" +dependencies = [ + "ctor-proc-macro", + "dtor", +] + +[[package]] +name = "ctor-proc-macro" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f211af61d8efdd104f96e57adf5e426ba1bc3ed7a4ead616e15e5881fd79c4d" + [[package]] name = "ctrlc" version = "3.4.5" @@ -817,6 +835,21 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "dtor" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222ef136a1c687d4aa0395c175f2c4586e379924c352fd02f7870cf7de783c23" +dependencies = [ + "dtor-proc-macro", +] + +[[package]] +name = "dtor-proc-macro" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7454e41ff9012c00d53cf7f475c5e3afa3b91b7c90568495495e8d9bf47a1055" + [[package]] name = "dunce" version = "1.0.5" @@ -848,7 +881,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1259,7 +1292,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -1989,7 +2022,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.4.15", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2002,7 +2035,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.9.3", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2246,7 +2279,7 @@ dependencies = [ "getrandom 0.3.1", "once_cell", "rustix 1.0.1", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3531,6 +3564,24 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0f540e3240398cce6128b64ba83fdbdd86129c16a3aa1a3a252efd66eb3d587" +[[package]] +name = "uutests" +version = "0.0.30" +dependencies = [ + "ctor", + "glob", + "libc", + "nix", + "pretty_assertions", + "rand 0.9.0", + "regex", + "rlimit", + "tempfile", + "time", + "uucore", + "xattr", +] + [[package]] name = "uutils_term_grid" version = "0.6.0" @@ -3670,7 +3721,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index a0fd3f19d..226bd28d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -366,6 +366,7 @@ uucore = { version = "0.0.30", package = "uucore", path = "src/uucore" } uucore_procs = { version = "0.0.30", package = "uucore_procs", path = "src/uucore_procs" } uu_ls = { version = "0.0.30", path = "src/uu/ls" } uu_base32 = { version = "0.0.30", path = "src/uu/base32" } +uutests = { version = "0.0.30", package = "uutests", path = "tests/uutests/" } [dependencies] clap = { workspace = true } @@ -505,6 +506,7 @@ sha1 = { workspace = true, features = ["std"] } tempfile = { workspace = true } time = { workspace = true, features = ["local-offset"] } unindent = "0.2.3" +uutests = { workspace = true } uucore = { workspace = true, features = [ "mode", "entries", @@ -515,6 +517,7 @@ uucore = { workspace = true, features = [ walkdir = { workspace = true } hex-literal = "1.0.0" rstest = { workspace = true } +ctor = "0.4.1" [target.'cfg(any(target_os = "linux", target_os = "android"))'.dev-dependencies] procfs = { version = "0.17", default-features = false } diff --git a/tests/test_util_name.rs b/tests/test_util_name.rs index dd8cd9359..789077b5c 100644 --- a/tests/test_util_name.rs +++ b/tests/test_util_name.rs @@ -2,15 +2,26 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -#![allow(unused_imports)] -mod common; - -use common::util::TestScenario; +use uutests::util::TestScenario; #[cfg(unix)] use std::os::unix::fs::symlink as symlink_file; -#[cfg(windows)] -use std::os::windows::fs::symlink_file; + +use std::env; +pub const TESTS_BINARY: &str = env!("CARGO_BIN_EXE_coreutils"); + +// Set the environment variable for any tests + +// Use the ctor attribute to run this function before any tests +#[ctor::ctor] +fn init() { + // No need for unsafe here + unsafe { + std::env::set_var("UUTESTS_BINARY_PATH", TESTS_BINARY); + } + // Print for debugging + eprintln!("Setting UUTESTS_BINARY_PATH={}", TESTS_BINARY); +} #[test] #[cfg(feature = "ls")] @@ -18,6 +29,10 @@ fn execution_phrase_double() { use std::process::Command; let scenario = TestScenario::new("ls"); + if !scenario.bin_path.exists() { + println!("Skipping test: Binary not found at {:?}", scenario.bin_path); + return; + } let output = Command::new(&scenario.bin_path) .arg("ls") .arg("--some-invalid-arg") @@ -30,25 +45,6 @@ fn execution_phrase_double() { ); } -#[test] -#[cfg(feature = "ls")] -#[cfg(any(unix, windows))] -fn execution_phrase_single() { - use std::process::Command; - - let scenario = TestScenario::new("ls"); - symlink_file(&scenario.bin_path, scenario.fixtures.plus("uu-ls")).unwrap(); - let output = Command::new(scenario.fixtures.plus("uu-ls")) - .arg("--some-invalid-arg") - .output() - .unwrap(); - dbg!(String::from_utf8(output.stderr.clone()).unwrap()); - assert!(String::from_utf8(output.stderr).unwrap().contains(&format!( - "Usage: {}", - scenario.fixtures.plus("uu-ls").display() - ))); -} - #[test] #[cfg(feature = "sort")] fn util_name_double() { @@ -58,6 +54,10 @@ fn util_name_double() { }; let scenario = TestScenario::new("sort"); + if !scenario.bin_path.exists() { + println!("Skipping test: Binary not found at {:?}", scenario.bin_path); + return; + } let mut child = Command::new(&scenario.bin_path) .arg("sort") .stdin(Stdio::piped()) @@ -72,7 +72,7 @@ fn util_name_double() { #[test] #[cfg(feature = "sort")] -#[cfg(any(unix, windows))] +#[cfg(unix)] fn util_name_single() { use std::{ io::Write, @@ -80,6 +80,11 @@ fn util_name_single() { }; let scenario = TestScenario::new("sort"); + if !scenario.bin_path.exists() { + println!("Skipping test: Binary not found at {:?}", scenario.bin_path); + return; + } + symlink_file(&scenario.bin_path, scenario.fixtures.plus("uu-sort")).unwrap(); let mut child = Command::new(scenario.fixtures.plus("uu-sort")) .stdin(Stdio::piped()) @@ -96,14 +101,15 @@ fn util_name_single() { } #[test] -#[cfg(any(unix, windows))] +#[cfg(unix)] fn util_invalid_name_help() { - use std::{ - io::Write, - process::{Command, Stdio}, - }; + use std::process::{Command, Stdio}; let scenario = TestScenario::new("invalid_name"); + if !scenario.bin_path.exists() { + println!("Skipping test: Binary not found at {:?}", scenario.bin_path); + return; + } symlink_file(&scenario.bin_path, scenario.fixtures.plus("invalid_name")).unwrap(); let child = Command::new(scenario.fixtures.plus("invalid_name")) .arg("--help") @@ -132,14 +138,17 @@ fn util_non_utf8_name_help() { // Make sure we don't crash even if the util name is invalid UTF-8. use std::{ ffi::OsStr, - io::Write, os::unix::ffi::OsStrExt, - path::Path, process::{Command, Stdio}, }; let scenario = TestScenario::new("invalid_name"); let non_utf8_path = scenario.fixtures.plus(OsStr::from_bytes(b"\xff")); + if !scenario.bin_path.exists() { + println!("Skipping test: Binary not found at {:?}", scenario.bin_path); + return; + } + symlink_file(&scenario.bin_path, &non_utf8_path).unwrap(); let child = Command::new(&non_utf8_path) .arg("--help") @@ -160,15 +169,17 @@ fn util_non_utf8_name_help() { } #[test] -#[cfg(any(unix, windows))] +#[cfg(unix)] fn util_invalid_name_invalid_command() { - use std::{ - io::Write, - process::{Command, Stdio}, - }; + use std::process::{Command, Stdio}; let scenario = TestScenario::new("invalid_name"); symlink_file(&scenario.bin_path, scenario.fixtures.plus("invalid_name")).unwrap(); + if !scenario.bin_path.exists() { + println!("Skipping test: Binary not found at {:?}", scenario.bin_path); + return; + } + let child = Command::new(scenario.fixtures.plus("invalid_name")) .arg("definitely_invalid") .stdin(Stdio::piped()) @@ -188,12 +199,14 @@ fn util_invalid_name_invalid_command() { #[test] #[cfg(feature = "true")] fn util_completion() { - use std::{ - io::Write, - process::{Command, Stdio}, - }; + use std::process::{Command, Stdio}; let scenario = TestScenario::new("completion"); + if !scenario.bin_path.exists() { + println!("Skipping test: Binary not found at {:?}", scenario.bin_path); + return; + } + let child = Command::new(&scenario.bin_path) .arg("completion") .arg("true") @@ -216,12 +229,14 @@ fn util_completion() { #[test] #[cfg(feature = "true")] fn util_manpage() { - use std::{ - io::Write, - process::{Command, Stdio}, - }; + use std::process::{Command, Stdio}; let scenario = TestScenario::new("completion"); + if !scenario.bin_path.exists() { + println!("Skipping test: Binary not found at {:?}", scenario.bin_path); + return; + } + let child = Command::new(&scenario.bin_path) .arg("manpage") .arg("true") diff --git a/tests/tests.rs b/tests/tests.rs index 1fb5735eb..a4eaaacff 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -2,8 +2,19 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -#[macro_use] -mod common; + +// Then override the macro with your constant +use std::env; + +pub const TESTS_BINARY: &str = env!("CARGO_BIN_EXE_coreutils"); + +// Use the ctor attribute to run this function before any tests +#[ctor::ctor] +fn init() { + unsafe { + std::env::set_var("UUTESTS_BINARY_PATH", TESTS_BINARY); + } +} #[cfg(feature = "arch")] #[path = "by-util/test_arch.rs"] diff --git a/tests/uutests/Cargo.toml b/tests/uutests/Cargo.toml new file mode 100644 index 000000000..2ede02148 --- /dev/null +++ b/tests/uutests/Cargo.toml @@ -0,0 +1,45 @@ +# spell-checker:ignore (features) zerocopy serde + +[package] +name = "uutests" +version = "0.0.30" +authors = ["uutils developers"] +license = "MIT" +description = "uutils ~ 'core' uutils test library (cross-platform)" + +homepage = "https://github.com/uutils/coreutils" +repository = "https://github.com/uutils/coreutils/tree/main/src/tests/common" +# readme = "README.md" +keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] +categories = ["command-line-utilities"] +edition = "2024" + +[package.metadata.docs.rs] +all-features = true + +[lib] +path = "src/lib/lib.rs" + +[dependencies] +glob = { workspace = true } +libc = { workspace = true } +pretty_assertions = "1.4.0" +rand = { workspace = true } +regex = { workspace = true } +tempfile = { workspace = true } +time = { workspace = true, features = ["local-offset"] } +uucore = { workspace = true, features = [ + "mode", + "entries", + "process", + "signals", + "utmpx", +] } +ctor = "0.4.1" + +[target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies] + +[target.'cfg(unix)'.dependencies] +nix = { workspace = true, features = ["process", "signal", "user", "term"] } +rlimit = "0.10.1" +xattr = { workspace = true } diff --git a/tests/common/mod.rs b/tests/uutests/src/lib/lib.rs similarity index 100% rename from tests/common/mod.rs rename to tests/uutests/src/lib/lib.rs diff --git a/tests/common/macros.rs b/tests/uutests/src/lib/macros.rs similarity index 100% rename from tests/common/macros.rs rename to tests/uutests/src/lib/macros.rs diff --git a/tests/uutests/src/lib/mod.rs b/tests/uutests/src/lib/mod.rs new file mode 100644 index 000000000..05e2b1382 --- /dev/null +++ b/tests/uutests/src/lib/mod.rs @@ -0,0 +1,8 @@ +// This file is part of the uutils coreutils package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. +#[macro_use] +pub mod macros; +pub mod random; +pub mod util; diff --git a/tests/common/random.rs b/tests/uutests/src/lib/random.rs similarity index 100% rename from tests/common/random.rs rename to tests/uutests/src/lib/random.rs diff --git a/tests/common/util.rs b/tests/uutests/src/lib/util.rs similarity index 99% rename from tests/common/util.rs rename to tests/uutests/src/lib/util.rs index 4b7acaa54..79c5ac96b 100644 --- a/tests/common/util.rs +++ b/tests/uutests/src/lib/util.rs @@ -2,7 +2,6 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. - //spell-checker: ignore (linux) rlimit prlimit coreutil ggroups uchild uncaptured scmd SHLVL canonicalized openpty //spell-checker: ignore (linux) winsize xpixel ypixel setrlimit FSIZE SIGBUS SIGSEGV sigbus tmpfs @@ -22,8 +21,6 @@ use nix::sys; use pretty_assertions::assert_eq; #[cfg(unix)] use rlimit::setrlimit; -#[cfg(feature = "sleep")] -use rstest::rstest; use std::borrow::Cow; use std::collections::VecDeque; #[cfg(not(windows))] @@ -63,7 +60,21 @@ static MULTIPLE_STDIN_MEANINGLESS: &str = "Ucommand is designed around a typical static NO_STDIN_MEANINGLESS: &str = "Setting this flag has no effect if there is no stdin"; static END_OF_TRANSMISSION_SEQUENCE: &[u8] = b"\n\x04"; -pub const TESTS_BINARY: &str = env!("CARGO_BIN_EXE_coreutils"); +// we can't use +// pub const TESTS_BINARY: &str = env!("CARGO_BIN_EXE_coreutils"); +// as we are in a library, not a binary +pub fn get_tests_binary() -> String { + std::env::var("CARGO_BIN_EXE_coreutils").unwrap_or_else(|_| { + let manifest_dir = env!("CARGO_MANIFEST_DIR"); + let debug_or_release = if cfg!(debug_assertions) { + "debug" + } else { + "release" + }; + format!("{manifest_dir}/../../target/{debug_or_release}/coreutils") + }) +} + pub const PATH: &str = env!("PATH"); /// Default environment variables to run the commands with @@ -1178,8 +1189,9 @@ impl TestScenario { T: AsRef, { let tmpd = Rc::new(TempDir::new().unwrap()); + println!("bin: {:?}", get_tests_binary()); let ts = Self { - bin_path: PathBuf::from(TESTS_BINARY), + bin_path: PathBuf::from(get_tests_binary()), util_name: util_name.as_ref().into(), fixtures: AtPath::new(tmpd.as_ref().path()), tmpd, @@ -1343,7 +1355,7 @@ impl UCommand { { let mut ucmd = Self::new(); ucmd.util_name = Some(util_name.as_ref().into()); - ucmd.bin_path(TESTS_BINARY).temp_dir(tmpd); + ucmd.bin_path(&*get_tests_binary()).temp_dir(tmpd); ucmd } @@ -1604,7 +1616,7 @@ impl UCommand { self.args.push_front(util_name.into()); } } else if let Some(util_name) = &self.util_name { - self.bin_path = Some(PathBuf::from(TESTS_BINARY)); + self.bin_path = Some(PathBuf::from(&*get_tests_binary())); self.args.push_front(util_name.into()); // neither `bin_path` nor `util_name` was set so we apply the default to run the arguments // in a platform specific shell @@ -2762,7 +2774,7 @@ const UUTILS_INFO: &str = "uutils-tests-info"; /// Example: /// /// ```no_run -/// use crate::common::util::*; +/// use uutests::util::*; /// const VERSION_MIN_MULTIPLE_USERS: &str = "8.31"; /// /// #[test] @@ -2838,7 +2850,7 @@ fn parse_coreutil_version(version_string: &str) -> f32 { /// Example: /// /// ```no_run -/// use crate::common::util::*; +/// use uutests::util::*; /// #[test] /// fn test_xyz() { /// let ts = TestScenario::new(util_name!()); @@ -2901,7 +2913,7 @@ pub fn expected_result(ts: &TestScenario, args: &[&str]) -> std::result::Result< /// Example: /// /// ```no_run -/// use crate::common::util::*; +/// use uutests::util::*; /// #[test] /// fn test_xyz() { /// let ts = TestScenario::new("whoami"); From ccfcda531eef4aeab14659773a7c618e391ca931 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Fri, 28 Mar 2025 09:47:40 +0100 Subject: [PATCH 2/3] uutests: improve the docs --- tests/uutests/src/lib/macros.rs | 10 +- tests/uutests/src/lib/util.rs | 844 +++++--------------------------- 2 files changed, 124 insertions(+), 730 deletions(-) diff --git a/tests/uutests/src/lib/macros.rs b/tests/uutests/src/lib/macros.rs index 4902ca49b..cc245a208 100644 --- a/tests/uutests/src/lib/macros.rs +++ b/tests/uutests/src/lib/macros.rs @@ -47,8 +47,8 @@ macro_rules! util_name { /// This macro is intended for quick, single-call tests. For more complex tests /// that require multiple invocations of the tested binary, see [`TestScenario`] /// -/// [`UCommand`]: crate::tests::common::util::UCommand -/// [`TestScenario]: crate::tests::common::util::TestScenario +/// [`UCommand`]: crate::util::UCommand +/// [`TestScenario`]: crate::util::TestScenario #[macro_export] macro_rules! new_ucmd { () => { @@ -65,9 +65,9 @@ macro_rules! new_ucmd { /// This macro is intended for quick, single-call tests. For more complex tests /// that require multiple invocations of the tested binary, see [`TestScenario`] /// -/// [`UCommand`]: crate::tests::common::util::UCommand -/// [`AtPath`]: crate::tests::common::util::AtPath -/// [`TestScenario]: crate::tests::common::util::TestScenario +/// [`UCommand`]: crate::util::UCommand +/// [`AtPath`]: crate::util::AtPath +/// [`TestScenario`]: crate::util::TestScenario #[macro_export] macro_rules! at_and_ucmd { () => {{ diff --git a/tests/uutests/src/lib/util.rs b/tests/uutests/src/lib/util.rs index 79c5ac96b..bef500f5c 100644 --- a/tests/uutests/src/lib/util.rs +++ b/tests/uutests/src/lib/util.rs @@ -49,6 +49,8 @@ use std::time::{Duration, Instant}; use std::{env, hint, mem, thread}; use tempfile::{Builder, TempDir}; +use std::sync::OnceLock; + static TESTS_DIR: &str = "tests"; static FIXTURES_DIR: &str = "fixtures"; @@ -60,19 +62,26 @@ static MULTIPLE_STDIN_MEANINGLESS: &str = "Ucommand is designed around a typical static NO_STDIN_MEANINGLESS: &str = "Setting this flag has no effect if there is no stdin"; static END_OF_TRANSMISSION_SEQUENCE: &[u8] = b"\n\x04"; -// we can't use -// pub const TESTS_BINARY: &str = env!("CARGO_BIN_EXE_coreutils"); -// as we are in a library, not a binary -pub fn get_tests_binary() -> String { - std::env::var("CARGO_BIN_EXE_coreutils").unwrap_or_else(|_| { - let manifest_dir = env!("CARGO_MANIFEST_DIR"); - let debug_or_release = if cfg!(debug_assertions) { - "debug" - } else { - "release" - }; - format!("{manifest_dir}/../../target/{debug_or_release}/coreutils") +static TESTS_BINARY_PATH: OnceLock = OnceLock::new(); +/// This function needs the env variable UUTESTS_BINARY_PATH +/// which will very probably be env!("`CARGO_BIN_EXE_`") +/// because here, we are in a crate but we need the name of the final binary +pub fn get_tests_binary() -> &'static str { + TESTS_BINARY_PATH.get_or_init(|| { + if let Ok(path) = env::var("UUTESTS_BINARY_PATH") { + return PathBuf::from(path); + } + panic!("Could not determine coreutils binary path. Please set UUTESTS_BINARY_PATH environment variable"); }) + .to_str() + .unwrap() +} + +#[macro_export] +macro_rules! get_tests_binary { + () => { + $crate::util::get_tests_binary() + }; } pub const PATH: &str = env!("PATH"); @@ -394,6 +403,13 @@ impl CmdResult { self.exit_status().code().unwrap() } + /// Verify the exit code of the program + /// + /// # Examples + /// + /// ```rust,ignore + /// new_ucmd!().arg("--definitely-invalid").fails().code_is(1); + /// ``` #[track_caller] pub fn code_is(&self, expected_code: i32) -> &Self { let fails = self.code() != expected_code; @@ -452,6 +468,12 @@ impl CmdResult { /// but you might find yourself using this function if /// 1. you can not know exactly what stdout will be or /// 2. you know that stdout will also be empty + /// + /// # Examples + /// + /// ```rust,ignore + /// scene.ucmd().fails().no_stderr(); + /// ``` #[track_caller] pub fn no_stderr(&self) -> &Self { assert!( @@ -468,6 +490,13 @@ impl CmdResult { /// but you might find yourself using this function if /// 1. you can not know exactly what stderr will be or /// 2. you know that stderr will also be empty + /// new_ucmd!() + /// + /// # Examples + /// + /// ```rust,ignore + /// scene.ucmd().fails().no_stdout(); + /// ``` #[track_caller] pub fn no_stdout(&self) -> &Self { assert!( @@ -690,6 +719,16 @@ impl CmdResult { )) } + /// Verify if stdout contains a specific string + /// + /// # Examples + /// + /// ```rust,ignore + /// new_ucmd!() + /// .arg("--help") + /// .succeeds() + /// .stdout_contains("Options:"); + /// ``` #[track_caller] pub fn stdout_contains>(&self, cmp: T) -> &Self { assert!( @@ -701,6 +740,16 @@ impl CmdResult { self } + /// Verify if stdout contains a specific line + /// + /// # Examples + /// + /// ```rust,ignore + /// new_ucmd!() + /// .arg("--help") + /// .succeeds() + /// .stdout_contains_line("Options:"); + /// ``` #[track_caller] pub fn stdout_contains_line>(&self, cmp: T) -> &Self { assert!( @@ -712,6 +761,17 @@ impl CmdResult { self } + /// Verify if stderr contains a specific string + /// + /// # Examples + /// + /// ```rust,ignore + /// new_ucmd!() + /// .arg("-l") + /// .arg("IaMnOtAsIgNaL") + /// .fails() + /// .stderr_contains("IaMnOtAsIgNaL"); + /// ``` #[track_caller] pub fn stderr_contains>(&self, cmp: T) -> &Self { assert!( @@ -723,6 +783,17 @@ impl CmdResult { self } + /// Verify if stdout does not contain a specific string + /// + /// # Examples + /// + /// ```rust,ignore + /// new_ucmd!() + /// .arg("-l") + /// .arg("IaMnOtAsIgNaL") + /// .fails() + /// .stdout_does_not_contain("Valid-signal"); + /// ``` #[track_caller] pub fn stdout_does_not_contain>(&self, cmp: T) -> &Self { assert!( @@ -734,6 +805,17 @@ impl CmdResult { self } + /// Verify if st stderr does not contain a specific string + /// + /// # Examples + /// + /// ```rust,ignore + /// new_ucmd!() + /// .arg("-l") + /// .arg("IaMnOtAsIgNaL") + /// .fails() + /// .stderr_does_not_contain("Valid-signal"); + /// ``` #[track_caller] pub fn stderr_does_not_contain>(&self, cmp: T) -> &Self { assert!(!self.stderr_str().contains(cmp.as_ref())); @@ -1189,9 +1271,9 @@ impl TestScenario { T: AsRef, { let tmpd = Rc::new(TempDir::new().unwrap()); - println!("bin: {:?}", get_tests_binary()); + println!("bin: {:?}", get_tests_binary!()); let ts = Self { - bin_path: PathBuf::from(get_tests_binary()), + bin_path: PathBuf::from(get_tests_binary!()), util_name: util_name.as_ref().into(), fixtures: AtPath::new(tmpd.as_ref().path()), tmpd, @@ -1284,10 +1366,10 @@ impl Drop for TestScenario { #[cfg(unix)] #[derive(Debug, Default)] pub struct TerminalSimulation { - size: Option, - stdin: bool, - stdout: bool, - stderr: bool, + pub size: Option, + pub stdin: bool, + pub stdout: bool, + pub stderr: bool, } /// A `UCommand` is a builder wrapping an individual Command that provides several additional features: @@ -1355,7 +1437,7 @@ impl UCommand { { let mut ucmd = Self::new(); ucmd.util_name = Some(util_name.as_ref().into()); - ucmd.bin_path(&*get_tests_binary()).temp_dir(tmpd); + ucmd.bin_path(&*get_tests_binary!()).temp_dir(tmpd); ucmd } @@ -1392,7 +1474,8 @@ impl UCommand { /// Set the working directory for this [`UCommand`] /// - /// Per default the working directory is set to the [`UCommands`] temporary directory. + /// Per default the working directory is set to the [`UCommand`] temporary directory. + /// pub fn current_dir(&mut self, current_dir: T) -> &mut Self where T: Into, @@ -1505,7 +1588,7 @@ impl UCommand { /// /// After the timeout elapsed these `run` methods (besides [`UCommand::run_no_wait`]) will /// panic. When [`UCommand::run_no_wait`] is used, this timeout is applied to - /// [`UChild::wait_with_output`] including all other waiting methods in [`UChild`] implicitly + /// `wait_with_output` including all other waiting methods in [`UChild`] implicitly /// using `wait_with_output()` and additionally [`UChild::kill`]. The default timeout of `kill` /// will be overwritten by this `timeout`. pub fn timeout(&mut self, timeout: Duration) -> &mut Self { @@ -1616,7 +1699,7 @@ impl UCommand { self.args.push_front(util_name.into()); } } else if let Some(util_name) = &self.util_name { - self.bin_path = Some(PathBuf::from(&*get_tests_binary())); + self.bin_path = Some(PathBuf::from(&*get_tests_binary!())); self.args.push_front(util_name.into()); // neither `bin_path` nor `util_name` was set so we apply the default to run the arguments // in a platform specific shell @@ -1811,7 +1894,6 @@ impl UCommand { let (mut command, captured_stdout, captured_stderr, stdin_pty) = self.build(); log_info("run", self.to_string()); - let child = command.spawn().unwrap(); let mut child = UChild::from(self, child, captured_stdout, captured_stderr, stdin_pty); @@ -2307,12 +2389,12 @@ impl UChild { /// Wait for the child process to terminate and return a [`CmdResult`]. /// - /// See [`UChild::wait_with_output`] for details on timeouts etc. This method can also be run if + /// See `wait_with_output` for details on timeouts etc. This method can also be run if /// the child process was killed with [`UChild::kill`]. /// /// # Errors /// - /// Returns the error from the call to [`UChild::wait_with_output`] if any + /// Returns the error from the call to `wait_with_output` if any pub fn wait(self) -> io::Result { let (bin_path, util_name, tmpd) = ( self.bin_path.clone(), @@ -2591,9 +2673,7 @@ impl UChild { /// the methods below when exiting the child process. /// /// * [`UChild::wait`] - /// * [`UChild::wait_with_output`] /// * [`UChild::pipe_in_and_wait`] - /// * [`UChild::pipe_in_and_wait_with_output`] /// /// Usually, there's no need to join manually but if needed, the [`UChild::join`] method can be /// used . @@ -2650,7 +2730,7 @@ impl UChild { /// [`UChild::pipe_in`]. /// /// # Errors - /// If [`ChildStdin::write_all`] or [`ChildStdin::flush`] returned an error + /// If [`std::process::ChildStdin::write_all`] or [`std::process::ChildStdin::flush`] returned an error pub fn try_write_in>>(&mut self, data: T) -> io::Result<()> { let ignore_stdin_write_error = self.ignore_stdin_write_error; let mut writer = self.access_stdin_as_writer(); @@ -2672,7 +2752,7 @@ impl UChild { /// Close the child process stdout. /// - /// Note this will have no effect if the output was captured with [`CapturedOutput`] which is the + /// Note this will have no effect if the output was captured with CapturedOutput which is the /// default if [`UCommand::set_stdout`] wasn't called. pub fn close_stdout(&mut self) -> &mut Self { self.raw.stdout.take(); @@ -2681,7 +2761,7 @@ impl UChild { /// Close the child process stderr. /// - /// Note this will have no effect if the output was captured with [`CapturedOutput`] which is the + /// Note this will have no effect if the output was captured with CapturedOutput which is the /// default if [`UCommand::set_stderr`] wasn't called. pub fn close_stderr(&mut self) -> &mut Self { self.raw.stderr.take(); @@ -2986,6 +3066,15 @@ mod tests { // spell-checker:ignore (tests) asdfsadfa use super::*; + // Create a init for the test with a fake value (not needed) + #[cfg(test)] + #[ctor::ctor] + fn init() { + unsafe { + std::env::set_var("UUTESTS_BINARY_PATH", ""); + } + } + pub fn run_cmd>(cmd: T) -> CmdResult { UCommand::new().arg(cmd).run() } @@ -3193,168 +3282,6 @@ mod tests { res.stdout_does_not_match(&positive); } - #[cfg(feature = "echo")] - #[test] - fn test_normalized_newlines_stdout_is() { - let ts = TestScenario::new("echo"); - let res = ts.ucmd().args(&["-ne", "A\r\nB\nC"]).run(); - - res.normalized_newlines_stdout_is("A\r\nB\nC"); - res.normalized_newlines_stdout_is("A\nB\nC"); - res.normalized_newlines_stdout_is("A\nB\r\nC"); - } - - #[cfg(feature = "echo")] - #[test] - #[should_panic] - fn test_normalized_newlines_stdout_is_fail() { - let ts = TestScenario::new("echo"); - let res = ts.ucmd().args(&["-ne", "A\r\nB\nC"]).run(); - - res.normalized_newlines_stdout_is("A\r\nB\nC\n"); - } - - #[cfg(feature = "echo")] - #[test] - fn test_cmd_result_stdout_check_and_stdout_str_check() { - let result = TestScenario::new("echo").ucmd().arg("Hello world").run(); - - result.stdout_str_check(|stdout| stdout.ends_with("world\n")); - result.stdout_check(|stdout| stdout.get(0..2).unwrap().eq(b"He")); - result.no_stderr(); - } - - #[cfg(feature = "echo")] - #[test] - fn test_cmd_result_stderr_check_and_stderr_str_check() { - let ts = TestScenario::new("echo"); - let result = run_cmd(format!( - "{} {} Hello world >&2", - ts.bin_path.display(), - ts.util_name - )); - - result.stderr_str_check(|stderr| stderr.ends_with("world\n")); - result.stderr_check(|stdout| stdout.get(0..2).unwrap().eq(b"He")); - result.no_stdout(); - } - - #[cfg(feature = "echo")] - #[test] - #[should_panic] - fn test_cmd_result_stdout_str_check_when_false_then_panics() { - let result = TestScenario::new("echo").ucmd().arg("Hello world").run(); - result.stdout_str_check(str::is_empty); - } - - #[cfg(feature = "echo")] - #[test] - #[should_panic] - fn test_cmd_result_stdout_check_when_false_then_panics() { - let result = TestScenario::new("echo").ucmd().arg("Hello world").run(); - result.stdout_check(<[u8]>::is_empty); - } - - #[cfg(feature = "echo")] - #[test] - #[should_panic] - fn test_cmd_result_stderr_str_check_when_false_then_panics() { - let result = TestScenario::new("echo").ucmd().arg("Hello world").run(); - result.stderr_str_check(|s| !s.is_empty()); - } - - #[cfg(feature = "echo")] - #[test] - #[should_panic] - fn test_cmd_result_stderr_check_when_false_then_panics() { - let result = TestScenario::new("echo").ucmd().arg("Hello world").run(); - result.stderr_check(|s| !s.is_empty()); - } - - #[cfg(feature = "echo")] - #[test] - #[should_panic] - fn test_cmd_result_stdout_check_when_predicate_panics_then_panic() { - let result = TestScenario::new("echo").ucmd().run(); - result.stdout_str_check(|_| panic!("Just testing")); - } - - #[cfg(feature = "echo")] - #[cfg(unix)] - #[test] - fn test_cmd_result_signal_when_normal_exit_then_no_signal() { - let result = TestScenario::new("echo").ucmd().run(); - assert!(result.signal().is_none()); - } - - #[cfg(feature = "sleep")] - #[cfg(unix)] - #[test] - #[should_panic = "Program must be run first or has not finished"] - fn test_cmd_result_signal_when_still_running_then_panic() { - let mut child = TestScenario::new("sleep").ucmd().arg("60").run_no_wait(); - - child - .make_assertion() - .is_alive() - .with_current_output() - .signal(); - } - - #[cfg(feature = "sleep")] - #[cfg(unix)] - #[test] - fn test_cmd_result_signal_when_kill_then_signal() { - let mut child = TestScenario::new("sleep").ucmd().arg("60").run_no_wait(); - - child.kill(); - child - .make_assertion() - .is_not_alive() - .with_current_output() - .signal_is(9) - .signal_name_is("SIGKILL") - .signal_name_is("KILL") - .signal_name_is("9") - .signal() - .expect("Signal was none"); - - let result = child.wait().unwrap(); - result - .signal_is(9) - .signal_name_is("SIGKILL") - .signal_name_is("KILL") - .signal_name_is("9") - .signal() - .expect("Signal was none"); - } - - #[cfg(feature = "sleep")] - #[cfg(unix)] - #[rstest] - #[case::signal_only_part_of_name("IGKILL")] // spell-checker: disable-line - #[case::signal_just_sig("SIG")] - #[case::signal_value_too_high("100")] - #[case::signal_value_negative("-1")] - #[should_panic = "Invalid signal name or value"] - fn test_cmd_result_signal_when_invalid_signal_name_then_panic(#[case] signal_name: &str) { - let mut child = TestScenario::new("sleep").ucmd().arg("60").run_no_wait(); - child.kill(); - let result = child.wait().unwrap(); - result.signal_name_is(signal_name); - } - - #[test] - #[cfg(feature = "sleep")] - #[cfg(unix)] - fn test_cmd_result_signal_name_is_accepts_lowercase() { - let mut child = TestScenario::new("sleep").ucmd().arg("60").run_no_wait(); - child.kill(); - let result = child.wait().unwrap(); - result.signal_name_is("sigkill"); - result.signal_name_is("kill"); - } - #[test] #[cfg(unix)] fn test_parse_coreutil_version() { @@ -3437,7 +3364,6 @@ mod tests { #[test] #[cfg(unix)] - #[cfg(feature = "whoami")] fn test_run_ucmd_as_root() { if is_ci() { println!("TEST SKIPPED (cannot run inside CI)"); @@ -3463,327 +3389,6 @@ mod tests { } } - // This error was first detected when running tail so tail is used here but - // should fail with any command that takes piped input. - // See also https://github.com/uutils/coreutils/issues/3895 - #[cfg(feature = "tail")] - #[test] - #[cfg_attr(not(feature = "expensive_tests"), ignore)] - fn test_when_piped_input_then_no_broken_pipe() { - let ts = TestScenario::new("tail"); - for i in 0..10000 { - dbg!(i); - let test_string = "a\nb\n"; - ts.ucmd() - .args(&["-n", "0"]) - .pipe_in(test_string) - .succeeds() - .no_stdout() - .no_stderr(); - } - } - - #[cfg(feature = "echo")] - #[test] - fn test_uchild_when_run_with_a_non_blocking_util() { - let ts = TestScenario::new("echo"); - ts.ucmd() - .arg("hello world") - .run() - .success() - .stdout_only("hello world\n"); - } - - // Test basically that most of the methods of UChild are working - #[cfg(feature = "echo")] - #[test] - fn test_uchild_when_run_no_wait_with_a_non_blocking_util() { - let ts = TestScenario::new("echo"); - let mut child = ts.ucmd().arg("hello world").run_no_wait(); - - // check `child.is_alive()` and `child.delay()` is working - let mut trials = 10; - while child.is_alive() { - assert!( - trials > 0, - "Assertion failed: child process is still alive." - ); - - child.delay(500); - trials -= 1; - } - - assert!(!child.is_alive()); - - // check `child.is_not_alive()` is working - assert!(child.is_not_alive()); - - // check the current output is correct - std::assert_eq!(child.stdout(), "hello world\n"); - assert!(child.stderr().is_empty()); - - // check the current output of echo is empty. We already called `child.stdout()` and `echo` - // exited so there's no additional output after the first call of `child.stdout()` - assert!(child.stdout().is_empty()); - assert!(child.stderr().is_empty()); - - // check that we're still able to access all output of the child process, even after exit - // and call to `child.stdout()` - std::assert_eq!(child.stdout_all(), "hello world\n"); - assert!(child.stderr_all().is_empty()); - - // we should be able to call kill without panics, even if the process already exited - child.make_assertion().is_not_alive(); - child.kill(); - - // we should be able to call wait without panics and apply some assertions - child.wait().unwrap().code_is(0).no_stdout().no_stderr(); - } - - #[cfg(feature = "cat")] - #[test] - fn test_uchild_when_pipe_in() { - let ts = TestScenario::new("cat"); - let mut child = ts.ucmd().set_stdin(Stdio::piped()).run_no_wait(); - child.pipe_in("content"); - child.wait().unwrap().stdout_only("content").success(); - - ts.ucmd().pipe_in("content").run().stdout_is("content"); - } - - #[cfg(feature = "rm")] - #[test] - fn test_uchild_when_run_no_wait_with_a_blocking_command() { - let ts = TestScenario::new("rm"); - let at = &ts.fixtures; - - at.mkdir("a"); - at.touch("a/empty"); - - #[cfg(target_vendor = "apple")] - let delay: u64 = 2000; - #[cfg(not(target_vendor = "apple"))] - let delay: u64 = 1000; - - let yes = if cfg!(windows) { "y\r\n" } else { "y\n" }; - - let mut child = ts - .ucmd() - .set_stdin(Stdio::piped()) - .stderr_to_stdout() - .args(&["-riv", "a"]) - .run_no_wait(); - child - .make_assertion_with_delay(delay) - .is_alive() - .with_current_output() - .stdout_is("rm: descend into directory 'a'? "); - - #[cfg(windows)] - let expected = "rm: descend into directory 'a'? \ - rm: remove regular empty file 'a\\empty'? "; - #[cfg(unix)] - let expected = "rm: descend into directory 'a'? \ - rm: remove regular empty file 'a/empty'? "; - child.write_in(yes); - child - .make_assertion_with_delay(delay) - .is_alive() - .with_all_output() - .stdout_is(expected); - - #[cfg(windows)] - let expected = "removed 'a\\empty'\nrm: remove directory 'a'? "; - #[cfg(unix)] - let expected = "removed 'a/empty'\nrm: remove directory 'a'? "; - - child - .write_in(yes) - .make_assertion_with_delay(delay) - .is_alive() - .with_exact_output(44, 0) - .stdout_only(expected); - - let expected = "removed directory 'a'\n"; - - child.write_in(yes); - child.wait().unwrap().stdout_only(expected).success(); - } - - #[cfg(feature = "tail")] - #[test] - fn test_uchild_when_run_with_stderr_to_stdout() { - let ts = TestScenario::new("tail"); - let at = &ts.fixtures; - - at.write("data", "file data\n"); - - let expected_stdout = "==> data <==\n\ - file data\n\ - tail: cannot open 'missing' for reading: No such file or directory\n"; - ts.ucmd() - .args(&["data", "missing"]) - .stderr_to_stdout() - .fails() - .stdout_only(expected_stdout); - } - - #[cfg(feature = "cat")] - #[cfg(unix)] - #[test] - fn test_uchild_when_no_capture_reading_from_infinite_source() { - use regex::Regex; - - let ts = TestScenario::new("cat"); - - let expected_stdout = b"\0".repeat(12345); - let mut child = ts - .ucmd() - .set_stdin(Stdio::from(File::open("/dev/zero").unwrap())) - .set_stdout(Stdio::piped()) - .run_no_wait(); - - child - .make_assertion() - .with_exact_output(12345, 0) - .stdout_only_bytes(expected_stdout); - - child - .kill() - .make_assertion() - .with_current_output() - .stdout_matches(&Regex::new("[\0].*").unwrap()) - .no_stderr(); - } - - #[cfg(feature = "sleep")] - #[test] - fn test_uchild_when_wait_and_timeout_is_reached_then_timeout_error() { - let ts = TestScenario::new("sleep"); - let child = ts - .ucmd() - .timeout(Duration::from_secs(1)) - .arg("10.0") - .run_no_wait(); - - match child.wait() { - Err(error) if error.kind() == io::ErrorKind::Other => { - std::assert_eq!(error.to_string(), "wait: Timeout of '1s' reached"); - } - Err(error) => panic!("Assertion failed: Expected error with timeout but was: {error}"), - Ok(_) => panic!("Assertion failed: Expected timeout of `wait`."), - } - } - - #[cfg(feature = "sleep")] - #[rstest] - #[timeout(Duration::from_secs(5))] - fn test_uchild_when_kill_and_timeout_higher_than_kill_time_then_no_panic() { - let ts = TestScenario::new("sleep"); - let mut child = ts - .ucmd() - .timeout(Duration::from_secs(60)) - .arg("20.0") - .run_no_wait(); - - child.kill().make_assertion().is_not_alive(); - } - - #[cfg(feature = "sleep")] - #[test] - fn test_uchild_when_try_kill_and_timeout_is_reached_then_error() { - let ts = TestScenario::new("sleep"); - let mut child = ts.ucmd().timeout(Duration::ZERO).arg("10.0").run_no_wait(); - - match child.try_kill() { - Err(error) if error.kind() == io::ErrorKind::Other => { - std::assert_eq!(error.to_string(), "kill: Timeout of '0s' reached"); - } - Err(error) => panic!("Assertion failed: Expected error with timeout but was: {error}"), - Ok(()) => panic!("Assertion failed: Expected timeout of `try_kill`."), - } - } - - #[cfg(feature = "sleep")] - #[test] - #[should_panic = "kill: Timeout of '0s' reached"] - fn test_uchild_when_kill_with_timeout_and_timeout_is_reached_then_panic() { - let ts = TestScenario::new("sleep"); - let mut child = ts.ucmd().timeout(Duration::ZERO).arg("10.0").run_no_wait(); - - child.kill(); - panic!("Assertion failed: Expected timeout of `kill`."); - } - - #[cfg(feature = "sleep")] - #[test] - #[should_panic(expected = "wait: Timeout of '1.1s' reached")] - fn test_ucommand_when_run_with_timeout_and_timeout_is_reached_then_panic() { - let ts = TestScenario::new("sleep"); - ts.ucmd() - .timeout(Duration::from_millis(1100)) - .arg("10.0") - .run(); - - panic!("Assertion failed: Expected timeout of `run`.") - } - - #[cfg(feature = "sleep")] - #[rstest] - #[timeout(Duration::from_secs(10))] - fn test_ucommand_when_run_with_timeout_higher_then_execution_time_then_no_panic() { - let ts = TestScenario::new("sleep"); - ts.ucmd().timeout(Duration::from_secs(60)).arg("1.0").run(); - } - - #[cfg(feature = "echo")] - #[test] - fn test_ucommand_when_default() { - let shell_cmd = format!("{TESTS_BINARY} echo -n hello"); - - let mut command = UCommand::new(); - command.arg(&shell_cmd).succeeds().stdout_is("hello"); - - #[cfg(target_os = "android")] - let (expected_bin, expected_arg) = (PathBuf::from("/system/bin/sh"), OsString::from("-c")); - #[cfg(all(unix, not(target_os = "android")))] - let (expected_bin, expected_arg) = (PathBuf::from("/bin/sh"), OsString::from("-c")); - #[cfg(windows)] - let (expected_bin, expected_arg) = (PathBuf::from("cmd"), OsString::from("/C")); - - std::assert_eq!(&expected_bin, command.bin_path.as_ref().unwrap()); - assert!(command.util_name.is_none()); - std::assert_eq!(command.args, &[expected_arg, OsString::from(&shell_cmd)]); - assert!(command.tmpd.is_some()); - } - - #[cfg(feature = "echo")] - #[test] - fn test_ucommand_with_util() { - let tmpd = tempfile::tempdir().unwrap(); - let mut command = UCommand::with_util("echo", Rc::new(tmpd)); - - command - .args(&["-n", "hello"]) - .succeeds() - .stdout_only("hello"); - - std::assert_eq!( - &PathBuf::from(TESTS_BINARY), - command.bin_path.as_ref().unwrap() - ); - std::assert_eq!("echo", &command.util_name.unwrap()); - std::assert_eq!( - &[ - OsString::from("echo"), - OsString::from("-n"), - OsString::from("hello") - ], - command.args.make_contiguous() - ); - assert!(command.tmpd.is_some()); - } - #[cfg(all(unix, not(any(target_os = "macos", target_os = "openbsd"))))] #[test] fn test_compare_xattrs() { @@ -3806,217 +3411,6 @@ mod tests { assert!(compare_xattrs(&file_path1, &file_path2)); } - #[cfg(unix)] - #[cfg(feature = "env")] - #[test] - fn test_simulation_of_terminal_false() { - let scene = TestScenario::new("util"); - - let out = scene.ccmd("env").arg("sh").arg("is_a_tty.sh").succeeds(); - std::assert_eq!( - String::from_utf8_lossy(out.stdout()), - "stdin is not a tty\nstdout is not a tty\nstderr is not a tty\n" - ); - std::assert_eq!( - String::from_utf8_lossy(out.stderr()), - "This is an error message.\n" - ); - } - - #[cfg(unix)] - #[cfg(feature = "env")] - #[test] - fn test_simulation_of_terminal_true() { - let scene = TestScenario::new("util"); - - let out = scene - .ccmd("env") - .arg("sh") - .arg("is_a_tty.sh") - .terminal_simulation(true) - .succeeds(); - std::assert_eq!( - String::from_utf8_lossy(out.stdout()), - "stdin is a tty\r\nterminal size: 30 80\r\nstdout is a tty\r\nstderr is a tty\r\n" - ); - std::assert_eq!( - String::from_utf8_lossy(out.stderr()), - "This is an error message.\r\n" - ); - } - - #[cfg(unix)] - #[cfg(feature = "env")] - #[test] - fn test_simulation_of_terminal_for_stdin_only() { - let scene = TestScenario::new("util"); - - let out = scene - .ccmd("env") - .arg("sh") - .arg("is_a_tty.sh") - .terminal_sim_stdio(TerminalSimulation { - stdin: true, - stdout: false, - stderr: false, - ..Default::default() - }) - .succeeds(); - std::assert_eq!( - String::from_utf8_lossy(out.stdout()), - "stdin is a tty\nterminal size: 30 80\nstdout is not a tty\nstderr is not a tty\n" - ); - std::assert_eq!( - String::from_utf8_lossy(out.stderr()), - "This is an error message.\n" - ); - } - - #[cfg(unix)] - #[cfg(feature = "env")] - #[test] - fn test_simulation_of_terminal_for_stdout_only() { - let scene = TestScenario::new("util"); - - let out = scene - .ccmd("env") - .arg("sh") - .arg("is_a_tty.sh") - .terminal_sim_stdio(TerminalSimulation { - stdin: false, - stdout: true, - stderr: false, - ..Default::default() - }) - .succeeds(); - std::assert_eq!( - String::from_utf8_lossy(out.stdout()), - "stdin is not a tty\r\nstdout is a tty\r\nstderr is not a tty\r\n" - ); - std::assert_eq!( - String::from_utf8_lossy(out.stderr()), - "This is an error message.\n" - ); - } - - #[cfg(unix)] - #[cfg(feature = "env")] - #[test] - fn test_simulation_of_terminal_for_stderr_only() { - let scene = TestScenario::new("util"); - - let out = scene - .ccmd("env") - .arg("sh") - .arg("is_a_tty.sh") - .terminal_sim_stdio(TerminalSimulation { - stdin: false, - stdout: false, - stderr: true, - ..Default::default() - }) - .succeeds(); - std::assert_eq!( - String::from_utf8_lossy(out.stdout()), - "stdin is not a tty\nstdout is not a tty\nstderr is a tty\n" - ); - std::assert_eq!( - String::from_utf8_lossy(out.stderr()), - "This is an error message.\r\n" - ); - } - - #[cfg(unix)] - #[cfg(feature = "env")] - #[test] - fn test_simulation_of_terminal_size_information() { - let scene = TestScenario::new("util"); - - let out = scene - .ccmd("env") - .arg("sh") - .arg("is_a_tty.sh") - .terminal_sim_stdio(TerminalSimulation { - size: Some(libc::winsize { - ws_col: 40, - ws_row: 10, - ws_xpixel: 40 * 8, - ws_ypixel: 10 * 10, - }), - stdout: true, - stdin: true, - stderr: true, - }) - .succeeds(); - std::assert_eq!( - String::from_utf8_lossy(out.stdout()), - "stdin is a tty\r\nterminal size: 10 40\r\nstdout is a tty\r\nstderr is a tty\r\n" - ); - std::assert_eq!( - String::from_utf8_lossy(out.stderr()), - "This is an error message.\r\n" - ); - } - - #[cfg(unix)] - #[cfg(feature = "env")] - #[test] - fn test_simulation_of_terminal_pty_sends_eot_automatically() { - let scene = TestScenario::new("util"); - - let mut cmd = scene.ccmd("env"); - cmd.timeout(std::time::Duration::from_secs(10)); - cmd.args(&["cat", "-"]); - cmd.terminal_simulation(true); - let child = cmd.run_no_wait(); - let out = child.wait().unwrap(); // cat would block if there is no eot - - std::assert_eq!(String::from_utf8_lossy(out.stderr()), ""); - std::assert_eq!(String::from_utf8_lossy(out.stdout()), "\r\n"); - } - - #[cfg(unix)] - #[cfg(feature = "env")] - #[test] - fn test_simulation_of_terminal_pty_pipes_into_data_and_sends_eot_automatically() { - let scene = TestScenario::new("util"); - - let message = "Hello stdin forwarding!"; - - let mut cmd = scene.ccmd("env"); - cmd.args(&["cat", "-"]); - cmd.terminal_simulation(true); - cmd.pipe_in(message); - let child = cmd.run_no_wait(); - let out = child.wait().unwrap(); - - std::assert_eq!( - String::from_utf8_lossy(out.stdout()), - format!("{message}\r\n") - ); - std::assert_eq!(String::from_utf8_lossy(out.stderr()), ""); - } - - #[cfg(unix)] - #[cfg(feature = "env")] - #[test] - fn test_simulation_of_terminal_pty_write_in_data_and_sends_eot_automatically() { - let scene = TestScenario::new("util"); - - let mut cmd = scene.ccmd("env"); - cmd.args(&["cat", "-"]); - cmd.terminal_simulation(true); - let mut child = cmd.run_no_wait(); - child.write_in("Hello stdin forwarding via write_in!"); - let out = child.wait().unwrap(); - - std::assert_eq!( - String::from_utf8_lossy(out.stdout()), - "Hello stdin forwarding via write_in!\r\n" - ); - std::assert_eq!(String::from_utf8_lossy(out.stderr()), ""); - } - #[cfg(unix)] #[test] fn test_application_of_process_resource_limits_unlimited_file_size() { From a0179ea2392424ee07f0ec31ef1f9a17603f53cf Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Fri, 28 Mar 2025 09:51:51 +0100 Subject: [PATCH 3/3] uutests: adjust the tests to use them --- tests/by-util/test_arch.rs | 4 +- tests/by-util/test_base32.rs | 4 +- tests/by-util/test_base64.rs | 4 +- tests/by-util/test_basename.rs | 4 +- tests/by-util/test_basenc.rs | 4 +- tests/by-util/test_cat.rs | 49 +++++++- tests/by-util/test_chcon.rs | 5 +- tests/by-util/test_chgrp.rs | 5 +- tests/by-util/test_chmod.rs | 6 +- tests/by-util/test_chown.rs | 5 +- tests/by-util/test_chroot.rs | 7 +- tests/by-util/test_cksum.rs | 7 +- tests/by-util/test_comm.rs | 4 +- tests/by-util/test_cp.rs | 21 ++-- tests/by-util/test_csplit.rs | 5 +- tests/by-util/test_cut.rs | 5 +- tests/by-util/test_date.rs | 5 +- tests/by-util/test_dd.rs | 21 ++-- tests/by-util/test_df.rs | 6 +- tests/by-util/test_dir.rs | 4 +- tests/by-util/test_dircolors.rs | 4 +- tests/by-util/test_dirname.rs | 4 +- tests/by-util/test_du.rs | 9 +- tests/by-util/test_echo.rs | 118 ++++++++++++++++- tests/by-util/test_env.rs | 216 +++++++++++++++++++++++++++++++- tests/by-util/test_expand.rs | 4 +- tests/by-util/test_expr.rs | 8 +- tests/by-util/test_factor.rs | 6 +- tests/by-util/test_false.rs | 7 +- tests/by-util/test_fmt.rs | 4 +- tests/by-util/test_fold.rs | 4 +- tests/by-util/test_groups.rs | 5 +- tests/by-util/test_hashsum.rs | 10 +- tests/by-util/test_head.rs | 5 +- tests/by-util/test_hostid.rs | 4 +- tests/by-util/test_hostname.rs | 4 +- tests/by-util/test_id.rs | 5 +- tests/by-util/test_install.rs | 5 +- tests/by-util/test_join.rs | 4 +- tests/by-util/test_kill.rs | 6 +- tests/by-util/test_link.rs | 5 +- tests/by-util/test_ln.rs | 5 +- tests/by-util/test_logname.rs | 4 +- tests/by-util/test_ls.rs | 11 +- tests/by-util/test_mkdir.rs | 6 +- tests/by-util/test_mkfifo.rs | 4 +- tests/by-util/test_mknod.rs | 4 +- tests/by-util/test_mktemp.rs | 5 +- tests/by-util/test_more.rs | 6 +- tests/by-util/test_mv.rs | 10 +- tests/by-util/test_nice.rs | 4 +- tests/by-util/test_nl.rs | 5 +- tests/by-util/test_nohup.rs | 5 +- tests/by-util/test_nproc.rs | 4 +- tests/by-util/test_numfmt.rs | 4 +- tests/by-util/test_od.rs | 5 +- tests/by-util/test_paste.rs | 5 +- tests/by-util/test_pathchk.rs | 4 +- tests/by-util/test_pinky.rs | 11 +- tests/by-util/test_pr.rs | 4 +- tests/by-util/test_printenv.rs | 3 +- tests/by-util/test_printf.rs | 4 +- tests/by-util/test_ptx.rs | 5 +- tests/by-util/test_pwd.rs | 5 +- tests/by-util/test_readlink.rs | 5 +- tests/by-util/test_realpath.rs | 5 +- tests/by-util/test_rm.rs | 63 +++++++++- tests/by-util/test_rmdir.rs | 5 +- tests/by-util/test_runcon.rs | 4 +- tests/by-util/test_seq.rs | 4 +- tests/by-util/test_shred.rs | 5 +- tests/by-util/test_shuf.rs | 5 +- tests/by-util/test_sleep.rs | 147 +++++++++++++++++++++- tests/by-util/test_sort.rs | 5 +- tests/by-util/test_split.rs | 6 +- tests/by-util/test_stat.rs | 6 +- tests/by-util/test_stdbuf.rs | 4 +- tests/by-util/test_stty.rs | 4 +- tests/by-util/test_sum.rs | 5 +- tests/by-util/test_sync.rs | 4 +- tests/by-util/test_tac.rs | 4 +- tests/by-util/test_tail.rs | 54 +++++++- tests/by-util/test_tee.rs | 9 +- tests/by-util/test_test.rs | 5 +- tests/by-util/test_timeout.rs | 4 +- tests/by-util/test_touch.rs | 5 +- tests/by-util/test_tr.rs | 5 +- tests/by-util/test_true.rs | 6 +- tests/by-util/test_truncate.rs | 5 +- tests/by-util/test_tsort.rs | 5 +- tests/by-util/test_tty.rs | 4 +- tests/by-util/test_uname.rs | 5 +- tests/by-util/test_unexpand.rs | 5 +- tests/by-util/test_uniq.rs | 5 +- tests/by-util/test_unlink.rs | 5 +- tests/by-util/test_uptime.rs | 5 +- tests/by-util/test_users.rs | 4 +- tests/by-util/test_vdir.rs | 4 +- tests/by-util/test_wc.rs | 6 +- tests/by-util/test_who.rs | 6 +- tests/by-util/test_whoami.rs | 8 +- tests/by-util/test_yes.rs | 4 +- 102 files changed, 1018 insertions(+), 157 deletions(-) diff --git a/tests/by-util/test_arch.rs b/tests/by-util/test_arch.rs index 2486f3d48..99a0cb9e8 100644 --- a/tests/by-util/test_arch.rs +++ b/tests/by-util/test_arch.rs @@ -2,7 +2,9 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_arch() { diff --git a/tests/by-util/test_base32.rs b/tests/by-util/test_base32.rs index eb75a4ddf..af5df848e 100644 --- a/tests/by-util/test_base32.rs +++ b/tests/by-util/test_base32.rs @@ -4,7 +4,9 @@ // file that was distributed with this source code. // -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_encode() { diff --git a/tests/by-util/test_base64.rs b/tests/by-util/test_base64.rs index 937e2b073..ba0e3adaf 100644 --- a/tests/by-util/test_base64.rs +++ b/tests/by-util/test_base64.rs @@ -2,7 +2,9 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_encode() { diff --git a/tests/by-util/test_basename.rs b/tests/by-util/test_basename.rs index 701d63eb4..e9c44dbe2 100644 --- a/tests/by-util/test_basename.rs +++ b/tests/by-util/test_basename.rs @@ -4,9 +4,11 @@ // file that was distributed with this source code. // spell-checker:ignore (words) reallylongexecutable nbaz -use crate::common::util::TestScenario; #[cfg(any(unix, target_os = "redox"))] use std::ffi::OsStr; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_help() { diff --git a/tests/by-util/test_basenc.rs b/tests/by-util/test_basenc.rs index c0f40cd1d..438fea6cc 100644 --- a/tests/by-util/test_basenc.rs +++ b/tests/by-util/test_basenc.rs @@ -5,7 +5,9 @@ // spell-checker: ignore (encodings) lsbf msbf -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_z85_not_padded_decode() { diff --git a/tests/by-util/test_cat.rs b/tests/by-util/test_cat.rs index 4f28d0527..be405dfc6 100644 --- a/tests/by-util/test_cat.rs +++ b/tests/by-util/test_cat.rs @@ -4,16 +4,18 @@ // file that was distributed with this source code. // spell-checker:ignore NOFILE nonewline cmdline -use crate::common::util::TestScenario; -#[cfg(not(windows))] -use crate::common::util::vec_of_size; #[cfg(any(target_os = "linux", target_os = "android"))] use rlimit::Resource; -#[cfg(target_os = "linux")] +#[cfg(unix)] use std::fs::File; use std::fs::OpenOptions; -#[cfg(not(windows))] use std::process::Stdio; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +#[cfg(not(windows))] +use uutests::util::vec_of_size; +use uutests::util_name; #[test] fn test_output_simple() { @@ -668,3 +670,40 @@ fn test_appending_same_input_output() { .no_stdout() .stderr_contains("input file is output file"); } + +#[cfg(unix)] +#[test] +fn test_uchild_when_no_capture_reading_from_infinite_source() { + use regex::Regex; + + let ts = TestScenario::new("cat"); + + let expected_stdout = b"\0".repeat(12345); + let mut child = ts + .ucmd() + .set_stdin(Stdio::from(File::open("/dev/zero").unwrap())) + .set_stdout(Stdio::piped()) + .run_no_wait(); + + child + .make_assertion() + .with_exact_output(12345, 0) + .stdout_only_bytes(expected_stdout); + + child + .kill() + .make_assertion() + .with_current_output() + .stdout_matches(&Regex::new("[\0].*").unwrap()) + .no_stderr(); +} + +#[test] +fn test_child_when_pipe_in() { + let ts = TestScenario::new("cat"); + let mut child = ts.ucmd().set_stdin(Stdio::piped()).run_no_wait(); + child.pipe_in("content"); + child.wait().unwrap().stdout_only("content").success(); + + ts.ucmd().pipe_in("content").run().stdout_is("content"); +} diff --git a/tests/by-util/test_chcon.rs b/tests/by-util/test_chcon.rs index d05571da0..419b595b5 100644 --- a/tests/by-util/test_chcon.rs +++ b/tests/by-util/test_chcon.rs @@ -10,7 +10,10 @@ use std::ffi::CString; use std::path::Path; use std::{io, iter, str}; -use crate::common::util::*; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn version() { diff --git a/tests/by-util/test_chgrp.rs b/tests/by-util/test_chgrp.rs index 2af7620ae..36250d507 100644 --- a/tests/by-util/test_chgrp.rs +++ b/tests/by-util/test_chgrp.rs @@ -4,8 +4,11 @@ // file that was distributed with this source code. // spell-checker:ignore (words) nosuchgroup groupname -use crate::common::util::TestScenario; use uucore::process::getegid; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_option() { diff --git a/tests/by-util/test_chmod.rs b/tests/by-util/test_chmod.rs index 48a2d7304..310bdb9d2 100644 --- a/tests/by-util/test_chmod.rs +++ b/tests/by-util/test_chmod.rs @@ -3,9 +3,13 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::{AtPath, TestScenario, UCommand}; use std::fs::{OpenOptions, Permissions, metadata, set_permissions}; use std::os::unix::fs::{OpenOptionsExt, PermissionsExt}; +use uutests::at_and_ucmd; +use uutests::util::{AtPath, TestScenario, UCommand}; + +use uutests::new_ucmd; +use uutests::util_name; static TEST_FILE: &str = "file"; static REFERENCE_FILE: &str = "reference"; diff --git a/tests/by-util/test_chown.rs b/tests/by-util/test_chown.rs index a13b5dad0..33bc4b850 100644 --- a/tests/by-util/test_chown.rs +++ b/tests/by-util/test_chown.rs @@ -4,10 +4,11 @@ // file that was distributed with this source code. // spell-checker:ignore (words) agroupthatdoesntexist auserthatdoesntexist cuuser groupname notexisting passgrp -use crate::common::util::{CmdResult, TestScenario, is_ci, run_ucmd_as_root}; #[cfg(any(target_os = "linux", target_os = "android"))] use uucore::process::geteuid; - +use uutests::new_ucmd; +use uutests::util::{CmdResult, TestScenario, is_ci, run_ucmd_as_root}; +use uutests::util_name; // Apparently some CI environments have configuration issues, e.g. with 'whoami' and 'id'. // If we are running inside the CI and "needle" is in "stderr" skipping this test is // considered okay. If we are not inside the CI this calls assert!(result.success). diff --git a/tests/by-util/test_chroot.rs b/tests/by-util/test_chroot.rs index cd3f4eecc..38c3727b1 100644 --- a/tests/by-util/test_chroot.rs +++ b/tests/by-util/test_chroot.rs @@ -4,9 +4,12 @@ // file that was distributed with this source code. // spell-checker:ignore (words) araba newroot userspec chdir pwd's isroot +use uutests::at_and_ucmd; +use uutests::new_ucmd; #[cfg(not(target_os = "android"))] -use crate::common::util::is_ci; -use crate::common::util::{TestScenario, run_ucmd_as_root}; +use uutests::util::is_ci; +use uutests::util::{TestScenario, run_ucmd_as_root}; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_cksum.rs b/tests/by-util/test_cksum.rs index 97761d5bf..c6b0f4c3a 100644 --- a/tests/by-util/test_cksum.rs +++ b/tests/by-util/test_cksum.rs @@ -4,7 +4,10 @@ // file that was distributed with this source code. // spell-checker:ignore (words) asdf algo algos asha mgmt xffname hexa GFYEQ HYQK Yqxb dont -use crate::common::util::TestScenario; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; const ALGOS: [&str; 11] = [ "sysv", "bsd", "crc", "md5", "sha1", "sha224", "sha256", "sha384", "sha512", "blake2b", "sm3", @@ -1681,7 +1684,7 @@ fn test_check_incorrectly_formatted_checksum_keeps_processing_hex() { /// This module reimplements the cksum-base64.pl GNU test. mod gnu_cksum_base64 { use super::*; - use crate::common::util::log_info; + use uutests::util::log_info; const PAIRS: [(&str, &str); 12] = [ ("sysv", "0 0 f"), diff --git a/tests/by-util/test_comm.rs b/tests/by-util/test_comm.rs index aa2b36962..058ab80ed 100644 --- a/tests/by-util/test_comm.rs +++ b/tests/by-util/test_comm.rs @@ -4,7 +4,9 @@ // file that was distributed with this source code. // spell-checker:ignore (words) defaultcheck nocheck helpb helpz nwordb nwordwordz wordtotal -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index d7af5faed..0d6526b47 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -4,7 +4,12 @@ // file that was distributed with this source code. // spell-checker:ignore (flags) reflink (fs) tmpfs (linux) rlimit Rlim NOFILE clob btrfs neve ROOTDIR USERDIR procfs outfile uufs xattrs // spell-checker:ignore bdfl hlsl IRWXO IRWXG getfattr -use crate::common::util::TestScenario; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::path_concat; +use uutests::util::TestScenario; +use uutests::util_name; + #[cfg(not(windows))] use std::fs::set_permissions; @@ -34,7 +39,7 @@ use std::time::Duration; #[cfg(any(target_os = "linux", target_os = "android"))] #[cfg(feature = "truncate")] -use crate::common::util::PATH; +use uutests::util::PATH; static TEST_EXISTING_FILE: &str = "existing_file.txt"; static TEST_HELLO_WORLD_SOURCE: &str = "hello_world.txt"; @@ -60,7 +65,7 @@ static TEST_NONEXISTENT_FILE: &str = "nonexistent_file.txt"; unix, not(any(target_os = "android", target_os = "macos", target_os = "openbsd")) ))] -use crate::common::util::compare_xattrs; +use uutests::util::compare_xattrs; /// Assert that mode, ownership, and permissions of two metadata objects match. #[cfg(all(not(windows), not(target_os = "freebsd")))] @@ -2372,7 +2377,7 @@ fn test_cp_target_file_dev_null() { #[test] #[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))] fn test_cp_one_file_system() { - use crate::common::util::AtPath; + use uutests::util::AtPath; use walkdir::WalkDir; let mut scene = TestScenario::new(util_name!()); @@ -4669,7 +4674,8 @@ fn test_cp_no_dereference_attributes_only_with_symlink() { /// contains the test for cp when the source and destination points to the same file mod same_file { - use crate::common::util::TestScenario; + use uutests::util::TestScenario; + use uutests::util_name; const FILE_NAME: &str = "foo"; const SYMLINK_NAME: &str = "symlink"; @@ -5594,8 +5600,9 @@ mod same_file { #[cfg(all(unix, not(target_os = "android")))] mod link_deref { - use crate::common::util::{AtPath, TestScenario}; use std::os::unix::fs::MetadataExt; + use uutests::util::{AtPath, TestScenario}; + use uutests::util_name; const FILE: &str = "file"; const FILE_LINK: &str = "file_link"; @@ -6037,8 +6044,8 @@ fn test_cp_no_file() { not(any(target_os = "android", target_os = "macos", target_os = "openbsd")) ))] fn test_cp_preserve_xattr_readonly_source() { - use crate::common::util::compare_xattrs; use std::process::Command; + use uutests::util::compare_xattrs; let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; diff --git a/tests/by-util/test_csplit.rs b/tests/by-util/test_csplit.rs index d571fb5cf..1029344d1 100644 --- a/tests/by-util/test_csplit.rs +++ b/tests/by-util/test_csplit.rs @@ -2,8 +2,11 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; use glob::glob; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; /// Returns a string of numbers with the given range, each on a new line. /// The upper bound is not included. diff --git a/tests/by-util/test_cut.rs b/tests/by-util/test_cut.rs index 7c74992ae..10f9a6c1e 100644 --- a/tests/by-util/test_cut.rs +++ b/tests/by-util/test_cut.rs @@ -5,7 +5,10 @@ // spell-checker:ignore defg -use crate::common::util::TestScenario; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; static INPUT: &str = "lists.txt"; diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index e15ed2e00..40b069c11 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -3,10 +3,13 @@ use chrono::{DateTime, Duration, Utc}; // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; use regex::Regex; #[cfg(all(unix, not(target_os = "macos")))] use uucore::process::geteuid; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_dd.rs b/tests/by-util/test_dd.rs index 757f98773..e46015b55 100644 --- a/tests/by-util/test_dd.rs +++ b/tests/by-util/test_dd.rs @@ -4,11 +4,14 @@ // file that was distributed with this source code. // spell-checker:ignore fname, tname, fpath, specfile, testfile, unspec, ifile, ofile, outfile, fullblock, urand, fileio, atoe, atoibm, availible, behaviour, bmax, bremain, btotal, cflags, creat, ctable, ctty, datastructures, doesnt, etoa, fileout, fname, gnudd, iconvflags, iseek, nocache, noctty, noerror, nofollow, nolinks, nonblock, oconvflags, oseek, outfile, parseargs, rlen, rmax, rposition, rremain, rsofar, rstat, sigusr, sigval, wlen, wstat abcdefghijklm abcdefghi nabcde nabcdefg abcdefg fifoname seekable -use crate::common::util::TestScenario; -#[cfg(all(unix, not(feature = "feat_selinux")))] -use crate::common::util::run_ucmd_as_root_with_stdin_stdout; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +#[cfg(unix)] +use uutests::util::run_ucmd_as_root_with_stdin_stdout; #[cfg(all(not(windows), feature = "printf"))] -use crate::common::util::{TESTS_BINARY, UCommand}; +use uutests::util::{UCommand, get_tests_binary}; +use uutests::util_name; use regex::Regex; use uucore::io::OwnedFileDescriptorOrHandle; @@ -1505,9 +1508,9 @@ fn test_skip_input_fifo() { #[test] fn test_multiple_processes_reading_stdin() { // TODO Investigate if this is possible on Windows. - let printf = format!("{TESTS_BINARY} printf 'abcdef\n'"); - let dd_skip = format!("{TESTS_BINARY} dd bs=1 skip=3 count=0"); - let dd = format!("{TESTS_BINARY} dd"); + let printf = format!("{} printf 'abcdef\n'", get_tests_binary()); + let dd_skip = format!("{} dd bs=1 skip=3 count=0", get_tests_binary()); + let dd = format!("{} dd", get_tests_binary()); UCommand::new() .arg(format!("{printf} | ( {dd_skip} && {dd} ) 2> /dev/null")) .succeeds() @@ -1609,7 +1612,7 @@ fn test_reading_partial_blocks_from_fifo() { // Start a `dd` process that reads from the fifo (so it will wait // until the writer process starts). - let mut reader_command = Command::new(TESTS_BINARY); + let mut reader_command = Command::new(get_tests_binary()); let child = reader_command .args(["dd", "ibs=3", "obs=3", &format!("if={fifoname}")]) .stdout(Stdio::piped()) @@ -1653,7 +1656,7 @@ fn test_reading_partial_blocks_from_fifo_unbuffered() { // until the writer process starts). // // `bs=N` takes precedence over `ibs=N` and `obs=N`. - let mut reader_command = Command::new(TESTS_BINARY); + let mut reader_command = Command::new(get_tests_binary()); let child = reader_command .args(["dd", "bs=3", "ibs=1", "obs=1", &format!("if={fifoname}")]) .stdout(Stdio::piped()) diff --git a/tests/by-util/test_df.rs b/tests/by-util/test_df.rs index d3692a7f0..95131e556 100644 --- a/tests/by-util/test_df.rs +++ b/tests/by-util/test_df.rs @@ -12,7 +12,11 @@ use std::collections::HashSet; -use crate::common::util::TestScenario; +#[cfg(not(any(target_os = "freebsd", target_os = "windows")))] +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_dir.rs b/tests/by-util/test_dir.rs index 3d16f8a67..ef455c6bd 100644 --- a/tests/by-util/test_dir.rs +++ b/tests/by-util/test_dir.rs @@ -2,8 +2,10 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; use regex::Regex; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; /* * As dir use the same functions than ls, we don't have to retest them here. diff --git a/tests/by-util/test_dircolors.rs b/tests/by-util/test_dircolors.rs index 6665d3bc7..28722f2e3 100644 --- a/tests/by-util/test_dircolors.rs +++ b/tests/by-util/test_dircolors.rs @@ -3,7 +3,9 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. // spell-checker:ignore overridable colorterm -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; use dircolors::{OutputFmt, StrUtils, guess_syntax}; diff --git a/tests/by-util/test_dirname.rs b/tests/by-util/test_dirname.rs index 9df287a12..3b8aee37d 100644 --- a/tests/by-util/test_dirname.rs +++ b/tests/by-util/test_dirname.rs @@ -2,7 +2,9 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_du.rs b/tests/by-util/test_du.rs index c205923ff..1edbeb63c 100644 --- a/tests/by-util/test_du.rs +++ b/tests/by-util/test_du.rs @@ -7,9 +7,14 @@ #[cfg(not(windows))] use regex::Regex; -use crate::common::util::TestScenario; +use uutests::at_and_ucmd; +use uutests::new_ucmd; #[cfg(not(target_os = "windows"))] -use crate::common::util::expected_result; +use uutests::unwrap_or_return; +use uutests::util::TestScenario; +#[cfg(not(target_os = "windows"))] +use uutests::util::expected_result; +use uutests::util_name; #[cfg(not(target_os = "openbsd"))] const SUB_DIR: &str = "subdir/deeper"; diff --git a/tests/by-util/test_echo.rs b/tests/by-util/test_echo.rs index d4430d056..1045d6a52 100644 --- a/tests/by-util/test_echo.rs +++ b/tests/by-util/test_echo.rs @@ -2,9 +2,12 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -// spell-checker:ignore (words) araba merci +// spell-checker:ignore (words) araba merci mright -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util::UCommand; +use uutests::util_name; #[test] fn test_default() { @@ -391,6 +394,64 @@ fn slash_eight_off_by_one() { .stdout_only(r"\8"); } +#[test] +fn test_normalized_newlines_stdout_is() { + let res = new_ucmd!().args(&["-ne", "A\r\nB\nC"]).run(); + + res.normalized_newlines_stdout_is("A\r\nB\nC"); + res.normalized_newlines_stdout_is("A\nB\nC"); + res.normalized_newlines_stdout_is("A\nB\r\nC"); +} + +#[test] +fn test_normalized_newlines_stdout_is_fail() { + new_ucmd!() + .args(&["-ne", "A\r\nB\nC"]) + .run() + .stdout_is("A\r\nB\nC"); +} + +#[test] +fn test_cmd_result_stdout_check_and_stdout_str_check() { + let result = new_ucmd!().arg("Hello world").run(); + + result.stdout_str_check(|stdout| stdout.ends_with("world\n")); + result.stdout_check(|stdout| stdout.get(0..2).unwrap().eq(b"He")); + result.no_stderr(); +} + +#[test] +fn test_cmd_result_stderr_check_and_stderr_str_check() { + let ts = TestScenario::new("echo"); + + let result = UCommand::new() + .arg(format!( + "{} {} Hello world >&2", + ts.bin_path.display(), + ts.util_name + )) + .run(); + + result.stderr_str_check(|stderr| stderr.ends_with("world\n")); + result.stderr_check(|stdout| stdout.get(0..2).unwrap().eq(b"He")); + result.no_stdout(); +} + +#[test] +fn test_cmd_result_stdout_str_check_when_false_then_panics() { + new_ucmd!() + .args(&["-e", "\\f"]) + .succeeds() + .stdout_only("\x0C\n"); +} + +#[cfg(unix)] +#[test] +fn test_cmd_result_signal_when_normal_exit_then_no_signal() { + let result = TestScenario::new("echo").ucmd().run(); + assert!(result.signal().is_none()); +} + mod posixly_correct { use super::*; @@ -442,3 +503,56 @@ mod posixly_correct { .stdout_only("foo"); } } + +#[test] +fn test_child_when_run_with_a_non_blocking_util() { + new_ucmd!() + .arg("hello world") + .run() + .success() + .stdout_only("hello world\n"); +} + +// Test basically that most of the methods of UChild are working +#[test] +fn test_uchild_when_run_no_wait_with_a_non_blocking_util() { + let mut child = new_ucmd!().arg("hello world").run_no_wait(); + + // check `child.is_alive()` and `child.delay()` is working + let mut trials = 10; + while child.is_alive() { + assert!( + trials > 0, + "Assertion failed: child process is still alive." + ); + + child.delay(500); + trials -= 1; + } + + assert!(!child.is_alive()); + + // check `child.is_not_alive()` is working + assert!(child.is_not_alive()); + + // check the current output is correct + std::assert_eq!(child.stdout(), "hello world\n"); + assert!(child.stderr().is_empty()); + + // check the current output of echo is empty. We already called `child.stdout()` and `echo` + // exited so there's no additional output after the first call of `child.stdout()` + assert!(child.stdout().is_empty()); + assert!(child.stderr().is_empty()); + + // check that we're still able to access all output of the child process, even after exit + // and call to `child.stdout()` + std::assert_eq!(child.stdout_all(), "hello world\n"); + assert!(child.stderr_all().is_empty()); + + // we should be able to call kill without panics, even if the process already exited + child.make_assertion().is_not_alive(); + child.kill(); + + // we should be able to call wait without panics and apply some assertions + child.wait().unwrap().code_is(0).no_stdout().no_stderr(); +} diff --git a/tests/by-util/test_env.rs b/tests/by-util/test_env.rs index c52c540e0..7a44b1877 100644 --- a/tests/by-util/test_env.rs +++ b/tests/by-util/test_env.rs @@ -2,12 +2,9 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -// spell-checker:ignore (words) bamf chdir rlimit prlimit COMSPEC cout cerr FFFD +// spell-checker:ignore (words) bamf chdir rlimit prlimit COMSPEC cout cerr FFFD winsize xpixel ypixel #![allow(clippy::missing_errors_doc)] -use crate::common::util::TestScenario; -#[cfg(unix)] -use crate::common::util::UChild; #[cfg(unix)] use nix::sys::signal::Signal; #[cfg(feature = "echo")] @@ -17,6 +14,13 @@ use std::path::Path; #[cfg(unix)] use std::process::Command; use tempfile::tempdir; +use uutests::new_ucmd; +#[cfg(unix)] +use uutests::util::TerminalSimulation; +use uutests::util::TestScenario; +#[cfg(unix)] +use uutests::util::UChild; +use uutests::util_name; #[cfg(unix)] struct Target { @@ -520,7 +524,7 @@ fn test_split_string_into_args_debug_output_whitespace_handling() { fn test_gnu_e20() { let scene = TestScenario::new(util_name!()); - let env_bin = String::from(crate::common::util::TESTS_BINARY) + " " + util_name!(); + let env_bin = String::from(uutests::util::get_tests_binary()) + " " + util_name!(); let (input, output) = ( [ @@ -1516,3 +1520,205 @@ mod test_raw_string_parser { ); } } + +#[cfg(unix)] +#[test] +fn test_simulation_of_terminal_false() { + let scene = TestScenario::new("util"); + + let out = scene.ccmd("env").arg("sh").arg("is_a_tty.sh").succeeds(); + std::assert_eq!( + String::from_utf8_lossy(out.stdout()), + "stdin is not a tty\nstdout is not a tty\nstderr is not a tty\n" + ); + std::assert_eq!( + String::from_utf8_lossy(out.stderr()), + "This is an error message.\n" + ); +} + +#[cfg(unix)] +#[test] +fn test_simulation_of_terminal_true() { + let scene = TestScenario::new("util"); + + let out = scene + .ccmd("env") + .arg("sh") + .arg("is_a_tty.sh") + .terminal_simulation(true) + .succeeds(); + std::assert_eq!( + String::from_utf8_lossy(out.stdout()), + "stdin is a tty\r\nterminal size: 30 80\r\nstdout is a tty\r\nstderr is a tty\r\n" + ); + std::assert_eq!( + String::from_utf8_lossy(out.stderr()), + "This is an error message.\r\n" + ); +} + +#[cfg(unix)] +#[test] +fn test_simulation_of_terminal_for_stdin_only() { + let scene = TestScenario::new("util"); + + let out = scene + .ccmd("env") + .arg("sh") + .arg("is_a_tty.sh") + .terminal_sim_stdio(TerminalSimulation { + stdin: true, + stdout: false, + stderr: false, + ..Default::default() + }) + .succeeds(); + std::assert_eq!( + String::from_utf8_lossy(out.stdout()), + "stdin is a tty\nterminal size: 30 80\nstdout is not a tty\nstderr is not a tty\n" + ); + std::assert_eq!( + String::from_utf8_lossy(out.stderr()), + "This is an error message.\n" + ); +} + +#[cfg(unix)] +#[test] +fn test_simulation_of_terminal_for_stdout_only() { + let scene = TestScenario::new("util"); + + let out = scene + .ccmd("env") + .arg("sh") + .arg("is_a_tty.sh") + .terminal_sim_stdio(TerminalSimulation { + stdin: false, + stdout: true, + stderr: false, + ..Default::default() + }) + .succeeds(); + std::assert_eq!( + String::from_utf8_lossy(out.stdout()), + "stdin is not a tty\r\nstdout is a tty\r\nstderr is not a tty\r\n" + ); + std::assert_eq!( + String::from_utf8_lossy(out.stderr()), + "This is an error message.\n" + ); +} + +#[cfg(unix)] +#[test] +fn test_simulation_of_terminal_for_stderr_only() { + let scene = TestScenario::new("util"); + + let out = scene + .ccmd("env") + .arg("sh") + .arg("is_a_tty.sh") + .terminal_sim_stdio(TerminalSimulation { + stdin: false, + stdout: false, + stderr: true, + ..Default::default() + }) + .succeeds(); + std::assert_eq!( + String::from_utf8_lossy(out.stdout()), + "stdin is not a tty\nstdout is not a tty\nstderr is a tty\n" + ); + std::assert_eq!( + String::from_utf8_lossy(out.stderr()), + "This is an error message.\r\n" + ); +} + +#[cfg(unix)] +#[test] +fn test_simulation_of_terminal_size_information() { + let scene = TestScenario::new("util"); + + let out = scene + .ccmd("env") + .arg("sh") + .arg("is_a_tty.sh") + .terminal_sim_stdio(TerminalSimulation { + size: Some(libc::winsize { + ws_col: 40, + ws_row: 10, + ws_xpixel: 40 * 8, + ws_ypixel: 10 * 10, + }), + stdout: true, + stdin: true, + stderr: true, + }) + .succeeds(); + std::assert_eq!( + String::from_utf8_lossy(out.stdout()), + "stdin is a tty\r\nterminal size: 10 40\r\nstdout is a tty\r\nstderr is a tty\r\n" + ); + std::assert_eq!( + String::from_utf8_lossy(out.stderr()), + "This is an error message.\r\n" + ); +} + +#[cfg(unix)] +#[test] +fn test_simulation_of_terminal_pty_sends_eot_automatically() { + let scene = TestScenario::new("util"); + + let mut cmd = scene.ccmd("env"); + cmd.timeout(std::time::Duration::from_secs(10)); + cmd.args(&["cat", "-"]); + cmd.terminal_simulation(true); + let child = cmd.run_no_wait(); + let out = child.wait().unwrap(); // cat would block if there is no eot + + std::assert_eq!(String::from_utf8_lossy(out.stderr()), ""); + std::assert_eq!(String::from_utf8_lossy(out.stdout()), "\r\n"); +} + +#[cfg(unix)] +#[test] +fn test_simulation_of_terminal_pty_pipes_into_data_and_sends_eot_automatically() { + let scene = TestScenario::new("util"); + + let message = "Hello stdin forwarding!"; + + let mut cmd = scene.ccmd("env"); + cmd.args(&["cat", "-"]); + cmd.terminal_simulation(true); + cmd.pipe_in(message); + let child = cmd.run_no_wait(); + let out = child.wait().unwrap(); + + std::assert_eq!( + String::from_utf8_lossy(out.stdout()), + format!("{message}\r\n") + ); + std::assert_eq!(String::from_utf8_lossy(out.stderr()), ""); +} + +#[cfg(unix)] +#[test] +fn test_simulation_of_terminal_pty_write_in_data_and_sends_eot_automatically() { + let scene = TestScenario::new("util"); + + let mut cmd = scene.ccmd("env"); + cmd.args(&["cat", "-"]); + cmd.terminal_simulation(true); + let mut child = cmd.run_no_wait(); + child.write_in("Hello stdin forwarding via write_in!"); + let out = child.wait().unwrap(); + + std::assert_eq!( + String::from_utf8_lossy(out.stdout()), + "Hello stdin forwarding via write_in!\r\n" + ); + std::assert_eq!(String::from_utf8_lossy(out.stderr()), ""); +} diff --git a/tests/by-util/test_expand.rs b/tests/by-util/test_expand.rs index 1d5608ef1..8e4de344e 100644 --- a/tests/by-util/test_expand.rs +++ b/tests/by-util/test_expand.rs @@ -2,8 +2,10 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; use uucore::display::Quotable; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; // spell-checker:ignore (ToDO) taaaa tbbbb tcccc #[test] diff --git a/tests/by-util/test_expr.rs b/tests/by-util/test_expr.rs index c391565e4..df2c27c1c 100644 --- a/tests/by-util/test_expr.rs +++ b/tests/by-util/test_expr.rs @@ -7,7 +7,9 @@ // spell-checker:ignore abbccd abcac acabc andand bigcmp bignum emptysub // spell-checker:ignore orempty oror -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_no_arguments() { @@ -400,7 +402,9 @@ fn test_long_input() { /// Regroup the testcases of the GNU test expr.pl mod gnu_expr { - use crate::common::util::TestScenario; + use uutests::new_ucmd; + use uutests::util::TestScenario; + use uutests::util_name; #[test] fn test_a() { diff --git a/tests/by-util/test_factor.rs b/tests/by-util/test_factor.rs index 4e784b701..2e86c82a7 100644 --- a/tests/by-util/test_factor.rs +++ b/tests/by-util/test_factor.rs @@ -10,7 +10,9 @@ clippy::cast_sign_loss )] -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; use std::time::{Duration, SystemTime}; @@ -44,11 +46,11 @@ fn test_repeated_exponents() { #[cfg(feature = "sort")] #[cfg(not(target_os = "android"))] fn test_parallel() { - use crate::common::util::AtPath; use hex_literal::hex; use sha1::{Digest, Sha1}; use std::{fs::OpenOptions, time::Duration}; use tempfile::TempDir; + use uutests::util::AtPath; // factor should only flush the buffer at line breaks let n_integers = 100_000; let mut input_string = String::new(); diff --git a/tests/by-util/test_false.rs b/tests/by-util/test_false.rs index 23b3e914b..fafd9e6a2 100644 --- a/tests/by-util/test_false.rs +++ b/tests/by-util/test_false.rs @@ -2,13 +2,12 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. - -use crate::common::util::TestScenario; use regex::Regex; - #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))] use std::fs::OpenOptions; - +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_no_args() { new_ucmd!().fails().no_output(); diff --git a/tests/by-util/test_fmt.rs b/tests/by-util/test_fmt.rs index c97e795f8..8d851d5ce 100644 --- a/tests/by-util/test_fmt.rs +++ b/tests/by-util/test_fmt.rs @@ -2,7 +2,9 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_fold.rs b/tests/by-util/test_fold.rs index 2ef182db1..d916a9c77 100644 --- a/tests/by-util/test_fold.rs +++ b/tests/by-util/test_fold.rs @@ -2,7 +2,9 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_groups.rs b/tests/by-util/test_groups.rs index 848b81621..984caef39 100644 --- a/tests/by-util/test_groups.rs +++ b/tests/by-util/test_groups.rs @@ -5,7 +5,10 @@ //spell-checker: ignore coreutil -use crate::common::util::{TestScenario, check_coreutil_version, expected_result, whoami}; +use uutests::new_ucmd; +use uutests::unwrap_or_return; +use uutests::util::{TestScenario, check_coreutil_version, expected_result, whoami}; +use uutests::util_name; const VERSION_MIN_MULTIPLE_USERS: &str = "8.31"; // this feature was introduced in GNU's coreutils 8.31 diff --git a/tests/by-util/test_hashsum.rs b/tests/by-util/test_hashsum.rs index f4c320ef9..12b18b83d 100644 --- a/tests/by-util/test_hashsum.rs +++ b/tests/by-util/test_hashsum.rs @@ -2,7 +2,10 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; + +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; // spell-checker:ignore checkfile, nonames, testf, ntestf macro_rules! get_hash( ($str:expr) => ( @@ -14,7 +17,7 @@ macro_rules! test_digest { ($($id:ident $t:ident $size:expr)*) => ($( mod $id { - use crate::common::util::*; + use uutests::util::*; static DIGEST_ARG: &'static str = concat!("--", stringify!($t)); static BITS_ARG: &'static str = concat!("--bits=", stringify!($size)); static EXPECTED_FILE: &'static str = concat!(stringify!($id), ".expected"); @@ -72,6 +75,9 @@ macro_rules! test_digest { #[cfg(windows)] #[test] fn test_text_mode() { + use uutests::new_ucmd; + use uutests::util_name; + // TODO Replace this with hard-coded files that store the // expected output of text mode on an input file that has // "\r\n" line endings. diff --git a/tests/by-util/test_head.rs b/tests/by-util/test_head.rs index 04b68b9c7..efba388dc 100644 --- a/tests/by-util/test_head.rs +++ b/tests/by-util/test_head.rs @@ -6,7 +6,6 @@ // spell-checker:ignore (words) bogusfile emptyfile abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstu // spell-checker:ignore (words) seekable -use crate::common::util::TestScenario; #[cfg(all( not(target_os = "windows"), not(target_os = "macos"), @@ -15,7 +14,9 @@ use crate::common::util::TestScenario; not(target_os = "openbsd") ))] use std::io::Read; - +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; static INPUT: &str = "lorem_ipsum.txt"; #[test] diff --git a/tests/by-util/test_hostid.rs b/tests/by-util/test_hostid.rs index e18deb893..198061b19 100644 --- a/tests/by-util/test_hostid.rs +++ b/tests/by-util/test_hostid.rs @@ -2,8 +2,10 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; use regex::Regex; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_normal() { diff --git a/tests/by-util/test_hostname.rs b/tests/by-util/test_hostname.rs index dc522a4d4..1611a590a 100644 --- a/tests/by-util/test_hostname.rs +++ b/tests/by-util/test_hostname.rs @@ -2,7 +2,9 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_hostname() { diff --git a/tests/by-util/test_id.rs b/tests/by-util/test_id.rs index 71707804f..e2e1826ff 100644 --- a/tests/by-util/test_id.rs +++ b/tests/by-util/test_id.rs @@ -5,7 +5,10 @@ // spell-checker:ignore (ToDO) coreutil -use crate::common::util::{TestScenario, check_coreutil_version, expected_result, is_ci, whoami}; +use uutests::new_ucmd; +use uutests::unwrap_or_return; +use uutests::util::{TestScenario, check_coreutil_version, expected_result, is_ci, whoami}; +use uutests::util_name; const VERSION_MIN_MULTIPLE_USERS: &str = "8.31"; // this feature was introduced in GNU's coreutils 8.31 diff --git a/tests/by-util/test_install.rs b/tests/by-util/test_install.rs index 6d8ba774b..145ac61f5 100644 --- a/tests/by-util/test_install.rs +++ b/tests/by-util/test_install.rs @@ -4,7 +4,6 @@ // file that was distributed with this source code. // spell-checker:ignore (words) helloworld nodir objdump n'source -use crate::common::util::{TestScenario, is_ci, run_ucmd_as_root}; #[cfg(not(target_os = "openbsd"))] use filetime::FileTime; use std::fs; @@ -14,6 +13,10 @@ use std::process::Command; #[cfg(any(target_os = "linux", target_os = "android"))] use std::thread::sleep; use uucore::process::{getegid, geteuid}; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::{TestScenario, is_ci, run_ucmd_as_root}; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_join.rs b/tests/by-util/test_join.rs index 7337064e0..e9924eea9 100644 --- a/tests/by-util/test_join.rs +++ b/tests/by-util/test_join.rs @@ -4,13 +4,15 @@ // file that was distributed with this source code. // spell-checker:ignore (words) autoformat nocheck -use crate::common::util::TestScenario; #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))] use std::fs::OpenOptions; #[cfg(unix)] use std::{ffi::OsStr, os::unix::ffi::OsStrExt}; #[cfg(windows)] use std::{ffi::OsString, os::windows::ffi::OsStringExt}; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_kill.rs b/tests/by-util/test_kill.rs index a4d6971fe..c163d47b8 100644 --- a/tests/by-util/test_kill.rs +++ b/tests/by-util/test_kill.rs @@ -2,13 +2,13 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. - // spell-checker:ignore IAMNOTASIGNAL - -use crate::common::util::TestScenario; use regex::Regex; use std::os::unix::process::ExitStatusExt; use std::process::{Child, Command}; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; // A child process the tests will try to kill. struct Target { diff --git a/tests/by-util/test_link.rs b/tests/by-util/test_link.rs index 9cc059666..d95ada986 100644 --- a/tests/by-util/test_link.rs +++ b/tests/by-util/test_link.rs @@ -2,7 +2,10 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_ln.rs b/tests/by-util/test_ln.rs index 57e793dd2..b8089f401 100644 --- a/tests/by-util/test_ln.rs +++ b/tests/by-util/test_ln.rs @@ -4,8 +4,11 @@ // file that was distributed with this source code. #![allow(clippy::similar_names)] -use crate::common::util::TestScenario; use std::path::PathBuf; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_logname.rs b/tests/by-util/test_logname.rs index 178b47048..c0f763bb6 100644 --- a/tests/by-util/test_logname.rs +++ b/tests/by-util/test_logname.rs @@ -2,8 +2,10 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::{TestScenario, is_ci}; use std::env; +use uutests::new_ucmd; +use uutests::util::{TestScenario, is_ci}; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index 444d5b8d8..3767b38ec 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -10,9 +10,6 @@ clippy::cast_possible_truncation )] -use crate::common::util::TestScenario; -#[cfg(any(unix, feature = "feat_selinux"))] -use crate::common::util::expected_result; #[cfg(all(unix, feature = "chmod"))] use nix::unistd::{close, dup}; use regex::Regex; @@ -29,6 +26,13 @@ use std::path::Path; use std::path::PathBuf; use std::thread::sleep; use std::time::Duration; +use uutests::new_ucmd; +#[cfg(unix)] +use uutests::unwrap_or_return; +use uutests::util::TestScenario; +#[cfg(any(unix, feature = "feat_selinux"))] +use uutests::util::expected_result; +use uutests::{at_and_ucmd, util_name}; const LONG_ARGS: &[&str] = &[ "-l", @@ -2232,6 +2236,7 @@ fn test_ls_recursive_1() { #[cfg(unix)] mod quoting { use super::TestScenario; + use uutests::util_name; /// Create a directory with "dirname", then for each check, assert that the /// output is correct. diff --git a/tests/by-util/test_mkdir.rs b/tests/by-util/test_mkdir.rs index 45c1bcf02..e544e3423 100644 --- a/tests/by-util/test_mkdir.rs +++ b/tests/by-util/test_mkdir.rs @@ -7,11 +7,15 @@ #![allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)] -use crate::common::util::TestScenario; #[cfg(not(windows))] use libc::mode_t; #[cfg(not(windows))] use std::os::unix::fs::PermissionsExt; +#[cfg(not(windows))] +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_mkfifo.rs b/tests/by-util/test_mkfifo.rs index b4c3c7f2b..79eed4d62 100644 --- a/tests/by-util/test_mkfifo.rs +++ b/tests/by-util/test_mkfifo.rs @@ -2,7 +2,9 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_mknod.rs b/tests/by-util/test_mknod.rs index e0a091778..644306fff 100644 --- a/tests/by-util/test_mknod.rs +++ b/tests/by-util/test_mknod.rs @@ -2,7 +2,9 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] #[cfg(not(windows))] diff --git a/tests/by-util/test_mktemp.rs b/tests/by-util/test_mktemp.rs index c35ddf31b..65d0db8ce 100644 --- a/tests/by-util/test_mktemp.rs +++ b/tests/by-util/test_mktemp.rs @@ -4,7 +4,10 @@ // file that was distributed with this source code. // spell-checker:ignore (words) gpghome -use crate::common::util::TestScenario; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; use uucore::display::Quotable; diff --git a/tests/by-util/test_more.rs b/tests/by-util/test_more.rs index 3c40c8fd9..e71e87114 100644 --- a/tests/by-util/test_more.rs +++ b/tests/by-util/test_more.rs @@ -2,8 +2,12 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; use std::io::IsTerminal; +#[cfg(target_family = "unix")] +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_more_no_arg() { diff --git a/tests/by-util/test_mv.rs b/tests/by-util/test_mv.rs index e9bed3949..7db0588b3 100644 --- a/tests/by-util/test_mv.rs +++ b/tests/by-util/test_mv.rs @@ -4,10 +4,12 @@ // file that was distributed with this source code. // // spell-checker:ignore mydir -use crate::common::util::TestScenario; use filetime::FileTime; use rstest::rstest; use std::io::Write; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::{at_and_ucmd, util_name}; #[test] fn test_mv_invalid_arg() { @@ -1670,7 +1672,7 @@ fn test_mv_dir_into_path_slash() { fn test_acl() { use std::process::Command; - use crate::common::util::compare_xattrs; + use uutests::util::compare_xattrs; let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; @@ -1766,10 +1768,11 @@ fn test_move_should_not_fallback_to_copy() { #[cfg(target_os = "linux")] mod inter_partition_copying { - use crate::common::util::TestScenario; use std::fs::{read_to_string, set_permissions, write}; use std::os::unix::fs::{PermissionsExt, symlink}; use tempfile::TempDir; + use uutests::util::TestScenario; + use uutests::util_name; // Ensure that the copying code used in an inter-partition move unlinks the destination symlink. #[test] @@ -1823,6 +1826,7 @@ mod inter_partition_copying { // that it would output the proper error message. #[test] pub(crate) fn test_mv_unlinks_dest_symlink_error_message() { + use uutests::util::TestScenario; let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; diff --git a/tests/by-util/test_nice.rs b/tests/by-util/test_nice.rs index 802b25344..b53a4118b 100644 --- a/tests/by-util/test_nice.rs +++ b/tests/by-util/test_nice.rs @@ -3,7 +3,9 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. // spell-checker:ignore libc's setpriority -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] #[cfg(not(target_os = "android"))] diff --git a/tests/by-util/test_nl.rs b/tests/by-util/test_nl.rs index 4e8dbe5cb..7e9fb7c14 100644 --- a/tests/by-util/test_nl.rs +++ b/tests/by-util/test_nl.rs @@ -4,7 +4,10 @@ // file that was distributed with this source code. // // spell-checker:ignore binvalid finvalid hinvalid iinvalid linvalid nabcabc nabcabcabc ninvalid vinvalid winvalid dabc näää -use crate::common::util::TestScenario; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_nohup.rs b/tests/by-util/test_nohup.rs index 187950100..d58a7e24d 100644 --- a/tests/by-util/test_nohup.rs +++ b/tests/by-util/test_nohup.rs @@ -3,9 +3,12 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. // spell-checker:ignore winsize Openpty openpty xpixel ypixel ptyprocess -use crate::common::util::TestScenario; #[cfg(not(target_os = "openbsd"))] use std::thread::sleep; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; // General observation: nohup.out will not be created in tests run by cargo test // because stdin/stdout is not attached to a TTY. diff --git a/tests/by-util/test_nproc.rs b/tests/by-util/test_nproc.rs index 2dd32a79b..c06eed8f0 100644 --- a/tests/by-util/test_nproc.rs +++ b/tests/by-util/test_nproc.rs @@ -3,7 +3,9 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. // spell-checker:ignore incorrectnumber -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_numfmt.rs b/tests/by-util/test_numfmt.rs index 57af46598..21b327043 100644 --- a/tests/by-util/test_numfmt.rs +++ b/tests/by-util/test_numfmt.rs @@ -4,7 +4,9 @@ // file that was distributed with this source code. // spell-checker:ignore (paths) gnutest ronna quetta -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_od.rs b/tests/by-util/test_od.rs index bb95ccf72..5b1bb2f76 100644 --- a/tests/by-util/test_od.rs +++ b/tests/by-util/test_od.rs @@ -5,8 +5,11 @@ // spell-checker:ignore abcdefghijklmnopqrstuvwxyz Anone -use crate::common::util::TestScenario; use unindent::unindent; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; // octal dump of 'abcdefghijklmnopqrstuvwxyz\n' static ALPHA_OUT: &str = " diff --git a/tests/by-util/test_paste.rs b/tests/by-util/test_paste.rs index 53f2dead6..c4c1097f8 100644 --- a/tests/by-util/test_paste.rs +++ b/tests/by-util/test_paste.rs @@ -5,7 +5,10 @@ // spell-checker:ignore bsdutils toybox -use crate::common::util::TestScenario; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; struct TestData<'b> { name: &'b str, diff --git a/tests/by-util/test_pathchk.rs b/tests/by-util/test_pathchk.rs index 599a23084..6e6b5dd85 100644 --- a/tests/by-util/test_pathchk.rs +++ b/tests/by-util/test_pathchk.rs @@ -2,7 +2,9 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_no_args() { diff --git a/tests/by-util/test_pinky.rs b/tests/by-util/test_pinky.rs index 6192a7bb5..6418906ae 100644 --- a/tests/by-util/test_pinky.rs +++ b/tests/by-util/test_pinky.rs @@ -3,13 +3,16 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -#[cfg(target_os = "openbsd")] -use crate::common::util::TestScenario; -#[cfg(not(target_os = "openbsd"))] -use crate::common::util::{TestScenario, expected_result}; use pinky::Capitalize; #[cfg(not(target_os = "openbsd"))] use uucore::entries::{Locate, Passwd}; +use uutests::new_ucmd; +use uutests::unwrap_or_return; +#[cfg(target_os = "openbsd")] +use uutests::util::TestScenario; +#[cfg(not(target_os = "openbsd"))] +use uutests::util::{TestScenario, expected_result}; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_pr.rs b/tests/by-util/test_pr.rs index f99495edc..1dcb162c0 100644 --- a/tests/by-util/test_pr.rs +++ b/tests/by-util/test_pr.rs @@ -4,9 +4,11 @@ // file that was distributed with this source code. // spell-checker:ignore (ToDO) Sdivide -use crate::common::util::{TestScenario, UCommand}; use chrono::{DateTime, Duration, Utc}; use std::fs::metadata; +use uutests::new_ucmd; +use uutests::util::{TestScenario, UCommand}; +use uutests::util_name; const DATE_TIME_FORMAT: &str = "%b %d %H:%M %Y"; diff --git a/tests/by-util/test_printenv.rs b/tests/by-util/test_printenv.rs index c9eb3c60e..aa8910ba5 100644 --- a/tests/by-util/test_printenv.rs +++ b/tests/by-util/test_printenv.rs @@ -2,7 +2,8 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_get_all() { diff --git a/tests/by-util/test_printf.rs b/tests/by-util/test_printf.rs index be9826d92..df1fafd60 100644 --- a/tests/by-util/test_printf.rs +++ b/tests/by-util/test_printf.rs @@ -2,7 +2,9 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn basic_literal() { diff --git a/tests/by-util/test_ptx.rs b/tests/by-util/test_ptx.rs index 20d4a3280..6f7f34d17 100644 --- a/tests/by-util/test_ptx.rs +++ b/tests/by-util/test_ptx.rs @@ -3,7 +3,10 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. // spell-checker:ignore roff -use crate::common::util::TestScenario; + +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_pwd.rs b/tests/by-util/test_pwd.rs index c5cb7f32e..77826b878 100644 --- a/tests/by-util/test_pwd.rs +++ b/tests/by-util/test_pwd.rs @@ -6,7 +6,10 @@ use std::path::PathBuf; -use crate::common::util::{TestScenario, UCommand}; +use uutests::new_ucmd; +use uutests::util::{TestScenario, UCommand}; +//use uutests::at_and_ucmd; +use uutests::{at_and_ucmd, util_name}; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_readlink.rs b/tests/by-util/test_readlink.rs index eef42eeeb..33840c9a1 100644 --- a/tests/by-util/test_readlink.rs +++ b/tests/by-util/test_readlink.rs @@ -3,7 +3,10 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. // spell-checker:ignore regfile -use crate::common::util::{TestScenario, get_root_path}; +use uutests::new_ucmd; +use uutests::path_concat; +use uutests::util::{TestScenario, get_root_path}; +use uutests::{at_and_ucmd, util_name}; static GIBBERISH: &str = "supercalifragilisticexpialidocious"; diff --git a/tests/by-util/test_realpath.rs b/tests/by-util/test_realpath.rs index 14c2aa881..93c0ebb19 100644 --- a/tests/by-util/test_realpath.rs +++ b/tests/by-util/test_realpath.rs @@ -3,7 +3,10 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. // spell-checker:ignore nusr -use crate::common::util::{TestScenario, get_root_path}; +use uutests::new_ucmd; +use uutests::path_concat; +use uutests::util::{TestScenario, get_root_path}; +use uutests::{at_and_ucmd, util_name}; #[cfg(windows)] use regex::Regex; diff --git a/tests/by-util/test_rm.rs b/tests/by-util/test_rm.rs index 8610ef5ce..d022d754e 100644 --- a/tests/by-util/test_rm.rs +++ b/tests/by-util/test_rm.rs @@ -6,7 +6,10 @@ use std::process::Stdio; -use crate::common::util::TestScenario; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { @@ -777,6 +780,64 @@ fn test_non_utf8() { assert!(!at.file_exists(file)); } +#[test] +fn test_uchild_when_run_no_wait_with_a_blocking_command() { + let ts = TestScenario::new("rm"); + let at = &ts.fixtures; + + at.mkdir("a"); + at.touch("a/empty"); + + #[cfg(target_vendor = "apple")] + let delay: u64 = 2000; + #[cfg(not(target_vendor = "apple"))] + let delay: u64 = 1000; + + let yes = if cfg!(windows) { "y\r\n" } else { "y\n" }; + + let mut child = ts + .ucmd() + .set_stdin(Stdio::piped()) + .stderr_to_stdout() + .args(&["-riv", "a"]) + .run_no_wait(); + child + .make_assertion_with_delay(delay) + .is_alive() + .with_current_output() + .stdout_is("rm: descend into directory 'a'? "); + + #[cfg(windows)] + let expected = "rm: descend into directory 'a'? \ + rm: remove regular empty file 'a\\empty'? "; + #[cfg(unix)] + let expected = "rm: descend into directory 'a'? \ + rm: remove regular empty file 'a/empty'? "; + child.write_in(yes); + child + .make_assertion_with_delay(delay) + .is_alive() + .with_all_output() + .stdout_is(expected); + + #[cfg(windows)] + let expected = "removed 'a\\empty'\nrm: remove directory 'a'? "; + #[cfg(unix)] + let expected = "removed 'a/empty'\nrm: remove directory 'a'? "; + + child + .write_in(yes) + .make_assertion_with_delay(delay) + .is_alive() + .with_exact_output(44, 0) + .stdout_only(expected); + + let expected = "removed directory 'a'\n"; + + child.write_in(yes); + child.wait().unwrap().stdout_only(expected).success(); +} + #[test] fn test_recursive_interactive() { let (at, mut ucmd) = at_and_ucmd!(); diff --git a/tests/by-util/test_rmdir.rs b/tests/by-util/test_rmdir.rs index cfd9b5c6c..09a711eaf 100644 --- a/tests/by-util/test_rmdir.rs +++ b/tests/by-util/test_rmdir.rs @@ -2,7 +2,10 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; const DIR: &str = "dir"; const DIR_FILE: &str = "dir/file"; diff --git a/tests/by-util/test_runcon.rs b/tests/by-util/test_runcon.rs index ec1f4f8b3..c024f571d 100644 --- a/tests/by-util/test_runcon.rs +++ b/tests/by-util/test_runcon.rs @@ -6,7 +6,9 @@ #![cfg(feature = "feat_selinux")] -use crate::common::util::*; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; // TODO: Check the implementation of `--compute` somehow. diff --git a/tests/by-util/test_seq.rs b/tests/by-util/test_seq.rs index 95caa0ccb..83bdb7a82 100644 --- a/tests/by-util/test_seq.rs +++ b/tests/by-util/test_seq.rs @@ -3,7 +3,9 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. // spell-checker:ignore lmnop xlmnop -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_shred.rs b/tests/by-util/test_shred.rs index f05aed72c..8e1f4c736 100644 --- a/tests/by-util/test_shred.rs +++ b/tests/by-util/test_shred.rs @@ -5,7 +5,10 @@ // spell-checker:ignore wipesync -use crate::common::util::TestScenario; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_shuf.rs b/tests/by-util/test_shuf.rs index d42cada01..ad64c52ca 100644 --- a/tests/by-util/test_shuf.rs +++ b/tests/by-util/test_shuf.rs @@ -4,7 +4,10 @@ // file that was distributed with this source code. // spell-checker:ignore (ToDO) unwritable -use crate::common::util::TestScenario; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_sleep.rs b/tests/by-util/test_sleep.rs index 2708b01c1..25672d91a 100644 --- a/tests/by-util/test_sleep.rs +++ b/tests/by-util/test_sleep.rs @@ -5,10 +5,13 @@ use rstest::rstest; // spell-checker:ignore dont SIGBUS SIGSEGV sigsegv sigbus -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[cfg(unix)] use nix::sys::signal::Signal::{SIGBUS, SIGSEGV}; +use std::io::ErrorKind; use std::time::{Duration, Instant}; #[test] @@ -252,8 +255,8 @@ fn test_sleep_when_input_has_only_whitespace_then_error(#[case] input: &str) { #[test] fn test_sleep_when_multiple_input_some_with_error_then_shows_all_errors() { let expected = "invalid time interval 'abc': Invalid input: abc\n\ - sleep: invalid time interval '1years': Invalid time unit: 'years' at position 2\n\ - sleep: invalid time interval ' ': Found only whitespace in input"; + sleep: invalid time interval '1years': Invalid time unit: 'years' at position 2\n\ + sleep: invalid time interval ' ': Found only whitespace in input"; // Even if one of the arguments is valid, but the rest isn't, we should still fail and exit early. // So, the timeout of 10 seconds ensures we haven't executed `thread::sleep` with the only valid @@ -272,3 +275,141 @@ fn test_negative_interval() { .fails() .usage_error("invalid time interval '-1': Number was negative"); } + +#[cfg(unix)] +#[test] +#[should_panic = "Program must be run first or has not finished"] +fn test_cmd_result_signal_when_still_running_then_panic() { + let mut child = TestScenario::new("sleep").ucmd().arg("60").run_no_wait(); + + child + .make_assertion() + .is_alive() + .with_current_output() + .signal(); +} + +#[cfg(unix)] +#[test] +fn test_cmd_result_signal_when_kill_then_signal() { + let mut child = TestScenario::new("sleep").ucmd().arg("60").run_no_wait(); + + child.kill(); + child + .make_assertion() + .is_not_alive() + .with_current_output() + .signal_is(9) + .signal_name_is("SIGKILL") + .signal_name_is("KILL") + .signal_name_is("9") + .signal() + .expect("Signal was none"); + + let result = child.wait().unwrap(); + result + .signal_is(9) + .signal_name_is("SIGKILL") + .signal_name_is("KILL") + .signal_name_is("9") + .signal() + .expect("Signal was none"); +} + +#[cfg(unix)] +#[rstest] +#[case::signal_only_part_of_name("IGKILL")] // spell-checker: disable-line +#[case::signal_just_sig("SIG")] +#[case::signal_value_too_high("100")] +#[case::signal_value_negative("-1")] +#[should_panic = "Invalid signal name or value"] +fn test_cmd_result_signal_when_invalid_signal_name_then_panic(#[case] signal_name: &str) { + let mut child = TestScenario::new("sleep").ucmd().arg("60").run_no_wait(); + child.kill(); + let result = child.wait().unwrap(); + result.signal_name_is(signal_name); +} + +#[test] +#[cfg(unix)] +fn test_cmd_result_signal_name_is_accepts_lowercase() { + let mut child = TestScenario::new("sleep").ucmd().arg("60").run_no_wait(); + child.kill(); + let result = child.wait().unwrap(); + result.signal_name_is("sigkill"); + result.signal_name_is("kill"); +} + +#[test] +fn test_uchild_when_wait_and_timeout_is_reached_then_timeout_error() { + let ts = TestScenario::new("sleep"); + let child = ts + .ucmd() + .timeout(Duration::from_secs(1)) + .arg("10.0") + .run_no_wait(); + + match child.wait() { + Err(error) if error.kind() == ErrorKind::Other => { + std::assert_eq!(error.to_string(), "wait: Timeout of '1s' reached"); + } + Err(error) => panic!("Assertion failed: Expected error with timeout but was: {error}"), + Ok(_) => panic!("Assertion failed: Expected timeout of `wait`."), + } +} + +#[rstest] +#[timeout(Duration::from_secs(5))] +fn test_uchild_when_kill_and_timeout_higher_than_kill_time_then_no_panic() { + let ts = TestScenario::new("sleep"); + let mut child = ts + .ucmd() + .timeout(Duration::from_secs(60)) + .arg("20.0") + .run_no_wait(); + + child.kill().make_assertion().is_not_alive(); +} + +#[test] +fn test_uchild_when_try_kill_and_timeout_is_reached_then_error() { + let ts = TestScenario::new("sleep"); + let mut child = ts.ucmd().timeout(Duration::ZERO).arg("10.0").run_no_wait(); + + match child.try_kill() { + Err(error) if error.kind() == ErrorKind::Other => { + std::assert_eq!(error.to_string(), "kill: Timeout of '0s' reached"); + } + Err(error) => panic!("Assertion failed: Expected error with timeout but was: {error}"), + Ok(()) => panic!("Assertion failed: Expected timeout of `try_kill`."), + } +} + +#[test] +#[should_panic = "kill: Timeout of '0s' reached"] +fn test_uchild_when_kill_with_timeout_and_timeout_is_reached_then_panic() { + let ts = TestScenario::new("sleep"); + let mut child = ts.ucmd().timeout(Duration::ZERO).arg("10.0").run_no_wait(); + + child.kill(); + panic!("Assertion failed: Expected timeout of `kill`."); +} + +#[test] +#[should_panic(expected = "wait: Timeout of '1.1s' reached")] +fn test_ucommand_when_run_with_timeout_and_timeout_is_reached_then_panic() { + let ts = TestScenario::new("sleep"); + ts.ucmd() + .timeout(Duration::from_millis(1100)) + .arg("10.0") + .run(); + + panic!("Assertion failed: Expected timeout of `run`.") +} + +#[rstest] +#[timeout(Duration::from_secs(10))] +fn test_ucommand_when_run_with_timeout_higher_then_execution_time_then_no_panic() { + let ts = TestScenario::new("sleep"); + ts.ucmd().timeout(Duration::from_secs(60)).arg("1.0").run(); +} diff --git a/tests/by-util/test_sort.rs b/tests/by-util/test_sort.rs index 5e13369ca..1f3b2a8b1 100644 --- a/tests/by-util/test_sort.rs +++ b/tests/by-util/test_sort.rs @@ -8,7 +8,10 @@ use std::time::Duration; -use crate::common::util::TestScenario; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; fn test_helper(file_name: &str, possible_args: &[&str]) { for args in possible_args { diff --git a/tests/by-util/test_split.rs b/tests/by-util/test_split.rs index a12f8d580..042b2c251 100644 --- a/tests/by-util/test_split.rs +++ b/tests/by-util/test_split.rs @@ -4,7 +4,6 @@ // file that was distributed with this source code. // spell-checker:ignore xzaaa sixhundredfiftyonebytes ninetyonebytes threebytes asciilowercase ghijkl mnopq rstuv wxyz fivelines twohundredfortyonebytes onehundredlines nbbbb dxen ncccc rlimit NOFILE -use crate::common::util::{AtPath, TestScenario}; use rand::{Rng, SeedableRng, rng}; use regex::Regex; #[cfg(any(target_os = "linux", target_os = "android"))] @@ -16,6 +15,11 @@ use std::{ fs::{File, read_dir}, io::{BufWriter, Read, Write}, }; +use uutests::util::{AtPath, TestScenario}; + +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util_name; fn random_chars(n: usize) -> String { rng() diff --git a/tests/by-util/test_stat.rs b/tests/by-util/test_stat.rs index a0835c8f2..ffe99bcb6 100644 --- a/tests/by-util/test_stat.rs +++ b/tests/by-util/test_stat.rs @@ -3,7 +3,11 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::{TestScenario, expected_result}; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::unwrap_or_return; +use uutests::util::{TestScenario, expected_result}; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_stdbuf.rs b/tests/by-util/test_stdbuf.rs index 379af607a..c4294c6af 100644 --- a/tests/by-util/test_stdbuf.rs +++ b/tests/by-util/test_stdbuf.rs @@ -2,8 +2,10 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. +use uutests::new_ucmd; #[cfg(not(target_os = "windows"))] -use crate::common::util::TestScenario; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn invalid_input() { diff --git a/tests/by-util/test_stty.rs b/tests/by-util/test_stty.rs index 5cc6d39d0..7ccc56e5d 100644 --- a/tests/by-util/test_stty.rs +++ b/tests/by-util/test_stty.rs @@ -4,7 +4,9 @@ // file that was distributed with this source code. // spell-checker:ignore parenb parmrk ixany iuclc onlcr ofdel icanon noflsh -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_sum.rs b/tests/by-util/test_sum.rs index 163f691b6..a87084cb4 100644 --- a/tests/by-util/test_sum.rs +++ b/tests/by-util/test_sum.rs @@ -2,7 +2,10 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_sync.rs b/tests/by-util/test_sync.rs index 9eb2c33df..757dc65c1 100644 --- a/tests/by-util/test_sync.rs +++ b/tests/by-util/test_sync.rs @@ -2,9 +2,11 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; use std::fs; use tempfile::tempdir; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_tac.rs b/tests/by-util/test_tac.rs index b5931ce53..f725615b3 100644 --- a/tests/by-util/test_tac.rs +++ b/tests/by-util/test_tac.rs @@ -3,7 +3,9 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. // spell-checker:ignore axxbxx bxxaxx axxx axxxx xxaxx xxax xxxxa axyz zyax zyxa -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_tail.rs b/tests/by-util/test_tail.rs index c4da1de6d..76a93b7c6 100644 --- a/tests/by-util/test_tail.rs +++ b/tests/by-util/test_tail.rs @@ -13,12 +13,6 @@ clippy::cast_possible_truncation )] -use crate::common::random::{AlphanumericNewline, RandomizedString}; -use crate::common::util::TestScenario; -#[cfg(unix)] -use crate::common::util::expected_result; -#[cfg(not(windows))] -use crate::common::util::is_ci; use pretty_assertions::assert_eq; use rand::distr::Alphanumeric; use rstest::rstest; @@ -45,6 +39,18 @@ use tail::chunks::BUFFER_SIZE as CHUNK_BUFFER_SIZE; not(target_os = "openbsd") ))] use tail::text; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::random::{AlphanumericNewline, RandomizedString}; +#[cfg(unix)] +use uutests::unwrap_or_return; +use uutests::util::TestScenario; +#[cfg(unix)] +use uutests::util::expected_result; +#[cfg(unix)] +#[cfg(not(windows))] +use uutests::util::is_ci; +use uutests::util_name; const FOOBAR_TXT: &str = "foobar.txt"; const FOOBAR_2_TXT: &str = "foobar2.txt"; @@ -4805,3 +4811,39 @@ fn test_following_with_pid() { child.kill(); } + +// This error was first detected when running tail so tail is used here but +// should fail with any command that takes piped input. +// See also https://github.com/uutils/coreutils/issues/3895 +#[test] +#[cfg_attr(not(feature = "expensive_tests"), ignore)] +fn test_when_piped_input_then_no_broken_pipe() { + let ts = TestScenario::new("tail"); + for i in 0..10000 { + dbg!(i); + let test_string = "a\nb\n"; + ts.ucmd() + .args(&["-n", "0"]) + .pipe_in(test_string) + .succeeds() + .no_stdout() + .no_stderr(); + } +} + +#[test] +fn test_child_when_run_with_stderr_to_stdout() { + let ts = TestScenario::new("tail"); + let at = &ts.fixtures; + + at.write("data", "file data\n"); + + let expected_stdout = "==> data <==\n\ + file data\n\ + tail: cannot open 'missing' for reading: No such file or directory\n"; + ts.ucmd() + .args(&["data", "missing"]) + .stderr_to_stdout() + .fails() + .stdout_only(expected_stdout); +} diff --git a/tests/by-util/test_tee.rs b/tests/by-util/test_tee.rs index e4e24acb4..12f4f04e8 100644 --- a/tests/by-util/test_tee.rs +++ b/tests/by-util/test_tee.rs @@ -4,7 +4,9 @@ // file that was distributed with this source code. #![allow(clippy::borrow_as_ptr)] -use crate::common::util::TestScenario; +use uutests::util::TestScenario; +use uutests::{at_and_ucmd, new_ucmd, util_name}; + use regex::Regex; #[cfg(target_os = "linux")] use std::fmt::Write; @@ -160,12 +162,15 @@ fn test_tee_no_more_writeable_2() { #[cfg(target_os = "linux")] mod linux_only { - use crate::common::util::{AtPath, CmdResult, TestScenario, UCommand}; + use uutests::util::{AtPath, CmdResult, TestScenario, UCommand}; use std::fmt::Write; use std::fs::File; use std::process::Stdio; use std::time::Duration; + use uutests::at_and_ucmd; + use uutests::new_ucmd; + use uutests::util_name; fn make_broken_pipe() -> File { use libc::c_int; diff --git a/tests/by-util/test_test.rs b/tests/by-util/test_test.rs index 41d83c520..1dba782f5 100644 --- a/tests/by-util/test_test.rs +++ b/tests/by-util/test_test.rs @@ -5,7 +5,10 @@ // spell-checker:ignore (words) egid euid pseudofloat -use crate::common::util::TestScenario; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_empty_test_equivalent_to_false() { diff --git a/tests/by-util/test_timeout.rs b/tests/by-util/test_timeout.rs index 423d7f041..20d3e8fef 100644 --- a/tests/by-util/test_timeout.rs +++ b/tests/by-util/test_timeout.rs @@ -3,7 +3,9 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. // spell-checker:ignore dont -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index 120159672..c3b5f1ae1 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -4,12 +4,15 @@ // file that was distributed with this source code. // spell-checker:ignore (formats) cymdhm cymdhms mdhm mdhms ymdhm ymdhms datetime mktime -use crate::common::util::{AtPath, TestScenario}; use filetime::FileTime; #[cfg(not(target_os = "freebsd"))] use filetime::set_symlink_file_times; use std::fs::remove_file; use std::path::PathBuf; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::{AtPath, TestScenario}; +use uutests::util_name; fn get_file_times(at: &AtPath, path: &str) -> (FileTime, FileTime) { let m = at.metadata(path); diff --git a/tests/by-util/test_tr.rs b/tests/by-util/test_tr.rs index e58872da9..964fb5df2 100644 --- a/tests/by-util/test_tr.rs +++ b/tests/by-util/test_tr.rs @@ -3,7 +3,10 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. // spell-checker:ignore aabbaa aabbcc aabc abbb abbbcddd abcc abcdefabcdef abcdefghijk abcdefghijklmn abcdefghijklmnop ABCDEFGHIJKLMNOPQRS abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFZZ abcxyz ABCXYZ abcxyzabcxyz ABCXYZABCXYZ acbdef alnum amzamz AMZXAMZ bbbd cclass cefgm cntrl compl dabcdef dncase Gzabcdefg PQRST upcase wxyzz xdigit XXXYYY xycde xyyye xyyz xyzzzzxyzzzz ZABCDEF Zamz Cdefghijkl Cdefghijklmn asdfqqwweerr qwerr asdfqwer qwer aassddffqwer asdfqwer -use crate::common::util::TestScenario; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[cfg(unix)] use std::{ffi::OsStr, os::unix::ffi::OsStrExt}; diff --git a/tests/by-util/test_true.rs b/tests/by-util/test_true.rs index 7711d9b72..34f82c602 100644 --- a/tests/by-util/test_true.rs +++ b/tests/by-util/test_true.rs @@ -2,12 +2,12 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. - -use crate::common::util::TestScenario; use regex::Regex; - #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))] use std::fs::OpenOptions; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_no_args() { diff --git a/tests/by-util/test_truncate.rs b/tests/by-util/test_truncate.rs index f8e4dbe1a..32e1b1520 100644 --- a/tests/by-util/test_truncate.rs +++ b/tests/by-util/test_truncate.rs @@ -5,8 +5,11 @@ // spell-checker:ignore (words) RFILE -use crate::common::util::TestScenario; use std::io::{Seek, SeekFrom, Write}; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; static FILE1: &str = "truncate_test_1"; static FILE2: &str = "truncate_test_2"; diff --git a/tests/by-util/test_tsort.rs b/tests/by-util/test_tsort.rs index 8c51883b4..c957a59a1 100644 --- a/tests/by-util/test_tsort.rs +++ b/tests/by-util/test_tsort.rs @@ -4,7 +4,10 @@ // file that was distributed with this source code. #![allow(clippy::cast_possible_wrap)] -use crate::common::util::TestScenario; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_tty.rs b/tests/by-util/test_tty.rs index c1a6dc501..c0124328c 100644 --- a/tests/by-util/test_tty.rs +++ b/tests/by-util/test_tty.rs @@ -4,7 +4,9 @@ // file that was distributed with this source code. use std::fs::File; -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] #[cfg(not(windows))] diff --git a/tests/by-util/test_uname.rs b/tests/by-util/test_uname.rs index d41bd3cd6..986312f68 100644 --- a/tests/by-util/test_uname.rs +++ b/tests/by-util/test_uname.rs @@ -2,7 +2,10 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_unexpand.rs b/tests/by-util/test_unexpand.rs index 89f76c072..8b447ecdb 100644 --- a/tests/by-util/test_unexpand.rs +++ b/tests/by-util/test_unexpand.rs @@ -3,7 +3,10 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. // spell-checker:ignore contenta -use crate::common::util::TestScenario; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_uniq.rs b/tests/by-util/test_uniq.rs index 0aa01e46c..b59b5e495 100644 --- a/tests/by-util/test_uniq.rs +++ b/tests/by-util/test_uniq.rs @@ -4,8 +4,11 @@ // file that was distributed with this source code. // spell-checker:ignore nabcd badoption schar -use crate::common::util::TestScenario; use uucore::posix::OBSOLETE; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; static INPUT: &str = "sorted.txt"; static OUTPUT: &str = "sorted-output.txt"; diff --git a/tests/by-util/test_unlink.rs b/tests/by-util/test_unlink.rs index 187ac922e..36d1630d3 100644 --- a/tests/by-util/test_unlink.rs +++ b/tests/by-util/test_unlink.rs @@ -2,7 +2,10 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_uptime.rs b/tests/by-util/test_uptime.rs index 1a2afd638..ff5c01df5 100644 --- a/tests/by-util/test_uptime.rs +++ b/tests/by-util/test_uptime.rs @@ -6,7 +6,10 @@ // spell-checker:ignore bincode serde utmp runlevel testusr testx #![allow(clippy::cast_possible_wrap, clippy::unreadable_literal)] -use crate::common::util::TestScenario; +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[cfg(not(any(target_os = "macos", target_os = "openbsd")))] use bincode::serialize; diff --git a/tests/by-util/test_users.rs b/tests/by-util/test_users.rs index d000552d3..ec77ffff5 100644 --- a/tests/by-util/test_users.rs +++ b/tests/by-util/test_users.rs @@ -2,7 +2,9 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_vdir.rs b/tests/by-util/test_vdir.rs index 97d5b847f..cf389f45e 100644 --- a/tests/by-util/test_vdir.rs +++ b/tests/by-util/test_vdir.rs @@ -2,8 +2,10 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::TestScenario; use regex::Regex; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; /* * As vdir use the same functions than ls, we don't have to retest them here. diff --git a/tests/by-util/test_wc.rs b/tests/by-util/test_wc.rs index a48b05581..b97d6c471 100644 --- a/tests/by-util/test_wc.rs +++ b/tests/by-util/test_wc.rs @@ -3,7 +3,11 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::common::util::{TestScenario, vec_of_size}; +#[cfg(target_os = "linux")] +use uutests::at_and_ucmd; +use uutests::new_ucmd; +use uutests::util::{TestScenario, vec_of_size}; +use uutests::util_name; // spell-checker:ignore (flags) lwmcL clmwL ; (path) bogusfile emptyfile manyemptylines moby notrailingnewline onelongemptyline onelongword weirdchars #[test] diff --git a/tests/by-util/test_who.rs b/tests/by-util/test_who.rs index 252c26ec1..74475895c 100644 --- a/tests/by-util/test_who.rs +++ b/tests/by-util/test_who.rs @@ -5,8 +5,10 @@ // spell-checker:ignore (flags) runlevel mesg -use crate::common::util::{TestScenario, expected_result}; - +use uutests::new_ucmd; +use uutests::unwrap_or_return; +use uutests::util::{TestScenario, expected_result}; +use uutests::util_name; #[test] fn test_invalid_arg() { new_ucmd!().arg("--definitely-invalid").fails_with_code(1); diff --git a/tests/by-util/test_whoami.rs b/tests/by-util/test_whoami.rs index bc0a9908c..32fdf719a 100644 --- a/tests/by-util/test_whoami.rs +++ b/tests/by-util/test_whoami.rs @@ -3,9 +3,13 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. +use uutests::new_ucmd; #[cfg(unix)] -use crate::common::util::expected_result; -use crate::common::util::{TestScenario, is_ci, whoami}; +use uutests::unwrap_or_return; +#[cfg(unix)] +use uutests::util::expected_result; +use uutests::util::{TestScenario, is_ci, whoami}; +use uutests::util_name; #[test] fn test_invalid_arg() { diff --git a/tests/by-util/test_yes.rs b/tests/by-util/test_yes.rs index 9f5f84ed8..b2706de75 100644 --- a/tests/by-util/test_yes.rs +++ b/tests/by-util/test_yes.rs @@ -8,7 +8,9 @@ use std::process::ExitStatus; #[cfg(unix)] use std::os::unix::process::ExitStatusExt; -use crate::common::util::TestScenario; +use uutests::new_ucmd; +use uutests::util::TestScenario; +use uutests::util_name; #[cfg(unix)] fn check_termination(result: ExitStatus) {