mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-09-16 19:56:17 +00:00
Merge branch 'master' into fix_chroot_2687
This commit is contained in:
commit
3e985cb029
49 changed files with 632 additions and 335 deletions
|
@ -113,12 +113,18 @@ fn test_wrap_bad_arg() {
|
|||
|
||||
#[test]
|
||||
fn test_base32_extra_operand() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
|
||||
// Expect a failure when multiple files are specified.
|
||||
new_ucmd!()
|
||||
ts.ucmd()
|
||||
.arg("a.txt")
|
||||
.arg("b.txt")
|
||||
.fails()
|
||||
.stderr_only("base32: extra operand 'b.txt'\nTry 'base32 --help' for more information.");
|
||||
.stderr_only(format!(
|
||||
"{0}: extra operand 'b.txt'\nTry '{1} {0} --help' for more information.",
|
||||
ts.util_name,
|
||||
ts.bin_path.to_string_lossy()
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -95,12 +95,18 @@ fn test_wrap_bad_arg() {
|
|||
|
||||
#[test]
|
||||
fn test_base64_extra_operand() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
|
||||
// Expect a failure when multiple files are specified.
|
||||
new_ucmd!()
|
||||
ts.ucmd()
|
||||
.arg("a.txt")
|
||||
.arg("b.txt")
|
||||
.fails()
|
||||
.stderr_only("base64: extra operand 'b.txt'\nTry 'base64 --help' for more information.");
|
||||
.stderr_only(format!(
|
||||
"{0}: extra operand 'b.txt'\nTry '{1} {0} --help' for more information.",
|
||||
ts.util_name,
|
||||
ts.bin_path.to_string_lossy()
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -56,6 +56,12 @@ fn test_kill_list_all_signals() {
|
|||
.stdout_contains("HUP");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_kill_list_final_new_line() {
|
||||
let re = Regex::new("\\n$").unwrap();
|
||||
assert!(re.is_match(new_ucmd!().arg("-l").succeeds().stdout_str()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_kill_list_all_signals_as_table() {
|
||||
// Check for a few signals. Do not try to be comprehensive.
|
||||
|
|
|
@ -347,6 +347,7 @@ fn test_ls_long_format() {
|
|||
// A line of the output should be:
|
||||
// One of the characters -bcCdDlMnpPsStTx?
|
||||
// rwx, with - for missing permissions, thrice.
|
||||
// Zero or one "." for indicating a file with security context
|
||||
// A number, preceded by column whitespace, and followed by a single space.
|
||||
// A username, currently [^ ], followed by column whitespace, twice (or thrice for Hurd).
|
||||
// A number, followed by a single space.
|
||||
|
@ -356,13 +357,13 @@ fn test_ls_long_format() {
|
|||
// and followed by a single space.
|
||||
// Whatever comes after is irrelevant to this specific test.
|
||||
scene.ucmd().arg(arg).arg("test-long-dir").succeeds().stdout_matches(&Regex::new(
|
||||
r"\n[-bcCdDlMnpPsStTx?]([r-][w-][xt-]){3} +\d+ [^ ]+ +[^ ]+( +[^ ]+)? +\d+ [A-Z][a-z]{2} {0,2}\d{0,2} {0,2}[0-9:]+ "
|
||||
r"\n[-bcCdDlMnpPsStTx?]([r-][w-][xt-]){3}\.? +\d+ [^ ]+ +[^ ]+( +[^ ]+)? +\d+ [A-Z][a-z]{2} {0,2}\d{0,2} {0,2}[0-9:]+ "
|
||||
).unwrap());
|
||||
}
|
||||
|
||||
// This checks for the line with the .. entry. The uname and group should be digits.
|
||||
scene.ucmd().arg("-lan").arg("test-long-dir").succeeds().stdout_matches(&Regex::new(
|
||||
r"\nd([r-][w-][xt-]){3} +\d+ \d+ +\d+( +\d+)? +\d+ [A-Z][a-z]{2} {0,2}\d{0,2} {0,2}[0-9:]+ \.\."
|
||||
r"\nd([r-][w-][xt-]){3}\.? +\d+ \d+ +\d+( +\d+)? +\d+ [A-Z][a-z]{2} {0,2}\d{0,2} {0,2}[0-9:]+ \.\."
|
||||
).unwrap());
|
||||
}
|
||||
|
||||
|
@ -370,6 +371,7 @@ fn test_ls_long_format() {
|
|||
/// This test is mainly about coloring, but, the recursion, symlink `->` processing,
|
||||
/// and `.` and `..` being present in `-a` all need to work for the test to pass.
|
||||
/// This test does not really test anything provided by `-l` but the file names and symlinks.
|
||||
#[cfg(all(feature = "ln", feature = "mkdir", feature = "touch"))]
|
||||
#[test]
|
||||
#[cfg(all(feature = "ln", feature = "mkdir", feature = "touch"))]
|
||||
fn test_ls_long_symlink_color() {
|
||||
|
@ -636,55 +638,57 @@ fn test_ls_long_formats() {
|
|||
let at = &scene.fixtures;
|
||||
at.touch(&at.plus_as_string("test-long-formats"));
|
||||
|
||||
// Zero or one "." for indicating a file with security context
|
||||
|
||||
// Regex for three names, so all of author, group and owner
|
||||
let re_three = Regex::new(r"[xrw-]{9} \d ([-0-9_a-z]+ ){3}0").unwrap();
|
||||
let re_three = Regex::new(r"[xrw-]{9}\.? \d ([-0-9_a-z]+ ){3}0").unwrap();
|
||||
|
||||
#[cfg(unix)]
|
||||
let re_three_num = Regex::new(r"[xrw-]{9} \d (\d+ ){3}0").unwrap();
|
||||
let re_three_num = Regex::new(r"[xrw-]{9}\.? \d (\d+ ){3}0").unwrap();
|
||||
|
||||
// Regex for two names, either:
|
||||
// - group and owner
|
||||
// - author and owner
|
||||
// - author and group
|
||||
let re_two = Regex::new(r"[xrw-]{9} \d ([-0-9_a-z]+ ){2}0").unwrap();
|
||||
let re_two = Regex::new(r"[xrw-]{9}\.? \d ([-0-9_a-z]+ ){2}0").unwrap();
|
||||
|
||||
#[cfg(unix)]
|
||||
let re_two_num = Regex::new(r"[xrw-]{9} \d (\d+ ){2}0").unwrap();
|
||||
let re_two_num = Regex::new(r"[xrw-]{9}\.? \d (\d+ ){2}0").unwrap();
|
||||
|
||||
// Regex for one name: author, group or owner
|
||||
let re_one = Regex::new(r"[xrw-]{9} \d [-0-9_a-z]+ 0").unwrap();
|
||||
let re_one = Regex::new(r"[xrw-]{9}\.? \d [-0-9_a-z]+ 0").unwrap();
|
||||
|
||||
#[cfg(unix)]
|
||||
let re_one_num = Regex::new(r"[xrw-]{9} \d \d+ 0").unwrap();
|
||||
let re_one_num = Regex::new(r"[xrw-]{9}\.? \d \d+ 0").unwrap();
|
||||
|
||||
// Regex for no names
|
||||
let re_zero = Regex::new(r"[xrw-]{9} \d 0").unwrap();
|
||||
let re_zero = Regex::new(r"[xrw-]{9}\.? \d 0").unwrap();
|
||||
|
||||
let result = scene
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-l")
|
||||
.arg("--author")
|
||||
.arg("test-long-formats")
|
||||
.succeeds();
|
||||
assert!(re_three.is_match(result.stdout_str()));
|
||||
.succeeds()
|
||||
.stdout_matches(&re_three);
|
||||
|
||||
let result = scene
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-l1")
|
||||
.arg("--author")
|
||||
.arg("test-long-formats")
|
||||
.succeeds();
|
||||
assert!(re_three.is_match(result.stdout_str()));
|
||||
.succeeds()
|
||||
.stdout_matches(&re_three);
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let result = scene
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-n")
|
||||
.arg("--author")
|
||||
.arg("test-long-formats")
|
||||
.succeeds();
|
||||
assert!(re_three_num.is_match(result.stdout_str()));
|
||||
.succeeds()
|
||||
.stdout_matches(&re_three_num);
|
||||
}
|
||||
|
||||
for arg in &[
|
||||
|
@ -694,22 +698,22 @@ fn test_ls_long_formats() {
|
|||
"-lG --author", // only author and owner
|
||||
"-l --no-group --author", // only author and owner
|
||||
] {
|
||||
let result = scene
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&arg.split(' ').collect::<Vec<_>>())
|
||||
.arg("test-long-formats")
|
||||
.succeeds();
|
||||
assert!(re_two.is_match(result.stdout_str()));
|
||||
.succeeds()
|
||||
.stdout_matches(&re_two);
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let result = scene
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-n")
|
||||
.args(&arg.split(' ').collect::<Vec<_>>())
|
||||
.arg("test-long-formats")
|
||||
.succeeds();
|
||||
assert!(re_two_num.is_match(result.stdout_str()));
|
||||
.succeeds()
|
||||
.stdout_matches(&re_two_num);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -723,22 +727,22 @@ fn test_ls_long_formats() {
|
|||
"-l --no-group", // only owner
|
||||
"-gG --author", // only author
|
||||
] {
|
||||
let result = scene
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&arg.split(' ').collect::<Vec<_>>())
|
||||
.arg("test-long-formats")
|
||||
.succeeds();
|
||||
assert!(re_one.is_match(result.stdout_str()));
|
||||
.succeeds()
|
||||
.stdout_matches(&re_one);
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let result = scene
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-n")
|
||||
.args(&arg.split(' ').collect::<Vec<_>>())
|
||||
.arg("test-long-formats")
|
||||
.succeeds();
|
||||
assert!(re_one_num.is_match(result.stdout_str()));
|
||||
.succeeds()
|
||||
.stdout_matches(&re_one_num);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -755,22 +759,22 @@ fn test_ls_long_formats() {
|
|||
"-og1",
|
||||
"-og1l",
|
||||
] {
|
||||
let result = scene
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&arg.split(' ').collect::<Vec<_>>())
|
||||
.arg("test-long-formats")
|
||||
.succeeds();
|
||||
assert!(re_zero.is_match(result.stdout_str()));
|
||||
.succeeds()
|
||||
.stdout_matches(&re_zero);
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let result = scene
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-n")
|
||||
.args(&arg.split(' ').collect::<Vec<_>>())
|
||||
.arg("test-long-formats")
|
||||
.succeeds();
|
||||
assert!(re_zero.is_match(result.stdout_str()));
|
||||
.succeeds()
|
||||
.stdout_matches(&re_zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1248,7 +1252,7 @@ fn test_ls_inode() {
|
|||
at.touch(file);
|
||||
|
||||
let re_short = Regex::new(r" *(\d+) test_inode").unwrap();
|
||||
let re_long = Regex::new(r" *(\d+) [xrw-]{10} \d .+ test_inode").unwrap();
|
||||
let re_long = Regex::new(r" *(\d+) [xrw-]{10}\.? \d .+ test_inode").unwrap();
|
||||
|
||||
let result = scene.ucmd().arg("test_inode").arg("-i").succeeds();
|
||||
assert!(re_short.is_match(result.stdout_str()));
|
||||
|
@ -2272,3 +2276,68 @@ fn test_ls_dangling_symlinks() {
|
|||
.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" });
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "feat_selinux")]
|
||||
fn test_ls_context1() {
|
||||
use selinux::{self, KernelSupport};
|
||||
if selinux::kernel_support() == KernelSupport::Unsupported {
|
||||
println!("test skipped: Kernel has no support for SElinux context",);
|
||||
return;
|
||||
}
|
||||
|
||||
let file = "test_ls_context_file";
|
||||
let expected = format!("unconfined_u:object_r:user_tmp_t:s0 {}\n", file);
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.touch(file);
|
||||
ucmd.args(&["-Z", file]).succeeds().stdout_is(expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "feat_selinux")]
|
||||
fn test_ls_context2() {
|
||||
use selinux::{self, KernelSupport};
|
||||
if selinux::kernel_support() == KernelSupport::Unsupported {
|
||||
println!("test skipped: Kernel has no support for SElinux context",);
|
||||
return;
|
||||
}
|
||||
let ts = TestScenario::new(util_name!());
|
||||
for c_flag in &["-Z", "--context"] {
|
||||
ts.ucmd()
|
||||
.args(&[c_flag, &"/"])
|
||||
.succeeds()
|
||||
.stdout_only(unwrap_or_return!(expected_result(&ts, &[c_flag, &"/"])).stdout_str());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "feat_selinux")]
|
||||
fn test_ls_context_format() {
|
||||
use selinux::{self, KernelSupport};
|
||||
if selinux::kernel_support() == KernelSupport::Unsupported {
|
||||
println!("test skipped: Kernel has no support for SElinux context",);
|
||||
return;
|
||||
}
|
||||
let ts = TestScenario::new(util_name!());
|
||||
// NOTE:
|
||||
// --format=long/verbose matches the output of GNU's ls for --context
|
||||
// except for the size count which may differ to the size count reported by GNU's ls.
|
||||
for word in &[
|
||||
"across",
|
||||
"commas",
|
||||
"horizontal",
|
||||
// "long",
|
||||
"single-column",
|
||||
// "verbose",
|
||||
"vertical",
|
||||
] {
|
||||
let format = format!("--format={}", word);
|
||||
ts.ucmd()
|
||||
.args(&[&"-Z", &format.as_str(), &"/"])
|
||||
.succeeds()
|
||||
.stdout_only(
|
||||
unwrap_or_return!(expected_result(&ts, &[&"-Z", &format.as_str(), &"/"]))
|
||||
.stdout_str(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,69 @@
|
|||
use crate::common::util::*;
|
||||
use std::io::Read;
|
||||
|
||||
#[test]
|
||||
fn test_hex_rejects_sign_after_identifier() {
|
||||
new_ucmd!()
|
||||
.args(&["0x-123ABC"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("invalid hexadecimal argument: '0x-123ABC'")
|
||||
.stderr_contains("for more information.");
|
||||
new_ucmd!()
|
||||
.args(&["0x+123ABC"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("invalid hexadecimal argument: '0x+123ABC'")
|
||||
.stderr_contains("for more information.");
|
||||
new_ucmd!()
|
||||
.args(&["-0x-123ABC"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("invalid hexadecimal argument: '-0x-123ABC'")
|
||||
.stderr_contains("for more information.");
|
||||
new_ucmd!()
|
||||
.args(&["-0x+123ABC"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("invalid hexadecimal argument: '-0x+123ABC'")
|
||||
.stderr_contains("for more information.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hex_lowercase_uppercase() {
|
||||
new_ucmd!()
|
||||
.args(&["0xa", "0xA"])
|
||||
.succeeds()
|
||||
.stdout_is("10\n");
|
||||
new_ucmd!()
|
||||
.args(&["0Xa", "0XA"])
|
||||
.succeeds()
|
||||
.stdout_is("10\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hex_big_number() {
|
||||
new_ucmd!()
|
||||
.args(&[
|
||||
"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
|
||||
"0x100000000000000000000000000000000",
|
||||
])
|
||||
.succeeds()
|
||||
.stdout_is(
|
||||
"340282366920938463463374607431768211455\n340282366920938463463374607431768211456\n",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hex_identifier_in_wrong_place() {
|
||||
new_ucmd!()
|
||||
.args(&["1234ABCD0x"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("invalid hexadecimal argument: '1234ABCD0x'")
|
||||
.stderr_contains("for more information.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rejects_nan() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
|
|
|
@ -1169,7 +1169,7 @@ pub fn check_coreutil_version(
|
|||
if s.contains(&format!("(GNU coreutils) {}", version_expected)) {
|
||||
Ok(format!("{}: {}", UUTILS_INFO, 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_found = parse_coreutil_version(s);
|
||||
let version_expected = version_expected.parse::<f32>().unwrap_or_default();
|
||||
if version_found > version_expected {
|
||||
Ok(format!("{}: version for the reference coreutil '{}' is higher than expected; expected: {}, found: {}", UUTILS_INFO, util_name, version_expected, version_found))
|
||||
|
@ -1182,6 +1182,20 @@ pub fn check_coreutil_version(
|
|||
)
|
||||
}
|
||||
|
||||
// simple heuristic to parse the coreutils SemVer string, e.g. "id (GNU coreutils) 8.32.263-0475"
|
||||
fn parse_coreutil_version(version_string: &str) -> f32 {
|
||||
version_string
|
||||
.split_whitespace()
|
||||
.last()
|
||||
.unwrap()
|
||||
.split('.')
|
||||
.take(2)
|
||||
.collect::<Vec<_>>()
|
||||
.join(".")
|
||||
.parse::<f32>()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// This runs the GNU coreutils `util_name` binary in `$PATH` in order to
|
||||
/// dynamically gather reference values on the system.
|
||||
/// If the `util_name` in `$PATH` doesn't include a coreutils version string,
|
||||
|
@ -1474,6 +1488,36 @@ mod tests {
|
|||
res.normalized_newlines_stdout_is("A\r\nB\nC\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_parse_coreutil_version() {
|
||||
use std::assert_eq;
|
||||
assert_eq!(
|
||||
parse_coreutil_version("id (GNU coreutils) 9.0.123-0123").to_string(),
|
||||
"9"
|
||||
);
|
||||
assert_eq!(
|
||||
parse_coreutil_version("id (GNU coreutils) 8.32.263-0475").to_string(),
|
||||
"8.32"
|
||||
);
|
||||
assert_eq!(
|
||||
parse_coreutil_version("id (GNU coreutils) 8.25.123-0123").to_string(),
|
||||
"8.25"
|
||||
);
|
||||
assert_eq!(
|
||||
parse_coreutil_version("id (GNU coreutils) 9.0").to_string(),
|
||||
"9"
|
||||
);
|
||||
assert_eq!(
|
||||
parse_coreutil_version("id (GNU coreutils) 8.32").to_string(),
|
||||
"8.32"
|
||||
);
|
||||
assert_eq!(
|
||||
parse_coreutil_version("id (GNU coreutils) 8.25").to_string(),
|
||||
"8.25"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_check_coreutil_version() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue