mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-09-16 19:56:17 +00:00
Merge branch 'main' into hbina-tr-reimplement-expansion
This commit is contained in:
commit
da728dd2b6
338 changed files with 5042 additions and 38041 deletions
|
@ -74,9 +74,8 @@ fn test_invalid_file() {
|
|||
at.mkdir(folder_name);
|
||||
ts.ucmd()
|
||||
.arg(folder_name)
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("cksum: asdf: Is a directory");
|
||||
.succeeds()
|
||||
.stdout_only("4294967295 0 asdf\n");
|
||||
}
|
||||
|
||||
// Make sure crc is correct for files larger than 32 bytes
|
||||
|
|
|
@ -170,3 +170,11 @@ fn no_arguments() {
|
|||
fn one_argument() {
|
||||
new_ucmd!().arg("a").fails().no_stdout().no_stderr();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_no_such_file() {
|
||||
new_ucmd!()
|
||||
.args(&["bogus_file_1", "bogus_file_2"])
|
||||
.fails()
|
||||
.stderr_only("comm: bogus_file_1: No such file or directory");
|
||||
}
|
||||
|
|
|
@ -725,6 +725,21 @@ fn test_cp_parents_dest_not_directory() {
|
|||
.stderr_contains("with --parents, the destination must be a directory");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_cp_writable_special_file_permissions() {
|
||||
new_ucmd!().arg("/dev/null").arg("/dev/zero").succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_cp_issue_1665() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.arg("/dev/null").arg("foo").succeeds();
|
||||
assert!(at.file_exists("foo"));
|
||||
assert_eq!(at.read("foo"), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_preserve_no_args() {
|
||||
new_ucmd!()
|
||||
|
@ -1364,3 +1379,42 @@ fn test_canonicalize_symlink() {
|
|||
.no_stderr()
|
||||
.no_stdout();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_copy_through_just_created_symlink() {
|
||||
for &create_t in &[true, false] {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.mkdir("a");
|
||||
at.mkdir("b");
|
||||
at.mkdir("c");
|
||||
#[cfg(unix)]
|
||||
fs::symlink("../t", at.plus("a/1")).unwrap();
|
||||
#[cfg(target_os = "windows")]
|
||||
symlink_file("../t", at.plus("a/1")).unwrap();
|
||||
at.touch("b/1");
|
||||
if create_t {
|
||||
at.touch("t");
|
||||
}
|
||||
ucmd.arg("--no-dereference")
|
||||
.arg("a/1")
|
||||
.arg("b/1")
|
||||
.arg("c")
|
||||
.fails()
|
||||
.stderr_only(if cfg!(not(target_os = "windows")) {
|
||||
"cp: will not copy 'b/1' through just-created symlink 'c/1'"
|
||||
} else {
|
||||
"cp: will not copy 'b/1' through just-created symlink 'c\\1'"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_copy_through_dangling_symlink() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.touch("file");
|
||||
at.symlink_file("nonexistent", "target");
|
||||
ucmd.arg("file")
|
||||
.arg("target")
|
||||
.fails()
|
||||
.stderr_only("cp: not writing through dangling symlink 'target'");
|
||||
}
|
||||
|
|
|
@ -262,7 +262,9 @@ fn test_nocreat_causes_failure_when_outfile_not_present() {
|
|||
ucmd.args(&["conv=nocreat", of!(&fname)])
|
||||
.pipe_in("")
|
||||
.fails()
|
||||
.stderr_is("dd Error: No such file or directory (os error 2)");
|
||||
.stderr_only(
|
||||
"dd: failed to open 'this-file-does-not-exist.txt': No such file or directory",
|
||||
);
|
||||
assert!(!fix.file_exists(fname));
|
||||
}
|
||||
|
||||
|
|
|
@ -328,3 +328,31 @@ fn single_file_with_header() {
|
|||
.succeeds()
|
||||
.stdout_is("A 1\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_line_feeds() {
|
||||
new_ucmd!()
|
||||
.arg("non-line_feeds_1.txt")
|
||||
.arg("non-line_feeds_2.txt")
|
||||
.succeeds()
|
||||
.stdout_only_fixture("non-line_feeds.expected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_unicode() {
|
||||
new_ucmd!()
|
||||
.arg("non-unicode_1.bin")
|
||||
.arg("non-unicode_2.bin")
|
||||
.succeeds()
|
||||
.stdout_only_fixture("non-unicode.expected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn null_line_endings() {
|
||||
new_ucmd!()
|
||||
.arg("-z")
|
||||
.arg("non-unicode_1.bin")
|
||||
.arg("non-unicode_2.bin")
|
||||
.succeeds()
|
||||
.stdout_only_fixture("z.expected");
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ fn test_link_no_circular() {
|
|||
|
||||
ucmd.args(&[link, link])
|
||||
.fails()
|
||||
.stderr_is("link: No such file or directory (os error 2)\n");
|
||||
.stderr_is("link: cannot create link 'test_link_no_circular' to 'test_link_no_circular': No such file or directory");
|
||||
assert!(!at.file_exists(link));
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ fn test_link_nonexistent_file() {
|
|||
|
||||
ucmd.args(&[file, link])
|
||||
.fails()
|
||||
.stderr_is("link: No such file or directory (os error 2)\n");
|
||||
.stderr_only("link: cannot create link 'test_link_nonexistent_file_link' to 'test_link_nonexistent_file': No such file or directory");
|
||||
assert!(!at.file_exists(file));
|
||||
assert!(!at.file_exists(link));
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ use std::collections::HashMap;
|
|||
use std::path::Path;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
#[cfg(not(windows))]
|
||||
extern crate libc;
|
||||
#[cfg(not(windows))]
|
||||
|
@ -40,6 +39,198 @@ fn test_ls_i() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_ls_ordering() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
at.mkdir("some-dir1");
|
||||
at.mkdir("some-dir2");
|
||||
at.mkdir("some-dir3");
|
||||
at.mkdir("some-dir4");
|
||||
at.mkdir("some-dir5");
|
||||
at.mkdir("some-dir6");
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-Rl")
|
||||
.succeeds()
|
||||
.stdout_matches(&Regex::new("some-dir1:\\ntotal 0").unwrap());
|
||||
}
|
||||
|
||||
//#[cfg(all(feature = "mknod"))]
|
||||
#[test]
|
||||
fn test_ls_devices() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
at.mkdir("some-dir1");
|
||||
|
||||
// Regex tests correct device ID and correct (no pad) spacing for a single file
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
{
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-al")
|
||||
.arg("/dev/null")
|
||||
.succeeds()
|
||||
.stdout_matches(&Regex::new("[^ ] 3, 2 [^ ]").unwrap());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-al")
|
||||
.arg("/dev/null")
|
||||
.succeeds()
|
||||
.stdout_matches(&Regex::new("[^ ] 1, 3 [^ ]").unwrap());
|
||||
}
|
||||
|
||||
// Regex tests alignment against a file (stdout is a link to a tty)
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let res = scene
|
||||
.ucmd()
|
||||
.arg("-alL")
|
||||
.arg("/dev/null")
|
||||
.arg("/dev/stdout")
|
||||
.succeeds();
|
||||
|
||||
let null_len = String::from_utf8(res.stdout().to_owned())
|
||||
.ok()
|
||||
.unwrap()
|
||||
.lines()
|
||||
.next()
|
||||
.unwrap()
|
||||
.strip_suffix("/dev/null")
|
||||
.unwrap()
|
||||
.len();
|
||||
|
||||
let stdout_len = String::from_utf8(res.stdout().to_owned())
|
||||
.ok()
|
||||
.unwrap()
|
||||
.lines()
|
||||
.nth(1)
|
||||
.unwrap()
|
||||
.strip_suffix("/dev/stdout")
|
||||
.unwrap()
|
||||
.len();
|
||||
|
||||
assert_eq!(stdout_len, null_len);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "chmod"))]
|
||||
#[test]
|
||||
fn test_ls_io_errors() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
at.mkdir("some-dir1");
|
||||
at.mkdir("some-dir2");
|
||||
at.symlink_file("does_not_exist", "some-dir2/dangle");
|
||||
at.mkdir("some-dir3");
|
||||
at.mkdir("some-dir3/some-dir4");
|
||||
at.mkdir("some-dir3/some-dir5");
|
||||
at.mkdir("some-dir3/some-dir6");
|
||||
at.mkdir("some-dir3/some-dir7");
|
||||
at.mkdir("some-dir3/some-dir8");
|
||||
|
||||
scene.ccmd("chmod").arg("000").arg("some-dir1").succeeds();
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-1")
|
||||
.arg("some-dir1")
|
||||
.fails()
|
||||
.stderr_contains("cannot open directory")
|
||||
.stderr_contains("Permission denied");
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-Li")
|
||||
.arg("some-dir2")
|
||||
.fails()
|
||||
.stderr_contains("cannot access")
|
||||
.stderr_contains("No such file or directory")
|
||||
.stdout_contains(if cfg!(windows) { "dangle" } else { "? dangle" });
|
||||
|
||||
scene
|
||||
.ccmd("chmod")
|
||||
.arg("000")
|
||||
.arg("some-dir3/some-dir4")
|
||||
.succeeds();
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-laR")
|
||||
.arg("some-dir3")
|
||||
.fails()
|
||||
.stderr_contains("some-dir4")
|
||||
.stderr_contains("cannot open directory")
|
||||
.stderr_contains("Permission denied")
|
||||
.stdout_contains("some-dir4");
|
||||
|
||||
// test we don't double print on dangling link metadata errors
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-iRL")
|
||||
.arg("some-dir2")
|
||||
.fails()
|
||||
.stderr_does_not_contain(
|
||||
"ls: cannot access 'some-dir2/dangle': No such file or directory\nls: cannot access 'some-dir2/dangle': No such file or directory"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ls_only_dirs_formatting() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
at.mkdir("some-dir1");
|
||||
at.mkdir("some-dir2");
|
||||
at.mkdir("some-dir3");
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
scene.ucmd().arg("-1").arg("-R").succeeds().stdout_only(
|
||||
".:\nsome-dir1\nsome-dir2\nsome-dir3\n\n./some-dir1:\n\n./some-dir2:\n\n./some-dir3:\n",
|
||||
);
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
scene.ucmd().arg("-1").arg("-R").succeeds().stdout_only(
|
||||
".:\nsome-dir1\nsome-dir2\nsome-dir3\n\n.\\some-dir1:\n\n.\\some-dir2:\n\n.\\some-dir3:\n",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ls_walk_glob() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
at.touch(".test-1");
|
||||
at.mkdir("some-dir");
|
||||
at.touch(
|
||||
Path::new("some-dir")
|
||||
.join("test-2~")
|
||||
.as_os_str()
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
#[allow(clippy::trivial_regex)]
|
||||
let re_pwd = Regex::new(r"^\.\n").unwrap();
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-1")
|
||||
.arg("--ignore-backups")
|
||||
.arg("some-dir")
|
||||
.succeeds()
|
||||
.stdout_does_not_contain("test-2~")
|
||||
.stdout_does_not_contain("..")
|
||||
.stdout_does_not_match(&re_pwd);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_ls_a() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
@ -1523,6 +1714,41 @@ fn test_ls_hidden_windows() {
|
|||
scene.ucmd().arg("-a").succeeds().stdout_contains(file);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[test]
|
||||
fn test_ls_hidden_link_windows() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file = "visibleWindowsFileNoDot";
|
||||
at.touch(file);
|
||||
|
||||
let link = "hiddenWindowsLinkNoDot";
|
||||
at.symlink_dir(file, link);
|
||||
// hide the link
|
||||
scene.cmd("attrib").arg("/l").arg("+h").arg(link).succeeds();
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.succeeds()
|
||||
.stdout_contains(file)
|
||||
.stdout_does_not_contain(link);
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-a")
|
||||
.succeeds()
|
||||
.stdout_contains(file)
|
||||
.stdout_contains(link);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[test]
|
||||
fn test_ls_success_on_c_drv_root_windows() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
scene.ucmd().arg("C:\\").succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ls_version_sort() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
|
@ -1903,6 +2129,7 @@ fn test_ls_ignore_hide() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_ls_ignore_backups() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
@ -2269,12 +2496,59 @@ fn test_ls_dangling_symlinks() {
|
|||
.succeeds()
|
||||
.stdout_contains("dangle");
|
||||
|
||||
#[cfg(not(windows))]
|
||||
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" });
|
||||
.fails()
|
||||
.stderr_contains("cannot access")
|
||||
.stdout_contains("? dangle");
|
||||
|
||||
#[cfg(windows)]
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-Li")
|
||||
.arg("temp_dir")
|
||||
.succeeds()
|
||||
.stdout_contains("dangle");
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-Ll")
|
||||
.arg("temp_dir")
|
||||
.fails()
|
||||
.stdout_contains("l?????????");
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
// Check padding is the same for real files and dangling links, in non-long formats
|
||||
at.touch("temp_dir/real_file");
|
||||
|
||||
let real_file_res = scene.ucmd().arg("-Li1").arg("temp_dir").fails();
|
||||
let real_file_stdout_len = String::from_utf8(real_file_res.stdout().to_owned())
|
||||
.ok()
|
||||
.unwrap()
|
||||
.lines()
|
||||
.nth(1)
|
||||
.unwrap()
|
||||
.strip_suffix("real_file")
|
||||
.unwrap()
|
||||
.len();
|
||||
|
||||
let dangle_file_res = scene.ucmd().arg("-Li1").arg("temp_dir").fails();
|
||||
let dangle_stdout_len = String::from_utf8(dangle_file_res.stdout().to_owned())
|
||||
.ok()
|
||||
.unwrap()
|
||||
.lines()
|
||||
.next()
|
||||
.unwrap()
|
||||
.strip_suffix("dangle")
|
||||
.unwrap()
|
||||
.len();
|
||||
|
||||
assert_eq!(real_file_stdout_len, dangle_stdout_len);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -232,6 +232,40 @@ fn test_mv_force_replace_file() {
|
|||
assert!(at.file_exists(file_b));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_same_file() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file_a = "test_mv_same_file_a";
|
||||
|
||||
at.touch(file_a);
|
||||
ucmd.arg(file_a).arg(file_a).fails().stderr_is(format!(
|
||||
"mv: '{f}' and '{f}' are the same file\n",
|
||||
f = file_a,
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_same_file_not_dot_dir() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let dir = "test_mv_errors_dir";
|
||||
|
||||
at.mkdir(dir);
|
||||
ucmd.arg(dir).arg(dir).fails().stderr_is(format!(
|
||||
"mv: cannot move '{d}' to a subdirectory of itself, '{d}/{d}'",
|
||||
d = dir,
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_same_file_dot_dir() {
|
||||
let (_at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
ucmd.arg(".")
|
||||
.arg(".")
|
||||
.fails()
|
||||
.stderr_is("mv: '.' and '.' are the same file\n".to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_simple_backup() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
|
|
@ -505,3 +505,66 @@ fn test_round() {
|
|||
.stdout_only(exp.join("\n") + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_suffix_is_added_if_not_supplied() {
|
||||
new_ucmd!()
|
||||
.args(&["--suffix=TEST"])
|
||||
.pipe_in("1000")
|
||||
.succeeds()
|
||||
.stdout_only("1000TEST\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_suffix_is_preserved() {
|
||||
new_ucmd!()
|
||||
.args(&["--suffix=TEST"])
|
||||
.pipe_in("1000TEST")
|
||||
.succeeds()
|
||||
.stdout_only("1000TEST\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_suffix_is_only_applied_to_selected_field() {
|
||||
new_ucmd!()
|
||||
.args(&["--suffix=TEST", "--field=2"])
|
||||
.pipe_in("1000 2000 3000")
|
||||
.succeeds()
|
||||
.stdout_only("1000 2000TEST 3000\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_with_suffix_on_input() {
|
||||
new_ucmd!()
|
||||
.args(&["--suffix=b", "--to=si"])
|
||||
.pipe_in("2000b")
|
||||
.succeeds()
|
||||
.stdout_only("2.0Kb\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_without_suffix_on_input() {
|
||||
new_ucmd!()
|
||||
.args(&["--suffix=b", "--to=si"])
|
||||
.pipe_in("2000")
|
||||
.succeeds()
|
||||
.stdout_only("2.0Kb\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_with_suffix_and_delimiter() {
|
||||
new_ucmd!()
|
||||
.args(&["--suffix=b", "--to=si", "-d=|"])
|
||||
.pipe_in("1000b|2000|3000")
|
||||
.succeeds()
|
||||
.stdout_only("1.0Kb|2000|3000\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_suffix_with_padding() {
|
||||
new_ucmd!()
|
||||
.args(&["--suffix=pad", "--padding=12"])
|
||||
.pipe_in("1000 2000 3000")
|
||||
.succeeds()
|
||||
.stdout_only(" 1000pad 2000 3000\n");
|
||||
}
|
||||
|
|
|
@ -24,14 +24,11 @@ fn test_capitalize() {
|
|||
fn test_long_format() {
|
||||
let login = "root";
|
||||
let pw: Passwd = Passwd::locate(login).unwrap();
|
||||
let real_name = pw.user_info().replace("&", &pw.name().capitalize());
|
||||
let real_name = pw.user_info.replace("&", &pw.name.capitalize());
|
||||
let ts = TestScenario::new(util_name!());
|
||||
ts.ucmd().arg("-l").arg(login).succeeds().stdout_is(format!(
|
||||
"Login name: {:<28}In real life: {}\nDirectory: {:<29}Shell: {}\n\n",
|
||||
login,
|
||||
real_name,
|
||||
pw.user_dir(),
|
||||
pw.user_shell()
|
||||
login, real_name, pw.user_dir, pw.user_shell
|
||||
));
|
||||
|
||||
ts.ucmd()
|
||||
|
|
|
@ -280,7 +280,7 @@ fn test_rm_force_no_operand() {
|
|||
fn test_rm_no_operand() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
ts.ucmd().fails().stderr_is(&format!(
|
||||
"{0}: missing an argument\n{0}: for help, try '{1} {0} --help'\n",
|
||||
"{0}: missing operand\nTry '{1} {0} --help' for more information.\n",
|
||||
ts.util_name,
|
||||
ts.bin_path.to_string_lossy()
|
||||
));
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// spell-checker:ignore lmnop xlmnop
|
||||
use crate::common::util::*;
|
||||
use std::io::Read;
|
||||
|
||||
|
@ -473,6 +474,15 @@ fn test_width_decimal_scientific_notation_trailing_zeros_increment() {
|
|||
.no_stderr();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_width_negative_decimal_notation() {
|
||||
new_ucmd!()
|
||||
.args(&["-w", "-.1", ".1", ".11"])
|
||||
.succeeds()
|
||||
.stdout_is("-0.1\n00.0\n00.1\n")
|
||||
.no_stderr();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_width_negative_scientific_notation() {
|
||||
new_ucmd!()
|
||||
|
@ -480,6 +490,54 @@ fn test_width_negative_scientific_notation() {
|
|||
.succeeds()
|
||||
.stdout_is("-0.001\n00.999\n")
|
||||
.no_stderr();
|
||||
new_ucmd!()
|
||||
.args(&["-w", "-1.e-3", "1"])
|
||||
.succeeds()
|
||||
.stdout_is("-0.001\n00.999\n")
|
||||
.no_stderr();
|
||||
new_ucmd!()
|
||||
.args(&["-w", "-1.0e-4", "1"])
|
||||
.succeeds()
|
||||
.stdout_is("-0.00010\n00.99990\n")
|
||||
.no_stderr();
|
||||
new_ucmd!()
|
||||
.args(&["-w", "-.1e2", "10", "100"])
|
||||
.succeeds()
|
||||
.stdout_is(
|
||||
"-010
|
||||
0000
|
||||
0010
|
||||
0020
|
||||
0030
|
||||
0040
|
||||
0050
|
||||
0060
|
||||
0070
|
||||
0080
|
||||
0090
|
||||
0100
|
||||
",
|
||||
)
|
||||
.no_stderr();
|
||||
new_ucmd!()
|
||||
.args(&["-w", "-0.1e2", "10", "100"])
|
||||
.succeeds()
|
||||
.stdout_is(
|
||||
"-010
|
||||
0000
|
||||
0010
|
||||
0020
|
||||
0030
|
||||
0040
|
||||
0050
|
||||
0060
|
||||
0070
|
||||
0080
|
||||
0090
|
||||
0100
|
||||
",
|
||||
)
|
||||
.no_stderr();
|
||||
}
|
||||
|
||||
/// Test that trailing zeros in the end argument do not contribute to width.
|
||||
|
@ -619,3 +677,19 @@ fn test_rounding_end() {
|
|||
.stdout_is("1\n")
|
||||
.no_stderr();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_error_float() {
|
||||
new_ucmd!()
|
||||
.arg("lmnop")
|
||||
.fails()
|
||||
.usage_error("invalid floating point argument: 'lmnop'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_error_hex() {
|
||||
new_ucmd!()
|
||||
.arg("0xlmnop")
|
||||
.fails()
|
||||
.usage_error("invalid hexadecimal argument: '0xlmnop'");
|
||||
}
|
||||
|
|
|
@ -340,10 +340,10 @@ fn test_dictionary_order() {
|
|||
fn test_dictionary_order2() {
|
||||
for non_dictionary_order2_param in &["-d"] {
|
||||
new_ucmd!()
|
||||
.pipe_in("a👦🏻aa b\naaaa b") // spell-checker:disable-line
|
||||
.pipe_in("a👦🏻aa\tb\naaaa\tb") // spell-checker:disable-line
|
||||
.arg(non_dictionary_order2_param) // spell-checker:disable-line
|
||||
.succeeds()
|
||||
.stdout_only("a👦🏻aa b\naaaa b\n"); // spell-checker:disable-line
|
||||
.stdout_only("a👦🏻aa\tb\naaaa\tb\n"); // spell-checker:disable-line
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -918,6 +918,7 @@ fn test_compress_merge() {
|
|||
|
||||
#[test]
|
||||
fn test_compress_fail() {
|
||||
#[cfg(not(windows))]
|
||||
TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.args(&[
|
||||
|
@ -930,6 +931,21 @@ fn test_compress_fail() {
|
|||
])
|
||||
.fails()
|
||||
.stderr_only("sort: couldn't execute compress program: errno 2");
|
||||
// With coverage, it fails with a different error:
|
||||
// "thread 'main' panicked at 'called `Option::unwrap()` on ...
|
||||
// So, don't check the output
|
||||
#[cfg(windows)]
|
||||
TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.args(&[
|
||||
"ext_sort.txt",
|
||||
"-n",
|
||||
"--compress-program",
|
||||
"nonexistent-program",
|
||||
"-S",
|
||||
"10",
|
||||
])
|
||||
.fails();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -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 asciilowercase
|
||||
extern crate rand;
|
||||
extern crate regex;
|
||||
|
||||
|
@ -16,7 +16,7 @@ use std::io::Write;
|
|||
use std::path::Path;
|
||||
use std::{
|
||||
fs::{read_dir, File},
|
||||
io::BufWriter,
|
||||
io::{BufWriter, Read},
|
||||
};
|
||||
|
||||
fn random_chars(n: usize) -> String {
|
||||
|
@ -340,3 +340,87 @@ fn test_split_invalid_bytes_size() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn file_read(at: &AtPath, filename: &str) -> String {
|
||||
let mut s = String::new();
|
||||
at.open(filename).read_to_string(&mut s).unwrap();
|
||||
s
|
||||
}
|
||||
|
||||
// TODO Use char::from_digit() in Rust v1.51.0 or later.
|
||||
fn char_from_digit(n: usize) -> char {
|
||||
(b'a' + n as u8) as char
|
||||
}
|
||||
|
||||
/// Test for the default suffix length behavior: dynamically increasing size.
|
||||
#[test]
|
||||
fn test_alphabetic_dynamic_suffix_length() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
// Split into chunks of one byte each.
|
||||
//
|
||||
// The input file has (26^2) - 26 + 1 = 651 bytes. This is just
|
||||
// enough to force `split` to dynamically increase the length of
|
||||
// the filename for the very last chunk.
|
||||
//
|
||||
// We expect the output files to be named
|
||||
//
|
||||
// xaa, xab, xac, ..., xyx, xyy, xyz, xzaaa
|
||||
//
|
||||
ucmd.args(&["-b", "1", "sixhundredfiftyonebytes.txt"])
|
||||
.succeeds();
|
||||
for i in 0..25 {
|
||||
for j in 0..26 {
|
||||
let filename = format!("x{}{}", char_from_digit(i), char_from_digit(j),);
|
||||
let contents = file_read(&at, &filename);
|
||||
assert_eq!(contents, "a");
|
||||
}
|
||||
}
|
||||
assert_eq!(file_read(&at, "xzaaa"), "a");
|
||||
}
|
||||
|
||||
/// Test for the default suffix length behavior: dynamically increasing size.
|
||||
#[test]
|
||||
fn test_numeric_dynamic_suffix_length() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
// Split into chunks of one byte each, use numbers instead of
|
||||
// letters as file suffixes.
|
||||
//
|
||||
// The input file has (10^2) - 10 + 1 = 91 bytes. This is just
|
||||
// enough to force `split` to dynamically increase the length of
|
||||
// the filename for the very last chunk.
|
||||
//
|
||||
// x00, x01, x02, ..., x87, x88, x89, x9000
|
||||
//
|
||||
ucmd.args(&["-d", "-b", "1", "ninetyonebytes.txt"])
|
||||
.succeeds();
|
||||
for i in 0..90 {
|
||||
let filename = format!("x{:02}", i);
|
||||
let contents = file_read(&at, &filename);
|
||||
assert_eq!(contents, "a");
|
||||
}
|
||||
assert_eq!(file_read(&at, "x9000"), "a");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_suffixes_exhausted() {
|
||||
new_ucmd!()
|
||||
.args(&["-b", "1", "-a", "1", "asciilowercase.txt"])
|
||||
.fails()
|
||||
.stderr_only("split: output file suffixes exhausted");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_verbose() {
|
||||
new_ucmd!()
|
||||
.args(&["-b", "5", "--verbose", "asciilowercase.txt"])
|
||||
.succeeds()
|
||||
.stdout_only(
|
||||
"creating file 'xaa'
|
||||
creating file 'xab'
|
||||
creating file 'xac'
|
||||
creating file 'xad'
|
||||
creating file 'xae'
|
||||
creating file 'xaf'
|
||||
",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -63,9 +63,7 @@ fn test_tee_append() {
|
|||
fn test_tee_no_more_writeable_1() {
|
||||
// equals to 'tee /dev/full out2 <multi_read' call
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let content = (1..=10)
|
||||
.map(|x| format!("{}\n", x.to_string()))
|
||||
.collect::<String>();
|
||||
let content = (1..=10).map(|x| format!("{}\n", x)).collect::<String>();
|
||||
let file_out = "tee_file_out";
|
||||
|
||||
ucmd.arg("/dev/full")
|
||||
|
@ -85,9 +83,7 @@ fn test_tee_no_more_writeable_2() {
|
|||
// but currently there is no way to redirect stdout to /dev/full
|
||||
// so this test is disabled
|
||||
let (_at, mut ucmd) = at_and_ucmd!();
|
||||
let _content = (1..=10)
|
||||
.map(|x| format!("{}\n", x.to_string()))
|
||||
.collect::<String>();
|
||||
let _content = (1..=10).map(|x| format!("{}\n", x)).collect::<String>();
|
||||
let file_out_a = "tee_file_out_a";
|
||||
let file_out_b = "tee_file_out_b";
|
||||
|
||||
|
|
|
@ -1230,14 +1230,7 @@ pub fn check_coreutil_version(
|
|||
.output()
|
||||
{
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
return Err(format!(
|
||||
"{}: '{}' {}",
|
||||
UUTILS_WARNING,
|
||||
util_name,
|
||||
e.to_string()
|
||||
))
|
||||
}
|
||||
Err(e) => return Err(format!("{}: '{}' {}", UUTILS_WARNING, util_name, e)),
|
||||
};
|
||||
std::str::from_utf8(&version_check.stdout).unwrap()
|
||||
.split('\n')
|
||||
|
@ -1247,7 +1240,7 @@ pub fn check_coreutil_version(
|
|||
|| Err(format!("{}: unexpected output format for reference coreutil: '{} --version'", UUTILS_WARNING, util_name)),
|
||||
|s| {
|
||||
if s.contains(&format!("(GNU coreutils) {}", version_expected)) {
|
||||
Ok(format!("{}: {}", UUTILS_INFO, s.to_string()))
|
||||
Ok(format!("{}: {}", UUTILS_INFO, s))
|
||||
} else if s.contains("(GNU coreutils)") {
|
||||
let version_found = parse_coreutil_version(s);
|
||||
let version_expected = version_expected.parse::<f32>().unwrap_or_default();
|
||||
|
|
2
tests/fixtures/join/non-line_feeds.expected
vendored
Normal file
2
tests/fixtures/join/non-line_feeds.expected
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
b
d
|
||||
a c f
|
2
tests/fixtures/join/non-line_feeds_1.txt
vendored
Normal file
2
tests/fixtures/join/non-line_feeds_1.txt
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
b
|
||||
a c
|
2
tests/fixtures/join/non-line_feeds_2.txt
vendored
Normal file
2
tests/fixtures/join/non-line_feeds_2.txt
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
d
|
||||
a f
|
BIN
tests/fixtures/join/non-unicode.expected
vendored
Normal file
BIN
tests/fixtures/join/non-unicode.expected
vendored
Normal file
Binary file not shown.
BIN
tests/fixtures/join/non-unicode_1.bin
vendored
Normal file
BIN
tests/fixtures/join/non-unicode_1.bin
vendored
Normal file
Binary file not shown.
BIN
tests/fixtures/join/non-unicode_2.bin
vendored
Normal file
BIN
tests/fixtures/join/non-unicode_2.bin
vendored
Normal file
Binary file not shown.
BIN
tests/fixtures/join/z.expected
vendored
Normal file
BIN
tests/fixtures/join/z.expected
vendored
Normal file
Binary file not shown.
1
tests/fixtures/split/asciilowercase.txt
vendored
Normal file
1
tests/fixtures/split/asciilowercase.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
abcdefghijklmnopqrstuvwxyz
|
1
tests/fixtures/split/ninetyonebytes.txt
vendored
Normal file
1
tests/fixtures/split/ninetyonebytes.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
1
tests/fixtures/split/sixhundredfiftyonebytes.txt
vendored
Normal file
1
tests/fixtures/split/sixhundredfiftyonebytes.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
Loading…
Add table
Add a link
Reference in a new issue