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

Merge branch 'main' into printf-rewrite

This commit is contained in:
Terts Diepraam 2023-11-20 13:53:11 +01:00
commit 6d2698b802
179 changed files with 2883 additions and 2016 deletions

View file

@ -540,3 +540,15 @@ fn test_write_to_self() {
"first_file_content.second_file_content."
);
}
#[test]
#[cfg(unix)]
fn test_error_loop() {
let (at, mut ucmd) = at_and_ucmd!();
at.symlink_file("2", "1");
at.symlink_file("3", "2");
at.symlink_file("1", "3");
ucmd.arg("1")
.fails()
.stderr_is("cat: 1: Too many levels of symbolic links\n");
}

View file

@ -24,8 +24,6 @@ use std::path::PathBuf;
#[cfg(any(target_os = "linux", target_os = "android"))]
use filetime::FileTime;
#[cfg(any(target_os = "linux", target_os = "android"))]
use rlimit::Resource;
#[cfg(target_os = "linux")]
use std::ffi::OsString;
#[cfg(any(target_os = "linux", target_os = "android"))]
@ -230,6 +228,22 @@ fn test_cp_arg_no_target_directory() {
.stderr_contains("cannot overwrite directory");
}
#[test]
fn test_cp_arg_no_target_directory_with_recursive() {
let (at, mut ucmd) = at_and_ucmd!();
at.mkdir("dir");
at.mkdir("dir2");
at.touch("dir/a");
at.touch("dir/b");
ucmd.arg("-rT").arg("dir").arg("dir2").succeeds();
assert!(at.plus("dir2").join("a").exists());
assert!(at.plus("dir2").join("b").exists());
assert!(!at.plus("dir2").join("dir").exists());
}
#[test]
fn test_cp_target_directory_is_file() {
new_ucmd!()
@ -2108,6 +2122,7 @@ fn test_cp_reflink_insufficient_permission() {
#[test]
fn test_closes_file_descriptors() {
use procfs::process::Process;
use rlimit::Resource;
let me = Process::myself().unwrap();
// The test suite runs in parallel, we have pipe, sockets
@ -2117,7 +2132,6 @@ fn test_closes_file_descriptors() {
let limit_fd: u64 = number_file_already_opened + 9;
// For debugging purposes:
#[cfg(not(target_os = "android"))]
for f in me.fd().unwrap() {
let fd = f.unwrap();
println!("{:?} {:?}", fd, fd.mode());
@ -3216,6 +3230,7 @@ fn test_cp_archive_on_directory_ending_dot() {
}
#[test]
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
fn test_cp_debug_default() {
let ts = TestScenario::new(util_name!());
let at = &ts.fixtures;
@ -3243,6 +3258,7 @@ fn test_cp_debug_default() {
}
#[test]
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
fn test_cp_debug_multiple_default() {
let ts = TestScenario::new(util_name!());
let at = &ts.fixtures;
@ -3418,7 +3434,7 @@ fn test_cp_debug_sparse_auto() {
}
#[test]
#[cfg(any(target_os = "linux", target_os = "android", target_os = "macos"))]
#[cfg(any(target_os = "linux", target_os = "macos"))]
fn test_cp_debug_reflink_auto() {
let ts = TestScenario::new(util_name!());
let at = &ts.fixtures;

View file

@ -1470,7 +1470,7 @@ fn test_seek_output_fifo() {
.args(&["count=0", "seek=1", "of=fifo", "status=noxfer"])
.run_no_wait();
std::fs::write(at.plus("fifo"), &vec![0; 512]).unwrap();
std::fs::write(at.plus("fifo"), vec![0; 512]).unwrap();
child
.wait()
@ -1492,7 +1492,7 @@ fn test_skip_input_fifo() {
.args(&["count=0", "skip=1", "if=fifo", "status=noxfer"])
.run_no_wait();
std::fs::write(at.plus("fifo"), &vec![0; 512]).unwrap();
std::fs::write(at.plus("fifo"), vec![0; 512]).unwrap();
child
.wait()

View file

@ -299,11 +299,13 @@ fn test_du_dereference_args() {
file2.write_all(b"amaz?ng").unwrap();
at.symlink_dir("subdir", "sublink");
let result = ts.ucmd().arg("-D").arg("-s").arg("sublink").succeeds();
let stdout = result.stdout_str();
for arg in ["-D", "-H", "--dereference-args"] {
let result = ts.ucmd().arg(arg).arg("-s").arg("sublink").succeeds();
let stdout = result.stdout_str();
assert!(!stdout.starts_with('0'));
assert!(stdout.contains("sublink"));
assert!(!stdout.starts_with('0'));
assert!(stdout.contains("sublink"));
}
// Without the option
let result = ts.ucmd().arg("-s").arg("sublink").succeeds();
@ -336,6 +338,42 @@ fn _du_dereference(s: &str) {
}
}
#[cfg(not(any(target_os = "windows", target_os = "android", target_os = "freebsd")))]
#[test]
fn test_du_no_dereference() {
let ts = TestScenario::new(util_name!());
let at = &ts.fixtures;
let dir = "a_dir";
let symlink = "symlink";
at.mkdir(dir);
at.symlink_dir(dir, symlink);
for arg in ["-P", "--no-dereference"] {
ts.ucmd()
.arg(arg)
.succeeds()
.stdout_contains(dir)
.stdout_does_not_contain(symlink);
// ensure no-dereference "wins"
ts.ucmd()
.arg("--dereference")
.arg(arg)
.succeeds()
.stdout_contains(dir)
.stdout_does_not_contain(symlink);
// ensure dereference "wins"
ts.ucmd()
.arg(arg)
.arg("--dereference")
.succeeds()
.stdout_contains(symlink)
.stdout_does_not_contain(dir);
}
}
#[test]
fn test_du_inodes_basic() {
let ts = TestScenario::new(util_name!());
@ -403,6 +441,33 @@ fn test_du_inodes() {
}
}
#[test]
fn test_du_inodes_with_count_links() {
let ts = TestScenario::new(util_name!());
let at = &ts.fixtures;
at.mkdir("dir");
at.touch("dir/file");
at.hard_link("dir/file", "dir/hard_link_a");
at.hard_link("dir/file", "dir/hard_link_b");
// ensure the hard links are not counted without --count-links
ts.ucmd()
.arg("--inodes")
.arg("dir")
.succeeds()
.stdout_is("2\tdir\n");
for arg in ["-l", "--count-links"] {
ts.ucmd()
.arg("--inodes")
.arg(arg)
.arg("dir")
.succeeds()
.stdout_is("4\tdir\n");
}
}
#[test]
fn test_du_h_flag_empty_file() {
new_ucmd!()

View file

@ -994,9 +994,9 @@ fn test_ls_long() {
fn test_ls_long_format() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.mkdir(&at.plus_as_string("test-long-dir"));
at.mkdir(at.plus_as_string("test-long-dir"));
at.touch(at.plus_as_string("test-long-dir/test-long-file"));
at.mkdir(&at.plus_as_string("test-long-dir/test-long-dir"));
at.mkdir(at.plus_as_string("test-long-dir/test-long-dir"));
for arg in LONG_ARGS {
// Assuming sane username do not have spaces within them.
@ -1971,7 +1971,7 @@ fn test_ls_color() {
.join("nested_dir")
.to_string_lossy()
.to_string();
at.mkdir(&nested_dir);
at.mkdir(nested_dir);
at.mkdir("z");
let nested_file = Path::new("a")
.join("nested_file")

View file

@ -112,6 +112,15 @@ fn sub_b_string_handle_escapes() {
.stdout_only("hello \tworld");
}
#[test]
fn sub_b_string_validate_field_params() {
new_ucmd!()
.args(&["hello %7b", "world"])
.run()
.stdout_is("hello ")
.stderr_is("printf: %7b: invalid conversion specification\n");
}
#[test]
fn sub_b_string_ignore_subs() {
new_ucmd!()
@ -120,6 +129,31 @@ fn sub_b_string_ignore_subs() {
.stdout_only("hello world %% %i");
}
#[test]
fn sub_q_string_non_printable() {
new_ucmd!()
.args(&["non-printable: %q", "\"$test\""])
.succeeds()
.stdout_only("non-printable: '\"$test\"'");
}
#[test]
fn sub_q_string_validate_field_params() {
new_ucmd!()
.args(&["hello %7q", "world"])
.run()
.stdout_is("hello ")
.stderr_is("printf: %7q: invalid conversion specification\n");
}
#[test]
fn sub_q_string_special_non_printable() {
new_ucmd!()
.args(&["non-printable: %q", "test~"])
.succeeds()
.stdout_only("non-printable: test~");
}
#[test]
fn sub_char() {
new_ucmd!()
@ -229,6 +263,14 @@ fn sub_num_hex_upper() {
.stdout_only("thirty in hex is 1E");
}
#[test]
fn sub_num_hex_non_numerical() {
new_ucmd!()
.args(&["parameters need to be numbers %X", "%194"])
.fails()
.code_is(1);
}
#[test]
fn sub_num_float() {
new_ucmd!()

View file

@ -2,7 +2,7 @@
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
// spell-checker:ignore xzaaa sixhundredfiftyonebytes ninetyonebytes threebytes asciilowercase fghij klmno pqrst uvwxyz fivelines twohundredfortyonebytes onehundredlines nbbbb dxen ncccc
// spell-checker:ignore xzaaa sixhundredfiftyonebytes ninetyonebytes threebytes asciilowercase ghijkl mnopq rstuv wxyz fivelines twohundredfortyonebytes onehundredlines nbbbb dxen ncccc
use crate::common::util::{AtPath, TestScenario};
use rand::{thread_rng, Rng, SeedableRng};
@ -247,11 +247,18 @@ fn test_split_additional_suffix() {
}
#[test]
fn test_additional_suffix_no_slash() {
fn test_additional_suffix_dir_separator() {
#[cfg(unix)]
new_ucmd!()
.args(&["--additional-suffix", "a/b"])
.fails()
.usage_error("invalid suffix 'a/b', contains directory separator");
#[cfg(windows)]
new_ucmd!()
.args(&["--additional-suffix", "a\\b"])
.fails()
.usage_error("invalid suffix 'a\\b', contains directory separator");
}
#[test]
@ -697,54 +704,41 @@ fn test_split_overflow_bytes_size() {
assert_eq!(glob.collate(), at.read_bytes(name));
}
#[test]
#[cfg(target_pointer_width = "32")]
fn test_split_chunks_num_chunks_oversized_32() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.touch("file");
scene
.ucmd()
.args(&["--number", "5000000000", "sixhundredfiftyonebytes.txt"])
.fails()
.code_is(1)
.stderr_only("split: Number of chunks too big\n");
}
#[test]
fn test_split_stdin_num_chunks() {
new_ucmd!()
.args(&["--number=1"])
.fails()
.code_is(1)
.stderr_only("split: -: cannot determine file size\n");
let (at, mut ucmd) = at_and_ucmd!();
ucmd.args(&["--number=1"]).pipe_in("").succeeds();
assert_eq!(file_read(&at, "xaa"), "");
assert!(!at.plus("xab").exists());
}
#[test]
fn test_split_stdin_num_kth_chunk() {
new_ucmd!()
.args(&["--number=1/2"])
.fails()
.code_is(1)
.stderr_only("split: -: cannot determine file size\n");
.pipe_in("1\n2\n3\n4\n5\n")
.succeeds()
.stdout_only("1\n2\n3");
}
#[test]
fn test_split_stdin_num_line_chunks() {
new_ucmd!()
.args(&["--number=l/2"])
.fails()
.code_is(1)
.stderr_only("split: -: cannot determine file size\n");
let (at, mut ucmd) = at_and_ucmd!();
ucmd.args(&["--number=l/2"])
.pipe_in("1\n2\n3\n4\n5\n")
.succeeds();
assert_eq!(file_read(&at, "xaa"), "1\n2\n3\n");
assert_eq!(file_read(&at, "xab"), "4\n5\n");
assert!(!at.plus("xac").exists());
}
#[test]
fn test_split_stdin_num_kth_line_chunk() {
new_ucmd!()
.args(&["--number=l/2/5"])
.fails()
.code_is(1)
.stderr_only("split: -: cannot determine file size\n");
.pipe_in("1\n2\n3\n4\n5\n")
.succeeds()
.stdout_only("2\n");
}
fn file_read(at: &AtPath, filename: &str) -> String {
@ -824,6 +818,79 @@ fn test_hex_dynamic_suffix_length() {
assert_eq!(file_read(&at, "xf000"), "a");
}
/// Test for dynamic suffix length (auto-widening) disabled when suffix start number is specified
#[test]
fn test_dynamic_suffix_length_off_with_suffix_start() {
new_ucmd!()
.args(&["-b", "1", "--numeric-suffixes=89", "ninetyonebytes.txt"])
.fails()
.stderr_only("split: output file suffixes exhausted\n");
}
/// Test for dynamic suffix length (auto-widening) enabled when suffix start number is NOT specified
#[test]
fn test_dynamic_suffix_length_on_with_suffix_start_no_value() {
let (at, mut ucmd) = at_and_ucmd!();
ucmd.args(&["-b", "1", "--numeric-suffixes", "ninetyonebytes.txt"])
.succeeds();
assert_eq!(file_read(&at, "x9000"), "a");
}
/// Test for suffix auto-width with --number strategy and suffix start number
#[test]
fn test_suffix_auto_width_with_number() {
let (at, mut ucmd) = at_and_ucmd!();
ucmd.args(&["--numeric-suffixes=1", "--number=r/100", "fivelines.txt"])
.succeeds();
let glob = Glob::new(&at, ".", r"x\d\d\d$");
assert_eq!(glob.count(), 100);
assert_eq!(glob.collate(), at.read_bytes("fivelines.txt"));
assert_eq!(file_read(&at, "x001"), "1\n");
assert_eq!(file_read(&at, "x100"), "");
new_ucmd!()
.args(&["--numeric-suffixes=100", "--number=r/100", "fivelines.txt"])
.fails();
}
/// Test for edge case of specifying 0 for suffix length
#[test]
fn test_suffix_length_zero() {
let (at, mut ucmd) = at_and_ucmd!();
ucmd.args(&[
"--numeric-suffixes=1",
"--number=r/100",
"-a",
"0",
"fivelines.txt",
])
.succeeds();
let glob = Glob::new(&at, ".", r"x\d\d\d$");
assert_eq!(glob.count(), 100);
new_ucmd!()
.args(&[
"--numeric-suffixes=100",
"--number=r/100",
"-a",
"0",
"fivelines.txt",
])
.fails();
new_ucmd!()
.args(&[
"-b",
"1",
"--numeric-suffixes=89",
"-a",
"0",
"ninetyonebytes.txt",
])
.fails()
.stderr_only("split: output file suffixes exhausted\n");
}
#[test]
fn test_suffixes_exhausted() {
new_ucmd!()
@ -832,6 +899,14 @@ fn test_suffixes_exhausted() {
.stderr_only("split: output file suffixes exhausted\n");
}
#[test]
fn test_suffix_length_req() {
new_ucmd!()
.args(&["-n", "100", "-a", "1", "asciilowercase.txt"])
.fails()
.stderr_only("split: the suffix length needs to be at least 2\n");
}
#[test]
fn test_verbose() {
new_ucmd!()
@ -857,11 +932,11 @@ fn test_number_n() {
s
};
ucmd.args(&["-n", "5", "asciilowercase.txt"]).succeeds();
assert_eq!(file_read("xaa"), "abcde");
assert_eq!(file_read("xab"), "fghij");
assert_eq!(file_read("xac"), "klmno");
assert_eq!(file_read("xad"), "pqrst");
assert_eq!(file_read("xae"), "uvwxyz\n");
assert_eq!(file_read("xaa"), "abcdef");
assert_eq!(file_read("xab"), "ghijkl");
assert_eq!(file_read("xac"), "mnopq");
assert_eq!(file_read("xad"), "rstuv");
assert_eq!(file_read("xae"), "wxyz\n");
#[cfg(unix)]
new_ucmd!()
.args(&["--number=100", "/dev/null"])
@ -874,11 +949,11 @@ fn test_number_kth_of_n() {
new_ucmd!()
.args(&["--number=3/5", "asciilowercase.txt"])
.succeeds()
.stdout_only("klmno");
.stdout_only("mnopq");
new_ucmd!()
.args(&["--number=5/5", "asciilowercase.txt"])
.succeeds()
.stdout_only("uvwxyz\n");
.stdout_only("wxyz\n");
new_ucmd!()
.args(&["-e", "--number=99/100", "asciilowercase.txt"])
.succeeds()
@ -966,11 +1041,11 @@ fn test_split_number_with_io_blksize() {
};
ucmd.args(&["-n", "5", "asciilowercase.txt", "---io-blksize", "1024"])
.succeeds();
assert_eq!(file_read("xaa"), "abcde");
assert_eq!(file_read("xab"), "fghij");
assert_eq!(file_read("xac"), "klmno");
assert_eq!(file_read("xad"), "pqrst");
assert_eq!(file_read("xae"), "uvwxyz\n");
assert_eq!(file_read("xaa"), "abcdef");
assert_eq!(file_read("xab"), "ghijkl");
assert_eq!(file_read("xac"), "mnopq");
assert_eq!(file_read("xad"), "rstuv");
assert_eq!(file_read("xae"), "wxyz\n");
}
#[test]
@ -985,6 +1060,32 @@ fn test_split_default_with_io_blksize() {
assert_eq!(glob.collate(), at.read_bytes(name));
}
#[test]
fn test_split_invalid_io_blksize() {
new_ucmd!()
.args(&["---io-blksize=XYZ", "threebytes.txt"])
.fails()
.stderr_only("split: invalid IO block size: 'XYZ'\n");
new_ucmd!()
.args(&["---io-blksize=5000000000", "threebytes.txt"])
.fails()
.stderr_only("split: invalid IO block size: '5000000000'\n");
#[cfg(target_pointer_width = "32")]
new_ucmd!()
.args(&["---io-blksize=2146435072", "threebytes.txt"])
.fails()
.stderr_only("split: invalid IO block size: '2146435072'\n");
}
#[test]
fn test_split_number_oversized_stdin() {
new_ucmd!()
.args(&["--number=3", "---io-blksize=600"])
.pipe_in_fixture("sixhundredfiftyonebytes.txt")
.fails()
.stderr_only("split: -: cannot determine input size\n");
}
#[test]
fn test_invalid_suffix_length() {
new_ucmd!()
@ -1077,6 +1178,18 @@ fn test_elide_dev_null() {
assert!(!at.plus("xac").exists());
}
#[test]
#[cfg(unix)]
fn test_dev_zero() {
let (at, mut ucmd) = at_and_ucmd!();
ucmd.args(&["-n", "3", "/dev/zero"])
.fails()
.stderr_only("split: /dev/zero: cannot determine file size\n");
assert!(!at.plus("xaa").exists());
assert!(!at.plus("xab").exists());
assert!(!at.plus("xac").exists());
}
#[test]
fn test_lines() {
let (at, mut ucmd) = at_and_ucmd!();
@ -1102,6 +1215,15 @@ fn test_lines_kth() {
.stdout_only("20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n");
}
#[test]
#[cfg(unix)]
fn test_lines_kth_dev_null() {
new_ucmd!()
.args(&["-n", "l/3/10", "/dev/null"])
.succeeds()
.stdout_only("");
}
#[test]
fn test_line_bytes() {
let (at, mut ucmd) = at_and_ucmd!();
@ -1241,7 +1363,7 @@ fn test_numeric_suffix() {
}
#[test]
fn test_numeric_suffix_alias() {
fn test_numeric_suffix_inferred() {
let (at, mut ucmd) = at_and_ucmd!();
ucmd.args(&["-n", "4", "--numeric=9", "threebytes.txt"])
.succeeds()

View file

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

View file

@ -23,6 +23,7 @@ use std::io::Write;
use std::io::{Seek, SeekFrom};
#[cfg(all(
not(target_vendor = "apple"),
not(target_os = "android"),
not(target_os = "windows"),
not(target_os = "freebsd")
))]
@ -31,6 +32,7 @@ use std::process::Stdio;
use tail::chunks::BUFFER_SIZE as CHUNK_BUFFER_SIZE;
#[cfg(all(
not(target_vendor = "apple"),
not(target_os = "android"),
not(target_os = "windows"),
not(target_os = "freebsd")
))]

View file

@ -21,11 +21,9 @@ fn test_users_check_name() {
#[cfg(target_os = "linux")]
let util_name = util_name!();
#[cfg(target_vendor = "apple")]
let util_name = format!("g{}", util_name!());
let util_name = &format!("g{}", util_name!());
// note: clippy::needless_borrow *false positive*
#[allow(clippy::needless_borrow)]
let expected = TestScenario::new(&util_name)
let expected = TestScenario::new(util_name)
.cmd(util_name)
.env("LC_ALL", "C")
.succeeds()