mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-08-01 13:37:48 +00:00
Merge branch 'master' of github.com:uutils/coreutils into refactoring_parse_size
This commit is contained in:
commit
130bf49e5d
112 changed files with 489 additions and 350 deletions
|
@ -1,4 +1,4 @@
|
|||
// spell-checker:ignore (flags) reflink (fs) tmpfs
|
||||
// spell-checker:ignore (flags) reflink (fs) tmpfs (linux) rlimit Rlim NOFILE
|
||||
|
||||
use crate::common::util::*;
|
||||
#[cfg(not(windows))]
|
||||
|
@ -7,11 +7,15 @@ use std::fs::set_permissions;
|
|||
#[cfg(not(windows))]
|
||||
use std::os::unix::fs;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
#[cfg(windows)]
|
||||
use std::os::windows::fs::symlink_file;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use filetime::FileTime;
|
||||
#[cfg(target_os = "linux")]
|
||||
use rlimit::Resource;
|
||||
#[cfg(not(windows))]
|
||||
use std::env;
|
||||
#[cfg(target_os = "linux")]
|
||||
|
@ -1257,3 +1261,32 @@ fn test_cp_reflink_bad() {
|
|||
.fails()
|
||||
.stderr_contains("invalid argument");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_cp_reflink_insufficient_permission() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
at.make_file("unreadable")
|
||||
.set_permissions(PermissionsExt::from_mode(0o000))
|
||||
.unwrap();
|
||||
|
||||
ucmd.arg("-r")
|
||||
.arg("--reflink=auto")
|
||||
.arg("unreadable")
|
||||
.arg(TEST_EXISTING_FILE)
|
||||
.fails()
|
||||
.stderr_only("cp: 'unreadable' -> 'existing_file.txt': Permission denied (os error 13)");
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[test]
|
||||
fn test_closes_file_descriptors() {
|
||||
new_ucmd!()
|
||||
.arg("-r")
|
||||
.arg("--reflink=auto")
|
||||
.arg("dir_with_10_files/")
|
||||
.arg("dir_with_10_files_new/")
|
||||
.with_limit(Resource::NOFILE, 9, 9)
|
||||
.succeeds();
|
||||
}
|
||||
|
|
|
@ -257,18 +257,37 @@ fn test_du_time() {
|
|||
scene
|
||||
.ccmd("touch")
|
||||
.arg("-a")
|
||||
.arg("-m")
|
||||
.arg("-t")
|
||||
.arg("201505150000")
|
||||
.arg("date_test")
|
||||
.succeeds();
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--time")
|
||||
.ccmd("touch")
|
||||
.arg("-m")
|
||||
.arg("-t")
|
||||
.arg("201606160000")
|
||||
.arg("date_test")
|
||||
.succeeds()
|
||||
.stdout_only("0\t2015-05-15 00:00\tdate_test\n");
|
||||
.succeeds();
|
||||
|
||||
let result = scene.ucmd().arg("--time").arg("date_test").succeeds();
|
||||
result.stdout_only("0\t2016-06-16 00:00\tdate_test\n");
|
||||
|
||||
let result = scene.ucmd().arg("--time=atime").arg("date_test").succeeds();
|
||||
result.stdout_only("0\t2015-05-15 00:00\tdate_test\n");
|
||||
|
||||
let result = scene.ucmd().arg("--time=ctime").arg("date_test").succeeds();
|
||||
result.stdout_only("0\t2016-06-16 00:00\tdate_test\n");
|
||||
|
||||
#[cfg(not(target_env = "musl"))]
|
||||
{
|
||||
use regex::Regex;
|
||||
|
||||
let re_birth =
|
||||
Regex::new(r"0\t[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}\tdate_test").unwrap();
|
||||
let result = scene.ucmd().arg("--time=birth").arg("date_test").succeeds();
|
||||
result.stdout_matches(&re_birth);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
|
|
|
@ -288,13 +288,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();
|
||||
scenario
|
||||
.pipe_in_fixture("stdin.log")
|
||||
.args(&["--pages=1:2", "-n", "-"])
|
||||
.run()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &now_time())],
|
||||
vec![(&"{last_modified_time}".to_string(), &now)],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -381,22 +382,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();
|
||||
new_ucmd!()
|
||||
.args(&["--pages=1:2", "-m", "-n", test_file_path, test_file_path1])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &now_time())],
|
||||
vec![(&"{last_modified_time}".to_string(), &now)],
|
||||
);
|
||||
|
||||
let now = now_time();
|
||||
new_ucmd!()
|
||||
.args(&["--pages=2:4", "-m", "-n", test_file_path, test_file_path1])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path1,
|
||||
vec![(&"{last_modified_time}".to_string(), &now_time())],
|
||||
vec![(&"{last_modified_time}".to_string(), &now)],
|
||||
);
|
||||
|
||||
let now = now_time();
|
||||
new_ucmd!()
|
||||
.args(&[
|
||||
"--pages=1:2",
|
||||
|
@ -411,7 +415,7 @@ fn test_with_mpr() {
|
|||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path2,
|
||||
vec![(&"{last_modified_time}".to_string(), &now_time())],
|
||||
vec![(&"{last_modified_time}".to_string(), &now)],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -507,11 +511,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();
|
||||
scenario
|
||||
.args(&["+1:2", "-J", "-m", test_file_1, test_file_2])
|
||||
.run()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &now_time())],
|
||||
vec![(&"{last_modified_time}".to_string(), &now)],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,19 @@
|
|||
use crate::common::util::*;
|
||||
|
||||
#[test]
|
||||
fn test_rejects_nan() {
|
||||
new_ucmd!().args(&["NaN"]).fails().stderr_only(
|
||||
"seq: invalid 'not-a-number' argument: 'NaN'\nTry 'seq --help' for more information.",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rejects_non_floats() {
|
||||
new_ucmd!().args(&["foo"]).fails().stderr_only(
|
||||
"seq: invalid floating point argument: 'foo'\nTry 'seq --help' for more information.",
|
||||
);
|
||||
}
|
||||
|
||||
// ---- Tests for the big integer based path ----
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -163,6 +163,14 @@ fn test_multiple_decimals_numeric() {
|
|||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_numeric_with_trailing_invalid_chars() {
|
||||
test_helper(
|
||||
"numeric_trailing_chars",
|
||||
&["-n", "--numeric-sort", "--sort=numeric"],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check_zero_terminated_failure() {
|
||||
new_ucmd!()
|
||||
|
|
|
@ -289,15 +289,19 @@ fn test_filter_command_fails() {
|
|||
#[test]
|
||||
fn test_split_lines_number() {
|
||||
// Test if stdout/stderr for '--lines' option is correct
|
||||
new_ucmd!()
|
||||
.args(&["--lines", "2"])
|
||||
.pipe_in("abcde")
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
at.touch("file");
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&["--lines", "2", "file"])
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.no_stdout();
|
||||
new_ucmd!()
|
||||
.args(&["--lines", "2fb"])
|
||||
.pipe_in("abcde")
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&["--lines", "2fb", "file"])
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stderr_only("split: invalid number of lines: ‘2fb’");
|
||||
|
|
|
@ -449,3 +449,20 @@ fn test_touch_mtime_dst_fails() {
|
|||
ucmd.args(&["-m", "-t", &s, file]).fails();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_touch_system_fails() {
|
||||
let (_at, mut ucmd) = at_and_ucmd!();
|
||||
let file = "/";
|
||||
ucmd.args(&[file])
|
||||
.fails()
|
||||
.stderr_contains("setting times of '/'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_touch_trailing_slash() {
|
||||
let (_at, mut ucmd) = at_and_ucmd!();
|
||||
let file = "no-file/";
|
||||
ucmd.args(&[file]).fails();
|
||||
}
|
||||
|
|
|
@ -50,14 +50,14 @@ macro_rules! new_ucmd {
|
|||
/// Convenience macro for acquiring a [`UCommand`] builder and a test path.
|
||||
///
|
||||
/// Returns a tuple containing the following:
|
||||
/// - an [`AsPath`] that points to a unique temporary test directory
|
||||
/// - an [`AtPath`] that points to a unique temporary test directory
|
||||
/// - a [`UCommand`] builder for invoking the binary to be tested
|
||||
///
|
||||
/// This macro is intended for quick, single-call tests. For more complex tests
|
||||
/// that require multiple invocations of the tested binary, see [`TestScenario`]
|
||||
///
|
||||
/// [`UCommand`]: crate::tests::common::util::UCommand
|
||||
/// [`AsPath`]: crate::tests::common::util::AsPath
|
||||
/// [`AtPath`]: crate::tests::common::util::AtPath
|
||||
/// [`TestScenario]: crate::tests::common::util::TestScenario
|
||||
#[macro_export]
|
||||
macro_rules! at_and_ucmd {
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
//spell-checker: ignore (linux) rlimit prlimit Rlim
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
#[cfg(target_os = "linux")]
|
||||
use rlimit::{prlimit, rlim};
|
||||
use std::env;
|
||||
#[cfg(not(windows))]
|
||||
use std::ffi::CString;
|
||||
|
@ -724,6 +729,8 @@ pub struct UCommand {
|
|||
stdout: Option<Stdio>,
|
||||
stderr: Option<Stdio>,
|
||||
bytes_into_stdin: Option<Vec<u8>>,
|
||||
#[cfg(target_os = "linux")]
|
||||
limits: Vec<(rlimit::Resource, rlim, rlim)>,
|
||||
}
|
||||
|
||||
impl UCommand {
|
||||
|
@ -758,6 +765,8 @@ impl UCommand {
|
|||
stdin: None,
|
||||
stdout: None,
|
||||
stderr: None,
|
||||
#[cfg(target_os = "linux")]
|
||||
limits: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -855,6 +864,17 @@ impl UCommand {
|
|||
self
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn with_limit(
|
||||
&mut self,
|
||||
resource: rlimit::Resource,
|
||||
soft_limit: rlim,
|
||||
hard_limit: rlim,
|
||||
) -> &mut Self {
|
||||
self.limits.push((resource, soft_limit, hard_limit));
|
||||
self
|
||||
}
|
||||
|
||||
/// Spawns the command, feeds the stdin if any, and returns the
|
||||
/// child process immediately.
|
||||
pub fn run_no_wait(&mut self) -> Child {
|
||||
|
@ -871,6 +891,17 @@ impl UCommand {
|
|||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
for &(resource, soft_limit, hard_limit) in &self.limits {
|
||||
prlimit(
|
||||
child.id() as i32,
|
||||
resource,
|
||||
Some((soft_limit, hard_limit)),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
if let Some(ref input) = self.bytes_into_stdin {
|
||||
let write_result = child
|
||||
.stdin
|
||||
|
|
0
tests/fixtures/cp/dir_with_10_files/0
vendored
Normal file
0
tests/fixtures/cp/dir_with_10_files/0
vendored
Normal file
0
tests/fixtures/cp/dir_with_10_files/1
vendored
Normal file
0
tests/fixtures/cp/dir_with_10_files/1
vendored
Normal file
0
tests/fixtures/cp/dir_with_10_files/2
vendored
Normal file
0
tests/fixtures/cp/dir_with_10_files/2
vendored
Normal file
0
tests/fixtures/cp/dir_with_10_files/3
vendored
Normal file
0
tests/fixtures/cp/dir_with_10_files/3
vendored
Normal file
0
tests/fixtures/cp/dir_with_10_files/4
vendored
Normal file
0
tests/fixtures/cp/dir_with_10_files/4
vendored
Normal file
0
tests/fixtures/cp/dir_with_10_files/5
vendored
Normal file
0
tests/fixtures/cp/dir_with_10_files/5
vendored
Normal file
0
tests/fixtures/cp/dir_with_10_files/6
vendored
Normal file
0
tests/fixtures/cp/dir_with_10_files/6
vendored
Normal file
0
tests/fixtures/cp/dir_with_10_files/7
vendored
Normal file
0
tests/fixtures/cp/dir_with_10_files/7
vendored
Normal file
0
tests/fixtures/cp/dir_with_10_files/8
vendored
Normal file
0
tests/fixtures/cp/dir_with_10_files/8
vendored
Normal file
0
tests/fixtures/cp/dir_with_10_files/9
vendored
Normal file
0
tests/fixtures/cp/dir_with_10_files/9
vendored
Normal file
|
@ -1,3 +1,4 @@
|
|||
K
|
||||
844K
|
||||
981K
|
||||
11M
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
K
|
||||
^ no match for key
|
||||
_
|
||||
844K
|
||||
____
|
||||
____
|
||||
|
|
1
tests/fixtures/sort/human_block_sizes.txt
vendored
1
tests/fixtures/sort/human_block_sizes.txt
vendored
|
@ -9,3 +9,4 @@
|
|||
844K
|
||||
981K
|
||||
13M
|
||||
K
|
5
tests/fixtures/sort/numeric_trailing_chars.expected
vendored
Normal file
5
tests/fixtures/sort/numeric_trailing_chars.expected
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
-.05,
|
||||
-x
|
||||
0.abc
|
||||
0foo
|
||||
100
|
15
tests/fixtures/sort/numeric_trailing_chars.expected.debug
vendored
Normal file
15
tests/fixtures/sort/numeric_trailing_chars.expected.debug
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
-.05,
|
||||
____
|
||||
_____
|
||||
-x
|
||||
^ no match for key
|
||||
__
|
||||
0.abc
|
||||
__
|
||||
_____
|
||||
0foo
|
||||
_
|
||||
____
|
||||
100
|
||||
___
|
||||
____
|
5
tests/fixtures/sort/numeric_trailing_chars.txt
vendored
Normal file
5
tests/fixtures/sort/numeric_trailing_chars.txt
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
0foo
|
||||
0.abc
|
||||
100
|
||||
-.05,
|
||||
-x
|
Loading…
Add table
Add a link
Reference in a new issue