2015-11-16 05:25:01 +00:00
|
|
|
|
//
|
|
|
|
|
// This file is part of the uutils coreutils package.
|
|
|
|
|
//
|
|
|
|
|
// (c) mahkoh (ju.orth [at] gmail [dot] com)
|
2021-04-23 00:29:04 +00:00
|
|
|
|
// (c) Daniel Rocco <drocco@gmail.com>
|
2015-11-16 05:25:01 +00:00
|
|
|
|
//
|
|
|
|
|
// For the full copyright and license information, please view the LICENSE
|
|
|
|
|
// file that was distributed with this source code.
|
|
|
|
|
//
|
|
|
|
|
|
2021-06-05 03:16:48 +00:00
|
|
|
|
// spell-checker:ignore (words) egid euid pseudofloat
|
2021-05-30 05:10:54 +00:00
|
|
|
|
|
2020-05-25 17:05:26 +00:00
|
|
|
|
use crate::common::util::*;
|
2015-11-16 05:25:01 +00:00
|
|
|
|
|
2021-04-23 00:29:04 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_empty_test_equivalent_to_false() {
|
|
|
|
|
new_ucmd!().run().status_code(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_empty_string_is_false() {
|
|
|
|
|
new_ucmd!().arg("").run().status_code(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_solo_not() {
|
|
|
|
|
new_ucmd!().arg("!").succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_solo_and_or_or_is_a_literal() {
|
|
|
|
|
// /bin/test '' -a '' => 1; so test(1) must interpret `-a` by itself as
|
|
|
|
|
// a literal string
|
|
|
|
|
new_ucmd!().arg("-a").succeeds();
|
|
|
|
|
new_ucmd!().arg("-o").succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-25 00:49:24 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_some_literals() {
|
|
|
|
|
let scenario = TestScenario::new(util_name!());
|
|
|
|
|
let tests = [
|
|
|
|
|
"a string",
|
|
|
|
|
"(",
|
|
|
|
|
")",
|
|
|
|
|
"-",
|
|
|
|
|
"--",
|
|
|
|
|
"-0",
|
|
|
|
|
"-f",
|
|
|
|
|
"--help",
|
|
|
|
|
"--version",
|
|
|
|
|
"-eq",
|
|
|
|
|
"-lt",
|
|
|
|
|
"-ef",
|
|
|
|
|
"[",
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for test in &tests {
|
|
|
|
|
scenario.ucmd().arg(test).succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// run the inverse of all these tests
|
|
|
|
|
for test in &tests {
|
|
|
|
|
scenario.ucmd().arg("!").arg(test).run().status_code(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-23 00:29:04 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_double_not_is_false() {
|
|
|
|
|
new_ucmd!().args(&["!", "!"]).run().status_code(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_and_not_is_false() {
|
|
|
|
|
new_ucmd!().args(&["-a", "!"]).run().status_code(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_not_and_is_false() {
|
|
|
|
|
// `-a` is a literal here & has nonzero length
|
|
|
|
|
new_ucmd!().args(&["!", "-a"]).run().status_code(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_not_and_not_succeeds() {
|
|
|
|
|
new_ucmd!().args(&["!", "-a", "!"]).succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_simple_or() {
|
|
|
|
|
new_ucmd!().args(&["foo", "-o", ""]).succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_negated_or() {
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["!", "foo", "-o", "bar"])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(1);
|
|
|
|
|
new_ucmd!().args(&["foo", "-o", "!", "bar"]).succeeds();
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["!", "foo", "-o", "!", "bar"])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2021-05-30 05:10:54 +00:00
|
|
|
|
fn test_string_length_of_nothing() {
|
2021-04-23 00:29:04 +00:00
|
|
|
|
// odd but matches GNU, which must interpret -n as a literal here
|
|
|
|
|
new_ucmd!().arg("-n").succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2021-05-30 05:10:54 +00:00
|
|
|
|
fn test_string_length_of_empty() {
|
2021-04-23 00:29:04 +00:00
|
|
|
|
new_ucmd!().args(&["-n", ""]).run().status_code(1);
|
|
|
|
|
|
|
|
|
|
// STRING equivalent to -n STRING
|
|
|
|
|
new_ucmd!().arg("").run().status_code(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_nothing_is_empty() {
|
|
|
|
|
// -z is a literal here and has nonzero length
|
|
|
|
|
new_ucmd!().arg("-z").succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_zero_len_of_empty() {
|
|
|
|
|
new_ucmd!().args(&["-z", ""]).succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_zero_len_equals_zero_len() {
|
|
|
|
|
new_ucmd!().args(&["", "=", ""]).succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_zero_len_not_equals_zero_len_is_false() {
|
|
|
|
|
new_ucmd!().args(&["", "!=", ""]).run().status_code(1);
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-06 12:28:54 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_double_equal_is_string_comparison_op() {
|
|
|
|
|
// undocumented but part of the GNU test suite
|
|
|
|
|
new_ucmd!().args(&["t", "==", "t"]).succeeds();
|
|
|
|
|
new_ucmd!().args(&["t", "==", "f"]).run().status_code(1);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-23 00:29:04 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_string_comparison() {
|
|
|
|
|
let scenario = TestScenario::new(util_name!());
|
|
|
|
|
let tests = [
|
|
|
|
|
["foo", "!=", "bar"],
|
|
|
|
|
["contained\nnewline", "=", "contained\nnewline"],
|
|
|
|
|
["(", "=", "("],
|
|
|
|
|
["(", "!=", ")"],
|
2021-07-25 00:49:24 +00:00
|
|
|
|
["(", "!=", "="],
|
2021-04-23 00:29:04 +00:00
|
|
|
|
["!", "=", "!"],
|
2021-05-06 12:28:54 +00:00
|
|
|
|
["=", "=", "="],
|
2021-04-23 00:29:04 +00:00
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for test in &tests {
|
|
|
|
|
scenario.ucmd().args(&test[..]).succeeds();
|
|
|
|
|
}
|
2021-05-06 12:28:54 +00:00
|
|
|
|
|
|
|
|
|
// run the inverse of all these tests
|
|
|
|
|
for test in &tests {
|
|
|
|
|
scenario
|
|
|
|
|
.ucmd()
|
|
|
|
|
.arg("!")
|
|
|
|
|
.args(&test[..])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(1);
|
|
|
|
|
}
|
2021-04-23 00:29:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[ignore = "fixme: error reporting"]
|
|
|
|
|
fn test_dangling_string_comparison_is_error() {
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["missing_something", "="])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(2)
|
2021-06-21 22:22:30 +00:00
|
|
|
|
.stderr_is("test: missing argument after '='");
|
2021-04-23 00:29:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2021-05-30 05:10:54 +00:00
|
|
|
|
fn test_string_operator_is_literal_after_bang() {
|
2021-04-23 00:29:04 +00:00
|
|
|
|
let scenario = TestScenario::new(util_name!());
|
|
|
|
|
let tests = [
|
|
|
|
|
["!", "="],
|
|
|
|
|
["!", "!="],
|
|
|
|
|
["!", "-eq"],
|
|
|
|
|
["!", "-ne"],
|
|
|
|
|
["!", "-lt"],
|
|
|
|
|
["!", "-le"],
|
|
|
|
|
["!", "-gt"],
|
|
|
|
|
["!", "-ge"],
|
|
|
|
|
["!", "-ef"],
|
|
|
|
|
["!", "-nt"],
|
|
|
|
|
["!", "-ot"],
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for test in &tests {
|
|
|
|
|
scenario.ucmd().args(&test[..]).run().status_code(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_a_bunch_of_not() {
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["!", "", "!=", "", "-a", "!", "", "!=", ""])
|
|
|
|
|
.succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_pseudofloat_equal() {
|
2021-07-25 00:49:24 +00:00
|
|
|
|
// string comparison; test(1) doesn't support comparison of actual floats
|
2021-04-23 00:29:04 +00:00
|
|
|
|
new_ucmd!().args(&["123.45", "=", "123.45"]).succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_pseudofloat_not_equal() {
|
2021-07-25 00:49:24 +00:00
|
|
|
|
// string comparison; test(1) doesn't support comparison of actual floats
|
2021-04-23 00:29:04 +00:00
|
|
|
|
new_ucmd!().args(&["123.45", "!=", "123.450"]).succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_negative_arg_is_a_string() {
|
|
|
|
|
new_ucmd!().arg("-12345").succeeds();
|
2021-05-31 03:55:28 +00:00
|
|
|
|
new_ucmd!().arg("--qwert").succeeds(); // spell-checker:disable-line
|
2021-04-23 00:29:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_some_int_compares() {
|
|
|
|
|
let scenario = TestScenario::new(util_name!());
|
|
|
|
|
|
|
|
|
|
let tests = [
|
|
|
|
|
["0", "-eq", "0"],
|
|
|
|
|
["0", "-ne", "1"],
|
|
|
|
|
["421", "-lt", "3720"],
|
|
|
|
|
["0", "-le", "0"],
|
|
|
|
|
["11", "-gt", "10"],
|
|
|
|
|
["1024", "-ge", "512"],
|
|
|
|
|
["9223372036854775806", "-le", "9223372036854775807"],
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for test in &tests {
|
|
|
|
|
scenario.ucmd().args(&test[..]).succeeds();
|
|
|
|
|
}
|
2021-07-25 00:49:24 +00:00
|
|
|
|
|
|
|
|
|
// run the inverse of all these tests
|
|
|
|
|
for test in &tests {
|
|
|
|
|
scenario
|
|
|
|
|
.ucmd()
|
|
|
|
|
.arg("!")
|
|
|
|
|
.args(&test[..])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(1);
|
|
|
|
|
}
|
2021-04-23 00:29:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[ignore = "fixme: evaluation error (code 1); GNU returns 0"]
|
|
|
|
|
fn test_values_greater_than_i64_allowed() {
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["9223372036854775808", "-gt", "0"])
|
|
|
|
|
.succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_negative_int_compare() {
|
|
|
|
|
let scenario = TestScenario::new(util_name!());
|
|
|
|
|
|
|
|
|
|
let tests = [
|
|
|
|
|
["-1", "-eq", "-1"],
|
|
|
|
|
["-1", "-ne", "-2"],
|
|
|
|
|
["-3720", "-lt", "-421"],
|
|
|
|
|
["-10", "-le", "-10"],
|
|
|
|
|
["-21", "-gt", "-22"],
|
|
|
|
|
["-128", "-ge", "-256"],
|
|
|
|
|
["-9223372036854775808", "-le", "-9223372036854775807"],
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for test in &tests {
|
|
|
|
|
scenario.ucmd().args(&test[..]).succeeds();
|
|
|
|
|
}
|
2021-07-25 00:49:24 +00:00
|
|
|
|
|
|
|
|
|
// run the inverse of all these tests
|
|
|
|
|
for test in &tests {
|
|
|
|
|
scenario
|
|
|
|
|
.ucmd()
|
|
|
|
|
.arg("!")
|
|
|
|
|
.args(&test[..])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(1);
|
|
|
|
|
}
|
2021-04-23 00:29:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_float_inequality_is_error() {
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["123.45", "-ge", "6"])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(2)
|
2021-06-21 22:22:30 +00:00
|
|
|
|
.stderr_is("test: invalid integer '123.45'");
|
2021-04-23 00:29:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-27 01:27:29 +00:00
|
|
|
|
#[test]
|
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
|
fn test_invalid_utf8_integer_compare() {
|
|
|
|
|
use std::ffi::OsStr;
|
|
|
|
|
use std::os::unix::ffi::OsStrExt;
|
|
|
|
|
|
|
|
|
|
let source = [0x66, 0x6f, 0x80, 0x6f];
|
|
|
|
|
let arg = OsStr::from_bytes(&source[..]);
|
|
|
|
|
|
|
|
|
|
let mut cmd = new_ucmd!();
|
|
|
|
|
cmd.arg("123").arg("-ne");
|
|
|
|
|
cmd.raw.arg(arg);
|
|
|
|
|
|
|
|
|
|
cmd.run()
|
|
|
|
|
.status_code(2)
|
2021-09-03 14:10:39 +00:00
|
|
|
|
.stderr_is("test: invalid integer $'fo\\x80o'");
|
2021-04-27 01:27:29 +00:00
|
|
|
|
|
|
|
|
|
let mut cmd = new_ucmd!();
|
|
|
|
|
cmd.raw.arg(arg);
|
|
|
|
|
cmd.arg("-eq").arg("456");
|
|
|
|
|
|
|
|
|
|
cmd.run()
|
|
|
|
|
.status_code(2)
|
2021-09-03 14:10:39 +00:00
|
|
|
|
.stderr_is("test: invalid integer $'fo\\x80o'");
|
2021-04-27 01:27:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-23 00:29:04 +00:00
|
|
|
|
#[test]
|
|
|
|
|
#[ignore = "fixme: parse/evaluation error (code 2); GNU returns 1"]
|
|
|
|
|
fn test_file_is_itself() {
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["regular_file", "-ef", "regular_file"])
|
|
|
|
|
.succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[ignore = "fixme: parse/evaluation error (code 2); GNU returns 1"]
|
|
|
|
|
fn test_file_is_newer_than_and_older_than_itself() {
|
|
|
|
|
// odd but matches GNU
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["regular_file", "-nt", "regular_file"])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(1);
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["regular_file", "-ot", "regular_file"])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[ignore = "todo: implement these"]
|
|
|
|
|
fn test_newer_file() {
|
|
|
|
|
let scenario = TestScenario::new(util_name!());
|
|
|
|
|
|
|
|
|
|
scenario.cmd("touch").arg("newer_file").succeeds();
|
|
|
|
|
scenario
|
|
|
|
|
.cmd("touch")
|
|
|
|
|
.args(&["-m", "-d", "last Thursday", "regular_file"])
|
|
|
|
|
.succeeds();
|
|
|
|
|
|
|
|
|
|
scenario
|
|
|
|
|
.ucmd()
|
|
|
|
|
.args(&["newer_file", "-nt", "regular_file"])
|
|
|
|
|
.succeeds();
|
|
|
|
|
scenario
|
|
|
|
|
.ucmd()
|
|
|
|
|
.args(&["regular_file", "-ot", "newer_file"])
|
|
|
|
|
.succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_file_exists() {
|
|
|
|
|
new_ucmd!().args(&["-e", "regular_file"]).succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_nonexistent_file_does_not_exist() {
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["-e", "nonexistent_file"])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_nonexistent_file_is_not_regular() {
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["-f", "nonexistent_file"])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_file_exists_and_is_regular() {
|
|
|
|
|
new_ucmd!().args(&["-f", "regular_file"]).succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[cfg(not(windows))] // FIXME: implement on Windows
|
|
|
|
|
fn test_file_is_readable() {
|
|
|
|
|
new_ucmd!().args(&["-r", "regular_file"]).succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[cfg(not(windows))] // FIXME: implement on Windows
|
|
|
|
|
fn test_file_is_not_readable() {
|
|
|
|
|
let scenario = TestScenario::new(util_name!());
|
|
|
|
|
let mut ucmd = scenario.ucmd();
|
|
|
|
|
let mut chmod = scenario.cmd("chmod");
|
|
|
|
|
|
|
|
|
|
scenario.fixtures.touch("crypto_file");
|
|
|
|
|
chmod.args(&["u-r", "crypto_file"]).succeeds();
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["!", "-r", "crypto_file"]).succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[cfg(not(windows))] // FIXME: implement on Windows
|
|
|
|
|
fn test_file_is_writable() {
|
|
|
|
|
new_ucmd!().args(&["-w", "regular_file"]).succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[cfg(not(windows))] // FIXME: implement on Windows
|
|
|
|
|
fn test_file_is_not_writable() {
|
|
|
|
|
let scenario = TestScenario::new(util_name!());
|
|
|
|
|
let mut ucmd = scenario.ucmd();
|
|
|
|
|
let mut chmod = scenario.cmd("chmod");
|
|
|
|
|
|
|
|
|
|
scenario.fixtures.touch("immutable_file");
|
|
|
|
|
chmod.args(&["u-w", "immutable_file"]).succeeds();
|
|
|
|
|
|
|
|
|
|
ucmd.args(&["!", "-w", "immutable_file"]).succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_file_is_not_executable() {
|
|
|
|
|
new_ucmd!().args(&["!", "-x", "regular_file"]).succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[cfg(not(windows))] // FIXME: implement on Windows
|
|
|
|
|
fn test_file_is_executable() {
|
|
|
|
|
let scenario = TestScenario::new(util_name!());
|
|
|
|
|
let mut chmod = scenario.cmd("chmod");
|
|
|
|
|
|
|
|
|
|
chmod.args(&["u+x", "regular_file"]).succeeds();
|
|
|
|
|
|
|
|
|
|
scenario.ucmd().args(&["-x", "regular_file"]).succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_is_not_empty() {
|
|
|
|
|
new_ucmd!().args(&["-s", "non_empty_file"]).succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_nonexistent_file_size_test_is_false() {
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["-s", "nonexistent_file"])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_not_is_not_empty() {
|
|
|
|
|
new_ucmd!().args(&["!", "-s", "regular_file"]).succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
|
fn test_symlink_is_symlink() {
|
|
|
|
|
let scenario = TestScenario::new(util_name!());
|
2021-05-26 11:07:04 +00:00
|
|
|
|
let at = &scenario.fixtures;
|
2021-04-23 00:29:04 +00:00
|
|
|
|
|
2021-05-26 11:07:04 +00:00
|
|
|
|
at.symlink_file("regular_file", "symlink");
|
2021-04-23 00:29:04 +00:00
|
|
|
|
|
|
|
|
|
// FIXME: implement on Windows
|
|
|
|
|
scenario.ucmd().args(&["-h", "symlink"]).succeeds();
|
|
|
|
|
scenario.ucmd().args(&["-L", "symlink"]).succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_file_is_not_symlink() {
|
|
|
|
|
let scenario = TestScenario::new(util_name!());
|
|
|
|
|
|
|
|
|
|
scenario
|
|
|
|
|
.ucmd()
|
|
|
|
|
.args(&["!", "-h", "regular_file"])
|
|
|
|
|
.succeeds();
|
|
|
|
|
scenario
|
|
|
|
|
.ucmd()
|
|
|
|
|
.args(&["!", "-L", "regular_file"])
|
|
|
|
|
.succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_nonexistent_file_is_not_symlink() {
|
|
|
|
|
let scenario = TestScenario::new(util_name!());
|
|
|
|
|
|
|
|
|
|
scenario
|
|
|
|
|
.ucmd()
|
|
|
|
|
.args(&["!", "-h", "nonexistent_file"])
|
|
|
|
|
.succeeds();
|
|
|
|
|
scenario
|
|
|
|
|
.ucmd()
|
|
|
|
|
.args(&["!", "-L", "nonexistent_file"])
|
|
|
|
|
.succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-17 18:15:26 +00:00
|
|
|
|
#[test]
|
2021-08-24 06:53:20 +00:00
|
|
|
|
// FixME: freebsd fails with 'chmod: sticky_file: Inappropriate file type or format'
|
|
|
|
|
// Windows has no concept of sticky bit
|
|
|
|
|
#[cfg(not(any(windows, target_os = "freebsd")))]
|
2021-06-17 18:15:26 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-25 00:49:24 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_solo_empty_parenthetical_is_error() {
|
|
|
|
|
new_ucmd!().args(&["(", ")"]).run().status_code(2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_parenthesized_literal() {
|
|
|
|
|
let scenario = TestScenario::new(util_name!());
|
|
|
|
|
let tests = [
|
|
|
|
|
"a string",
|
|
|
|
|
"(",
|
|
|
|
|
")",
|
|
|
|
|
"-",
|
|
|
|
|
"--",
|
|
|
|
|
"-0",
|
|
|
|
|
"-f",
|
|
|
|
|
"--help",
|
|
|
|
|
"--version",
|
|
|
|
|
"-e",
|
|
|
|
|
"-t",
|
|
|
|
|
"!",
|
|
|
|
|
"-n",
|
|
|
|
|
"-z",
|
|
|
|
|
"[",
|
|
|
|
|
"-a",
|
|
|
|
|
"-o",
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for test in &tests {
|
|
|
|
|
scenario.ucmd().arg("(").arg(test).arg(")").succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// run the inverse of all these tests
|
|
|
|
|
for test in &tests {
|
|
|
|
|
scenario
|
|
|
|
|
.ucmd()
|
|
|
|
|
.arg("!")
|
|
|
|
|
.arg("(")
|
|
|
|
|
.arg(test)
|
|
|
|
|
.arg(")")
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_parenthesized_op_compares_literal_parenthesis() {
|
|
|
|
|
// ensure we aren’t treating this case as “string length of literal equal
|
|
|
|
|
// sign”
|
|
|
|
|
new_ucmd!().args(&["(", "=", ")"]).run().status_code(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_parenthesized_string_comparison() {
|
|
|
|
|
let scenario = TestScenario::new(util_name!());
|
|
|
|
|
let tests = [
|
|
|
|
|
["(", "foo", "!=", "bar", ")"],
|
|
|
|
|
["(", "contained\nnewline", "=", "contained\nnewline", ")"],
|
|
|
|
|
["(", "(", "=", "(", ")"],
|
|
|
|
|
["(", "(", "!=", ")", ")"],
|
|
|
|
|
["(", "!", "=", "!", ")"],
|
|
|
|
|
["(", "=", "=", "=", ")"],
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for test in &tests {
|
|
|
|
|
scenario.ucmd().args(&test[..]).succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// run the inverse of all these tests
|
|
|
|
|
for test in &tests {
|
|
|
|
|
scenario
|
|
|
|
|
.ucmd()
|
|
|
|
|
.arg("!")
|
|
|
|
|
.args(&test[..])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_parenthesized_right_parenthesis_as_literal() {
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["(", "-f", ")", ")"])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(1);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-05 03:16:48 +00:00
|
|
|
|
#[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();
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-16 05:25:01 +00:00
|
|
|
|
#[test]
|
2021-05-30 05:10:54 +00:00
|
|
|
|
fn test_op_precedence_and_or_1() {
|
2020-04-13 18:36:03 +00:00
|
|
|
|
new_ucmd!().args(&[" ", "-o", "", "-a", ""]).succeeds();
|
2015-11-16 05:25:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-27 01:27:29 +00:00
|
|
|
|
#[test]
|
2021-05-30 05:10:54 +00:00
|
|
|
|
fn test_op_precedence_and_or_1_overridden_by_parentheses() {
|
2021-04-27 01:27:29 +00:00
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["(", " ", "-o", "", ")", "-a", ""])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(1);
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-16 05:25:01 +00:00
|
|
|
|
#[test]
|
2021-05-30 05:10:54 +00:00
|
|
|
|
fn test_op_precedence_and_or_2() {
|
2016-08-23 11:52:43 +00:00
|
|
|
|
new_ucmd!()
|
2016-08-13 21:59:21 +00:00
|
|
|
|
.args(&["", "-a", "", "-o", " ", "-a", " "])
|
|
|
|
|
.succeeds();
|
2015-11-16 05:25:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-27 01:27:29 +00:00
|
|
|
|
#[test]
|
2021-05-30 05:10:54 +00:00
|
|
|
|
fn test_op_precedence_and_or_2_overridden_by_parentheses() {
|
2021-04-27 01:27:29 +00:00
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["", "-a", "(", "", "-o", " ", ")", "-a", " "])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(1);
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-06 12:28:54 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_negated_boolean_precedence() {
|
|
|
|
|
let scenario = TestScenario::new(util_name!());
|
|
|
|
|
|
|
|
|
|
let tests = [
|
|
|
|
|
vec!["!", "(", "foo", ")", "-o", "bar"],
|
|
|
|
|
vec!["!", "", "-o", "", "-a", ""],
|
|
|
|
|
vec!["!", "(", "", "-a", "", ")", "-o", ""],
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for test in &tests {
|
|
|
|
|
scenario.ucmd().args(&test[..]).succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let negative_tests = [
|
|
|
|
|
vec!["!", "-n", "", "-a", ""],
|
|
|
|
|
vec!["", "-a", "", "-o", ""],
|
|
|
|
|
vec!["!", "", "-a", "", "-o", ""],
|
|
|
|
|
vec!["!", "(", "", "-a", "", ")", "-a", ""],
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for test in &negative_tests {
|
|
|
|
|
scenario.ucmd().args(&test[..]).run().status_code(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2021-05-30 05:10:54 +00:00
|
|
|
|
fn test_bang_bool_op_precedence() {
|
2021-05-06 12:28:54 +00:00
|
|
|
|
// For a Boolean combination of two literals, bang inverts the entire expression
|
|
|
|
|
new_ucmd!().args(&["!", "", "-a", ""]).succeeds();
|
|
|
|
|
new_ucmd!().args(&["!", "", "-o", ""]).succeeds();
|
|
|
|
|
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["!", "a value", "-o", "another value"])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(1);
|
|
|
|
|
|
|
|
|
|
// Introducing a UOP — even one that is equivalent to a bare string — causes
|
|
|
|
|
// bang to invert only the first term
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["!", "-n", "", "-a", ""])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(1);
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["!", "", "-a", "-n", ""])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(1);
|
|
|
|
|
|
|
|
|
|
// for compound Boolean expressions, bang inverts the _next_ expression
|
|
|
|
|
// only, not the entire compound expression
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["!", "", "-a", "", "-a", ""])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(1);
|
|
|
|
|
|
|
|
|
|
// parentheses can override this
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["!", "(", "", "-a", "", "-a", "", ")"])
|
|
|
|
|
.succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2021-05-30 05:10:54 +00:00
|
|
|
|
fn test_inverted_parenthetical_bool_op_precedence() {
|
2021-05-06 12:28:54 +00:00
|
|
|
|
// For a Boolean combination of two literals, bang inverts the entire expression
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["!", "a value", "-o", "another value"])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(1);
|
|
|
|
|
|
|
|
|
|
// only the parenthetical is inverted, not the entire expression
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["!", "(", "a value", ")", "-o", "another value"])
|
|
|
|
|
.succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-27 01:27:29 +00:00
|
|
|
|
#[test]
|
|
|
|
|
#[ignore = "fixme: error reporting"]
|
|
|
|
|
fn test_dangling_parenthesis() {
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["(", "(", "a", "!=", "b", ")", "-o", "-n", "c"])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(2);
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["(", "(", "a", "!=", "b", ")", "-o", "-n", "c", ")"])
|
|
|
|
|
.succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_complicated_parenthesized_expression() {
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&[
|
|
|
|
|
"(", "(", "!", "(", "a", "=", "b", ")", "-o", "c", "=", "d", ")", "-a", "(", "q", "!=",
|
|
|
|
|
"r", ")", ")",
|
|
|
|
|
])
|
|
|
|
|
.succeeds();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_erroneous_parenthesized_expression() {
|
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["a", "!=", "(", "b", "-a", "b", ")", "!=", "c"])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(2)
|
2021-06-21 22:22:30 +00:00
|
|
|
|
.stderr_is("test: extra argument 'b'");
|
2021-04-27 01:27:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-16 05:25:01 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_or_as_filename() {
|
2021-04-23 00:29:04 +00:00
|
|
|
|
new_ucmd!()
|
|
|
|
|
.args(&["x", "-a", "-z", "-o"])
|
|
|
|
|
.run()
|
|
|
|
|
.status_code(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[ignore = "GNU considers this an error"]
|
2021-05-30 05:10:54 +00:00
|
|
|
|
fn test_string_length_and_nothing() {
|
2021-04-23 00:29:04 +00:00
|
|
|
|
new_ucmd!().args(&["-n", "a", "-a"]).run().status_code(2);
|
2015-11-16 05:25:01 +00:00
|
|
|
|
}
|
2021-06-18 13:56:00 +00:00
|
|
|
|
|
|
|
|
|
#[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 ']'");
|
|
|
|
|
}
|
2021-06-29 18:49:02 +00:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_bracket_syntax_help() {
|
|
|
|
|
let scenario = TestScenario::new("[");
|
|
|
|
|
let mut ucmd = scenario.ucmd();
|
|
|
|
|
|
|
|
|
|
ucmd.arg("--help").succeeds().stdout_contains("USAGE:");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_bracket_syntax_version() {
|
|
|
|
|
let scenario = TestScenario::new("[");
|
|
|
|
|
let mut ucmd = scenario.ucmd();
|
|
|
|
|
|
|
|
|
|
ucmd.arg("--version")
|
|
|
|
|
.succeeds()
|
|
|
|
|
.stdout_matches(&r"\[ \d+\.\d+\.\d+".parse().unwrap());
|
|
|
|
|
}
|