1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-08-01 21:47:46 +00:00

Merge branch 'master' into numfmt/round-and-c-locale

This commit is contained in:
Sylvestre Ledru 2021-06-23 12:39:55 +02:00 committed by GitHub
commit d40fc65ee6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
56 changed files with 700 additions and 328 deletions

View file

@ -103,7 +103,7 @@ fn test_wrap_bad_arg() {
.arg(wrap_param)
.arg("b")
.fails()
.stderr_only("base32: Invalid wrap size: b: invalid digit found in string\n");
.stderr_only("base32: Invalid wrap size: 'b': invalid digit found in string\n");
}
}
@ -114,7 +114,7 @@ fn test_base32_extra_operand() {
.arg("a.txt")
.arg("a.txt")
.fails()
.stderr_only("base32: extra operand a.txt");
.stderr_only("base32: extra operand 'a.txt'");
}
#[test]

View file

@ -89,7 +89,7 @@ fn test_wrap_bad_arg() {
.arg(wrap_param)
.arg("b")
.fails()
.stderr_only("base64: Invalid wrap size: b: invalid digit found in string\n");
.stderr_only("base64: Invalid wrap size: 'b': invalid digit found in string\n");
}
}
@ -100,7 +100,7 @@ fn test_base64_extra_operand() {
.arg("a.txt")
.arg("a.txt")
.fails()
.stderr_only("base64: extra operand a.txt");
.stderr_only("base64: extra operand 'a.txt'");
}
#[test]

View file

@ -172,14 +172,14 @@ fn test_chown_only_colon() {
// expected:
// $ chown -v :: file.txt 2>out_err ; echo $? ; cat out_err
// 1
// chown: invalid group: ::
// chown: invalid group: '::'
scene
.ucmd()
.arg("::")
.arg("--verbose")
.arg(file1)
.fails()
.stderr_contains(&"invalid group: ::");
.stderr_contains(&"invalid group: '::'");
}
#[test]

View file

@ -1325,3 +1325,16 @@ fn test_copy_dir_with_symlinks() {
ucmd.args(&["-r", "dir", "copy"]).succeeds();
assert_eq!(at.resolve_link("copy/file-link"), "file");
}
#[test]
#[cfg(not(windows))]
fn test_copy_symlink_force() {
let (at, mut ucmd) = at_and_ucmd!();
at.touch("file");
at.symlink_file("file", "file-link");
at.touch("copy");
ucmd.args(&["file-link", "copy", "-f", "--no-dereference"])
.succeeds();
assert_eq!(at.resolve_link("copy"), "file");
}

View file

@ -162,7 +162,7 @@ fn test_directory_and_no_such_file() {
fn test_equal_as_delimiter() {
new_ucmd!()
.args(&["-f", "2", "-d="])
.pipe_in("--libdir=./out/lib")
.pipe_in("--dir=./out/lib")
.succeeds()
.stdout_only("./out/lib\n");
}

View file

@ -117,7 +117,7 @@ fn test_date_format_without_plus() {
new_ucmd!()
.arg("%s")
.fails()
.stderr_contains("date: invalid date %s")
.stderr_contains("date: invalid date '%s'")
.code_is(1);
}

View file

@ -355,7 +355,7 @@ fn test_du_no_permission() {
let result = scene.ucmd().arg(SUB_DIR_LINKS).run(); // TODO: replace with ".fails()" once `du` is fixed
result.stderr_contains(
"du: cannot read directory subdir/links: Permission denied (os error 13)",
"du: cannot read directory 'subdir/links': Permission denied (os error 13)",
);
#[cfg(target_os = "linux")]

View file

@ -255,21 +255,21 @@ fn test_head_invalid_num() {
new_ucmd!()
.args(&["-c", "1024R", "emptyfile.txt"])
.fails()
.stderr_is("head: invalid number of bytes: 1024R");
.stderr_is("head: invalid number of bytes: '1024R'");
new_ucmd!()
.args(&["-n", "1024R", "emptyfile.txt"])
.fails()
.stderr_is("head: invalid number of lines: 1024R");
.stderr_is("head: invalid number of lines: '1024R'");
#[cfg(not(target_pointer_width = "128"))]
new_ucmd!()
.args(&["-c", "1Y", "emptyfile.txt"])
.fails()
.stderr_is("head: invalid number of bytes: 1Y: Value too large for defined data type");
.stderr_is("head: invalid number of bytes: '1Y': Value too large for defined data type");
#[cfg(not(target_pointer_width = "128"))]
new_ucmd!()
.args(&["-n", "1Y", "emptyfile.txt"])
.fails()
.stderr_is("head: invalid number of lines: 1Y: Value too large for defined data type");
.stderr_is("head: invalid number of lines: '1Y': Value too large for defined data type");
#[cfg(target_pointer_width = "32")]
{
let sizes = ["1000G", "10T"];
@ -279,7 +279,7 @@ fn test_head_invalid_num() {
.fails()
.code_is(1)
.stderr_only(format!(
"head: invalid number of bytes: {}: Value too large for defined data type",
"head: invalid number of bytes: '{}': Value too large for defined data type",
size
));
}

View file

@ -432,7 +432,7 @@ fn check_coreutil_version(util_name: &str, version_expected: &str) -> String {
let scene = TestScenario::new(util_name);
let version_check = scene
.cmd_keepenv(&util_name)
.env("LANGUAGE", "C")
.env("LC_ALL", "C")
.arg("--version")
.run();
version_check
@ -476,7 +476,7 @@ fn expected_result(args: &[&str]) -> Result<CmdResult, String> {
let scene = TestScenario::new(util_name);
let result = scene
.cmd_keepenv(util_name)
.env("LANGUAGE", "C")
.env("LC_ALL", "C")
.args(args)
.run();

View file

@ -168,7 +168,7 @@ fn test_ls_width() {
.ucmd()
.args(&option.split(' ').collect::<Vec<_>>())
.fails()
.stderr_only("ls: invalid line width: 1a");
.stderr_only("ls: invalid line width: '1a'");
}
}
@ -2021,3 +2021,28 @@ fn test_ls_path() {
.run()
.stdout_is(expected_stdout);
}
#[test]
fn test_ls_dangling_symlinks() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.mkdir("temp_dir");
at.symlink_file("does_not_exist", "temp_dir/dangle");
scene.ucmd().arg("-L").arg("temp_dir/dangle").fails();
scene.ucmd().arg("-H").arg("temp_dir/dangle").fails();
scene
.ucmd()
.arg("temp_dir/dangle")
.succeeds()
.stdout_contains("dangle");
scene
.ucmd()
.arg("-Li")
.arg("temp_dir")
.succeeds() // this should fail, though at the moment, ls lacks a way to propagate errors encountered during display
.stdout_contains(if cfg!(windows) { "dangle" } else { "? dangle" });
}

View file

@ -17,7 +17,10 @@ static TEST_TEMPLATE8: &str = "tempXXXl/ate";
#[cfg(windows)]
static TEST_TEMPLATE8: &str = "tempXXXl\\ate";
#[cfg(not(windows))]
const TMPDIR: &str = "TMPDIR";
#[cfg(windows)]
const TMPDIR: &str = "TMP";
#[test]
fn test_mktemp_mktemp() {
@ -386,7 +389,7 @@ fn test_mktemp_tmpdir_one_arg() {
let scene = TestScenario::new(util_name!());
let result = scene
.ucmd()
.ucmd_keepenv()
.arg("--tmpdir")
.arg("apt-key-gpghome.XXXXXXXXXX")
.succeeds();
@ -399,7 +402,7 @@ fn test_mktemp_directory_tmpdir() {
let scene = TestScenario::new(util_name!());
let result = scene
.ucmd()
.ucmd_keepenv()
.arg("--directory")
.arg("--tmpdir")
.arg("apt-key-gpghome.XXXXXXXXXX")

View file

@ -614,7 +614,7 @@ fn test_mv_overwrite_nonempty_dir() {
// Not same error as GNU; the error message is a rust builtin
// TODO: test (and implement) correct error message (or at least decide whether to do so)
// Current: "mv: couldn't rename path (Directory not empty; from=a; to=b)"
// GNU: "mv: cannot move a to b: Directory not empty"
// GNU: "mv: cannot move 'a' to 'b': Directory not empty"
// Verbose output for the move should not be shown on failure
let result = ucmd.arg("-vT").arg(dir_a).arg(dir_b).fails();
@ -638,7 +638,7 @@ fn test_mv_backup_dir() {
.arg(dir_b)
.succeeds()
.stdout_only(format!(
"{} -> {} (backup: {}~)\n",
"'{}' -> '{}' (backup: '{}~')\n",
dir_a, dir_b, dir_b
));
@ -672,7 +672,7 @@ fn test_mv_errors() {
// $ at.touch file && at.mkdir dir
// $ mv -T file dir
// err == mv: cannot overwrite directory dir with non-directory
// err == mv: cannot overwrite directory 'dir' with non-directory
scene
.ucmd()
.arg("-T")
@ -680,13 +680,13 @@ fn test_mv_errors() {
.arg(dir)
.fails()
.stderr_is(format!(
"mv: cannot overwrite directory {} with non-directory\n",
"mv: cannot overwrite directory '{}' with non-directory\n",
dir
));
// $ at.mkdir dir && at.touch file
// $ mv dir file
// err == mv: cannot overwrite non-directory file with directory dir
// err == mv: cannot overwrite non-directory 'file' with directory 'dir'
assert!(!scene
.ucmd()
.arg(dir)
@ -713,7 +713,7 @@ fn test_mv_verbose() {
.arg(file_a)
.arg(file_b)
.succeeds()
.stdout_only(format!("{} -> {}\n", file_a, file_b));
.stdout_only(format!("'{}' -> '{}'\n", file_a, file_b));
at.touch(file_a);
scene
@ -723,12 +723,13 @@ fn test_mv_verbose() {
.arg(file_b)
.succeeds()
.stdout_only(format!(
"{} -> {} (backup: {}~)\n",
"'{}' -> '{}' (backup: '{}~')\n",
file_a, file_b, file_b
));
}
#[test]
#[cfg(target_os = "linux")] // mkdir does not support -m on windows. Freebsd doesn't return a permission error either.
fn test_mv_permission_error() {
let scene = TestScenario::new("mkdir");
let folder1 = "bar";
@ -738,12 +739,11 @@ fn test_mv_permission_error() {
scene.ucmd().arg("-m777").arg(folder2).succeeds();
scene
.cmd_keepenv(util_name!())
.ccmd("mv")
.arg(folder2)
.arg(folder_to_move)
.run()
.stderr_str()
.ends_with("Permission denied");
.fails()
.stderr_contains("Permission denied");
}
// Todo:
@ -756,5 +756,5 @@ fn test_mv_permission_error() {
// -r--r--r-- 1 user user 0 okt 25 11:21 b
// $
// $ mv -v a b
// mv: try to overwrite b, overriding mode 0444 (r--r--r--)? y
// a -> b
// mv: try to overwrite 'b', overriding mode 0444 (r--r--r--)? y
// 'a' -> 'b'

View file

@ -106,7 +106,7 @@ fn expected_result(args: &[&str]) -> String {
#[allow(clippy::needless_borrow)]
TestScenario::new(&util_name)
.cmd_keepenv(util_name)
.env("LANGUAGE", "C")
.env("LC_ALL", "C")
.args(args)
.succeeds()
.stdout_move_str()

View file

@ -22,6 +22,7 @@ fn file_last_modified_time(ucmd: &UCommand, path: &str) -> String {
}
fn all_minutes(from: DateTime<Local>, to: DateTime<Local>) -> Vec<String> {
let to = to + Duration::minutes(1);
const FORMAT: &str = "%b %d %H:%M %Y";
let mut vec = vec![];
let mut current = from;

View file

@ -28,7 +28,8 @@ fn test_helper(file_name: &str, possible_args: &[&str]) {
fn test_buffer_sizes() {
let buffer_sizes = ["0", "50K", "50k", "1M", "100M"];
for buffer_size in &buffer_sizes {
new_ucmd!()
TestScenario::new(util_name!())
.ucmd_keepenv()
.arg("-n")
.arg("-S")
.arg(buffer_size)
@ -40,7 +41,8 @@ fn test_buffer_sizes() {
{
let buffer_sizes = ["1000G", "10T"];
for buffer_size in &buffer_sizes {
new_ucmd!()
TestScenario::new(util_name!())
.ucmd_keepenv()
.arg("-n")
.arg("-S")
.arg(buffer_size)
@ -877,7 +879,8 @@ fn test_compress() {
#[test]
fn test_compress_fail() {
new_ucmd!()
TestScenario::new(util_name!())
.ucmd_keepenv()
.args(&[
"ext_sort.txt",
"-n",
@ -892,7 +895,8 @@ fn test_compress_fail() {
#[test]
fn test_merge_batches() {
new_ucmd!()
TestScenario::new(util_name!())
.ucmd_keepenv()
.args(&["ext_sort.txt", "-n", "-S", "150b"])
.succeeds()
.stdout_only_fixture("ext_sort.expected");
@ -900,7 +904,8 @@ fn test_merge_batches() {
#[test]
fn test_merge_batch_size() {
new_ucmd!()
TestScenario::new(util_name!())
.ucmd_keepenv()
.arg("--batch-size=2")
.arg("-m")
.arg("--unique")

View file

@ -309,7 +309,7 @@ fn test_split_lines_number() {
.args(&["--lines", "2fb", "file"])
.fails()
.code_is(1)
.stderr_only("split: invalid number of lines: 2fb");
.stderr_only("split: invalid number of lines: '2fb'");
}
#[test]
@ -318,13 +318,13 @@ fn test_split_invalid_bytes_size() {
.args(&["-b", "1024R"])
.fails()
.code_is(1)
.stderr_only("split: invalid number of bytes: 1024R");
.stderr_only("split: invalid number of bytes: '1024R'");
#[cfg(not(target_pointer_width = "128"))]
new_ucmd!()
.args(&["-b", "1Y"])
.fails()
.code_is(1)
.stderr_only("split: invalid number of bytes: 1Y: Value too large for defined data type");
.stderr_only("split: invalid number of bytes: '1Y': Value too large for defined data type");
#[cfg(target_pointer_width = "32")]
{
let sizes = ["1000G", "10T"];
@ -334,7 +334,7 @@ fn test_split_invalid_bytes_size() {
.fails()
.code_is(1)
.stderr_only(format!(
"split: invalid number of bytes: {}: Value too large for defined data type",
"split: invalid number of bytes: '{}': Value too large for defined data type",
size
));
}

View file

@ -317,7 +317,7 @@ fn expected_result(args: &[&str]) -> String {
#[allow(clippy::needless_borrow)]
TestScenario::new(&util_name)
.cmd_keepenv(util_name)
.env("LANGUAGE", "C")
.env("LC_ALL", "C")
.args(args)
.succeeds()
.stdout_move_str()

View file

@ -63,12 +63,12 @@ fn test_stdbuf_invalid_mode_fails() {
.args(&[*option, "1024R", "head"])
.fails()
.code_is(125)
.stderr_only("stdbuf: invalid mode 1024R");
.stderr_only("stdbuf: invalid mode '1024R'");
#[cfg(not(target_pointer_width = "128"))]
new_ucmd!()
.args(&[*option, "1Y", "head"])
.fails()
.code_is(125)
.stderr_contains("stdbuf: invalid mode 1Y: Value too large for defined data type");
.stderr_contains("stdbuf: invalid mode '1Y': Value too large for defined data type");
}
}

View file

@ -364,21 +364,21 @@ fn test_tail_invalid_num() {
new_ucmd!()
.args(&["-c", "1024R", "emptyfile.txt"])
.fails()
.stderr_is("tail: invalid number of bytes: 1024R");
.stderr_is("tail: invalid number of bytes: '1024R'");
new_ucmd!()
.args(&["-n", "1024R", "emptyfile.txt"])
.fails()
.stderr_is("tail: invalid number of lines: 1024R");
.stderr_is("tail: invalid number of lines: '1024R'");
#[cfg(not(target_pointer_width = "128"))]
new_ucmd!()
.args(&["-c", "1Y", "emptyfile.txt"])
.fails()
.stderr_is("tail: invalid number of bytes: 1Y: Value too large for defined data type");
.stderr_is("tail: invalid number of bytes: '1Y': Value too large for defined data type");
#[cfg(not(target_pointer_width = "128"))]
new_ucmd!()
.args(&["-n", "1Y", "emptyfile.txt"])
.fails()
.stderr_is("tail: invalid number of lines: 1Y: Value too large for defined data type");
.stderr_is("tail: invalid number of lines: '1Y': Value too large for defined data type");
#[cfg(target_pointer_width = "32")]
{
let sizes = ["1000G", "10T"];
@ -388,7 +388,7 @@ fn test_tail_invalid_num() {
.fails()
.code_is(1)
.stderr_only(format!(
"tail: invalid number of bytes: {}: Value too large for defined data type",
"tail: invalid number of bytes: '{}': Value too large for defined data type",
size
));
}

View file

@ -165,7 +165,7 @@ fn test_dangling_string_comparison_is_error() {
.args(&["missing_something", "="])
.run()
.status_code(2)
.stderr_is("test: missing argument after =");
.stderr_is("test: missing argument after '='");
}
#[test]
@ -265,7 +265,7 @@ fn test_float_inequality_is_error() {
.args(&["123.45", "-ge", "6"])
.run()
.status_code(2)
.stderr_is("test: invalid integer 123.45");
.stderr_is("test: invalid integer '123.45'");
}
#[test]
@ -283,7 +283,7 @@ fn test_invalid_utf8_integer_compare() {
cmd.run()
.status_code(2)
.stderr_is("test: invalid integer fo<EFBFBD>o");
.stderr_is("test: invalid integer 'fo<66>o'");
let mut cmd = new_ucmd!();
cmd.raw.arg(arg);
@ -291,7 +291,7 @@ fn test_invalid_utf8_integer_compare() {
cmd.run()
.status_code(2)
.stderr_is("test: invalid integer fo<EFBFBD>o");
.stderr_is("test: invalid integer 'fo<66>o'");
}
#[test]
@ -674,7 +674,7 @@ fn test_erroneous_parenthesized_expression() {
.args(&["a", "!=", "(", "b", "-a", "b", ")", "!=", "c"])
.run()
.status_code(2)
.stderr_is("test: extra argument b");
.stderr_is("test: extra argument 'b'");
}
#[test]
@ -690,3 +690,31 @@ fn test_or_as_filename() {
fn test_string_length_and_nothing() {
new_ucmd!().args(&["-n", "a", "-a"]).run().status_code(2);
}
#[test]
fn test_bracket_syntax_success() {
let scenario = TestScenario::new("[");
let mut ucmd = scenario.ucmd();
ucmd.args(&["1", "-eq", "1", "]"]).succeeds();
}
#[test]
fn test_bracket_syntax_failure() {
let scenario = TestScenario::new("[");
let mut ucmd = scenario.ucmd();
ucmd.args(&["1", "-eq", "2", "]"]).run().status_code(1);
}
#[test]
fn test_bracket_syntax_missing_right_bracket() {
let scenario = TestScenario::new("[");
let mut ucmd = scenario.ucmd();
// Missing closing bracket takes precedence over other possible errors.
ucmd.args(&["1", "-eq"])
.run()
.status_code(2)
.stderr_is("[: missing ']'");
}

View file

@ -249,7 +249,7 @@ fn test_size_and_reference() {
#[test]
fn test_error_filename_only() {
// truncate: you must specify either --size or --reference
// truncate: you must specify either '--size' or '--reference'
new_ucmd!().args(&["file"]).fails().stderr_contains(
"error: The following required arguments were not provided:
--reference <RFILE>
@ -262,15 +262,15 @@ fn test_invalid_numbers() {
new_ucmd!()
.args(&["-s", "0X", "file"])
.fails()
.stderr_contains("Invalid number: 0X");
.stderr_contains("Invalid number: '0X'");
new_ucmd!()
.args(&["-s", "0XB", "file"])
.fails()
.stderr_contains("Invalid number: 0XB");
.stderr_contains("Invalid number: '0XB'");
new_ucmd!()
.args(&["-s", "0B", "file"])
.fails()
.stderr_contains("Invalid number: 0B");
.stderr_contains("Invalid number: '0B'");
}
#[test]
@ -299,13 +299,13 @@ fn test_truncate_bytes_size() {
.args(&["--size", "1024R", "file"])
.fails()
.code_is(1)
.stderr_only("truncate: Invalid number: 1024R");
.stderr_only("truncate: Invalid number: '1024R'");
#[cfg(not(target_pointer_width = "128"))]
new_ucmd!()
.args(&["--size", "1Y", "file"])
.fails()
.code_is(1)
.stderr_only("truncate: Invalid number: 1Y: Value too large for defined data type");
.stderr_only("truncate: Invalid number: '1Y': Value too large for defined data type");
#[cfg(target_pointer_width = "32")]
{
let sizes = ["1000G", "10T"];
@ -315,7 +315,7 @@ fn test_truncate_bytes_size() {
.fails()
.code_is(1)
.stderr_only(format!(
"truncate: Invalid number: {}: Value too large for defined data type",
"truncate: Invalid number: '{}': Value too large for defined data type",
size
));
}

View file

@ -17,7 +17,7 @@ fn test_users_check_name() {
#[allow(clippy::needless_borrow)]
let expected = TestScenario::new(&util_name)
.cmd_keepenv(util_name)
.env("LANGUAGE", "C")
.env("LC_ALL", "C")
.succeeds()
.stdout_move_str();

View file

@ -158,13 +158,12 @@ fn test_users() {
let mut v_actual: Vec<&str> = actual.split_whitespace().collect();
let mut v_expect: Vec<&str> = expect.split_whitespace().collect();
// TODO: `--users` differs from GNU's output on macOS
// Diff < left / right > :
// <"runner console 2021-05-20 22:03 00:08 196\n"
// >"runner console 2021-05-20 22:03 old 196\n"
// TODO: `--users` sometimes differs from GNU's output on macOS (race condition?)
// actual: "runner console Jun 23 06:37 00:34 196\n"
// expect: "runner console Jun 23 06:37 old 196\n"
if cfg!(target_os = "macos") {
v_actual.remove(4);
v_expect.remove(4);
v_actual.remove(5);
v_expect.remove(5);
}
assert_eq!(v_actual, v_expect);
@ -242,7 +241,7 @@ fn expected_result(args: &[&str]) -> String {
#[allow(clippy::needless_borrow)]
TestScenario::new(&util_name)
.cmd_keepenv(util_name)
.env("LANGUAGE", "C")
.env("LC_ALL", "C")
.args(args)
.succeeds()
.stdout_move_str()