mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-08-01 21:47:46 +00:00
Merge branch 'master' into master
This commit is contained in:
commit
ae1935c3cb
313 changed files with 11869 additions and 7613 deletions
|
@ -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]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -438,7 +438,7 @@ fn test_domain_socket() {
|
|||
let child = new_ucmd!().args(&[socket_path]).run_no_wait();
|
||||
barrier.wait();
|
||||
let stdout = &child.wait_with_output().unwrap().stdout;
|
||||
let output = String::from_utf8_lossy(&stdout);
|
||||
let output = String::from_utf8_lossy(stdout);
|
||||
assert_eq!("a\tb", output);
|
||||
|
||||
thread.join().unwrap();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// spell-checker:ignore (words) nosuchgroup
|
||||
// spell-checker:ignore (words) nosuchgroup groupname
|
||||
|
||||
use crate::common::util::*;
|
||||
use rust_users::*;
|
||||
|
@ -10,6 +10,33 @@ fn test_invalid_option() {
|
|||
|
||||
static DIR: &str = "/tmp";
|
||||
|
||||
// we should always get both arguments, regardless of whether --reference was used
|
||||
#[test]
|
||||
fn test_help() {
|
||||
new_ucmd!()
|
||||
.arg("--help")
|
||||
.succeeds()
|
||||
.stdout_contains("ARGS:\n <GROUP> \n <FILE>... ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_help_ref() {
|
||||
new_ucmd!()
|
||||
.arg("--help")
|
||||
.arg("--reference=ref_file")
|
||||
.succeeds()
|
||||
.stdout_contains("ARGS:\n <GROUP> \n <FILE>... ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ref_help() {
|
||||
new_ucmd!()
|
||||
.arg("--reference=ref_file")
|
||||
.arg("--help")
|
||||
.succeeds()
|
||||
.stdout_contains("ARGS:\n <GROUP> \n <FILE>... ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_group() {
|
||||
new_ucmd!()
|
||||
|
@ -121,9 +148,52 @@ fn test_reference() {
|
|||
fn test_reference() {
|
||||
new_ucmd!()
|
||||
.arg("-v")
|
||||
.arg("--reference=/etc/passwd")
|
||||
.arg("--reference=ref_file")
|
||||
.arg("/etc")
|
||||
.succeeds();
|
||||
.fails()
|
||||
// group name can differ, so just check the first part of the message
|
||||
.stderr_contains("chgrp: changing group of '/etc': Operation not permitted (os error 1)\nfailed to change group of '/etc' from ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
fn test_reference_multi_no_equal() {
|
||||
new_ucmd!()
|
||||
.arg("-v")
|
||||
.arg("--reference")
|
||||
.arg("ref_file")
|
||||
.arg("file1")
|
||||
.arg("file2")
|
||||
.succeeds()
|
||||
.stderr_contains("chgrp: group of 'file1' retained as ")
|
||||
.stderr_contains("\nchgrp: group of 'file2' retained as ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
fn test_reference_last() {
|
||||
new_ucmd!()
|
||||
.arg("-v")
|
||||
.arg("file1")
|
||||
.arg("file2")
|
||||
.arg("file3")
|
||||
.arg("--reference")
|
||||
.arg("ref_file")
|
||||
.succeeds()
|
||||
.stderr_contains("chgrp: group of 'file1' retained as ")
|
||||
.stderr_contains("\nchgrp: group of 'file2' retained as ")
|
||||
.stderr_contains("\nchgrp: group of 'file3' retained as ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_files() {
|
||||
new_ucmd!()
|
||||
.arg("-v")
|
||||
.arg("groupname")
|
||||
.fails()
|
||||
.stderr_contains(
|
||||
"error: The following required arguments were not provided:\n <FILE>...\n",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -135,7 +205,7 @@ fn test_big_p() {
|
|||
.arg("bin")
|
||||
.arg("/proc/self/cwd")
|
||||
.fails()
|
||||
.stderr_is(
|
||||
.stderr_contains(
|
||||
"chgrp: changing group of '/proc/self/cwd': Operation not permitted (os error 1)\n",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -618,7 +618,7 @@ fn test_cp_deref() {
|
|||
// Check the content of the destination file that was copied.
|
||||
assert_eq!(at.read(TEST_COPY_TO_FOLDER_FILE), "Hello, World!\n");
|
||||
let path_to_check = path_to_new_symlink.to_str().unwrap();
|
||||
assert_eq!(at.read(&path_to_check), "Hello, World!\n");
|
||||
assert_eq!(at.read(path_to_check), "Hello, World!\n");
|
||||
}
|
||||
#[test]
|
||||
fn test_cp_no_deref() {
|
||||
|
@ -655,7 +655,7 @@ fn test_cp_no_deref() {
|
|||
// Check the content of the destination file that was copied.
|
||||
assert_eq!(at.read(TEST_COPY_TO_FOLDER_FILE), "Hello, World!\n");
|
||||
let path_to_check = path_to_new_symlink.to_str().unwrap();
|
||||
assert_eq!(at.read(&path_to_check), "Hello, World!\n");
|
||||
assert_eq!(at.read(path_to_check), "Hello, World!\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -726,6 +726,15 @@ fn test_cp_parents_dest_not_directory() {
|
|||
.stderr_contains("with --parents, the destination must be a directory");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_preserve_no_args() {
|
||||
new_ucmd!()
|
||||
.arg(TEST_COPY_FROM_FOLDER_FILE)
|
||||
.arg(TEST_HELLO_WORLD_DEST)
|
||||
.arg("--preserve")
|
||||
.succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
// For now, disable the test on Windows. Symlinks aren't well support on Windows.
|
||||
// It works on Unix for now and it works locally when run from a powershell
|
||||
|
@ -823,7 +832,7 @@ fn test_cp_deref_folder_to_folder() {
|
|||
|
||||
// Check the content of the symlink
|
||||
let path_to_check = path_to_new_symlink.to_str().unwrap();
|
||||
assert_eq!(at.read(&path_to_check), "Hello, World!\n");
|
||||
assert_eq!(at.read(path_to_check), "Hello, World!\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -923,7 +932,7 @@ fn test_cp_no_deref_folder_to_folder() {
|
|||
|
||||
// Check the content of the symlink
|
||||
let path_to_check = path_to_new_symlink.to_str().unwrap();
|
||||
assert_eq!(at.read(&path_to_check), "Hello, World!\n");
|
||||
assert_eq!(at.read(path_to_check), "Hello, World!\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1290,3 +1299,42 @@ fn test_closes_file_descriptors() {
|
|||
.with_limit(Resource::NOFILE, 9, 9)
|
||||
.succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_copy_dir_symlink() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.mkdir("dir");
|
||||
at.symlink_dir("dir", "dir-link");
|
||||
ucmd.args(&["-r", "dir-link", "copy"]).succeeds();
|
||||
assert_eq!(at.resolve_link("copy"), "dir");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_copy_dir_with_symlinks() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.mkdir("dir");
|
||||
at.make_file("dir/file");
|
||||
|
||||
TestScenario::new("ln")
|
||||
.ucmd()
|
||||
.arg("-sr")
|
||||
.arg(at.subdir.join("dir/file"))
|
||||
.arg(at.subdir.join("dir/file-link"))
|
||||
.succeeds();
|
||||
|
||||
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");
|
||||
}
|
||||
|
|
|
@ -157,3 +157,12 @@ fn test_directory_and_no_such_file() {
|
|||
.run()
|
||||
.stderr_is("cut: some: No such file or directory\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_equal_as_delimiter() {
|
||||
new_ucmd!()
|
||||
.args(&["-f", "2", "-d="])
|
||||
.pipe_in("--dir=./out/lib")
|
||||
.succeeds()
|
||||
.stdout_only("./out/lib\n");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
// * This file is part of the uutils coreutils package.
|
||||
// *
|
||||
// * For the full copyright and license information, please view the LICENSE
|
||||
// * file that was distributed with this source code.
|
||||
|
||||
// spell-checker:ignore (paths) sublink subwords
|
||||
|
||||
use crate::common::util::*;
|
||||
|
||||
const SUB_DIR: &str = "subdir/deeper";
|
||||
const SUB_DEEPER_DIR: &str = "subdir/deeper/deeper_dir";
|
||||
const SUB_DIR_LINKS: &str = "subdir/links";
|
||||
const SUB_DIR_LINKS_DEEPER_SYM_DIR: &str = "subdir/links/deeper_dir";
|
||||
const SUB_FILE: &str = "subdir/links/subwords.txt";
|
||||
const SUB_LINK: &str = "subdir/links/sublink.txt";
|
||||
|
||||
|
@ -16,7 +23,7 @@ fn _du_basics(s: &str) {
|
|||
let answer = "32\t./subdir
|
||||
8\t./subdir/deeper
|
||||
24\t./subdir/links
|
||||
40\t./
|
||||
40\t.
|
||||
";
|
||||
assert_eq!(s, answer);
|
||||
}
|
||||
|
@ -25,7 +32,7 @@ fn _du_basics(s: &str) {
|
|||
let answer = "28\t./subdir
|
||||
8\t./subdir/deeper
|
||||
16\t./subdir/links
|
||||
36\t./
|
||||
36\t.
|
||||
";
|
||||
assert_eq!(s, answer);
|
||||
}
|
||||
|
@ -49,15 +56,15 @@ fn test_du_basics_subdir() {
|
|||
|
||||
#[cfg(target_vendor = "apple")]
|
||||
fn _du_basics_subdir(s: &str) {
|
||||
assert_eq!(s, "4\tsubdir/deeper\n");
|
||||
assert_eq!(s, "4\tsubdir/deeper/deeper_dir\n8\tsubdir/deeper\n");
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
fn _du_basics_subdir(s: &str) {
|
||||
assert_eq!(s, "0\tsubdir/deeper\n");
|
||||
assert_eq!(s, "0\tsubdir/deeper\\deeper_dir\n0\tsubdir/deeper\n");
|
||||
}
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn _du_basics_subdir(s: &str) {
|
||||
assert_eq!(s, "8\tsubdir/deeper\n");
|
||||
assert_eq!(s, "8\tsubdir/deeper/deeper_dir\n16\tsubdir/deeper\n");
|
||||
}
|
||||
#[cfg(all(
|
||||
not(target_vendor = "apple"),
|
||||
|
@ -73,6 +80,26 @@ fn _du_basics_subdir(s: &str) {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_du_invalid_size() {
|
||||
let args = &["block-size", "threshold"];
|
||||
for s in args {
|
||||
new_ucmd!()
|
||||
.arg(format!("--{}=1fb4t", s))
|
||||
.arg("/tmp")
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stderr_only(format!("du: invalid --{} argument '1fb4t'", s));
|
||||
#[cfg(not(target_pointer_width = "128"))]
|
||||
new_ucmd!()
|
||||
.arg(format!("--{}=1Y", s))
|
||||
.arg("/tmp")
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stderr_only(format!("du: --{} argument '1Y' too large", s));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_du_basics_bad_name() {
|
||||
new_ucmd!()
|
||||
|
@ -185,12 +212,7 @@ fn test_du_d_flag() {
|
|||
{
|
||||
let result_reference = scene.cmd("du").arg("-d1").run();
|
||||
if result_reference.succeeded() {
|
||||
assert_eq!(
|
||||
// TODO: gnu `du` doesn't use trailing "/" here
|
||||
// result.stdout_str(), result_reference.stdout_str()
|
||||
result.stdout_str().trim_end_matches("/\n"),
|
||||
result_reference.stdout_str().trim_end_matches('\n')
|
||||
);
|
||||
assert_eq!(result.stdout_str(), result_reference.stdout_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -199,15 +221,15 @@ fn test_du_d_flag() {
|
|||
|
||||
#[cfg(target_vendor = "apple")]
|
||||
fn _du_d_flag(s: &str) {
|
||||
assert_eq!(s, "16\t./subdir\n20\t./\n");
|
||||
assert_eq!(s, "20\t./subdir\n24\t.\n");
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
fn _du_d_flag(s: &str) {
|
||||
assert_eq!(s, "8\t./subdir\n8\t./\n");
|
||||
assert_eq!(s, "8\t.\\subdir\n8\t.\n");
|
||||
}
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn _du_d_flag(s: &str) {
|
||||
assert_eq!(s, "28\t./subdir\n36\t./\n");
|
||||
assert_eq!(s, "36\t./subdir\n44\t.\n");
|
||||
}
|
||||
#[cfg(all(
|
||||
not(target_vendor = "apple"),
|
||||
|
@ -217,9 +239,127 @@ 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");
|
||||
assert_eq!(s, "28\t./subdir\n36\t.\n");
|
||||
} else {
|
||||
assert_eq!(s, "8\t./subdir\n8\t./\n");
|
||||
assert_eq!(s, "8\t./subdir\n8\t.\n");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_du_dereference() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
at.symlink_dir(SUB_DEEPER_DIR, SUB_DIR_LINKS_DEEPER_SYM_DIR);
|
||||
|
||||
let result = scene.ucmd().arg("-L").arg(SUB_DIR_LINKS).succeeds();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let result_reference = scene.cmd("du").arg("-L").arg(SUB_DIR_LINKS).run();
|
||||
if result_reference.succeeded() {
|
||||
assert_eq!(result.stdout_str(), result_reference.stdout_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_du_dereference(result.stdout_str());
|
||||
}
|
||||
|
||||
#[cfg(target_vendor = "apple")]
|
||||
fn _du_dereference(s: &str) {
|
||||
assert_eq!(s, "4\tsubdir/links/deeper_dir\n16\tsubdir/links\n");
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
fn _du_dereference(s: &str) {
|
||||
assert_eq!(s, "0\tsubdir/links\\deeper_dir\n8\tsubdir/links\n");
|
||||
}
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn _du_dereference(s: &str) {
|
||||
assert_eq!(s, "8\tsubdir/links/deeper_dir\n24\tsubdir/links\n");
|
||||
}
|
||||
#[cfg(all(
|
||||
not(target_vendor = "apple"),
|
||||
not(target_os = "windows"),
|
||||
not(target_os = "freebsd")
|
||||
))]
|
||||
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 {
|
||||
assert_eq!(s, "0\tsubdir/links/deeper_dir\n8\tsubdir/links\n");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_du_inodes_basic() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let result = scene.ucmd().arg("--inodes").succeeds();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let result_reference = scene.cmd("du").arg("--inodes").run();
|
||||
assert_eq!(result.stdout_str(), result_reference.stdout_str());
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
_du_inodes_basic(result.stdout_str());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn _du_inodes_basic(s: &str) {
|
||||
assert_eq!(
|
||||
s,
|
||||
"2\t.\\subdir\\deeper\\deeper_dir
|
||||
4\t.\\subdir\\deeper
|
||||
3\t.\\subdir\\links
|
||||
8\t.\\subdir
|
||||
11\t.
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
fn _du_inodes_basic(s: &str) {
|
||||
assert_eq!(
|
||||
s,
|
||||
"2\t./subdir/deeper/deeper_dir
|
||||
4\t./subdir/deeper
|
||||
3\t./subdir/links
|
||||
8\t./subdir
|
||||
11\t.
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_du_inodes() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--summarize")
|
||||
.arg("--inodes")
|
||||
.succeeds()
|
||||
.stdout_only("11\t.\n");
|
||||
|
||||
let result = scene
|
||||
.ucmd()
|
||||
.arg("--separate-dirs")
|
||||
.arg("--inodes")
|
||||
.succeeds();
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
result.stdout_contains("3\t.\\subdir\\links\n");
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
result.stdout_contains("3\t./subdir/links\n");
|
||||
result.stdout_contains("3\t.\n");
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let result_reference = scene.cmd("du").arg("--separate-dirs").arg("--inodes").run();
|
||||
assert_eq!(result.stdout_str(), result_reference.stdout_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -286,7 +426,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")]
|
||||
|
@ -312,3 +452,134 @@ fn _du_no_permission(s: &str) {
|
|||
fn _du_no_permission(s: &str) {
|
||||
assert_eq!(s, "4\tsubdir/links\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_du_one_file_system() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
|
||||
let result = scene.ucmd().arg("-x").arg(SUB_DIR).succeeds();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let result_reference = scene.cmd("du").arg("-x").arg(SUB_DIR).run();
|
||||
if result_reference.succeeded() {
|
||||
assert_eq!(result.stdout_str(), result_reference.stdout_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
_du_basics_subdir(result.stdout_str());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_du_threshold() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
|
||||
let threshold = if cfg!(windows) { "7K" } else { "10K" };
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg(format!("--threshold={}", threshold))
|
||||
.succeeds()
|
||||
.stdout_contains("links")
|
||||
.stdout_does_not_contain("deeper_dir");
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg(format!("--threshold=-{}", threshold))
|
||||
.succeeds()
|
||||
.stdout_does_not_contain("links")
|
||||
.stdout_contains("deeper_dir");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_du_apparent_size() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let result = scene.ucmd().arg("--apparent-size").succeeds();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let result_reference = scene.cmd("du").arg("--apparent-size").run();
|
||||
assert_eq!(result.stdout_str(), result_reference.stdout_str());
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
_du_apparent_size(result.stdout_str());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn _du_apparent_size(s: &str) {
|
||||
assert_eq!(
|
||||
s,
|
||||
"1\t.\\subdir\\deeper\\deeper_dir
|
||||
1\t.\\subdir\\deeper
|
||||
6\t.\\subdir\\links
|
||||
6\t.\\subdir
|
||||
6\t.
|
||||
"
|
||||
);
|
||||
}
|
||||
#[cfg(target_vendor = "apple")]
|
||||
fn _du_apparent_size(s: &str) {
|
||||
assert_eq!(
|
||||
s,
|
||||
"1\t./subdir/deeper/deeper_dir
|
||||
1\t./subdir/deeper
|
||||
6\t./subdir/links
|
||||
6\t./subdir
|
||||
6\t.
|
||||
"
|
||||
);
|
||||
}
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn _du_apparent_size(s: &str) {
|
||||
assert_eq!(
|
||||
s,
|
||||
"1\t./subdir/deeper/deeper_dir
|
||||
2\t./subdir/deeper
|
||||
6\t./subdir/links
|
||||
8\t./subdir
|
||||
8\t.
|
||||
"
|
||||
);
|
||||
}
|
||||
#[cfg(all(
|
||||
not(target_vendor = "apple"),
|
||||
not(target_os = "windows"),
|
||||
not(target_os = "freebsd")
|
||||
))]
|
||||
fn _du_apparent_size(s: &str) {
|
||||
assert_eq!(
|
||||
s,
|
||||
"5\t./subdir/deeper/deeper_dir
|
||||
9\t./subdir/deeper
|
||||
10\t./subdir/links
|
||||
22\t./subdir
|
||||
26\t.
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_du_bytes() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let result = scene.ucmd().arg("--bytes").succeeds();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let result_reference = scene.cmd("du").arg("--bytes").run();
|
||||
assert_eq!(result.stdout_str(), result_reference.stdout_str());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
result.stdout_contains("5145\t.\\subdir\n");
|
||||
#[cfg(target_vendor = "apple")]
|
||||
result.stdout_contains("5625\t./subdir\n");
|
||||
#[cfg(target_os = "freebsd")]
|
||||
result.stdout_contains("7193\t./subdir\n");
|
||||
#[cfg(all(
|
||||
not(target_vendor = "apple"),
|
||||
not(target_os = "windows"),
|
||||
not(target_os = "freebsd")
|
||||
))]
|
||||
result.stdout_contains("21529\t./subdir\n");
|
||||
}
|
||||
|
|
|
@ -187,11 +187,10 @@ fn test_change_directory() {
|
|||
.arg(&temporary_path)
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
assert_eq!(
|
||||
out.lines()
|
||||
.any(|line| line.ends_with(temporary_path.file_name().unwrap().to_str().unwrap())),
|
||||
false
|
||||
);
|
||||
|
||||
assert!(!out
|
||||
.lines()
|
||||
.any(|line| line.ends_with(temporary_path.file_name().unwrap().to_str().unwrap())));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1,41 +1,176 @@
|
|||
use crate::common::util::*;
|
||||
|
||||
// spell-checker:ignore (ToDO) coreutil
|
||||
|
||||
// These tests run the GNU coreutils `(g)groups` binary in `$PATH` in order to gather reference values.
|
||||
// If the `(g)groups` in `$PATH` doesn't include a coreutils version string,
|
||||
// or the version is too low, the test is skipped.
|
||||
|
||||
// The reference version is 8.32. Here 8.30 was chosen because right now there's no
|
||||
// ubuntu image for github action available with a higher version than 8.30.
|
||||
const VERSION_MIN: &str = "8.30"; // minimum Version for the reference `groups` in $PATH
|
||||
const VERSION_MIN_MULTIPLE_USERS: &str = "8.31"; // this feature was introduced in GNU's coreutils 8.31
|
||||
const UUTILS_WARNING: &str = "uutils-tests-warning";
|
||||
const UUTILS_INFO: &str = "uutils-tests-info";
|
||||
|
||||
macro_rules! unwrap_or_return {
|
||||
( $e:expr ) => {
|
||||
match $e {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
println!("{}: test skipped: {}", UUTILS_INFO, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn whoami() -> String {
|
||||
// Apparently some CI environments have configuration issues, e.g. with 'whoami' and 'id'.
|
||||
//
|
||||
// From the Logs: "Build (ubuntu-18.04, x86_64-unknown-linux-gnu, feat_os_unix, use-cross)"
|
||||
// whoami: cannot find name for user ID 1001
|
||||
// id --name: cannot find name for user ID 1001
|
||||
// id --name: cannot find name for group ID 116
|
||||
//
|
||||
// However, when running "id" from within "/bin/bash" it looks fine:
|
||||
// id: "uid=1001(runner) gid=118(docker) groups=118(docker),4(adm),101(systemd-journal)"
|
||||
// whoami: "runner"
|
||||
|
||||
// Use environment variable to get current user instead of
|
||||
// invoking `whoami` and fall back to user "nobody" on error.
|
||||
std::env::var("USER").unwrap_or_else(|e| {
|
||||
println!("{}: {}, using \"nobody\" instead", UUTILS_WARNING, e);
|
||||
"nobody".to_string()
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_groups() {
|
||||
let result = new_ucmd!().run();
|
||||
println!("result.stdout = {}", result.stdout_str());
|
||||
println!("result.stderr = {}", result.stderr_str());
|
||||
if is_ci() && result.stdout_str().trim().is_empty() {
|
||||
// In the CI, some server are failing to return the group.
|
||||
// As seems to be a configuration issue, ignoring it
|
||||
return;
|
||||
}
|
||||
result.success();
|
||||
assert!(!result.stdout_str().trim().is_empty());
|
||||
let exp_result = unwrap_or_return!(expected_result(&[]));
|
||||
|
||||
result
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str())
|
||||
.code_is(exp_result.code());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_groups_arg() {
|
||||
// get the username with the "id -un" command
|
||||
let result = TestScenario::new("id").ucmd_keepenv().arg("-un").run();
|
||||
println!("result.stdout = {}", result.stdout_str());
|
||||
println!("result.stderr = {}", result.stderr_str());
|
||||
let s1 = String::from(result.stdout_str().trim());
|
||||
if is_ci() && s1.parse::<f64>().is_ok() {
|
||||
// In the CI, some server are failing to return id -un.
|
||||
// So, if we are getting a uid, just skip this test
|
||||
// As seems to be a configuration issue, ignoring it
|
||||
#[cfg(unix)]
|
||||
fn test_groups_username() {
|
||||
let test_users = [&whoami()[..]];
|
||||
|
||||
let result = new_ucmd!().args(&test_users).run();
|
||||
let exp_result = unwrap_or_return!(expected_result(&test_users));
|
||||
|
||||
result
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str())
|
||||
.code_is(exp_result.code());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_groups_username_multiple() {
|
||||
// TODO: [2021-06; jhscheer] refactor this as `let util_name = host_name_for(util_name!())` when that function is added to 'tests/common'
|
||||
#[cfg(target_os = "linux")]
|
||||
let util_name = util_name!();
|
||||
#[cfg(all(unix, not(target_os = "linux")))]
|
||||
let util_name = &format!("g{}", util_name!());
|
||||
let version_check_string = check_coreutil_version(util_name, VERSION_MIN_MULTIPLE_USERS);
|
||||
if version_check_string.starts_with(UUTILS_WARNING) {
|
||||
println!("{}\ntest skipped", version_check_string);
|
||||
return;
|
||||
}
|
||||
let test_users = ["root", "man", "postfix", "sshd", &whoami()];
|
||||
|
||||
println!("result.stdout = {}", result.stdout_str());
|
||||
println!("result.stderr = {}", result.stderr_str());
|
||||
result.success();
|
||||
assert!(!result.stdout_str().is_empty());
|
||||
let username = result.stdout_str().trim();
|
||||
let result = new_ucmd!().args(&test_users).run();
|
||||
let exp_result = unwrap_or_return!(expected_result(&test_users));
|
||||
|
||||
// call groups with the user name to check that we
|
||||
// are getting something
|
||||
new_ucmd!().arg(username).succeeds();
|
||||
assert!(!result.stdout_str().is_empty());
|
||||
result
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str())
|
||||
.code_is(exp_result.code());
|
||||
}
|
||||
|
||||
fn check_coreutil_version(util_name: &str, version_expected: &str) -> String {
|
||||
// example:
|
||||
// $ id --version | head -n 1
|
||||
// id (GNU coreutils) 8.32.162-4eda
|
||||
let scene = TestScenario::new(util_name);
|
||||
let version_check = scene
|
||||
.cmd_keepenv(&util_name)
|
||||
.env("LC_ALL", "C")
|
||||
.arg("--version")
|
||||
.run();
|
||||
version_check
|
||||
.stdout_str()
|
||||
.split('\n')
|
||||
.collect::<Vec<_>>()
|
||||
.get(0)
|
||||
.map_or_else(
|
||||
|| format!("{}: unexpected output format for reference coreutil: '{} --version'", UUTILS_WARNING, util_name),
|
||||
|s| {
|
||||
if s.contains(&format!("(GNU coreutils) {}", version_expected)) {
|
||||
s.to_string()
|
||||
} else if s.contains("(GNU coreutils)") {
|
||||
let version_found = s.split_whitespace().last().unwrap()[..4].parse::<f32>().unwrap_or_default();
|
||||
let version_expected = version_expected.parse::<f32>().unwrap_or_default();
|
||||
if version_found > version_expected {
|
||||
format!("{}: version for the reference coreutil '{}' is higher than expected; expected: {}, found: {}", UUTILS_INFO, util_name, version_expected, version_found)
|
||||
} else {
|
||||
format!("{}: version for the reference coreutil '{}' does not match; expected: {}, found: {}", UUTILS_WARNING, util_name, version_expected, version_found) }
|
||||
} else {
|
||||
format!("{}: no coreutils version string found for reference coreutils '{} --version'", UUTILS_WARNING, util_name)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_borrow)]
|
||||
#[cfg(unix)]
|
||||
fn expected_result(args: &[&str]) -> Result<CmdResult, String> {
|
||||
// TODO: [2021-06; jhscheer] refactor this as `let util_name = host_name_for(util_name!())` when that function is added to 'tests/common'
|
||||
#[cfg(target_os = "linux")]
|
||||
let util_name = util_name!();
|
||||
#[cfg(all(unix, not(target_os = "linux")))]
|
||||
let util_name = &format!("g{}", util_name!());
|
||||
|
||||
let version_check_string = check_coreutil_version(util_name, VERSION_MIN);
|
||||
if version_check_string.starts_with(UUTILS_WARNING) {
|
||||
return Err(version_check_string);
|
||||
}
|
||||
println!("{}", version_check_string);
|
||||
|
||||
let scene = TestScenario::new(util_name);
|
||||
let result = scene
|
||||
.cmd_keepenv(util_name)
|
||||
.env("LC_ALL", "C")
|
||||
.args(args)
|
||||
.run();
|
||||
|
||||
let (stdout, stderr): (String, String) = if cfg!(target_os = "linux") {
|
||||
(
|
||||
result.stdout_str().to_string(),
|
||||
result.stderr_str().to_string(),
|
||||
)
|
||||
} else {
|
||||
// strip 'g' prefix from results:
|
||||
let from = util_name.to_string() + ":";
|
||||
let to = &from[1..];
|
||||
(
|
||||
result.stdout_str().replace(&from, to),
|
||||
result.stderr_str().replace(&from, to),
|
||||
)
|
||||
};
|
||||
|
||||
Ok(CmdResult::new(
|
||||
Some(result.tmpd()),
|
||||
Some(result.code()),
|
||||
result.succeeded(),
|
||||
stdout.as_bytes(),
|
||||
stderr.as_bytes(),
|
||||
))
|
||||
}
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
// spell-checker:ignore (words) bogusfile emptyfile
|
||||
// * This file is part of the uutils coreutils package.
|
||||
// *
|
||||
// * For the full copyright and license information, please view the LICENSE
|
||||
// * file that was distributed with this source code.
|
||||
|
||||
// spell-checker:ignore (words) bogusfile emptyfile abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstu
|
||||
|
||||
use crate::common::util::*;
|
||||
|
||||
|
@ -265,3 +270,61 @@ fn test_bad_utf8_lines() {
|
|||
.succeeds()
|
||||
.stdout_is_bytes(output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_head_invalid_num() {
|
||||
new_ucmd!()
|
||||
.args(&["-c", "1024R", "emptyfile.txt"])
|
||||
.fails()
|
||||
.stderr_is("head: invalid number of bytes: '1024R'");
|
||||
new_ucmd!()
|
||||
.args(&["-n", "1024R", "emptyfile.txt"])
|
||||
.fails()
|
||||
.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");
|
||||
#[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");
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
{
|
||||
let sizes = ["1000G", "10T"];
|
||||
for size in &sizes {
|
||||
new_ucmd!()
|
||||
.args(&["-c", size])
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stderr_only(format!(
|
||||
"head: invalid number of bytes: '{}': Value too large for defined data type",
|
||||
size
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_head_num_with_undocumented_sign_bytes() {
|
||||
// tail: '-' is not documented (8.32 man pages)
|
||||
// head: '+' is not documented (8.32 man pages)
|
||||
const ALPHABET: &str = "abcdefghijklmnopqrstuvwxyz";
|
||||
new_ucmd!()
|
||||
.args(&["-c", "5"])
|
||||
.pipe_in(ALPHABET)
|
||||
.succeeds()
|
||||
.stdout_is("abcde");
|
||||
new_ucmd!()
|
||||
.args(&["-c", "-5"])
|
||||
.pipe_in(ALPHABET)
|
||||
.succeeds()
|
||||
.stdout_is("abcdefghijklmnopqrstu");
|
||||
new_ucmd!()
|
||||
.args(&["-c", "+5"])
|
||||
.pipe_in(ALPHABET)
|
||||
.succeeds()
|
||||
.stdout_is("abcde");
|
||||
}
|
||||
|
|
|
@ -1,147 +1,186 @@
|
|||
use crate::common::util::*;
|
||||
|
||||
// Apparently some CI environments have configuration issues, e.g. with 'whoami' and 'id'.
|
||||
// If we are running inside the CI and "needle" is in "stderr" skipping this test is
|
||||
// considered okay. If we are not inside the CI this calls assert!(result.success).
|
||||
//
|
||||
// From the Logs: "Build (ubuntu-18.04, x86_64-unknown-linux-gnu, feat_os_unix, use-cross)"
|
||||
// stderr: "whoami: cannot find name for user ID 1001"
|
||||
// Maybe: "adduser --uid 1001 username" can put things right?
|
||||
// stderr = id: Could not find uid 1001: No such id: 1001
|
||||
fn skipping_test_is_okay(result: &CmdResult, needle: &str) -> bool {
|
||||
if !result.succeeded() {
|
||||
println!("result.stdout = {}", result.stdout_str());
|
||||
println!("result.stderr = {}", result.stderr_str());
|
||||
if is_ci() && result.stderr_str().contains(needle) {
|
||||
println!("test skipped:");
|
||||
return true;
|
||||
} else {
|
||||
result.success();
|
||||
// spell-checker:ignore (ToDO) coreutil
|
||||
|
||||
// These tests run the GNU coreutils `(g)id` binary in `$PATH` in order to gather reference values.
|
||||
// If the `(g)id` in `$PATH` doesn't include a coreutils version string,
|
||||
// or the version is too low, the test is skipped.
|
||||
|
||||
// The reference version is 8.32. Here 8.30 was chosen because right now there's no
|
||||
// ubuntu image for github action available with a higher version than 8.30.
|
||||
const VERSION_MIN: &str = "8.30"; // minimum Version for the reference `id` in $PATH
|
||||
const VERSION_MIN_MULTIPLE_USERS: &str = "8.31"; // this feature was introduced in GNU's coreutils 8.31
|
||||
const UUTILS_WARNING: &str = "uutils-tests-warning";
|
||||
const UUTILS_INFO: &str = "uutils-tests-info";
|
||||
|
||||
macro_rules! unwrap_or_return {
|
||||
( $e:expr ) => {
|
||||
match $e {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
println!("{}: test skipped: {}", UUTILS_INFO, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
};
|
||||
}
|
||||
|
||||
fn return_whoami_username() -> String {
|
||||
let scene = TestScenario::new("whoami");
|
||||
let result = scene.cmd("whoami").run();
|
||||
if skipping_test_is_okay(&result, "whoami: cannot find name for user ID") {
|
||||
println!("test skipped:");
|
||||
return String::from("");
|
||||
}
|
||||
fn whoami() -> String {
|
||||
// Apparently some CI environments have configuration issues, e.g. with 'whoami' and 'id'.
|
||||
//
|
||||
// From the Logs: "Build (ubuntu-18.04, x86_64-unknown-linux-gnu, feat_os_unix, use-cross)"
|
||||
// whoami: cannot find name for user ID 1001
|
||||
// id --name: cannot find name for user ID 1001
|
||||
// id --name: cannot find name for group ID 116
|
||||
//
|
||||
// However, when running "id" from within "/bin/bash" it looks fine:
|
||||
// id: "uid=1001(runner) gid=118(docker) groups=118(docker),4(adm),101(systemd-journal)"
|
||||
// whoami: "runner"
|
||||
|
||||
result.stdout_str().trim().to_string()
|
||||
// Use environment variable to get current user instead of
|
||||
// invoking `whoami` and fall back to user "nobody" on error.
|
||||
std::env::var("USER").unwrap_or_else(|e| {
|
||||
println!("{}: {}, using \"nobody\" instead", UUTILS_WARNING, e);
|
||||
"nobody".to_string()
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_id() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
#[cfg(unix)]
|
||||
fn test_id_no_specified_user() {
|
||||
let result = new_ucmd!().run();
|
||||
let exp_result = unwrap_or_return!(expected_result(&[]));
|
||||
let mut _exp_stdout = exp_result.stdout_str().to_string();
|
||||
|
||||
let result = scene.ucmd().arg("-u").succeeds();
|
||||
let uid = result.stdout_str().trim();
|
||||
|
||||
let result = scene.ucmd().run();
|
||||
if skipping_test_is_okay(&result, "Could not find uid") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Verify that the id found by --user/-u exists in the list
|
||||
result.stdout_contains(uid);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_id_from_name() {
|
||||
let username = return_whoami_username();
|
||||
if username.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let result = scene.ucmd().arg(&username).run();
|
||||
if skipping_test_is_okay(&result, "Could not find uid") {
|
||||
return;
|
||||
}
|
||||
|
||||
let uid = result.stdout_str().trim();
|
||||
|
||||
let result = scene.ucmd().run();
|
||||
if skipping_test_is_okay(&result, "Could not find uid") {
|
||||
return;
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
// NOTE: (SELinux NotImplemented) strip 'context' part from exp_stdout:
|
||||
if let Some(context_offset) = exp_result.stdout_str().find(" context=") {
|
||||
_exp_stdout.replace_range(context_offset.._exp_stdout.len() - 1, "");
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
// Verify that the id found by --user/-u exists in the list
|
||||
.stdout_contains(uid)
|
||||
// Verify that the username found by whoami exists in the list
|
||||
.stdout_contains(username);
|
||||
.stdout_is(_exp_stdout)
|
||||
.stderr_is(exp_result.stderr_str())
|
||||
.code_is(exp_result.code());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_id_name_from_id() {
|
||||
let result = new_ucmd!().arg("-nu").run();
|
||||
#[cfg(unix)]
|
||||
fn test_id_single_user() {
|
||||
let test_users = [&whoami()[..]];
|
||||
|
||||
let username_id = result.stdout_str().trim();
|
||||
|
||||
let username_whoami = return_whoami_username();
|
||||
if username_whoami.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
assert_eq!(username_id, username_whoami);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_id_group() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let mut exp_result = unwrap_or_return!(expected_result(&test_users));
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&test_users)
|
||||
.run()
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str().replace(": Invalid argument", ""))
|
||||
.code_is(exp_result.code());
|
||||
|
||||
let mut result = scene.ucmd().arg("-g").succeeds();
|
||||
let s1 = result.stdout_str().trim();
|
||||
assert!(s1.parse::<f64>().is_ok());
|
||||
|
||||
result = scene.ucmd().arg("--group").succeeds();
|
||||
let s1 = result.stdout_str().trim();
|
||||
assert!(s1.parse::<f64>().is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_id_groups() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
|
||||
let result = scene.ucmd().arg("-G").succeeds();
|
||||
let groups = result.stdout_str().trim().split_whitespace();
|
||||
for s in groups {
|
||||
assert!(s.parse::<f64>().is_ok());
|
||||
}
|
||||
|
||||
let result = scene.ucmd().arg("--groups").succeeds();
|
||||
let groups = result.stdout_str().trim().split_whitespace();
|
||||
for s in groups {
|
||||
assert!(s.parse::<f64>().is_ok());
|
||||
// u/g/G z/n
|
||||
for &opt in &["--user", "--group", "--groups"] {
|
||||
let mut args = vec![opt];
|
||||
args.extend_from_slice(&test_users);
|
||||
exp_result = unwrap_or_return!(expected_result(&args));
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.run()
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str().replace(": Invalid argument", ""))
|
||||
.code_is(exp_result.code());
|
||||
args.push("--zero");
|
||||
exp_result = unwrap_or_return!(expected_result(&args));
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.run()
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str().replace(": Invalid argument", ""))
|
||||
.code_is(exp_result.code());
|
||||
args.push("--name");
|
||||
exp_result = unwrap_or_return!(expected_result(&args));
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.run()
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str().replace(": Invalid argument", ""))
|
||||
.code_is(exp_result.code());
|
||||
args.pop();
|
||||
exp_result = unwrap_or_return!(expected_result(&args));
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.run()
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str().replace(": Invalid argument", ""))
|
||||
.code_is(exp_result.code());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_id_user() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
#[cfg(unix)]
|
||||
fn test_id_single_user_non_existing() {
|
||||
let args = &["hopefully_non_existing_username"];
|
||||
let result = new_ucmd!().args(args).run();
|
||||
let exp_result = unwrap_or_return!(expected_result(args));
|
||||
|
||||
let result = scene.ucmd().arg("-u").succeeds();
|
||||
let s1 = result.stdout_str().trim();
|
||||
assert!(s1.parse::<f64>().is_ok());
|
||||
|
||||
let result = scene.ucmd().arg("--user").succeeds();
|
||||
let s1 = result.stdout_str().trim();
|
||||
assert!(s1.parse::<f64>().is_ok());
|
||||
// It is unknown why on macOS (and possibly others?) `id` adds "Invalid argument".
|
||||
// coreutils 8.32: $ LC_ALL=C id foobar
|
||||
// macOS: stderr: "id: 'foobar': no such user: Invalid argument"
|
||||
// linux: stderr: "id: 'foobar': no such user"
|
||||
result
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str().replace(": Invalid argument", ""))
|
||||
.code_is(exp_result.code());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_id_name() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
for &opt in &["--user", "--group", "--groups"] {
|
||||
let args = [opt, "--name"];
|
||||
let result = scene.ucmd().args(&args).run();
|
||||
let exp_result = unwrap_or_return!(expected_result(&args));
|
||||
result
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str())
|
||||
.code_is(exp_result.code());
|
||||
|
||||
if opt == "--user" {
|
||||
assert_eq!(result.stdout_str().trim_end(), whoami());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_id_real() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
for &opt in &["--user", "--group", "--groups"] {
|
||||
let args = [opt, "--real"];
|
||||
let result = scene.ucmd().args(&args).run();
|
||||
let exp_result = unwrap_or_return!(expected_result(&args));
|
||||
result
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str())
|
||||
.code_is(exp_result.code());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(unix, not(target_os = "linux")))]
|
||||
fn test_id_pretty_print() {
|
||||
let username = return_whoami_username();
|
||||
if username.is_empty() {
|
||||
return;
|
||||
}
|
||||
// `-p` is BSD only and not supported on GNU's `id`
|
||||
let username = whoami();
|
||||
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let result = scene.ucmd().arg("-p").run();
|
||||
let result = new_ucmd!().arg("-p").run();
|
||||
if result.stdout_str().trim().is_empty() {
|
||||
// this fails only on: "MinRustV (ubuntu-latest, feat_os_unix)"
|
||||
// `rustc 1.40.0 (73528e339 2019-12-16)`
|
||||
|
@ -150,20 +189,317 @@ fn test_id_pretty_print() {
|
|||
// stdout =
|
||||
// stderr = ', tests/common/util.rs:157:13
|
||||
println!("test skipped:");
|
||||
return;
|
||||
} else {
|
||||
result.success().stdout_contains(username);
|
||||
}
|
||||
|
||||
result.success().stdout_contains(username);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(unix, not(target_os = "linux")))]
|
||||
fn test_id_password_style() {
|
||||
let username = return_whoami_username();
|
||||
if username.is_empty() {
|
||||
// `-P` is BSD only and not supported on GNU's `id`
|
||||
let username = whoami();
|
||||
let result = new_ucmd!().arg("-P").arg(&username).succeeds();
|
||||
assert!(result.stdout_str().starts_with(&username));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_id_multiple_users() {
|
||||
#[cfg(target_os = "linux")]
|
||||
let util_name = util_name!();
|
||||
#[cfg(all(unix, not(target_os = "linux")))]
|
||||
let util_name = &format!("g{}", util_name!());
|
||||
let version_check_string = check_coreutil_version(util_name, VERSION_MIN_MULTIPLE_USERS);
|
||||
if version_check_string.starts_with(UUTILS_WARNING) {
|
||||
println!("{}\ntest skipped", version_check_string);
|
||||
return;
|
||||
}
|
||||
|
||||
let result = new_ucmd!().arg("-P").succeeds();
|
||||
// Same typical users that GNU test suite is using.
|
||||
let test_users = ["root", "man", "postfix", "sshd", &whoami()];
|
||||
|
||||
assert!(result.stdout_str().starts_with(&username));
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let mut exp_result = unwrap_or_return!(expected_result(&test_users));
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&test_users)
|
||||
.run()
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str().replace(": Invalid argument", ""))
|
||||
.code_is(exp_result.code());
|
||||
|
||||
// u/g/G z/n
|
||||
for &opt in &["--user", "--group", "--groups"] {
|
||||
let mut args = vec![opt];
|
||||
args.extend_from_slice(&test_users);
|
||||
exp_result = unwrap_or_return!(expected_result(&args));
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.run()
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str().replace(": Invalid argument", ""))
|
||||
.code_is(exp_result.code());
|
||||
args.push("--zero");
|
||||
exp_result = unwrap_or_return!(expected_result(&args));
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.run()
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str().replace(": Invalid argument", ""))
|
||||
.code_is(exp_result.code());
|
||||
args.push("--name");
|
||||
exp_result = unwrap_or_return!(expected_result(&args));
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.run()
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str().replace(": Invalid argument", ""))
|
||||
.code_is(exp_result.code());
|
||||
args.pop();
|
||||
exp_result = unwrap_or_return!(expected_result(&args));
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.run()
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str().replace(": Invalid argument", ""))
|
||||
.code_is(exp_result.code());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_id_multiple_users_non_existing() {
|
||||
#[cfg(target_os = "linux")]
|
||||
let util_name = util_name!();
|
||||
#[cfg(all(unix, not(target_os = "linux")))]
|
||||
let util_name = &format!("g{}", util_name!());
|
||||
let version_check_string = check_coreutil_version(util_name, VERSION_MIN_MULTIPLE_USERS);
|
||||
if version_check_string.starts_with(UUTILS_WARNING) {
|
||||
println!("{}\ntest skipped", version_check_string);
|
||||
return;
|
||||
}
|
||||
|
||||
let test_users = [
|
||||
"root",
|
||||
"hopefully_non_existing_username1",
|
||||
&whoami(),
|
||||
"man",
|
||||
"hopefully_non_existing_username2",
|
||||
"hopefully_non_existing_username3",
|
||||
"postfix",
|
||||
"sshd",
|
||||
"hopefully_non_existing_username4",
|
||||
&whoami(),
|
||||
];
|
||||
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let mut exp_result = unwrap_or_return!(expected_result(&test_users));
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&test_users)
|
||||
.run()
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str().replace(": Invalid argument", ""))
|
||||
.code_is(exp_result.code());
|
||||
|
||||
// u/g/G z/n
|
||||
for &opt in &["--user", "--group", "--groups"] {
|
||||
let mut args = vec![opt];
|
||||
args.extend_from_slice(&test_users);
|
||||
exp_result = unwrap_or_return!(expected_result(&args));
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.run()
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str().replace(": Invalid argument", ""))
|
||||
.code_is(exp_result.code());
|
||||
args.push("--zero");
|
||||
exp_result = unwrap_or_return!(expected_result(&args));
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.run()
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str().replace(": Invalid argument", ""))
|
||||
.code_is(exp_result.code());
|
||||
args.push("--name");
|
||||
exp_result = unwrap_or_return!(expected_result(&args));
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.run()
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str().replace(": Invalid argument", ""))
|
||||
.code_is(exp_result.code());
|
||||
args.pop();
|
||||
exp_result = unwrap_or_return!(expected_result(&args));
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.run()
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str().replace(": Invalid argument", ""))
|
||||
.code_is(exp_result.code());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_id_default_format() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
for &opt1 in &["--name", "--real"] {
|
||||
// id: cannot print only names or real IDs in default format
|
||||
let args = [opt1];
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.fails()
|
||||
.stderr_only(unwrap_or_return!(expected_result(&args)).stderr_str());
|
||||
for &opt2 in &["--user", "--group", "--groups"] {
|
||||
// u/g/G n/r
|
||||
let args = [opt2, opt1];
|
||||
let result = scene.ucmd().args(&args).run();
|
||||
let exp_result = unwrap_or_return!(expected_result(&args));
|
||||
result
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str())
|
||||
.code_is(exp_result.code());
|
||||
}
|
||||
}
|
||||
for &opt2 in &["--user", "--group", "--groups"] {
|
||||
// u/g/G
|
||||
let args = [opt2];
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.succeeds()
|
||||
.stdout_only(unwrap_or_return!(expected_result(&args)).stdout_str());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_id_zero() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
for z_flag in &["-z", "--zero"] {
|
||||
// id: option --zero not permitted in default format
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&[z_flag])
|
||||
.fails()
|
||||
.stderr_only(unwrap_or_return!(expected_result(&[z_flag])).stderr_str());
|
||||
for &opt1 in &["--name", "--real"] {
|
||||
// id: cannot print only names or real IDs in default format
|
||||
let args = [opt1, z_flag];
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.fails()
|
||||
.stderr_only(unwrap_or_return!(expected_result(&args)).stderr_str());
|
||||
for &opt2 in &["--user", "--group", "--groups"] {
|
||||
// u/g/G n/r z
|
||||
let args = [opt2, z_flag, opt1];
|
||||
let result = scene.ucmd().args(&args).run();
|
||||
let exp_result = unwrap_or_return!(expected_result(&args));
|
||||
result
|
||||
.stdout_is(exp_result.stdout_str())
|
||||
.stderr_is(exp_result.stderr_str())
|
||||
.code_is(exp_result.code());
|
||||
}
|
||||
}
|
||||
for &opt2 in &["--user", "--group", "--groups"] {
|
||||
// u/g/G z
|
||||
let args = [opt2, z_flag];
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&args)
|
||||
.succeeds()
|
||||
.stdout_only(unwrap_or_return!(expected_result(&args)).stdout_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_coreutil_version(util_name: &str, version_expected: &str) -> String {
|
||||
// example:
|
||||
// $ id --version | head -n 1
|
||||
// id (GNU coreutils) 8.32.162-4eda
|
||||
let scene = TestScenario::new(util_name);
|
||||
let version_check = scene
|
||||
.cmd_keepenv(&util_name)
|
||||
.env("LC_ALL", "C")
|
||||
.arg("--version")
|
||||
.run();
|
||||
version_check
|
||||
.stdout_str()
|
||||
.split('\n')
|
||||
.collect::<Vec<_>>()
|
||||
.get(0)
|
||||
.map_or_else(
|
||||
|| format!("{}: unexpected output format for reference coreutil: '{} --version'", UUTILS_WARNING, util_name),
|
||||
|s| {
|
||||
if s.contains(&format!("(GNU coreutils) {}", version_expected)) {
|
||||
s.to_string()
|
||||
} else if s.contains("(GNU coreutils)") {
|
||||
let version_found = s.split_whitespace().last().unwrap()[..4].parse::<f32>().unwrap_or_default();
|
||||
let version_expected = version_expected.parse::<f32>().unwrap_or_default();
|
||||
if version_found > version_expected {
|
||||
format!("{}: version for the reference coreutil '{}' is higher than expected; expected: {}, found: {}", UUTILS_INFO, util_name, version_expected, version_found)
|
||||
} else {
|
||||
format!("{}: version for the reference coreutil '{}' does not match; expected: {}, found: {}", UUTILS_WARNING, util_name, version_expected, version_found) }
|
||||
} else {
|
||||
format!("{}: no coreutils version string found for reference coreutils '{} --version'", UUTILS_WARNING, util_name)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_borrow)]
|
||||
#[cfg(unix)]
|
||||
fn expected_result(args: &[&str]) -> Result<CmdResult, String> {
|
||||
#[cfg(target_os = "linux")]
|
||||
let util_name = util_name!();
|
||||
#[cfg(all(unix, not(target_os = "linux")))]
|
||||
let util_name = &format!("g{}", util_name!());
|
||||
|
||||
let version_check_string = check_coreutil_version(util_name, VERSION_MIN);
|
||||
if version_check_string.starts_with(UUTILS_WARNING) {
|
||||
return Err(version_check_string);
|
||||
}
|
||||
println!("{}", version_check_string);
|
||||
|
||||
let scene = TestScenario::new(util_name);
|
||||
let result = scene
|
||||
.cmd_keepenv(util_name)
|
||||
.env("LC_ALL", "C")
|
||||
.args(args)
|
||||
.run();
|
||||
|
||||
let (stdout, stderr): (String, String) = if cfg!(target_os = "linux") {
|
||||
(
|
||||
result.stdout_str().to_string(),
|
||||
result.stderr_str().to_string(),
|
||||
)
|
||||
} else {
|
||||
// strip 'g' prefix from results:
|
||||
let from = util_name.to_string() + ":";
|
||||
let to = &from[1..];
|
||||
(
|
||||
result.stdout_str().replace(&from, to),
|
||||
result.stderr_str().replace(&from, to),
|
||||
)
|
||||
};
|
||||
|
||||
Ok(CmdResult::new(
|
||||
Some(result.tmpd()),
|
||||
Some(result.code()),
|
||||
result.succeeded(),
|
||||
stdout.as_bytes(),
|
||||
stderr.as_bytes(),
|
||||
))
|
||||
}
|
||||
|
|
|
@ -674,3 +674,410 @@ fn test_install_creating_leading_dir_fails_on_long_name() {
|
|||
.fails()
|
||||
.stderr_contains("failed to create");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install_dir() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let dir = "target_dir";
|
||||
let file1 = "source_file1";
|
||||
let file2 = "source_file2";
|
||||
|
||||
at.touch(file1);
|
||||
at.touch(file2);
|
||||
at.mkdir(dir);
|
||||
ucmd.arg(file1)
|
||||
.arg(file2)
|
||||
.arg(&format!("--target-directory={}", dir))
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(file1));
|
||||
assert!(at.file_exists(file2));
|
||||
assert!(at.file_exists(&format!("{}/{}", dir, file1)));
|
||||
assert!(at.file_exists(&format!("{}/{}", dir, file2)));
|
||||
}
|
||||
//
|
||||
// test backup functionality
|
||||
#[test]
|
||||
fn test_install_backup_short_no_args_files() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file_a = "test_install_simple_backup_file_a";
|
||||
let file_b = "test_install_simple_backup_file_b";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-b")
|
||||
.arg(file_a)
|
||||
.arg(file_b)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(file_a));
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(at.file_exists(&format!("{}~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install_backup_short_no_args_file_to_dir() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file = "test_install_simple_backup_file_a";
|
||||
let dest_dir = "test_install_dest/";
|
||||
let expect = format!("{}{}", dest_dir, file);
|
||||
|
||||
at.touch(file);
|
||||
at.mkdir(dest_dir);
|
||||
at.touch(&expect);
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-b")
|
||||
.arg(file)
|
||||
.arg(dest_dir)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(file));
|
||||
assert!(at.file_exists(&expect));
|
||||
assert!(at.file_exists(&format!("{}~", expect)));
|
||||
}
|
||||
|
||||
// Long --backup option is tested separately as it requires a slightly different
|
||||
// handling than '-b' does.
|
||||
#[test]
|
||||
fn test_install_backup_long_no_args_files() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file_a = "test_install_simple_backup_file_a";
|
||||
let file_b = "test_install_simple_backup_file_b";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--backup")
|
||||
.arg(file_a)
|
||||
.arg(file_b)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(file_a));
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(at.file_exists(&format!("{}~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install_backup_long_no_args_file_to_dir() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file = "test_install_simple_backup_file_a";
|
||||
let dest_dir = "test_install_dest/";
|
||||
let expect = format!("{}{}", dest_dir, file);
|
||||
|
||||
at.touch(file);
|
||||
at.mkdir(dest_dir);
|
||||
at.touch(&expect);
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--backup")
|
||||
.arg(file)
|
||||
.arg(dest_dir)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(file));
|
||||
assert!(at.file_exists(&expect));
|
||||
assert!(at.file_exists(&format!("{}~", expect)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install_backup_short_custom_suffix() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file_a = "test_install_backup_custom_suffix_file_a";
|
||||
let file_b = "test_install_backup_custom_suffix_file_b";
|
||||
let suffix = "super-suffix-of-the-century";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-b")
|
||||
.arg(format!("--suffix={}", suffix))
|
||||
.arg(file_a)
|
||||
.arg(file_b)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(file_a));
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(at.file_exists(&format!("{}{}", file_b, suffix)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install_backup_custom_suffix_via_env() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file_a = "test_install_backup_custom_suffix_file_a";
|
||||
let file_b = "test_install_backup_custom_suffix_file_b";
|
||||
let suffix = "super-suffix-of-the-century";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-b")
|
||||
.env("SIMPLE_BACKUP_SUFFIX", suffix)
|
||||
.arg(file_a)
|
||||
.arg(file_b)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(file_a));
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(at.file_exists(&format!("{}{}", file_b, suffix)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install_backup_numbered_with_t() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file_a = "test_install_backup_numbering_file_a";
|
||||
let file_b = "test_install_backup_numbering_file_b";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--backup=t")
|
||||
.arg(file_a)
|
||||
.arg(file_b)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(file_a));
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(at.file_exists(&format!("{}.~1~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install_backup_numbered_with_numbered() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file_a = "test_install_backup_numbering_file_a";
|
||||
let file_b = "test_install_backup_numbering_file_b";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--backup=numbered")
|
||||
.arg(file_a)
|
||||
.arg(file_b)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(file_a));
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(at.file_exists(&format!("{}.~1~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install_backup_existing() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file_a = "test_install_backup_numbering_file_a";
|
||||
let file_b = "test_install_backup_numbering_file_b";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--backup=existing")
|
||||
.arg(file_a)
|
||||
.arg(file_b)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(file_a));
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(at.file_exists(&format!("{}~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install_backup_nil() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file_a = "test_install_backup_numbering_file_a";
|
||||
let file_b = "test_install_backup_numbering_file_b";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--backup=nil")
|
||||
.arg(file_a)
|
||||
.arg(file_b)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(file_a));
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(at.file_exists(&format!("{}~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install_backup_numbered_if_existing_backup_existing() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file_a = "test_install_backup_numbering_file_a";
|
||||
let file_b = "test_install_backup_numbering_file_b";
|
||||
let file_b_backup = "test_install_backup_numbering_file_b.~1~";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
at.touch(file_b_backup);
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--backup=existing")
|
||||
.arg(file_a)
|
||||
.arg(file_b)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(file_a));
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(at.file_exists(file_b_backup));
|
||||
assert!(at.file_exists(&*format!("{}.~2~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install_backup_numbered_if_existing_backup_nil() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file_a = "test_install_backup_numbering_file_a";
|
||||
let file_b = "test_install_backup_numbering_file_b";
|
||||
let file_b_backup = "test_install_backup_numbering_file_b.~1~";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
at.touch(file_b_backup);
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--backup=nil")
|
||||
.arg(file_a)
|
||||
.arg(file_b)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(file_a));
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(at.file_exists(file_b_backup));
|
||||
assert!(at.file_exists(&*format!("{}.~2~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install_backup_simple() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file_a = "test_install_backup_numbering_file_a";
|
||||
let file_b = "test_install_backup_numbering_file_b";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--backup=simple")
|
||||
.arg(file_a)
|
||||
.arg(file_b)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(file_a));
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(at.file_exists(&format!("{}~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install_backup_never() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file_a = "test_install_backup_numbering_file_a";
|
||||
let file_b = "test_install_backup_numbering_file_b";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--backup=never")
|
||||
.arg(file_a)
|
||||
.arg(file_b)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(file_a));
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(at.file_exists(&format!("{}~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install_backup_none() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file_a = "test_install_backup_numbering_file_a";
|
||||
let file_b = "test_install_backup_numbering_file_b";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--backup=none")
|
||||
.arg(file_a)
|
||||
.arg(file_b)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(file_a));
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(!at.file_exists(&format!("{}~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install_backup_off() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file_a = "test_install_backup_numbering_file_a";
|
||||
let file_b = "test_install_backup_numbering_file_b";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--backup=off")
|
||||
.arg(file_a)
|
||||
.arg(file_b)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(file_a));
|
||||
assert!(at.file_exists(file_b));
|
||||
assert!(!at.file_exists(&format!("{}~", file_b)));
|
||||
}
|
||||
|
|
|
@ -428,20 +428,6 @@ fn test_symlink_relative() {
|
|||
assert_eq!(at.resolve_link(link), file_a);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hardlink_relative() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file_a = "test_hardlink_relative_a";
|
||||
let link = "test_hardlink_relative_link";
|
||||
|
||||
at.touch(file_a);
|
||||
|
||||
// relative hardlink
|
||||
ucmd.args(&["-r", "-v", file_a, link])
|
||||
.succeeds()
|
||||
.stdout_only(format!("'{}' -> '{}'\n", link, file_a));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_symlink_relative_path() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
@ -571,3 +557,34 @@ fn test_symlink_no_deref_file() {
|
|||
assert!(at.is_symlink(link));
|
||||
assert_eq!(at.resolve_link(link), file1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_relative_requires_symbolic() {
|
||||
new_ucmd!().args(&["-r", "foo", "bar"]).fails();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_relative_dst_already_symlink() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.touch("file1");
|
||||
at.symlink_file("file1", "file2");
|
||||
ucmd.arg("-srf").arg("file1").arg("file2").succeeds();
|
||||
at.is_symlink("file2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_relative_src_already_symlink() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.touch("file1");
|
||||
at.symlink_file("file1", "file2");
|
||||
ucmd.arg("-sr").arg("file2").arg("file3").succeeds();
|
||||
assert!(at.resolve_link("file3").ends_with("file1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_relative_recursive() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.mkdir("dir");
|
||||
ucmd.args(&["-sr", "dir", "dir/recursive"]).succeeds();
|
||||
assert_eq!(at.resolve_link("dir/recursive"), ".");
|
||||
}
|
||||
|
|
|
@ -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'");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -398,7 +398,7 @@ fn test_ls_long_formats() {
|
|||
.arg("--author")
|
||||
.arg("test-long-formats")
|
||||
.succeeds();
|
||||
assert!(re_three.is_match(&result.stdout_str()));
|
||||
assert!(re_three.is_match(result.stdout_str()));
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
|
@ -701,20 +701,20 @@ fn test_ls_styles() {
|
|||
.arg("-l")
|
||||
.arg("--time-style=full-iso")
|
||||
.succeeds();
|
||||
assert!(re_full.is_match(&result.stdout_str()));
|
||||
assert!(re_full.is_match(result.stdout_str()));
|
||||
//long-iso
|
||||
let result = scene
|
||||
.ucmd()
|
||||
.arg("-l")
|
||||
.arg("--time-style=long-iso")
|
||||
.succeeds();
|
||||
assert!(re_long.is_match(&result.stdout_str()));
|
||||
assert!(re_long.is_match(result.stdout_str()));
|
||||
//iso
|
||||
let result = scene.ucmd().arg("-l").arg("--time-style=iso").succeeds();
|
||||
assert!(re_iso.is_match(&result.stdout_str()));
|
||||
assert!(re_iso.is_match(result.stdout_str()));
|
||||
//locale
|
||||
let result = scene.ucmd().arg("-l").arg("--time-style=locale").succeeds();
|
||||
assert!(re_locale.is_match(&result.stdout_str()));
|
||||
assert!(re_locale.is_match(result.stdout_str()));
|
||||
|
||||
//Overwrite options tests
|
||||
let result = scene
|
||||
|
@ -723,19 +723,19 @@ fn test_ls_styles() {
|
|||
.arg("--time-style=long-iso")
|
||||
.arg("--time-style=iso")
|
||||
.succeeds();
|
||||
assert!(re_iso.is_match(&result.stdout_str()));
|
||||
assert!(re_iso.is_match(result.stdout_str()));
|
||||
let result = scene
|
||||
.ucmd()
|
||||
.arg("--time-style=iso")
|
||||
.arg("--full-time")
|
||||
.succeeds();
|
||||
assert!(re_full.is_match(&result.stdout_str()));
|
||||
assert!(re_full.is_match(result.stdout_str()));
|
||||
let result = scene
|
||||
.ucmd()
|
||||
.arg("--full-time")
|
||||
.arg("--time-style=iso")
|
||||
.succeeds();
|
||||
assert!(re_iso.is_match(&result.stdout_str()));
|
||||
assert!(re_iso.is_match(result.stdout_str()));
|
||||
|
||||
let result = scene
|
||||
.ucmd()
|
||||
|
@ -743,7 +743,7 @@ fn test_ls_styles() {
|
|||
.arg("--time-style=iso")
|
||||
.arg("--full-time")
|
||||
.succeeds();
|
||||
assert!(re_full.is_match(&result.stdout_str()));
|
||||
assert!(re_full.is_match(result.stdout_str()));
|
||||
|
||||
let result = scene
|
||||
.ucmd()
|
||||
|
@ -751,7 +751,7 @@ fn test_ls_styles() {
|
|||
.arg("-x")
|
||||
.arg("-l")
|
||||
.succeeds();
|
||||
assert!(re_full.is_match(&result.stdout_str()));
|
||||
assert!(re_full.is_match(result.stdout_str()));
|
||||
|
||||
at.touch("test2");
|
||||
let result = scene.ucmd().arg("--full-time").arg("-x").succeeds();
|
||||
|
@ -1143,7 +1143,7 @@ fn test_ls_indicator_style() {
|
|||
for opt in options {
|
||||
scene
|
||||
.ucmd()
|
||||
.arg(format!("{}", opt))
|
||||
.arg(opt.to_string())
|
||||
.succeeds()
|
||||
.stdout_contains(&"/");
|
||||
}
|
||||
|
@ -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" });
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
@ -122,7 +125,8 @@ fn test_mktemp_mktemp_t() {
|
|||
.arg(TEST_TEMPLATE8)
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("suffix cannot contain any path separators");
|
||||
.stderr_contains("invalid suffix")
|
||||
.stderr_contains("contains directory separator");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -386,7 +390,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 +403,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")
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -35,7 +35,7 @@ fn test_from_iec_i_requires_suffix() {
|
|||
new_ucmd!()
|
||||
.args(&["--from=iec-i", "1024"])
|
||||
.fails()
|
||||
.stderr_is("numfmt: missing 'i' suffix in input: ‘1024’ (e.g Ki/Mi/Gi)");
|
||||
.stderr_is("numfmt: missing 'i' suffix in input: '1024' (e.g Ki/Mi/Gi)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -123,7 +123,7 @@ fn test_header_error_if_non_numeric() {
|
|||
new_ucmd!()
|
||||
.args(&["--header=two"])
|
||||
.run()
|
||||
.stderr_is("numfmt: invalid header value ‘two’");
|
||||
.stderr_is("numfmt: invalid header value 'two'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -131,7 +131,7 @@ fn test_header_error_if_0() {
|
|||
new_ucmd!()
|
||||
.args(&["--header=0"])
|
||||
.run()
|
||||
.stderr_is("numfmt: invalid header value ‘0’");
|
||||
.stderr_is("numfmt: invalid header value '0'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -139,7 +139,7 @@ fn test_header_error_if_negative() {
|
|||
new_ucmd!()
|
||||
.args(&["--header=-3"])
|
||||
.run()
|
||||
.stderr_is("numfmt: invalid header value ‘-3’");
|
||||
.stderr_is("numfmt: invalid header value '-3'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -187,7 +187,7 @@ fn test_should_report_invalid_empty_number_on_empty_stdin() {
|
|||
.args(&["--from=auto"])
|
||||
.pipe_in("\n")
|
||||
.run()
|
||||
.stderr_is("numfmt: invalid number: ‘’\n");
|
||||
.stderr_is("numfmt: invalid number: ''\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -196,7 +196,7 @@ fn test_should_report_invalid_empty_number_on_blank_stdin() {
|
|||
.args(&["--from=auto"])
|
||||
.pipe_in(" \t \n")
|
||||
.run()
|
||||
.stderr_is("numfmt: invalid number: ‘’\n");
|
||||
.stderr_is("numfmt: invalid number: ''\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -205,14 +205,14 @@ fn test_should_report_invalid_suffix_on_stdin() {
|
|||
.args(&["--from=auto"])
|
||||
.pipe_in("1k")
|
||||
.run()
|
||||
.stderr_is("numfmt: invalid suffix in input: ‘1k’\n");
|
||||
.stderr_is("numfmt: invalid suffix in input: '1k'\n");
|
||||
|
||||
// GNU numfmt reports this one as “invalid number”
|
||||
new_ucmd!()
|
||||
.args(&["--from=auto"])
|
||||
.pipe_in("NaN")
|
||||
.run()
|
||||
.stderr_is("numfmt: invalid suffix in input: ‘NaN’\n");
|
||||
.stderr_is("numfmt: invalid suffix in input: 'NaN'\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -222,7 +222,7 @@ fn test_should_report_invalid_number_with_interior_junk() {
|
|||
.args(&["--from=auto"])
|
||||
.pipe_in("1x0K")
|
||||
.run()
|
||||
.stderr_is("numfmt: invalid number: ‘1x0K’\n");
|
||||
.stderr_is("numfmt: invalid number: '1x0K'\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -461,7 +461,7 @@ fn test_delimiter_overrides_whitespace_separator() {
|
|||
.args(&["-d,"])
|
||||
.pipe_in("1 234,56")
|
||||
.fails()
|
||||
.stderr_is("numfmt: invalid number: ‘1 234’\n");
|
||||
.stderr_is("numfmt: invalid number: '1 234'\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -481,3 +481,27 @@ fn test_delimiter_with_padding_and_fields() {
|
|||
.succeeds()
|
||||
.stdout_only(" 1.0K| 2.0K\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_round() {
|
||||
for (method, exp) in &[
|
||||
("from-zero", ["9.1K", "-9.1K", "9.1K", "-9.1K"]),
|
||||
("towards-zero", ["9.0K", "-9.0K", "9.0K", "-9.0K"]),
|
||||
("up", ["9.1K", "-9.0K", "9.1K", "-9.0K"]),
|
||||
("down", ["9.0K", "-9.1K", "9.0K", "-9.1K"]),
|
||||
("nearest", ["9.0K", "-9.0K", "9.1K", "-9.1K"]),
|
||||
] {
|
||||
new_ucmd!()
|
||||
.args(&[
|
||||
"--to=si",
|
||||
&format!("--round={}", method),
|
||||
"--",
|
||||
"9001",
|
||||
"-9001",
|
||||
"9099",
|
||||
"-9099",
|
||||
])
|
||||
.succeeds()
|
||||
.stdout_only(exp.join("\n") + "\n");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
// * This file is part of the uutils coreutils package.
|
||||
// *
|
||||
// * For the full copyright and license information, please view the LICENSE
|
||||
// * file that was distributed with this source code.
|
||||
|
||||
extern crate unindent;
|
||||
|
||||
use self::unindent::*;
|
||||
|
@ -804,3 +809,40 @@ fn test_traditional_only_label() {
|
|||
",
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_od_invalid_bytes() {
|
||||
const INVALID_SIZE: &str = "1fb4t";
|
||||
const BIG_SIZE: &str = "1Y";
|
||||
|
||||
// NOTE:
|
||||
// GNU's od (8.32) with option '--width' does not accept 'Y' as valid suffix.
|
||||
// According to the man page it should be valid in the same way it is valid for
|
||||
// '--read-bytes' and '--skip-bytes'.
|
||||
|
||||
let options = [
|
||||
"--read-bytes",
|
||||
"--skip-bytes",
|
||||
"--width",
|
||||
// "--strings", // TODO: consider testing here once '--strings' is implemented
|
||||
];
|
||||
for option in &options {
|
||||
new_ucmd!()
|
||||
.arg(format!("{}={}", option, INVALID_SIZE))
|
||||
.arg("file")
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stderr_only(format!(
|
||||
"od: invalid {} argument '{}'",
|
||||
option, INVALID_SIZE
|
||||
));
|
||||
|
||||
#[cfg(not(target_pointer_width = "128"))]
|
||||
new_ucmd!()
|
||||
.arg(format!("{}={}", option, BIG_SIZE))
|
||||
.arg("file")
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stderr_only(format!("od: {} argument '{}' too large", option, BIG_SIZE));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ fn test_posix_mode() {
|
|||
|
||||
// fail on long path
|
||||
new_ucmd!()
|
||||
.args(&["-p", &"dir".repeat(libc::PATH_MAX as usize + 1).as_str()])
|
||||
.args(&["-p", "dir".repeat(libc::PATH_MAX as usize + 1).as_str()])
|
||||
.fails()
|
||||
.no_stdout();
|
||||
|
||||
|
@ -46,7 +46,7 @@ fn test_posix_mode() {
|
|||
new_ucmd!()
|
||||
.args(&[
|
||||
"-p",
|
||||
&format!("dir/{}", "file".repeat(libc::FILENAME_MAX as usize + 1)).as_str(),
|
||||
format!("dir/{}", "file".repeat(libc::FILENAME_MAX as usize + 1)).as_str(),
|
||||
])
|
||||
.fails()
|
||||
.no_stdout();
|
||||
|
@ -76,7 +76,7 @@ fn test_posix_special() {
|
|||
|
||||
// fail on long path
|
||||
new_ucmd!()
|
||||
.args(&["-P", &"dir".repeat(libc::PATH_MAX as usize + 1).as_str()])
|
||||
.args(&["-P", "dir".repeat(libc::PATH_MAX as usize + 1).as_str()])
|
||||
.fails()
|
||||
.no_stdout();
|
||||
|
||||
|
@ -84,7 +84,7 @@ fn test_posix_special() {
|
|||
new_ucmd!()
|
||||
.args(&[
|
||||
"-P",
|
||||
&format!("dir/{}", "file".repeat(libc::FILENAME_MAX as usize + 1)).as_str(),
|
||||
format!("dir/{}", "file".repeat(libc::FILENAME_MAX as usize + 1)).as_str(),
|
||||
])
|
||||
.fails()
|
||||
.no_stdout();
|
||||
|
@ -117,7 +117,7 @@ fn test_posix_all() {
|
|||
.args(&[
|
||||
"-p",
|
||||
"-P",
|
||||
&"dir".repeat(libc::PATH_MAX as usize + 1).as_str(),
|
||||
"dir".repeat(libc::PATH_MAX as usize + 1).as_str(),
|
||||
])
|
||||
.fails()
|
||||
.no_stdout();
|
||||
|
@ -127,7 +127,7 @@ fn test_posix_all() {
|
|||
.args(&[
|
||||
"-p",
|
||||
"-P",
|
||||
&format!("dir/{}", "file".repeat(libc::FILENAME_MAX as usize + 1)).as_str(),
|
||||
format!("dir/{}", "file".repeat(libc::FILENAME_MAX as usize + 1)).as_str(),
|
||||
])
|
||||
.fails()
|
||||
.no_stdout();
|
||||
|
|
|
@ -102,9 +102,11 @@ fn expected_result(args: &[&str]) -> String {
|
|||
#[cfg(target_vendor = "apple")]
|
||||
let util_name = format!("g{}", util_name!());
|
||||
|
||||
// note: clippy::needless_borrow *false positive*
|
||||
#[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()
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
use crate::common::util::*;
|
||||
use chrono::offset::Local;
|
||||
use chrono::DateTime;
|
||||
use chrono::Duration;
|
||||
use std::fs::metadata;
|
||||
|
||||
fn file_last_modified_time(ucmd: &UCommand, path: &str) -> String {
|
||||
|
@ -20,8 +21,23 @@ fn file_last_modified_time(ucmd: &UCommand, path: &str) -> String {
|
|||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn now_time() -> String {
|
||||
Local::now().format("%b %d %H:%M %Y").to_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;
|
||||
while current < to {
|
||||
vec.push(current.format(FORMAT).to_string());
|
||||
current = current + Duration::minutes(1);
|
||||
}
|
||||
vec
|
||||
}
|
||||
|
||||
fn valid_last_modified_template_vars(from: DateTime<Local>) -> Vec<Vec<(String, String)>> {
|
||||
all_minutes(from, Local::now())
|
||||
.into_iter()
|
||||
.map(|time| vec![("{last_modified_time}".to_string(), time)])
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -33,10 +49,7 @@ fn test_without_any_options() {
|
|||
scenario
|
||||
.args(&[test_file_path])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
);
|
||||
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -48,10 +61,7 @@ fn test_with_numbering_option_with_number_width() {
|
|||
scenario
|
||||
.args(&["-n", "2", test_file_path])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
);
|
||||
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -66,10 +76,7 @@ fn test_with_long_header_option() {
|
|||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![
|
||||
(&"{last_modified_time}".to_string(), &value),
|
||||
(&"{header}".to_string(), &header.to_string()),
|
||||
],
|
||||
&[("{last_modified_time}", &value), ("{header}", header)],
|
||||
);
|
||||
|
||||
new_ucmd!()
|
||||
|
@ -77,10 +84,7 @@ fn test_with_long_header_option() {
|
|||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![
|
||||
(&"{last_modified_time}".to_string(), &value),
|
||||
(&"{header}".to_string(), &header.to_string()),
|
||||
],
|
||||
&[("{last_modified_time}", &value), ("{header}", header)],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -93,18 +97,12 @@ fn test_with_double_space_option() {
|
|||
scenario
|
||||
.args(&["-d", test_file_path])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
);
|
||||
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
|
||||
|
||||
new_ucmd!()
|
||||
.args(&["--double-space", test_file_path])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
);
|
||||
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -116,10 +114,7 @@ fn test_with_first_line_number_option() {
|
|||
scenario
|
||||
.args(&["-N", "5", "-n", test_file_path])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
);
|
||||
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -131,10 +126,7 @@ fn test_with_first_line_number_long_option() {
|
|||
scenario
|
||||
.args(&["--first-line-number=5", "-n", test_file_path])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
);
|
||||
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -146,10 +138,7 @@ fn test_with_number_option_with_custom_separator_char() {
|
|||
scenario
|
||||
.args(&["-nc", test_file_path])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
);
|
||||
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -161,10 +150,7 @@ fn test_with_number_option_with_custom_separator_char_and_width() {
|
|||
scenario
|
||||
.args(&["-nc1", test_file_path])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
);
|
||||
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -207,25 +193,19 @@ fn test_with_page_range() {
|
|||
scenario
|
||||
.args(&["--pages=15", test_file_path])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
);
|
||||
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
|
||||
|
||||
new_ucmd!()
|
||||
.args(&["+15", test_file_path])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
);
|
||||
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
|
||||
|
||||
new_ucmd!()
|
||||
.args(&["--pages=15:17", test_file_path])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path1,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
&[("{last_modified_time}", &value)],
|
||||
);
|
||||
|
||||
new_ucmd!()
|
||||
|
@ -233,7 +213,7 @@ fn test_with_page_range() {
|
|||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path1,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
&[("{last_modified_time}", &value)],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -246,10 +226,7 @@ fn test_with_no_header_trailer_option() {
|
|||
scenario
|
||||
.args(&["-t", test_file_path])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
);
|
||||
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -262,10 +239,7 @@ fn test_with_page_length_option() {
|
|||
scenario
|
||||
.args(&["--pages=2:3", "-l", "100", "-n", test_file_path])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
);
|
||||
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
|
||||
|
||||
new_ucmd!()
|
||||
.args(&["--pages=2:3", "-l", "5", "-n", test_file_path])
|
||||
|
@ -288,14 +262,14 @@ fn test_with_suppress_error_option() {
|
|||
fn test_with_stdin() {
|
||||
let expected_file_path = "stdin.log.expected";
|
||||
let mut scenario = new_ucmd!();
|
||||
let now = now_time();
|
||||
let start = Local::now();
|
||||
scenario
|
||||
.pipe_in_fixture("stdin.log")
|
||||
.args(&["--pages=1:2", "-n", "-"])
|
||||
.run()
|
||||
.stdout_is_templated_fixture(
|
||||
.stdout_is_templated_fixture_any(
|
||||
expected_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &now)],
|
||||
&valid_last_modified_template_vars(start),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -308,18 +282,12 @@ fn test_with_column() {
|
|||
scenario
|
||||
.args(&["--pages=3:5", "--column=3", "-n", test_file_path])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
);
|
||||
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
|
||||
|
||||
new_ucmd!()
|
||||
.args(&["--pages=3:5", "-3", "-n", test_file_path])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
);
|
||||
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -331,10 +299,7 @@ fn test_with_column_across_option() {
|
|||
scenario
|
||||
.args(&["--pages=3:5", "--column=3", "-a", "-n", test_file_path])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
);
|
||||
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -354,10 +319,7 @@ fn test_with_column_across_option_and_column_separator() {
|
|||
test_file_path,
|
||||
])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
);
|
||||
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
|
||||
|
||||
new_ucmd!()
|
||||
.args(&[
|
||||
|
@ -371,7 +333,7 @@ fn test_with_column_across_option_and_column_separator() {
|
|||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path1,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
&[("{last_modified_time}", &value)],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -382,25 +344,25 @@ fn test_with_mpr() {
|
|||
let expected_test_file_path = "mpr.log.expected";
|
||||
let expected_test_file_path1 = "mpr1.log.expected";
|
||||
let expected_test_file_path2 = "mpr2.log.expected";
|
||||
let now = now_time();
|
||||
let start = Local::now();
|
||||
new_ucmd!()
|
||||
.args(&["--pages=1:2", "-m", "-n", test_file_path, test_file_path1])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
.stdout_is_templated_fixture_any(
|
||||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &now)],
|
||||
&valid_last_modified_template_vars(start),
|
||||
);
|
||||
|
||||
let now = now_time();
|
||||
let start = Local::now();
|
||||
new_ucmd!()
|
||||
.args(&["--pages=2:4", "-m", "-n", test_file_path, test_file_path1])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
.stdout_is_templated_fixture_any(
|
||||
expected_test_file_path1,
|
||||
vec![(&"{last_modified_time}".to_string(), &now)],
|
||||
&valid_last_modified_template_vars(start),
|
||||
);
|
||||
|
||||
let now = now_time();
|
||||
let start = Local::now();
|
||||
new_ucmd!()
|
||||
.args(&[
|
||||
"--pages=1:2",
|
||||
|
@ -413,9 +375,9 @@ fn test_with_mpr() {
|
|||
test_file_path,
|
||||
])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
.stdout_is_templated_fixture_any(
|
||||
expected_test_file_path2,
|
||||
vec![(&"{last_modified_time}".to_string(), &now)],
|
||||
&valid_last_modified_template_vars(start),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -452,10 +414,7 @@ fn test_with_offset_space_option() {
|
|||
test_file_path,
|
||||
])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
);
|
||||
.stdout_is_templated_fixture(expected_test_file_path, &[("{last_modified_time}", &value)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -497,9 +456,9 @@ fn test_with_pr_core_utils_tests() {
|
|||
|
||||
scenario_with_expected_status.stdout_is_templated_fixture(
|
||||
test_file_path,
|
||||
vec![
|
||||
(&"{last_modified_time}".to_string(), &value),
|
||||
(&"{file_name}".to_string(), &input_file_path.to_string()),
|
||||
&[
|
||||
("{last_modified_time}", &value),
|
||||
("{file_name}", input_file_path),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
@ -511,12 +470,12 @@ fn test_with_join_lines_option() {
|
|||
let test_file_2 = "test.log";
|
||||
let expected_file_path = "joined.log.expected";
|
||||
let mut scenario = new_ucmd!();
|
||||
let now = now_time();
|
||||
let start = Local::now();
|
||||
scenario
|
||||
.args(&["+1:2", "-J", "-m", test_file_1, test_file_2])
|
||||
.run()
|
||||
.stdout_is_templated_fixture(
|
||||
.stdout_is_templated_fixture_any(
|
||||
expected_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &now)],
|
||||
&valid_last_modified_template_vars(start),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
// * This file is part of the uutils coreutils package.
|
||||
// *
|
||||
// * For the full copyright and license information, please view the LICENSE
|
||||
// * file that was distributed with this source code.
|
||||
|
||||
// spell-checker:ignore (words) ints
|
||||
|
||||
use crate::common::util::*;
|
||||
|
@ -21,17 +26,31 @@ fn test_helper(file_name: &str, possible_args: &[&str]) {
|
|||
|
||||
#[test]
|
||||
fn test_buffer_sizes() {
|
||||
let buffer_sizes = [
|
||||
"0", "50K", "50k", "1M", "100M", "1000G", "10T", "500E", "1Y",
|
||||
];
|
||||
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)
|
||||
.arg("ext_sort.txt")
|
||||
.succeeds()
|
||||
.stdout_is_fixture("ext_sort.expected");
|
||||
|
||||
#[cfg(not(target_pointer_width = "32"))]
|
||||
{
|
||||
let buffer_sizes = ["1000G", "10T"];
|
||||
for buffer_size in &buffer_sizes {
|
||||
TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.arg("-n")
|
||||
.arg("-S")
|
||||
.arg(buffer_size)
|
||||
.arg("ext_sort.txt")
|
||||
.succeeds()
|
||||
.stdout_is_fixture("ext_sort.expected");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,11 +62,39 @@ fn test_invalid_buffer_size() {
|
|||
.arg("-S")
|
||||
.arg(invalid_buffer_size)
|
||||
.fails()
|
||||
.code_is(2)
|
||||
.stderr_only(format!(
|
||||
"sort: failed to parse buffer size `{}`: invalid digit found in string",
|
||||
"sort: invalid --buffer-size argument '{}'",
|
||||
invalid_buffer_size
|
||||
));
|
||||
}
|
||||
#[cfg(not(target_pointer_width = "128"))]
|
||||
new_ucmd!()
|
||||
.arg("-n")
|
||||
.arg("-S")
|
||||
.arg("1Y")
|
||||
.arg("ext_sort.txt")
|
||||
.fails()
|
||||
.code_is(2)
|
||||
.stderr_only("sort: --buffer-size argument '1Y' too large");
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
{
|
||||
let buffer_sizes = ["1000G", "10T"];
|
||||
for buffer_size in &buffer_sizes {
|
||||
new_ucmd!()
|
||||
.arg("-n")
|
||||
.arg("-S")
|
||||
.arg(buffer_size)
|
||||
.arg("ext_sort.txt")
|
||||
.fails()
|
||||
.code_is(2)
|
||||
.stderr_only(format!(
|
||||
"sort: --buffer-size argument '{}' too large",
|
||||
buffer_size
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -80,11 +127,7 @@ fn test_months_whitespace() {
|
|||
|
||||
#[test]
|
||||
fn test_version_empty_lines() {
|
||||
new_ucmd!()
|
||||
.arg("-V")
|
||||
.arg("version-empty-lines.txt")
|
||||
.succeeds()
|
||||
.stdout_is("\n\n\n\n\n\n\n1.2.3-alpha\n1.2.3-alpha2\n\t\t\t1.12.4\n11.2.3\n");
|
||||
test_helper("version-empty-lines", &["-V", "--version-sort"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -409,10 +452,20 @@ fn test_human_block_sizes2() {
|
|||
.arg(human_numeric_sort_param)
|
||||
.pipe_in(input)
|
||||
.succeeds()
|
||||
.stdout_only("-8T\n0.8M\n8981K\n21G\n909991M\n");
|
||||
.stdout_only("-8T\n8981K\n0.8M\n909991M\n21G\n");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_human_numeric_zero_stable() {
|
||||
let input = "0M\n0K\n-0K\n-P\n-0M\n";
|
||||
new_ucmd!()
|
||||
.arg("-hs")
|
||||
.pipe_in(input)
|
||||
.succeeds()
|
||||
.stdout_only(input);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_month_default2() {
|
||||
for month_sort_param in &["-M", "--month-sort", "--sort=month"] {
|
||||
|
@ -717,26 +770,30 @@ fn test_pipe() {
|
|||
|
||||
#[test]
|
||||
fn test_check() {
|
||||
new_ucmd!()
|
||||
.arg("-c")
|
||||
.arg("check_fail.txt")
|
||||
.fails()
|
||||
.stdout_is("sort: check_fail.txt:6: disorder: 5\n");
|
||||
for diagnose_arg in &["-c", "--check", "--check=diagnose-first"] {
|
||||
new_ucmd!()
|
||||
.arg(diagnose_arg)
|
||||
.arg("check_fail.txt")
|
||||
.fails()
|
||||
.stdout_is("sort: check_fail.txt:6: disorder: 5\n");
|
||||
|
||||
new_ucmd!()
|
||||
.arg("-c")
|
||||
.arg("multiple_files.expected")
|
||||
.succeeds()
|
||||
.stdout_is("");
|
||||
new_ucmd!()
|
||||
.arg(diagnose_arg)
|
||||
.arg("multiple_files.expected")
|
||||
.succeeds()
|
||||
.stdout_is("");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check_silent() {
|
||||
new_ucmd!()
|
||||
.arg("-C")
|
||||
.arg("check_fail.txt")
|
||||
.fails()
|
||||
.stdout_is("");
|
||||
for silent_arg in &["-C", "--check=silent", "--check=quiet"] {
|
||||
new_ucmd!()
|
||||
.arg(silent_arg)
|
||||
.arg("check_fail.txt")
|
||||
.fails()
|
||||
.stdout_is("");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -790,5 +847,107 @@ fn test_nonexistent_file() {
|
|||
|
||||
#[test]
|
||||
fn test_blanks() {
|
||||
test_helper("blanks", &["-b", "--ignore-blanks"]);
|
||||
test_helper("blanks", &["-b", "--ignore-leading-blanks"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sort_multiple() {
|
||||
new_ucmd!()
|
||||
.args(&["no_trailing_newline1.txt", "no_trailing_newline2.txt"])
|
||||
.succeeds()
|
||||
.stdout_is("a\nb\nb\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sort_empty_chunk() {
|
||||
new_ucmd!()
|
||||
.args(&["-S", "40b"])
|
||||
.pipe_in("a\na\n")
|
||||
.succeeds()
|
||||
.stdout_is("a\na\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_compress() {
|
||||
new_ucmd!()
|
||||
.args(&[
|
||||
"ext_sort.txt",
|
||||
"-n",
|
||||
"--compress-program",
|
||||
"gzip",
|
||||
"-S",
|
||||
"10",
|
||||
])
|
||||
.succeeds()
|
||||
.stdout_only_fixture("ext_sort.expected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compress_fail() {
|
||||
TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.args(&[
|
||||
"ext_sort.txt",
|
||||
"-n",
|
||||
"--compress-program",
|
||||
"nonexistent-program",
|
||||
"-S",
|
||||
"10",
|
||||
])
|
||||
.fails()
|
||||
.stderr_only("sort: couldn't execute compress program: errno 2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_merge_batches() {
|
||||
TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.args(&["ext_sort.txt", "-n", "-S", "150b"])
|
||||
.succeeds()
|
||||
.stdout_only_fixture("ext_sort.expected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_merge_batch_size() {
|
||||
TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.arg("--batch-size=2")
|
||||
.arg("-m")
|
||||
.arg("--unique")
|
||||
.arg("merge_ints_interleaved_1.txt")
|
||||
.arg("merge_ints_interleaved_2.txt")
|
||||
.arg("merge_ints_interleaved_3.txt")
|
||||
.arg("merge_ints_interleaved_3.txt")
|
||||
.arg("merge_ints_interleaved_2.txt")
|
||||
.arg("merge_ints_interleaved_1.txt")
|
||||
.succeeds()
|
||||
.stdout_only_fixture("merge_ints_interleaved.expected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sigpipe_panic() {
|
||||
let mut cmd = new_ucmd!();
|
||||
let mut child = cmd.args(&["ext_sort.txt"]).run_no_wait();
|
||||
// Dropping the stdout should not lead to an error.
|
||||
// The "Broken pipe" error should be silently ignored.
|
||||
drop(child.stdout.take());
|
||||
assert_eq!(
|
||||
String::from_utf8(child.wait_with_output().unwrap().stderr),
|
||||
Ok(String::new())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conflict_check_out() {
|
||||
let check_flags = ["-c=silent", "-c=quiet", "-c=diagnose-first", "-c", "-C"];
|
||||
for check_flag in &check_flags {
|
||||
new_ucmd!()
|
||||
.arg(check_flag)
|
||||
.arg("-o=/dev/null")
|
||||
.fails()
|
||||
.stderr_contains(
|
||||
"error: The argument '--output <FILENAME>' cannot be used with '--check",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
// * This file is part of the uutils coreutils package.
|
||||
// *
|
||||
// * For the full copyright and license information, please view the LICENSE
|
||||
// * file that was distributed with this source code.
|
||||
|
||||
extern crate rand;
|
||||
extern crate regex;
|
||||
|
||||
|
@ -285,3 +290,53 @@ fn test_filter_command_fails() {
|
|||
ucmd.args(&["--filter=/a/path/that/totally/does/not/exist", name])
|
||||
.fails();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_lines_number() {
|
||||
// Test if stdout/stderr for '--lines' option is correct
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
at.touch("file");
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&["--lines", "2", "file"])
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.no_stdout();
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&["--lines", "2fb", "file"])
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stderr_only("split: invalid number of lines: '2fb'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_invalid_bytes_size() {
|
||||
new_ucmd!()
|
||||
.args(&["-b", "1024R"])
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.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");
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
{
|
||||
let sizes = ["1000G", "10T"];
|
||||
for size in &sizes {
|
||||
new_ucmd!()
|
||||
.args(&["-b", size])
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stderr_only(format!(
|
||||
"split: invalid number of bytes: '{}': Value too large for defined data type",
|
||||
size
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -313,9 +313,11 @@ fn expected_result(args: &[&str]) -> String {
|
|||
#[cfg(target_vendor = "apple")]
|
||||
let util_name = format!("g{}", util_name!());
|
||||
|
||||
// note: clippy::needless_borrow *false positive*
|
||||
#[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()
|
||||
|
|
|
@ -57,8 +57,18 @@ fn test_stdbuf_line_buffering_stdin_fails() {
|
|||
#[cfg(not(target_os = "windows"))]
|
||||
#[test]
|
||||
fn test_stdbuf_invalid_mode_fails() {
|
||||
new_ucmd!()
|
||||
.args(&["-i", "1024R", "head"])
|
||||
.fails()
|
||||
.stderr_is("stdbuf: invalid mode 1024R\nTry 'stdbuf --help' for more information.");
|
||||
let options = ["--input", "--output", "--error"];
|
||||
for option in &options {
|
||||
new_ucmd!()
|
||||
.args(&[*option, "1024R", "head"])
|
||||
.fails()
|
||||
.code_is(125)
|
||||
.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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
// * This file is part of the uutils coreutils package.
|
||||
// *
|
||||
// * For the full copyright and license information, please view the LICENSE
|
||||
// * file that was distributed with this source code.
|
||||
|
||||
// spell-checker:ignore (ToDO) abcdefghijklmnopqrstuvwxyz efghijklmnopqrstuvwxyz vwxyz emptyfile
|
||||
|
||||
extern crate tail;
|
||||
|
||||
use self::tail::parse_size;
|
||||
use crate::common::util::*;
|
||||
use std::char::from_digit;
|
||||
use std::io::Write;
|
||||
|
@ -236,41 +242,6 @@ fn test_bytes_big() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_size() {
|
||||
// No suffix.
|
||||
assert_eq!(Ok(1234), parse_size("1234"));
|
||||
|
||||
// kB is 1000
|
||||
assert_eq!(Ok(9 * 1000), parse_size("9kB"));
|
||||
|
||||
// K is 1024
|
||||
assert_eq!(Ok(2 * 1024), parse_size("2K"));
|
||||
|
||||
let suffixes = [
|
||||
('M', 2u32),
|
||||
('G', 3u32),
|
||||
('T', 4u32),
|
||||
('P', 5u32),
|
||||
('E', 6u32),
|
||||
];
|
||||
|
||||
for &(c, exp) in &suffixes {
|
||||
let s = format!("2{}B", c);
|
||||
assert_eq!(Ok(2 * (1000_u64).pow(exp)), parse_size(&s));
|
||||
|
||||
let s = format!("2{}", c);
|
||||
assert_eq!(Ok(2 * (1024_u64).pow(exp)), parse_size(&s));
|
||||
}
|
||||
|
||||
// Sizes that are too big.
|
||||
assert!(parse_size("1Z").is_err());
|
||||
assert!(parse_size("1Y").is_err());
|
||||
|
||||
// Bad number
|
||||
assert!(parse_size("328hdsf3290").is_err()); // spell-checker:disable-line
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lines_with_size_suffix() {
|
||||
const FILE: &str = "test_lines_with_size_suffix.txt";
|
||||
|
@ -320,12 +291,11 @@ fn test_multiple_input_files_with_suppressed_headers() {
|
|||
|
||||
#[test]
|
||||
fn test_multiple_input_quiet_flag_overrides_verbose_flag_for_suppressing_headers() {
|
||||
// TODO: actually the later one should win, i.e. -qv should lead to headers being printed, -vq to them being suppressed
|
||||
new_ucmd!()
|
||||
.arg(FOOBAR_TXT)
|
||||
.arg(FOOBAR_2_TXT)
|
||||
.arg("-q")
|
||||
.arg("-v")
|
||||
.arg("-q")
|
||||
.run()
|
||||
.stdout_is_fixture("foobar_multiple_quiet.expected");
|
||||
}
|
||||
|
@ -388,3 +358,61 @@ fn test_positive_zero_lines() {
|
|||
.succeeds()
|
||||
.stdout_is("a\nb\nc\nd\ne\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tail_invalid_num() {
|
||||
new_ucmd!()
|
||||
.args(&["-c", "1024R", "emptyfile.txt"])
|
||||
.fails()
|
||||
.stderr_is("tail: invalid number of bytes: '1024R'");
|
||||
new_ucmd!()
|
||||
.args(&["-n", "1024R", "emptyfile.txt"])
|
||||
.fails()
|
||||
.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");
|
||||
#[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");
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
{
|
||||
let sizes = ["1000G", "10T"];
|
||||
for size in &sizes {
|
||||
new_ucmd!()
|
||||
.args(&["-c", size])
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stderr_only(format!(
|
||||
"tail: invalid number of bytes: '{}': Value too large for defined data type",
|
||||
size
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tail_num_with_undocumented_sign_bytes() {
|
||||
// tail: '-' is not documented (8.32 man pages)
|
||||
// head: '+' is not documented (8.32 man pages)
|
||||
const ALPHABET: &str = "abcdefghijklmnopqrstuvwxyz";
|
||||
new_ucmd!()
|
||||
.args(&["-c", "5"])
|
||||
.pipe_in(ALPHABET)
|
||||
.succeeds()
|
||||
.stdout_is("vwxyz");
|
||||
new_ucmd!()
|
||||
.args(&["-c", "-5"])
|
||||
.pipe_in(ALPHABET)
|
||||
.succeeds()
|
||||
.stdout_is("vwxyz");
|
||||
new_ucmd!()
|
||||
.args(&["-c", "+5"])
|
||||
.pipe_in(ALPHABET)
|
||||
.succeeds()
|
||||
.stdout_is("efghijklmnopqrstuvwxyz");
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// file that was distributed with this source code.
|
||||
//
|
||||
|
||||
// spell-checker:ignore (words) pseudofloat
|
||||
// spell-checker:ignore (words) egid euid pseudofloat
|
||||
|
||||
use crate::common::util::*;
|
||||
|
||||
|
@ -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]
|
||||
|
@ -476,6 +476,73 @@ fn test_nonexistent_file_is_not_symlink() {
|
|||
.succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(windows))] // Windows has no concept of sticky bit
|
||||
fn test_file_is_sticky() {
|
||||
let scenario = TestScenario::new(util_name!());
|
||||
let mut ucmd = scenario.ucmd();
|
||||
let mut chmod = scenario.cmd("chmod");
|
||||
|
||||
scenario.fixtures.touch("sticky_file");
|
||||
chmod.args(&["+t", "sticky_file"]).succeeds();
|
||||
|
||||
ucmd.args(&["-k", "sticky_file"]).succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_file_is_not_sticky() {
|
||||
new_ucmd!()
|
||||
.args(&["-k", "regular_file"])
|
||||
.run()
|
||||
.status_code(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(windows))]
|
||||
fn test_file_owned_by_euid() {
|
||||
new_ucmd!().args(&["-O", "regular_file"]).succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(windows))]
|
||||
fn test_nonexistent_file_not_owned_by_euid() {
|
||||
new_ucmd!()
|
||||
.args(&["-O", "nonexistent_file"])
|
||||
.run()
|
||||
.status_code(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(not(windows), not(target_os = "freebsd")))]
|
||||
fn test_file_not_owned_by_euid() {
|
||||
new_ucmd!()
|
||||
.args(&["-f", "/bin/sh", "-a", "!", "-O", "/bin/sh"])
|
||||
.succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(windows))]
|
||||
fn test_file_owned_by_egid() {
|
||||
new_ucmd!().args(&["-G", "regular_file"]).succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(windows))]
|
||||
fn test_nonexistent_file_not_owned_by_egid() {
|
||||
new_ucmd!()
|
||||
.args(&["-G", "nonexistent_file"])
|
||||
.run()
|
||||
.status_code(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(not(windows), not(target_os = "freebsd")))]
|
||||
fn test_file_not_owned_by_egid() {
|
||||
new_ucmd!()
|
||||
.args(&["-f", "/bin/sh", "-a", "!", "-G", "/bin/sh"])
|
||||
.succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_op_precedence_and_or_1() {
|
||||
new_ucmd!().args(&[" ", "-o", "", "-a", ""]).succeeds();
|
||||
|
@ -607,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]
|
||||
|
@ -623,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 ']'");
|
||||
}
|
||||
|
|
|
@ -9,3 +9,39 @@ fn test_subcommand_return_code() {
|
|||
|
||||
new_ucmd!().arg("1").arg("false").run().status_code(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_command_with_args() {
|
||||
new_ucmd!()
|
||||
.args(&["1700", "echo", "-n", "abcd"])
|
||||
.succeeds()
|
||||
.stdout_only("abcd");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_verbose() {
|
||||
for &verbose_flag in &["-v", "--verbose"] {
|
||||
new_ucmd!()
|
||||
.args(&[verbose_flag, ".1", "sleep", "10"])
|
||||
.fails()
|
||||
.stderr_only("timeout: sending signal TERM to command 'sleep'");
|
||||
new_ucmd!()
|
||||
.args(&[verbose_flag, "-s0", "-k.1", ".1", "sleep", "10"])
|
||||
.fails()
|
||||
.stderr_only("timeout: sending signal EXIT to command 'sleep'\ntimeout: sending signal KILL to command 'sleep'");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero_timeout() {
|
||||
new_ucmd!()
|
||||
.args(&["-v", "0", "sleep", ".1"])
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.no_stdout();
|
||||
new_ucmd!()
|
||||
.args(&["-v", "0", "-s0", "-k0", "sleep", ".1"])
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.no_stdout();
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ use self::touch::filetime::{self, FileTime};
|
|||
extern crate time;
|
||||
|
||||
use crate::common::util::*;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn get_file_times(at: &AtPath, path: &str) -> (FileTime, FileTime) {
|
||||
let m = at.metadata(path);
|
||||
|
@ -374,6 +375,24 @@ fn test_touch_set_date2() {
|
|||
assert_eq!(mtime, start_of_year);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_touch_set_date3() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file = "test_touch_set_date";
|
||||
|
||||
ucmd.args(&["-d", "@1623786360", file])
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(at.file_exists(file));
|
||||
|
||||
let expected = FileTime::from_unix_time(1623786360, 0);
|
||||
let (atime, mtime) = get_file_times(&at, file);
|
||||
assert_eq!(atime, mtime);
|
||||
assert_eq!(atime, expected);
|
||||
assert_eq!(mtime, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_touch_set_date_wrong_format() {
|
||||
let (_at, mut ucmd) = at_and_ucmd!();
|
||||
|
@ -466,3 +485,37 @@ fn test_touch_trailing_slash() {
|
|||
let file = "no-file/";
|
||||
ucmd.args(&[file]).fails();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_touch_no_such_file_error_msg() {
|
||||
let dirname = "nonexistent";
|
||||
let filename = "file";
|
||||
let path = PathBuf::from(dirname).join(filename);
|
||||
let path_str = path.to_str().unwrap();
|
||||
|
||||
new_ucmd!().arg(&path).fails().stderr_only(format!(
|
||||
"touch: cannot touch '{}': No such file or directory",
|
||||
path_str
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_touch_permission_denied_error_msg() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
let dirname = "dir_with_read_only_access";
|
||||
let filename = "file";
|
||||
let path = PathBuf::from(dirname).join(filename);
|
||||
let path_str = path.to_str().unwrap();
|
||||
|
||||
// create dest without write permissions
|
||||
at.mkdir(dirname);
|
||||
at.set_readonly(dirname);
|
||||
|
||||
let full_path = at.plus_as_string(path_str);
|
||||
ucmd.arg(&full_path).fails().stderr_only(format!(
|
||||
"touch: cannot touch '{}': Permission denied",
|
||||
&full_path
|
||||
));
|
||||
}
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
// * This file is part of the uutils coreutils package.
|
||||
// *
|
||||
// * For the full copyright and license information, please view the LICENSE
|
||||
// * file that was distributed with this source code.
|
||||
|
||||
// spell-checker:ignore (words) RFILE
|
||||
|
||||
use crate::common::util::*;
|
||||
use std::io::{Seek, SeekFrom, Write};
|
||||
|
||||
|
@ -45,9 +52,18 @@ fn test_reference() {
|
|||
let at = &scene.fixtures;
|
||||
let mut file = at.make_file(FILE2);
|
||||
|
||||
scene.ucmd().arg("-s").arg("+5KB").arg(FILE1).run();
|
||||
// manpage: "A FILE argument that does not exist is created."
|
||||
// TODO: 'truncate' does not create the file in this case,
|
||||
// but should because '--no-create' wasn't specified.
|
||||
at.touch(FILE1); // TODO: remove this when 'no-create' is fixed
|
||||
scene.ucmd().arg("-s").arg("+5KB").arg(FILE1).succeeds();
|
||||
|
||||
scene.ucmd().arg("--reference").arg(FILE1).arg(FILE2).run();
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--reference")
|
||||
.arg(FILE1)
|
||||
.arg(FILE2)
|
||||
.succeeds();
|
||||
|
||||
file.seek(SeekFrom::End(0)).unwrap();
|
||||
let actual = file.seek(SeekFrom::Current(0)).unwrap();
|
||||
|
@ -231,23 +247,30 @@ fn test_size_and_reference() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_filename_only() {
|
||||
// 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>
|
||||
--size <SIZE>",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_numbers() {
|
||||
// TODO For compatibility with GNU, `truncate -s 0X` should cause
|
||||
// the same error as `truncate -s 0X file`, but currently it returns
|
||||
// a different error.
|
||||
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]
|
||||
|
@ -265,3 +288,36 @@ fn test_reference_with_size_file_not_found() {
|
|||
.fails()
|
||||
.stderr_contains("cannot stat 'a': No such file or directory");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_truncate_bytes_size() {
|
||||
// TODO: this should succeed without error, uncomment when '--no-create' is fixed
|
||||
// new_ucmd!()
|
||||
// .args(&["--no-create", "--size", "K", "file"])
|
||||
// .succeeds();
|
||||
new_ucmd!()
|
||||
.args(&["--size", "1024R", "file"])
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.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");
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
{
|
||||
let sizes = ["1000G", "10T"];
|
||||
for size in &sizes {
|
||||
new_ucmd!()
|
||||
.args(&["--size", size, "file"])
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stderr_only(format!(
|
||||
"truncate: Invalid number: '{}': Value too large for defined data type",
|
||||
size
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
use std::fs::File;
|
||||
|
||||
use crate::common::util::*;
|
||||
|
||||
#[test]
|
||||
#[cfg(not(windows))]
|
||||
fn test_dev_null() {
|
||||
new_ucmd!()
|
||||
.pipe_in("</dev/null")
|
||||
.set_stdin(File::open("/dev/null").unwrap())
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stdout_is("not a tty\n");
|
||||
}
|
||||
|
||||
|
@ -14,44 +17,58 @@ fn test_dev_null() {
|
|||
fn test_dev_null_silent() {
|
||||
new_ucmd!()
|
||||
.args(&["-s"])
|
||||
.pipe_in("</dev/null")
|
||||
.set_stdin(File::open("/dev/null").unwrap())
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stdout_is("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_close_stdin() {
|
||||
new_ucmd!().pipe_in("<&-").fails().stdout_is("not a tty\n");
|
||||
let mut child = new_ucmd!().run_no_wait();
|
||||
drop(child.stdin.take());
|
||||
let output = child.wait_with_output().unwrap();
|
||||
assert_eq!(output.status.code(), Some(1));
|
||||
assert_eq!(std::str::from_utf8(&output.stdout), Ok("not a tty\n"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_close_stdin_silent() {
|
||||
new_ucmd!()
|
||||
.args(&["-s"])
|
||||
.pipe_in("<&-")
|
||||
.fails()
|
||||
.stdout_is("");
|
||||
let mut child = new_ucmd!().arg("-s").run_no_wait();
|
||||
drop(child.stdin.take());
|
||||
let output = child.wait_with_output().unwrap();
|
||||
assert_eq!(output.status.code(), Some(1));
|
||||
assert!(output.stdout.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_close_stdin_silent_long() {
|
||||
new_ucmd!()
|
||||
.args(&["--silent"])
|
||||
.pipe_in("<&-")
|
||||
.fails()
|
||||
.stdout_is("");
|
||||
let mut child = new_ucmd!().arg("--silent").run_no_wait();
|
||||
drop(child.stdin.take());
|
||||
let output = child.wait_with_output().unwrap();
|
||||
assert_eq!(output.status.code(), Some(1));
|
||||
assert!(output.stdout.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_close_stdin_silent_alias() {
|
||||
new_ucmd!()
|
||||
.args(&["--quiet"])
|
||||
.pipe_in("<&-")
|
||||
.fails()
|
||||
.stdout_is("");
|
||||
let mut child = new_ucmd!().arg("--quiet").run_no_wait();
|
||||
drop(child.stdin.take());
|
||||
let output = child.wait_with_output().unwrap();
|
||||
assert_eq!(output.status.code(), Some(1));
|
||||
assert!(output.stdout.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wrong_argument() {
|
||||
new_ucmd!().args(&["a"]).fails();
|
||||
new_ucmd!().args(&["a"]).fails().code_is(2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(windows))]
|
||||
fn test_stdout_fail() {
|
||||
let mut child = new_ucmd!().run_no_wait();
|
||||
drop(child.stdout.take());
|
||||
let status = child.wait().unwrap();
|
||||
assert_eq!(status.code(), Some(3));
|
||||
}
|
||||
|
|
|
@ -13,9 +13,11 @@ fn test_users_check_name() {
|
|||
#[cfg(target_vendor = "apple")]
|
||||
let util_name = format!("g{}", util_name!());
|
||||
|
||||
// note: clippy::needless_borrow *false positive*
|
||||
#[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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
@ -238,9 +237,11 @@ fn expected_result(args: &[&str]) -> String {
|
|||
#[cfg(target_vendor = "apple")]
|
||||
let util_name = format!("g{}", util_name!());
|
||||
|
||||
// note: clippy::needless_borrow *false positive*
|
||||
#[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()
|
||||
|
|
|
@ -69,6 +69,22 @@ pub struct CmdResult {
|
|||
}
|
||||
|
||||
impl CmdResult {
|
||||
pub fn new(
|
||||
tmpd: Option<Rc<TempDir>>,
|
||||
code: Option<i32>,
|
||||
success: bool,
|
||||
stdout: &[u8],
|
||||
stderr: &[u8],
|
||||
) -> CmdResult {
|
||||
CmdResult {
|
||||
tmpd,
|
||||
code,
|
||||
success,
|
||||
stdout: stdout.to_vec(),
|
||||
stderr: stderr.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to the program's standard output as a slice of bytes
|
||||
pub fn stdout(&self) -> &[u8] {
|
||||
&self.stdout
|
||||
|
@ -207,6 +223,18 @@ impl CmdResult {
|
|||
self
|
||||
}
|
||||
|
||||
/// like `stdout_is`, but succeeds if any elements of `expected` matches stdout.
|
||||
pub fn stdout_is_any<T: AsRef<str> + std::fmt::Debug>(&self, expected: Vec<T>) -> &CmdResult {
|
||||
if !expected.iter().any(|msg| self.stdout_str() == msg.as_ref()) {
|
||||
panic!(
|
||||
"stdout was {}\nExpected any of {:#?}",
|
||||
self.stdout_str(),
|
||||
expected
|
||||
)
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Like `stdout_is` but newlines are normalized to `\n`.
|
||||
pub fn normalized_newlines_stdout_is<T: AsRef<str>>(&self, msg: T) -> &CmdResult {
|
||||
let msg = msg.as_ref().replace("\r\n", "\n");
|
||||
|
@ -231,7 +259,7 @@ impl CmdResult {
|
|||
pub fn stdout_is_templated_fixture<T: AsRef<OsStr>>(
|
||||
&self,
|
||||
file_rel_path: T,
|
||||
template_vars: Vec<(&String, &String)>,
|
||||
template_vars: &[(&str, &str)],
|
||||
) -> &CmdResult {
|
||||
let mut contents =
|
||||
String::from_utf8(read_scenario_fixture(&self.tmpd, file_rel_path)).unwrap();
|
||||
|
@ -241,6 +269,23 @@ impl CmdResult {
|
|||
self.stdout_is(contents)
|
||||
}
|
||||
|
||||
/// like `stdout_is_templated_fixture`, but succeeds if any replacement by `template_vars` results in the actual stdout.
|
||||
pub fn stdout_is_templated_fixture_any<T: AsRef<OsStr>>(
|
||||
&self,
|
||||
file_rel_path: T,
|
||||
template_vars: &[Vec<(String, String)>],
|
||||
) {
|
||||
let contents = String::from_utf8(read_scenario_fixture(&self.tmpd, file_rel_path)).unwrap();
|
||||
let possible_values = template_vars.iter().map(|vars| {
|
||||
let mut contents = contents.clone();
|
||||
for kv in vars.iter() {
|
||||
contents = contents.replace(&kv.0, &kv.1);
|
||||
}
|
||||
contents
|
||||
});
|
||||
self.stdout_is_any(possible_values.collect());
|
||||
}
|
||||
|
||||
/// asserts that the command resulted in stderr stream output that equals the
|
||||
/// passed in value, when both are trimmed of trailing whitespace
|
||||
/// stderr_only is a better choice unless stdout may or will be non-empty
|
||||
|
@ -625,11 +670,20 @@ impl AtPath {
|
|||
// Source:
|
||||
// http://stackoverflow.com/questions/31439011/getfinalpathnamebyhandle-without-prepended
|
||||
let prefix = "\\\\?\\";
|
||||
// FixME: replace ...
|
||||
#[allow(clippy::manual_strip)]
|
||||
if s.starts_with(prefix) {
|
||||
String::from(&s[prefix.len()..])
|
||||
} else {
|
||||
s
|
||||
}
|
||||
// ... with ...
|
||||
// if let Some(stripped) = s.strip_prefix(prefix) {
|
||||
// String::from(stripped)
|
||||
// } else {
|
||||
// s
|
||||
// }
|
||||
// ... when using MSRV with stabilized `strip_prefix()`
|
||||
}
|
||||
}
|
||||
|
||||
|
|
1
tests/fixtures/chgrp/file1
vendored
Normal file
1
tests/fixtures/chgrp/file1
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
target file 1
|
1
tests/fixtures/chgrp/file2
vendored
Normal file
1
tests/fixtures/chgrp/file2
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
target file 2
|
1
tests/fixtures/chgrp/file3
vendored
Normal file
1
tests/fixtures/chgrp/file3
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
target file 3
|
1
tests/fixtures/chgrp/ref_file
vendored
Normal file
1
tests/fixtures/chgrp/ref_file
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
Reference file
|
1
tests/fixtures/du/subdir/deeper/deeper_dir/deeper_words.txt
vendored
Normal file
1
tests/fixtures/du/subdir/deeper/deeper_dir/deeper_words.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
hello world!
|
|
@ -1,3 +1,4 @@
|
|||
0K
|
||||
K
|
||||
844K
|
||||
981K
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
0K
|
||||
__
|
||||
__
|
||||
K
|
||||
^ no match for key
|
||||
_
|
||||
|
|
3
tests/fixtures/sort/human_block_sizes.txt
vendored
3
tests/fixtures/sort/human_block_sizes.txt
vendored
|
@ -9,4 +9,5 @@
|
|||
844K
|
||||
981K
|
||||
13M
|
||||
K
|
||||
K
|
||||
0K
|
2
tests/fixtures/sort/no_trailing_newline1.txt
vendored
Normal file
2
tests/fixtures/sort/no_trailing_newline1.txt
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
a
|
||||
b
|
1
tests/fixtures/sort/no_trailing_newline2.txt
vendored
Normal file
1
tests/fixtures/sort/no_trailing_newline2.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
b
|
|
@ -8,4 +8,8 @@
|
|||
1.2.3-alpha
|
||||
1.2.3-alpha2
|
||||
11.2.3
|
||||
bar2
|
||||
bar2.0.0
|
||||
foo0.1
|
||||
foo1.0
|
||||
1.12.4
|
||||
|
|
45
tests/fixtures/sort/version-empty-lines.expected.debug
vendored
Normal file
45
tests/fixtures/sort/version-empty-lines.expected.debug
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
|
||||
^ no match for key
|
||||
^ no match for key
|
||||
|
||||
^ no match for key
|
||||
^ no match for key
|
||||
|
||||
^ no match for key
|
||||
^ no match for key
|
||||
|
||||
^ no match for key
|
||||
^ no match for key
|
||||
|
||||
^ no match for key
|
||||
^ no match for key
|
||||
|
||||
^ no match for key
|
||||
^ no match for key
|
||||
|
||||
^ no match for key
|
||||
^ no match for key
|
||||
1.2.3-alpha
|
||||
___________
|
||||
___________
|
||||
1.2.3-alpha2
|
||||
____________
|
||||
____________
|
||||
11.2.3
|
||||
______
|
||||
______
|
||||
bar2
|
||||
____
|
||||
____
|
||||
bar2.0.0
|
||||
________
|
||||
________
|
||||
foo0.1
|
||||
______
|
||||
______
|
||||
foo1.0
|
||||
______
|
||||
______
|
||||
>>>1.12.4
|
||||
_________
|
||||
_________
|
4
tests/fixtures/sort/version-empty-lines.txt
vendored
4
tests/fixtures/sort/version-empty-lines.txt
vendored
|
@ -9,3 +9,7 @@
|
|||
|
||||
|
||||
1.12.4
|
||||
foo1.0
|
||||
foo0.1
|
||||
bar2.0.0
|
||||
bar2
|
Loading…
Add table
Add a link
Reference in a new issue