1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-09-15 19:36:16 +00:00

Merge branch 'main' into dd-seconds-precision-3

This commit is contained in:
jfinkels 2023-03-19 13:29:14 -04:00 committed by GitHub
commit 59d34ce667
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
47 changed files with 1068 additions and 649 deletions

View file

@ -4,9 +4,8 @@ use std::fs::{metadata, set_permissions, OpenOptions, Permissions};
use std::os::unix::fs::{OpenOptionsExt, PermissionsExt};
use std::sync::Mutex;
extern crate libc;
use uucore::mode::strip_minus_from_mode;
extern crate chmod;
extern crate libc;
use self::libc::umask;
static TEST_FILE: &str = "file";
@ -503,35 +502,6 @@ fn test_chmod_symlink_non_existing_file_recursive() {
.no_stderr();
}
#[test]
fn test_chmod_strip_minus_from_mode() {
let tests = vec![
// ( before, after )
("chmod -v -xw -R FILE", "chmod -v xw -R FILE"),
("chmod g=rwx FILE -c", "chmod g=rwx FILE -c"),
(
"chmod -c -R -w,o+w FILE --preserve-root",
"chmod -c -R w,o+w FILE --preserve-root",
),
("chmod -c -R +w FILE ", "chmod -c -R +w FILE "),
("chmod a=r,=xX FILE", "chmod a=r,=xX FILE"),
(
"chmod -v --reference REF_FILE -R FILE",
"chmod -v --reference REF_FILE -R FILE",
),
("chmod -Rvc -w-x FILE", "chmod -Rvc w-x FILE"),
("chmod 755 -v FILE", "chmod 755 -v FILE"),
("chmod -v +0004 FILE -R", "chmod -v +0004 FILE -R"),
("chmod -v -0007 FILE -R", "chmod -v 0007 FILE -R"),
];
for test in tests {
let mut args: Vec<String> = test.0.split(' ').map(|v| v.to_string()).collect();
let _mode_had_minus_prefix = strip_minus_from_mode(&mut args);
assert_eq!(test.1, args.join(" "));
}
}
#[test]
fn test_chmod_keep_setgid() {
for (from, arg, to) in [
@ -671,3 +641,68 @@ fn test_quiet_n_verbose_used_multiple_times() {
.arg("file")
.succeeds();
}
#[test]
fn test_gnu_invalid_mode() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.touch("file");
scene.ucmd().arg("u+gr").arg("file").fails();
}
#[test]
fn test_gnu_options() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.touch("file");
scene.ucmd().arg("-w").arg("file").succeeds();
scene.ucmd().arg("file").arg("-w").succeeds();
scene.ucmd().arg("-w").arg("--").arg("file").succeeds();
}
#[test]
fn test_gnu_repeating_options() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.touch("file");
scene.ucmd().arg("-w").arg("-w").arg("file").succeeds();
scene
.ucmd()
.arg("-w")
.arg("-w")
.arg("-w")
.arg("file")
.succeeds();
}
#[test]
fn test_gnu_special_filenames() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let perms_before = Permissions::from_mode(0o100640);
let perms_after = Permissions::from_mode(0o100440);
make_file(&at.plus_as_string("--"), perms_before.mode());
scene.ucmd().arg("-w").arg("--").arg("--").succeeds();
assert_eq!(at.metadata("--").permissions(), perms_after);
set_permissions(at.plus("--"), perms_before.clone()).unwrap();
scene.ucmd().arg("--").arg("-w").arg("--").succeeds();
assert_eq!(at.metadata("--").permissions(), perms_after);
at.remove("--");
make_file(&at.plus_as_string("-w"), perms_before.mode());
scene.ucmd().arg("-w").arg("--").arg("-w").succeeds();
assert_eq!(at.metadata("-w").permissions(), perms_after);
set_permissions(at.plus("-w"), perms_before).unwrap();
scene.ucmd().arg("--").arg("-w").arg("-w").succeeds();
assert_eq!(at.metadata("-w").permissions(), perms_after);
}
#[test]
fn test_gnu_special_options() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.touch("file");
scene.ucmd().arg("--").arg("--").arg("file").succeeds();
scene.ucmd().arg("--").arg("--").fails();
}

View file

@ -44,16 +44,91 @@ fn test_date_rfc_3339() {
}
#[test]
fn test_date_rfc_8601() {
fn test_date_rfc_3339_invalid_arg() {
for param in ["--iso-3339", "--rfc-3"] {
new_ucmd!().arg(format!("{param}=foo")).fails();
}
}
#[test]
fn test_date_rfc_8601_default() {
let re = Regex::new(r"^\d{4}-\d{2}-\d{2}\n$").unwrap();
for param in ["--iso-8601", "--i"] {
new_ucmd!().arg(format!("{param}=ns")).succeeds();
new_ucmd!().arg(param).succeeds().stdout_matches(&re);
}
}
#[test]
fn test_date_rfc_8601() {
let re = Regex::new(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2},\d{9}[+-]\d{2}:\d{2}\n$").unwrap();
for param in ["--iso-8601", "--i"] {
new_ucmd!()
.arg(format!("{param}=ns"))
.succeeds()
.stdout_matches(&re);
}
}
#[test]
fn test_date_rfc_8601_invalid_arg() {
for param in ["--iso-8601", "--i"] {
new_ucmd!().arg(format!("{param}=@")).fails();
}
}
#[test]
fn test_date_rfc_8601_second() {
let re = Regex::new(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2}\n$").unwrap();
for param in ["--iso-8601", "--i"] {
new_ucmd!().arg(format!("{param}=second")).succeeds();
new_ucmd!()
.arg(format!("{param}=second"))
.succeeds()
.stdout_matches(&re);
new_ucmd!()
.arg(format!("{param}=seconds"))
.succeeds()
.stdout_matches(&re);
}
}
#[test]
fn test_date_rfc_8601_minute() {
let re = Regex::new(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}[+-]\d{2}:\d{2}\n$").unwrap();
for param in ["--iso-8601", "--i"] {
new_ucmd!()
.arg(format!("{param}=minute"))
.succeeds()
.stdout_matches(&re);
new_ucmd!()
.arg(format!("{param}=minutes"))
.succeeds()
.stdout_matches(&re);
}
}
#[test]
fn test_date_rfc_8601_hour() {
let re = Regex::new(r"^\d{4}-\d{2}-\d{2}T\d{2}[+-]\d{2}:\d{2}\n$").unwrap();
for param in ["--iso-8601", "--i"] {
new_ucmd!()
.arg(format!("{param}=hour"))
.succeeds()
.stdout_matches(&re);
new_ucmd!()
.arg(format!("{param}=hours"))
.succeeds()
.stdout_matches(&re);
}
}
#[test]
fn test_date_rfc_8601_date() {
let re = Regex::new(r"^\d{4}-\d{2}-\d{2}\n$").unwrap();
for param in ["--iso-8601", "--i"] {
new_ucmd!()
.arg(format!("{param}=date"))
.succeeds()
.stdout_matches(&re);
}
}
@ -198,6 +273,24 @@ fn test_date_set_valid_2() {
}
}
#[test]
fn test_date_for_invalid_file() {
let result = new_ucmd!().arg("--file").arg("invalid_file").fails();
result.no_stdout();
assert_eq!(
result.stderr_str().trim(),
"date: invalid_file: No such file or directory",
);
}
#[test]
fn test_date_for_file() {
let (at, mut ucmd) = at_and_ucmd!();
let file = "test_date_for_file";
at.touch(file);
ucmd.arg("--file").arg(file).succeeds();
}
#[test]
#[cfg(all(unix, not(target_os = "macos")))]
/// TODO: expected to fail currently; change to succeeds() when required.
@ -232,3 +325,13 @@ fn test_invalid_format_string() {
result.no_stdout();
assert!(result.stderr_str().starts_with("date: invalid format "));
}
#[test]
fn test_invalid_date_string() {
new_ucmd!()
.arg("-d")
.arg("foo")
.fails()
.no_stdout()
.stderr_contains("invalid date");
}

View file

@ -7,7 +7,7 @@ use regex::Regex;
use std::fs::{File, OpenOptions};
use std::io::{BufReader, Read, Write};
use std::path::PathBuf;
#[cfg(all(not(windows), not(target_os = "macos")))]
#[cfg(all(unix, not(target_os = "macos"), not(target_os = "freebsd")))]
use std::process::{Command, Stdio};
#[cfg(not(windows))]
use std::thread::sleep;
@ -1520,3 +1520,17 @@ fn test_skip_input_fifo() {
assert!(output.stdout.is_empty());
assert_eq!(&output.stderr, b"1+0 records in\n1+0 records out\n");
}
/// Test for reading part of stdin from each of two child processes.
#[cfg(all(not(windows), feature = "printf"))]
#[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");
UCommand::new()
.arg(format!("{printf} | ( {dd_skip} && {dd} ) 2> /dev/null"))
.succeeds()
.stdout_only("def\n");
}

View file

@ -82,10 +82,10 @@ fn _du_basics_subdir(s: &str) {
))]
fn _du_basics_subdir(s: &str) {
// MS-WSL linux has altered expected output
if !uucore::os::is_wsl_1() {
assert_eq!(s, "8\tsubdir/deeper\n");
} else {
if uucore::os::is_wsl_1() {
assert_eq!(s, "0\tsubdir/deeper\n");
} else {
assert_eq!(s, "8\tsubdir/deeper\n");
}
}
@ -164,10 +164,10 @@ fn _du_soft_link(s: &str) {
))]
fn _du_soft_link(s: &str) {
// MS-WSL linux has altered expected output
if !uucore::os::is_wsl_1() {
assert_eq!(s, "16\tsubdir/links\n");
} else {
if uucore::os::is_wsl_1() {
assert_eq!(s, "8\tsubdir/links\n");
} else {
assert_eq!(s, "16\tsubdir/links\n");
}
}
@ -212,10 +212,10 @@ fn _du_hard_link(s: &str) {
))]
fn _du_hard_link(s: &str) {
// MS-WSL linux has altered expected output
if !uucore::os::is_wsl_1() {
assert_eq!(s, "16\tsubdir/links\n");
} else {
if uucore::os::is_wsl_1() {
assert_eq!(s, "8\tsubdir/links\n");
} else {
assert_eq!(s, "16\tsubdir/links\n");
}
}
@ -255,10 +255,10 @@ fn _du_d_flag(s: &str) {
))]
fn _du_d_flag(s: &str) {
// MS-WSL linux has altered expected output
if !uucore::os::is_wsl_1() {
assert_eq!(s, "28\t./subdir\n36\t.\n");
} else {
if uucore::os::is_wsl_1() {
assert_eq!(s, "8\t./subdir\n8\t.\n");
} else {
assert_eq!(s, "28\t./subdir\n36\t.\n");
}
}
@ -303,10 +303,10 @@ fn _du_dereference(s: &str) {
))]
fn _du_dereference(s: &str) {
// MS-WSL linux has altered expected output
if !uucore::os::is_wsl_1() {
assert_eq!(s, "8\tsubdir/links/deeper_dir\n24\tsubdir/links\n");
} else {
if uucore::os::is_wsl_1() {
assert_eq!(s, "0\tsubdir/links/deeper_dir\n8\tsubdir/links\n");
} else {
assert_eq!(s, "8\tsubdir/links/deeper_dir\n24\tsubdir/links\n");
}
}

View file

@ -1280,7 +1280,7 @@ fn test_ls_long_formats() {
// Zero or one "." for indicating a file with security context
// Regex for three names, so all of author, group and owner
let re_three = Regex::new(r"[xrw-]{9}\.? \d ([-0-9_a-z]+ ){3}0").unwrap();
let re_three = Regex::new(r"[xrw-]{9}\.? \d ([-0-9_a-z_A-Z]+ ){3}0").unwrap();
#[cfg(unix)]
let re_three_num = Regex::new(r"[xrw-]{9}\.? \d (\d+ ){3}0").unwrap();
@ -1289,13 +1289,13 @@ fn test_ls_long_formats() {
// - group and owner
// - author and owner
// - author and group
let re_two = Regex::new(r"[xrw-]{9}\.? \d ([-0-9_a-z]+ ){2}0").unwrap();
let re_two = Regex::new(r"[xrw-]{9}\.? \d ([-0-9_a-z_A-Z]+ ){2}0").unwrap();
#[cfg(unix)]
let re_two_num = Regex::new(r"[xrw-]{9}\.? \d (\d+ ){2}0").unwrap();
// Regex for one name: author, group or owner
let re_one = Regex::new(r"[xrw-]{9}\.? \d [-0-9_a-z]+ 0").unwrap();
let re_one = Regex::new(r"[xrw-]{9}\.? \d [-0-9_a-z_A-Z]+ 0").unwrap();
#[cfg(unix)]
let re_one_num = Regex::new(r"[xrw-]{9}\.? \d \d+ 0").unwrap();

View file

@ -25,7 +25,6 @@ fn test_shred_remove() {
assert!(at.file_exists(file_b));
}
#[cfg(not(target_os = "freebsd"))]
#[test]
fn test_shred_force() {
let scene = TestScenario::new(util_name!());

View file

@ -10,7 +10,7 @@ fn test_output_is_random_permutation() {
let input_seq = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let input = input_seq
.iter()
.map(|x| x.to_string())
.map(ToString::to_string)
.collect::<Vec<String>>()
.join("\n");
@ -52,7 +52,7 @@ fn test_echo() {
.args(
&input_seq
.iter()
.map(|x| x.to_string())
.map(ToString::to_string)
.collect::<Vec<String>>(),
)
.succeeds();
@ -74,7 +74,7 @@ fn test_head_count() {
let input_seq = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let input = input_seq
.iter()
.map(|x| x.to_string())
.map(ToString::to_string)
.collect::<Vec<String>>()
.join("\n");
@ -105,7 +105,7 @@ fn test_repeat() {
let input_seq = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let input = input_seq
.iter()
.map(|x| x.to_string())
.map(ToString::to_string)
.collect::<Vec<String>>()
.join("\n");

View file

@ -10,11 +10,11 @@ fn test_invalid_time_interval() {
new_ucmd!()
.arg("xyz")
.fails()
.usage_error("invalid time interval 'xyz'");
.usage_error("invalid time interval 'xyz': Invalid character: 'x' at position 1");
new_ucmd!()
.args(&["--", "-1"])
.fails()
.usage_error("invalid time interval '-1'");
.usage_error("invalid time interval '-1': Number was negative");
}
#[test]
@ -204,14 +204,16 @@ fn test_sleep_when_input_has_only_whitespace_then_error(#[case] input: &str) {
.arg(input)
.timeout(Duration::from_secs(10))
.fails()
.usage_error(format!("invalid time interval '{input}'"));
.usage_error(format!(
"invalid time interval '{input}': Found only whitespace in input"
));
}
#[test]
fn test_sleep_when_multiple_input_some_with_error_then_shows_all_errors() {
let expected = "invalid time interval 'abc'\n\
sleep: invalid time interval '1years'\n\
sleep: invalid time interval ' '";
let expected = "invalid time interval 'abc': Invalid character: 'a' at position 1\n\
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
@ -228,5 +230,5 @@ fn test_negative_interval() {
new_ucmd!()
.args(&["--", "-1"])
.fails()
.usage_error("invalid time interval '-1'");
.usage_error("invalid time interval '-1': Number was negative");
}

View file

@ -4459,7 +4459,7 @@ fn test_follow_when_files_are_pointing_to_same_relative_file_and_file_stays_same
}
#[rstest]
#[case::exponent_exceed_float_max("1.0e2048")]
#[case::exponent_exceed_float_max("1.0e100000")]
#[case::underscore_delimiter("1_000")]
#[case::only_point(".")]
#[case::space_in_primes("' '")]

View file

@ -138,3 +138,19 @@ fn test_kill_after_long() {
.no_stdout()
.no_stderr();
}
#[test]
fn test_kill_subprocess() {
new_ucmd!()
.args(&[
// Make sure the CI can spawn the subprocess.
"10",
"sh",
"-c",
"sh -c \"trap 'echo xyz' TERM; sleep 30\"",
])
.fails()
.code_is(124)
.stdout_contains("xyz")
.stderr_contains("Terminated");
}

View file

@ -2822,7 +2822,7 @@ mod tests {
#[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(|s| s.is_empty());
result.stdout_check(<[u8]>::is_empty);
}
#[cfg(feature = "echo")]
@ -3065,9 +3065,10 @@ mod tests {
// check `child.is_alive()` and `child.delay()` is working
let mut trials = 10;
while child.is_alive() {
if trials <= 0 {
panic!("Assertion failed: child process is still alive.")
}
assert!(
trials > 0,
"Assertion failed: child process is still alive."
);
child.delay(500);
trials -= 1;