Move to use uutests

This commit is contained in:
Sylvestre Ledru
2025-03-29 09:36:33 +01:00
committed by Daniel Hofstetter
parent b95a5dae6a
commit fa608413b2
21 changed files with 153 additions and 4173 deletions
+10 -3
View File
@@ -3,7 +3,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() {
@@ -23,9 +25,12 @@ fn test_report_mutually_exclusive_with_others() {
#[cfg(target_os = "linux")]
mod linux {
use crate::common::util::TestScenario;
use regex::Regex;
use uutests::new_ucmd;
use uutests::util::TestScenario;
use uutests::util_name;
#[test]
fn test_fails_on_first_error() {
new_ucmd!()
@@ -56,7 +61,9 @@ mod linux {
#[cfg(not(target_os = "linux"))]
mod non_linux {
use crate::common::util::TestScenario;
use uutests::new_ucmd;
use uutests::util::TestScenario;
use uutests::util_name;
#[test]
fn test_fails_on_unsupported_platforms() {
+5 -1
View File
@@ -4,7 +4,11 @@
// file that was distributed with this source code.
#[cfg(target_os = "linux")]
use crate::common::util::TestScenario;
use uutests::new_ucmd;
#[cfg(target_os = "linux")]
use uutests::util::TestScenario;
#[cfg(target_os = "linux")]
use uutests::util_name;
#[test]
#[cfg(target_os = "linux")]
+4 -1
View File
@@ -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;
#[test]
fn test_invalid_arg() {
+10 -3
View File
@@ -3,7 +3,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() {
@@ -23,7 +25,10 @@ fn test_operations_mutually_exclusive() {
#[cfg(target_os = "linux")]
mod linux {
use crate::common::util::TestScenario;
use uutests::new_ucmd;
use uutests::util::TestScenario;
use uutests::util_name;
#[test]
fn test_fails_on_non_existing_path() {
@@ -48,7 +53,9 @@ mod linux {
#[cfg(not(target_os = "linux"))]
mod non_linux {
use crate::common::util::TestScenario;
use uutests::new_ucmd;
use uutests::util::TestScenario;
use uutests::util_name;
#[test]
fn test_fails_on_unsupported_platforms() {
+6 -1
View File
@@ -4,8 +4,13 @@
// file that was distributed with this source code.
// spell-checker:ignore (words) symdir somefakedir
use uutests::at_and_ucmd;
#[cfg(unix)]
use crate::common::util::TestScenario;
use uutests::new_ucmd;
#[cfg(unix)]
use uutests::util::TestScenario;
#[cfg(unix)]
use uutests::util_name;
#[cfg(unix)]
use regex::Regex;
+3 -1
View File
@@ -3,7 +3,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() {
+5 -1
View File
@@ -4,7 +4,11 @@
// file that was distributed with this source code.
#[cfg(target_os = "linux")]
use crate::common::util::TestScenario;
use uutests::new_ucmd;
#[cfg(target_os = "linux")]
use uutests::util::TestScenario;
#[cfg(target_os = "linux")]
use uutests::util_name;
#[test]
#[cfg(target_os = "linux")]
+3 -1
View File
@@ -3,8 +3,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 std::path::Path;
use uutests::new_ucmd;
use uutests::util::TestScenario;
use uutests::util_name;
fn write_file_content(dir: &Path, name: &str, content: &str) {
std::fs::create_dir_all(dir).unwrap();
+3 -1
View File
@@ -7,7 +7,9 @@ use std::io::Write;
use tempfile::NamedTempFile;
use crate::common::util::TestScenario;
use uutests::new_ucmd;
use uutests::util::TestScenario;
use uutests::util_name;
#[test]
fn test_invalid_arg() {
+6 -2
View File
@@ -3,7 +3,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_verb() {
@@ -24,7 +26,9 @@ fn test_no_terminal() {
#[cfg(not(target_family = "unix"))]
mod non_unix {
use crate::common::util::TestScenario;
use uutests::new_ucmd;
use uutests::util::TestScenario;
use uutests::util_name;
#[test]
fn test_fails_on_unsupported_platforms() {
+3 -2
View File
@@ -3,8 +3,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() {
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
+3 -1
View File
@@ -4,7 +4,9 @@
// file that was distributed with this source code.
// spell-checker:ignore (words) symdir somefakedir
use crate::common::util::TestScenario;
use uutests::new_ucmd;
use uutests::util::TestScenario;
use uutests::util_name;
#[test]
fn test_invalid_arg() {
+4 -1
View File
@@ -3,7 +3,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() {
+17 -7
View File
@@ -5,8 +5,11 @@
#[cfg(target_family = "unix")]
mod unix {
use crate::common::util::{TestScenario, UCommand, TESTS_BINARY};
use uutests::new_ucmd;
use uutests::util::get_tests_binary;
use uutests::util::TestScenario;
use uutests::util::UCommand;
use uutests::util_name;
#[test]
fn test_invalid_arg() {
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
@@ -77,8 +80,11 @@ mod unix {
#[test]
fn unprivileged_user_cannot_steal_controlling_tty() {
let shell_cmd =
format!("{TESTS_BINARY} setsid -w -c {TESTS_BINARY} setsid -w -c /b/usrin/true");
let shell_cmd = format!(
"{} setsid -w -c {} setsid -w -c /b/usrin/true",
get_tests_binary(),
get_tests_binary()
);
UCommand::new()
.terminal_simulation(true)
.arg(&shell_cmd)
@@ -92,7 +98,8 @@ mod unix {
#[test]
fn unprivileged_user_can_take_new_controlling_tty() {
let shell_cmd = format!(
"/usr/bin/cat /proc/self/stat; {TESTS_BINARY} setsid -w -c /usr/bin/cat /proc/self/stat"
"/usr/bin/cat /proc/self/stat; {} setsid -w -c /usr/bin/cat /proc/self/stat",
get_tests_binary()
);
let cmd_result = UCommand::new()
@@ -124,7 +131,8 @@ mod unix {
#[test]
fn setsid_takes_session_leadership() {
let shell_cmd = format!(
"/usr/bin/cat /proc/self/stat; {TESTS_BINARY} setsid /usr/bin/cat /proc/self/stat"
"/usr/bin/cat /proc/self/stat; {} setsid /usr/bin/cat /proc/self/stat",
get_tests_binary()
);
let cmd_result = UCommand::new()
@@ -161,7 +169,9 @@ mod unix {
#[cfg(not(target_family = "unix"))]
mod non_unix {
use crate::common::util::TestScenario;
use uutests::new_ucmd;
use uutests::util::TestScenario;
use uutests::util_name;
#[test]
fn unsupported_platforms() {
-93
View File
@@ -1,93 +0,0 @@
// 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.
/// Platform-independent helper for constructing a `PathBuf` from individual elements
#[macro_export]
macro_rules! path_concat {
($e:expr, ..$n:expr) => {{
use std::path::PathBuf;
let n = $n;
let mut pb = PathBuf::new();
for _ in 0..n {
pb.push($e);
}
pb.to_str().unwrap().to_owned()
}};
($($e:expr),*) => {{
use std::path::PathBuf;
let mut pb = PathBuf::new();
$(
pb.push($e);
)*
pb.to_str().unwrap().to_owned()
}};
}
/// Deduce the name of the test binary from the test filename.
///
/// e.g.: `tests/by-util/test_cat.rs` -> `cat`
#[macro_export]
macro_rules! util_name {
() => {
module_path!()
.split("_")
.nth(1)
.and_then(|s| s.split("::").next())
.expect("no test name")
};
}
/// Convenience macro for acquiring a [`UCommand`] builder.
///
/// Returns the following:
/// - a [`UCommand`] builder for invoking the binary to be tested
///
/// 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
#[macro_export]
macro_rules! new_ucmd {
() => {
TestScenario::new(util_name!()).ucmd()
};
}
/// Convenience macro for acquiring a [`UCommand`] builder and a test path.
///
/// Returns a tuple containing the following:
/// - an [`AtPath`] that points to a unique temporary test directory
/// - a [`UCommand`] builder for invoking the binary to be tested
///
/// 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
#[macro_export]
macro_rules! at_and_ucmd {
() => {{
let ts = TestScenario::new(util_name!());
(ts.fixtures.clone(), ts.ucmd())
}};
}
/// If `common::util::expected_result` returns an error, i.e. the `util` in `$PATH` doesn't
/// include a coreutils version string or the version is too low,
/// this macro can be used to automatically skip the test and print the reason.
#[macro_export]
macro_rules! unwrap_or_return {
( $e:expr ) => {
match $e {
Ok(x) => x,
Err(e) => {
println!("test skipped: {}", e);
return;
}
}
};
}
-8
View File
@@ -1,8 +0,0 @@
// 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;
-340
View File
@@ -1,340 +0,0 @@
// This file is part of the uutils util-linux package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
use rand::distr::{Distribution, Uniform};
use rand::{rng, Rng};
/// Samples alphanumeric characters `[A-Za-z0-9]` including newline `\n`
///
/// # Examples
///
/// ```rust,ignore
/// use rand::{Rng, thread_rng};
///
/// let vec = thread_rng()
/// .sample_iter(AlphanumericNewline)
/// .take(10)
/// .collect::<Vec<u8>>();
/// println!("Random chars: {}", String::from_utf8(vec).unwrap());
/// ```
#[derive(Clone, Copy, Debug)]
pub struct AlphanumericNewline;
impl AlphanumericNewline {
/// The charset to act upon
const CHARSET: &'static [u8] =
b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n";
/// Generate a random byte from [`Self::CHARSET`] and return it as `u8`.
///
/// # Arguments
///
/// * `rng`: A [`rand::Rng`]
///
/// returns: u8
fn random<R>(rng: &mut R) -> u8
where
R: Rng + ?Sized,
{
let idx = rng.random_range(0..Self::CHARSET.len());
Self::CHARSET[idx]
}
}
impl Distribution<u8> for AlphanumericNewline {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u8 {
Self::random(rng)
}
}
/// Generate a random string from a [`Distribution`]
///
/// # Examples
///
/// ```rust,ignore
/// use crate::common::random::{AlphanumericNewline, RandomString};
/// use rand::distributions::Alphanumeric;
///
/// // generates a 100 byte string with characters from AlphanumericNewline
/// let random_string = RandomString::generate(AlphanumericNewline, 100);
/// assert_eq!(100, random_string.len());
///
/// // generates a 100 byte string with 10 newline characters not ending with a newline
/// let string = RandomString::generate_with_delimiter(Alphanumeric, b'\n', 10, false, 100);
/// assert_eq!(100, random_string.len());
/// ```
pub struct RandomString;
impl RandomString {
/// Generate a random string from the given [`Distribution`] with the given `length` in bytes.
///
/// # Arguments
///
/// * `dist`: A u8 [`Distribution`]
/// * `length`: the length of the resulting string in bytes
///
/// returns: String
pub fn generate<D>(dist: D, length: usize) -> String
where
D: Distribution<u8>,
{
rng()
.sample_iter(dist)
.take(length)
.map(|b| b as char)
.collect()
}
/// Generate a random string from the [`Distribution`] with the given `length` in bytes. The
/// function takes a `delimiter`, which is randomly distributed in the string, such that exactly
/// `num_delimiter` amount of `delimiter`s occur. If `end_with_delimiter` is set, then the
/// string ends with the delimiter, else the string does not end with the delimiter.
///
/// # Arguments
///
/// * `dist`: A `u8` [`Distribution`]
/// * `delimiter`: A `u8` delimiter, which does not need to be included in the `Distribution`
/// * `num_delimiter`: The number of `delimiter`s contained in the resulting string
/// * `end_with_delimiter`: If the string shall end with the given delimiter
/// * `length`: the length of the resulting string in bytes
///
/// returns: String
///
/// # Examples
///
/// ```rust,ignore
/// use crate::common::random::{AlphanumericNewline, RandomString};
///
/// // generates a 100 byte string with 10 '\0' byte characters not ending with a '\0' byte
/// let string = RandomString::generate_with_delimiter(AlphanumericNewline, 0, 10, false, 100);
/// assert_eq!(100, random_string.len());
/// assert_eq!(
/// 10,
/// random_string.as_bytes().iter().filter(|p| **p == 0).count()
/// );
/// assert!(!random_string.as_bytes().ends_with(&[0]));
/// ```
pub fn generate_with_delimiter<D>(
dist: D,
delimiter: u8,
num_delimiter: usize,
end_with_delimiter: bool,
length: usize,
) -> String
where
D: Distribution<u8>,
{
if length == 0 {
return String::new();
} else if length == 1 {
return if num_delimiter > 0 {
String::from(delimiter as char)
} else {
String::from(rng().sample(&dist) as char)
};
}
let samples = length - 1;
let mut result: Vec<u8> = rng().sample_iter(&dist).take(samples).collect();
if num_delimiter == 0 {
result.push(rng().sample(&dist));
return String::from_utf8(result).unwrap();
}
let num_delimiter = if end_with_delimiter {
num_delimiter - 1
} else {
num_delimiter
};
// safe to unwrap because samples is at least 1, thus high > low
let between = Uniform::new(0, samples).unwrap();
for _ in 0..num_delimiter {
let mut pos = between.sample(&mut rng());
let turn = pos;
while result[pos] == delimiter {
pos += 1;
if pos >= samples {
pos = 0;
}
if pos == turn {
break;
}
}
result[pos] = delimiter;
}
if end_with_delimiter {
result.push(delimiter);
} else {
result.push(rng().sample(&dist));
}
String::from_utf8(result).unwrap()
}
}
#[cfg(test)]
mod tests {
use super::*;
use rand::distr::Alphanumeric;
#[test]
fn test_random_string_generate() {
let random_string = RandomString::generate(AlphanumericNewline, 0);
assert_eq!(0, random_string.len());
let random_string = RandomString::generate(AlphanumericNewline, 1);
assert_eq!(1, random_string.len());
let random_string = RandomString::generate(AlphanumericNewline, 100);
assert_eq!(100, random_string.len());
}
#[test]
fn test_random_string_generate_with_delimiter_when_length_is_zero() {
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 0, false, 0);
assert_eq!(0, random_string.len());
}
#[test]
fn test_random_string_generate_with_delimiter_when_num_delimiter_is_greater_than_length() {
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 2, false, 1);
assert_eq!(1, random_string.len());
assert!(random_string.as_bytes().contains(&0));
assert!(random_string.as_bytes().ends_with(&[0]));
}
#[test]
fn test_random_string_generate_with_delimiter_should_end_with_delimiter() {
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 1, true, 1);
assert_eq!(1, random_string.len());
assert_eq!(
1,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
assert!(random_string.as_bytes().ends_with(&[0]));
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 1, false, 1);
assert_eq!(1, random_string.len());
assert_eq!(
1,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
assert!(random_string.as_bytes().ends_with(&[0]));
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 1, true, 2);
assert_eq!(2, random_string.len());
assert_eq!(
1,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
assert!(random_string.as_bytes().ends_with(&[0]));
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 2, true, 2);
assert_eq!(2, random_string.len());
assert_eq!(
2,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
assert!(random_string.as_bytes().ends_with(&[0]));
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 1, true, 3);
assert_eq!(3, random_string.len());
assert_eq!(
1,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
assert!(random_string.as_bytes().ends_with(&[0]));
}
#[test]
fn test_random_string_generate_with_delimiter_should_not_end_with_delimiter() {
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 0, false, 1);
assert_eq!(1, random_string.len());
assert_eq!(
0,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 0, true, 1);
assert_eq!(1, random_string.len());
assert_eq!(
0,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 1, false, 2);
assert_eq!(2, random_string.len());
assert_eq!(
1,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
assert!(!random_string.as_bytes().ends_with(&[0]));
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 1, false, 3);
assert_eq!(3, random_string.len());
assert_eq!(
1,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
assert!(!random_string.as_bytes().ends_with(&[0]));
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 2, false, 3);
assert_eq!(3, random_string.len());
assert_eq!(
2,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
assert!(!random_string.as_bytes().ends_with(&[0]));
}
#[test]
fn test_generate_with_delimiter_with_greater_length() {
let random_string =
RandomString::generate_with_delimiter(Alphanumeric, 0, 100, false, 1000);
assert_eq!(1000, random_string.len());
assert_eq!(
100,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
assert!(!random_string.as_bytes().ends_with(&[0]));
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 100, true, 1000);
assert_eq!(1000, random_string.len());
assert_eq!(
100,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
assert!(random_string.as_bytes().ends_with(&[0]));
}
/// Originally used to exclude an error within the `random` module. The two
/// affected tests timed out on windows, but only in the ci. These tests are
/// also the source for the concrete numbers. The timed out tests are
/// `test_tail.rs::test_pipe_when_lines_option_given_input_size_has_multiple_size_of_buffer_size`
/// `test_tail.rs::test_pipe_when_bytes_option_given_input_size_has_multiple_size_of_buffer_size`.
#[test]
fn test_generate_random_strings_when_length_is_around_critical_buffer_sizes() {
let length = 8192 * 3;
let random_string = RandomString::generate(AlphanumericNewline, length);
assert_eq!(length, random_string.len());
let length = 8192 * 3 + 1;
let random_string =
RandomString::generate_with_delimiter(Alphanumeric, b'\n', 100, true, length);
assert_eq!(length, random_string.len());
assert_eq!(
100,
random_string
.as_bytes()
.iter()
.filter(|p| **p == b'\n')
.count()
);
assert!(!random_string.as_bytes().ends_with(&[0]));
}
}
-3701
View File
File diff suppressed because it is too large Load Diff
+13 -3
View File
@@ -1,10 +1,20 @@
// This file is part of the uutils coreutils package.
// This file is part of the uutils util-linux package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
#[macro_use]
mod common;
use std::env;
pub const TESTS_BINARY: &str = env!("CARGO_BIN_EXE_util-linux");
// Use the ctor attribute to run this function before any tests
#[ctor::ctor]
fn init() {
unsafe {
// Necessary for uutests to be able to find the binary
std::env::set_var("UUTESTS_BINARY_PATH", TESTS_BINARY);
}
}
#[cfg(feature = "lscpu")]
#[path = "by-util/test_lscpu.rs"]
mod test_lscpu;