mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-09-16 19:56:17 +00:00
Merge branch 'master' into chmod/compat
This commit is contained in:
commit
0e49913b84
52 changed files with 1277 additions and 789 deletions
|
@ -139,3 +139,23 @@ fn test_realpath_logical_mode() {
|
|||
.succeeds()
|
||||
.stdout_contains("dir1\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_realpath_dangling() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.symlink_file("nonexistent-file", "link");
|
||||
ucmd.arg("link")
|
||||
.succeeds()
|
||||
.stdout_only(at.plus_as_string("nonexistent-file\n"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_realpath_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")
|
||||
.succeeds()
|
||||
.stdout_only(at.plus_as_string("2\n"));
|
||||
}
|
||||
|
|
|
@ -1,126 +1,238 @@
|
|||
use crate::common::util::*;
|
||||
|
||||
const DIR: &str = "dir";
|
||||
const DIR_FILE: &str = "dir/file";
|
||||
const NESTED_DIR: &str = "dir/ect/ory";
|
||||
const NESTED_DIR_FILE: &str = "dir/ect/ory/file";
|
||||
|
||||
#[cfg(windows)]
|
||||
const NOT_FOUND: &str = "The system cannot find the file specified.";
|
||||
#[cfg(not(windows))]
|
||||
const NOT_FOUND: &str = "No such file or directory";
|
||||
|
||||
#[cfg(windows)]
|
||||
const NOT_EMPTY: &str = "The directory is not empty.";
|
||||
#[cfg(not(windows))]
|
||||
const NOT_EMPTY: &str = "Directory not empty";
|
||||
|
||||
#[cfg(windows)]
|
||||
const NOT_A_DIRECTORY: &str = "The directory name is invalid.";
|
||||
#[cfg(not(windows))]
|
||||
const NOT_A_DIRECTORY: &str = "Not a directory";
|
||||
|
||||
#[test]
|
||||
fn test_rmdir_empty_directory_no_parents() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let dir = "test_rmdir_empty_no_parents";
|
||||
|
||||
at.mkdir(dir);
|
||||
assert!(at.dir_exists(dir));
|
||||
at.mkdir(DIR);
|
||||
|
||||
ucmd.arg(dir).succeeds().no_stderr();
|
||||
ucmd.arg(DIR).succeeds().no_stderr();
|
||||
|
||||
assert!(!at.dir_exists(dir));
|
||||
assert!(!at.dir_exists(DIR));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rmdir_empty_directory_with_parents() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let dir = "test_rmdir_empty/with/parents";
|
||||
|
||||
at.mkdir_all(dir);
|
||||
assert!(at.dir_exists(dir));
|
||||
at.mkdir_all(NESTED_DIR);
|
||||
|
||||
ucmd.arg("-p").arg(dir).succeeds().no_stderr();
|
||||
ucmd.arg("-p").arg(NESTED_DIR).succeeds().no_stderr();
|
||||
|
||||
assert!(!at.dir_exists(dir));
|
||||
assert!(!at.dir_exists(NESTED_DIR));
|
||||
assert!(!at.dir_exists(DIR));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rmdir_nonempty_directory_no_parents() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let dir = "test_rmdir_nonempty_no_parents";
|
||||
let file = "test_rmdir_nonempty_no_parents/foo";
|
||||
|
||||
at.mkdir(dir);
|
||||
assert!(at.dir_exists(dir));
|
||||
at.mkdir(DIR);
|
||||
at.touch(DIR_FILE);
|
||||
|
||||
at.touch(file);
|
||||
assert!(at.file_exists(file));
|
||||
ucmd.arg(DIR)
|
||||
.fails()
|
||||
.stderr_is(format!("rmdir: failed to remove 'dir': {}", NOT_EMPTY));
|
||||
|
||||
ucmd.arg(dir).fails().stderr_is(
|
||||
"rmdir: failed to remove 'test_rmdir_nonempty_no_parents': Directory not \
|
||||
empty\n",
|
||||
);
|
||||
|
||||
assert!(at.dir_exists(dir));
|
||||
assert!(at.dir_exists(DIR));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rmdir_nonempty_directory_with_parents() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let dir = "test_rmdir_nonempty/with/parents";
|
||||
let file = "test_rmdir_nonempty/with/parents/foo";
|
||||
|
||||
at.mkdir_all(dir);
|
||||
assert!(at.dir_exists(dir));
|
||||
at.mkdir_all(NESTED_DIR);
|
||||
at.touch(NESTED_DIR_FILE);
|
||||
|
||||
at.touch(file);
|
||||
assert!(at.file_exists(file));
|
||||
ucmd.arg("-p").arg(NESTED_DIR).fails().stderr_is(format!(
|
||||
"rmdir: failed to remove 'dir/ect/ory': {}",
|
||||
NOT_EMPTY
|
||||
));
|
||||
|
||||
ucmd.arg("-p").arg(dir).fails().stderr_is(
|
||||
"rmdir: failed to remove 'test_rmdir_nonempty/with/parents': Directory not \
|
||||
empty\nrmdir: failed to remove 'test_rmdir_nonempty/with': Directory not \
|
||||
empty\nrmdir: failed to remove 'test_rmdir_nonempty': Directory not \
|
||||
empty\n",
|
||||
);
|
||||
|
||||
assert!(at.dir_exists(dir));
|
||||
assert!(at.dir_exists(NESTED_DIR));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rmdir_ignore_nonempty_directory_no_parents() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let dir = "test_rmdir_ignore_nonempty_no_parents";
|
||||
let file = "test_rmdir_ignore_nonempty_no_parents/foo";
|
||||
|
||||
at.mkdir(dir);
|
||||
assert!(at.dir_exists(dir));
|
||||
|
||||
at.touch(file);
|
||||
assert!(at.file_exists(file));
|
||||
at.mkdir(DIR);
|
||||
at.touch(DIR_FILE);
|
||||
|
||||
ucmd.arg("--ignore-fail-on-non-empty")
|
||||
.arg(dir)
|
||||
.arg(DIR)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.dir_exists(dir));
|
||||
assert!(at.dir_exists(DIR));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rmdir_ignore_nonempty_directory_with_parents() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let dir = "test_rmdir_ignore_nonempty/with/parents";
|
||||
let file = "test_rmdir_ignore_nonempty/with/parents/foo";
|
||||
|
||||
at.mkdir_all(dir);
|
||||
assert!(at.dir_exists(dir));
|
||||
|
||||
at.touch(file);
|
||||
assert!(at.file_exists(file));
|
||||
at.mkdir_all(NESTED_DIR);
|
||||
at.touch(NESTED_DIR_FILE);
|
||||
|
||||
ucmd.arg("--ignore-fail-on-non-empty")
|
||||
.arg("-p")
|
||||
.arg(dir)
|
||||
.arg(NESTED_DIR)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.dir_exists(dir));
|
||||
assert!(at.dir_exists(NESTED_DIR));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rmdir_remove_symlink_match_gnu_error() {
|
||||
fn test_rmdir_not_a_directory() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
let file = "file";
|
||||
let fl = "fl";
|
||||
at.touch(file);
|
||||
assert!(at.file_exists(file));
|
||||
at.symlink_file(file, fl);
|
||||
assert!(at.file_exists(fl));
|
||||
at.touch("file");
|
||||
|
||||
ucmd.arg("fl/")
|
||||
ucmd.arg("--ignore-fail-on-non-empty")
|
||||
.arg("file")
|
||||
.fails()
|
||||
.stderr_is("rmdir: failed to remove 'fl/': Not a directory");
|
||||
.no_stdout()
|
||||
.stderr_is(format!(
|
||||
"rmdir: failed to remove 'file': {}",
|
||||
NOT_A_DIRECTORY
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_verbose_single() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
at.mkdir(DIR);
|
||||
|
||||
ucmd.arg("-v")
|
||||
.arg(DIR)
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_is("rmdir: removing directory, 'dir'\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_verbose_multi() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
at.mkdir(DIR);
|
||||
|
||||
ucmd.arg("-v")
|
||||
.arg("does_not_exist")
|
||||
.arg(DIR)
|
||||
.fails()
|
||||
.stdout_is(
|
||||
"rmdir: removing directory, 'does_not_exist'\n\
|
||||
rmdir: removing directory, 'dir'\n",
|
||||
)
|
||||
.stderr_is(format!(
|
||||
"rmdir: failed to remove 'does_not_exist': {}",
|
||||
NOT_FOUND
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_verbose_nested_failure() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
at.mkdir_all(NESTED_DIR);
|
||||
at.touch("dir/ect/file");
|
||||
|
||||
ucmd.arg("-pv")
|
||||
.arg(NESTED_DIR)
|
||||
.fails()
|
||||
.stdout_is(
|
||||
"rmdir: removing directory, 'dir/ect/ory'\n\
|
||||
rmdir: removing directory, 'dir/ect'\n",
|
||||
)
|
||||
.stderr_is(format!("rmdir: failed to remove 'dir/ect': {}", NOT_EMPTY));
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn test_rmdir_ignore_nonempty_no_permissions() {
|
||||
use std::fs;
|
||||
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
// We make the *parent* dir read-only to prevent deleting the dir in it.
|
||||
at.mkdir_all("dir/ect/ory");
|
||||
at.touch("dir/ect/ory/file");
|
||||
let dir_ect = at.plus("dir/ect");
|
||||
let mut perms = fs::metadata(&dir_ect).unwrap().permissions();
|
||||
perms.set_readonly(true);
|
||||
fs::set_permissions(&dir_ect, perms.clone()).unwrap();
|
||||
|
||||
// rmdir should now get a permissions error that it interprets as
|
||||
// a non-empty error.
|
||||
ucmd.arg("--ignore-fail-on-non-empty")
|
||||
.arg("dir/ect/ory")
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.dir_exists("dir/ect/ory"));
|
||||
|
||||
// Politely restore permissions for cleanup
|
||||
perms.set_readonly(false);
|
||||
fs::set_permissions(&dir_ect, perms).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rmdir_remove_symlink_file() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
at.touch("file");
|
||||
at.symlink_file("file", "fl");
|
||||
|
||||
ucmd.arg("fl/").fails().stderr_is(format!(
|
||||
"rmdir: failed to remove 'fl/': {}",
|
||||
NOT_A_DIRECTORY
|
||||
));
|
||||
}
|
||||
|
||||
// This behavior is known to happen on Linux but not all Unixes
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[test]
|
||||
fn test_rmdir_remove_symlink_dir() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
at.mkdir("dir");
|
||||
at.symlink_dir("dir", "dl");
|
||||
|
||||
ucmd.arg("dl/")
|
||||
.fails()
|
||||
.stderr_is("rmdir: failed to remove 'dl/': Symbolic link not followed");
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[test]
|
||||
fn test_rmdir_remove_symlink_dangling() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
at.symlink_dir("dir", "dl");
|
||||
|
||||
ucmd.arg("dl/")
|
||||
.fails()
|
||||
.stderr_is("rmdir: failed to remove 'dl/': Symbolic link not followed");
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::common::util::*;
|
||||
|
||||
// spell-checker:ignore (flags) lwmcL clmwL ; (path) bogusfile emptyfile manyemptylines moby notrailingnewline onelongemptyline onelongword
|
||||
// spell-checker:ignore (flags) lwmcL clmwL ; (path) bogusfile emptyfile manyemptylines moby notrailingnewline onelongemptyline onelongword weirdchars
|
||||
|
||||
#[test]
|
||||
fn test_count_bytes_large_stdin() {
|
||||
|
@ -53,11 +53,16 @@ fn test_utf8() {
|
|||
.args(&["-lwmcL"])
|
||||
.pipe_in_fixture("UTF_8_test.txt")
|
||||
.run()
|
||||
.stdout_is(" 300 4969 22781 22213 79\n");
|
||||
// GNU returns " 300 2086 22219 22781 79"
|
||||
//
|
||||
// TODO: we should fix the word, character, and byte count to
|
||||
// match the behavior of GNU wc
|
||||
.stdout_is(" 303 2119 22457 23025 79\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_utf8_extra() {
|
||||
new_ucmd!()
|
||||
.arg("-lwmcL")
|
||||
.pipe_in_fixture("UTF_8_weirdchars.txt")
|
||||
.run()
|
||||
.stdout_is(" 25 87 442 513 48\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -200,22 +205,33 @@ fn test_file_bytes_dictate_width() {
|
|||
/// Test that getting counts from a directory is an error.
|
||||
#[test]
|
||||
fn test_read_from_directory_error() {
|
||||
// TODO To match GNU `wc`, the `stdout` should be:
|
||||
//
|
||||
// " 0 0 0 .\n"
|
||||
//
|
||||
#[cfg(not(windows))]
|
||||
const STDERR: &str = ".: Is a directory";
|
||||
#[cfg(windows)]
|
||||
const STDERR: &str = ".: Access is denied";
|
||||
|
||||
#[cfg(not(windows))]
|
||||
const STDOUT: &str = " 0 0 0 .\n";
|
||||
#[cfg(windows)]
|
||||
const STDOUT: &str = "";
|
||||
|
||||
new_ucmd!()
|
||||
.args(&["."])
|
||||
.fails()
|
||||
.stderr_contains(".: Is a directory\n")
|
||||
.stdout_is("0 0 0 .\n");
|
||||
.stderr_contains(STDERR)
|
||||
.stdout_is(STDOUT);
|
||||
}
|
||||
|
||||
/// Test that getting counts from nonexistent file is an error.
|
||||
#[test]
|
||||
fn test_read_from_nonexistent_file() {
|
||||
#[cfg(not(windows))]
|
||||
const MSG: &str = "bogusfile: No such file or directory";
|
||||
#[cfg(windows)]
|
||||
const MSG: &str = "bogusfile: The system cannot find the file specified";
|
||||
new_ucmd!()
|
||||
.args(&["bogusfile"])
|
||||
.fails()
|
||||
.stderr_contains("bogusfile: No such file or directory\n");
|
||||
.stderr_contains(MSG)
|
||||
.stdout_is("");
|
||||
}
|
||||
|
|
BIN
tests/fixtures/wc/UTF_8_test.txt
vendored
BIN
tests/fixtures/wc/UTF_8_test.txt
vendored
Binary file not shown.
25
tests/fixtures/wc/UTF_8_weirdchars.txt
vendored
Normal file
25
tests/fixtures/wc/UTF_8_weirdchars.txt
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
zero-width space inbetween these: xx
|
||||
and inbetween two spaces: [ ]
|
||||
and at the end of the line:
|
||||
|
||||
non-breaking space: x x [ ]
|
||||
|
||||
simple unicode: xµx [ µ ] µ
|
||||
|
||||
wide: xwx [ w ] w
|
||||
|
||||
simple emoji: x👩x [ 👩 ] 👩
|
||||
|
||||
complex emoji: x👩🔬x [ 👩🔬 ] 👩🔬
|
||||
|
||||
Hello, world!
|
||||
|
||||
line feed: xx [ ]
|
||||
|
||||
vertical tab: xx [ ]
|
||||
|
||||
horizontal tab: x x [ ]
|
||||
this should be the longest line:
|
||||
1234567 12345678 123456781234567812345678
|
||||
|
||||
Control character: xx [ ]
|
Loading…
Add table
Add a link
Reference in a new issue