mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-09-16 03:36:18 +00:00
Merge branch 'main' into tail_notify
This commit is contained in:
commit
eb21330ade
745 changed files with 27822 additions and 14671 deletions
|
@ -13,10 +13,9 @@ uu_factor = { path = "../../../src/uu/factor" }
|
|||
[dev-dependencies]
|
||||
array-init = "2.0.0"
|
||||
criterion = "0.3"
|
||||
rand = "0.7"
|
||||
rand = "0.8"
|
||||
rand_chacha = "0.2.2"
|
||||
|
||||
|
||||
[[bench]]
|
||||
name = "gcd"
|
||||
harness = false
|
||||
|
|
|
@ -34,7 +34,7 @@ fn test_base32_encode_file() {
|
|||
|
||||
#[test]
|
||||
fn test_decode() {
|
||||
for decode_param in &["-d", "--decode"] {
|
||||
for decode_param in &["-d", "--decode", "--dec"] {
|
||||
let input = "JBSWY3DPFQQFO33SNRSCC===\n"; // spell-checker:disable-line
|
||||
new_ucmd!()
|
||||
.arg(decode_param)
|
||||
|
@ -56,7 +56,7 @@ fn test_garbage() {
|
|||
|
||||
#[test]
|
||||
fn test_ignore_garbage() {
|
||||
for ignore_garbage_param in &["-i", "--ignore-garbage"] {
|
||||
for ignore_garbage_param in &["-i", "--ignore-garbage", "--ig"] {
|
||||
let input = "JBSWY\x013DPFQ\x02QFO33SNRSCC===\n"; // spell-checker:disable-line
|
||||
new_ucmd!()
|
||||
.arg("-d")
|
||||
|
@ -69,7 +69,7 @@ fn test_ignore_garbage() {
|
|||
|
||||
#[test]
|
||||
fn test_wrap() {
|
||||
for wrap_param in &["-w", "--wrap"] {
|
||||
for wrap_param in &["-w", "--wrap", "--wr"] {
|
||||
let input = "The quick brown fox jumps over the lazy dog.";
|
||||
new_ucmd!()
|
||||
.arg(wrap_param)
|
||||
|
@ -113,18 +113,12 @@ 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.
|
||||
ts.ucmd()
|
||||
new_ucmd!()
|
||||
.arg("a.txt")
|
||||
.arg("b.txt")
|
||||
.fails()
|
||||
.stderr_only(format!(
|
||||
"{0}: extra operand 'b.txt'\nTry '{1} {0} --help' for more information.",
|
||||
ts.util_name,
|
||||
ts.bin_path.to_string_lossy()
|
||||
));
|
||||
.usage_error("extra operand 'b.txt'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -26,7 +26,7 @@ fn test_base64_encode_file() {
|
|||
|
||||
#[test]
|
||||
fn test_decode() {
|
||||
for decode_param in &["-d", "--decode"] {
|
||||
for decode_param in &["-d", "--decode", "--dec"] {
|
||||
let input = "aGVsbG8sIHdvcmxkIQ=="; // spell-checker:disable-line
|
||||
new_ucmd!()
|
||||
.arg(decode_param)
|
||||
|
@ -48,7 +48,7 @@ fn test_garbage() {
|
|||
|
||||
#[test]
|
||||
fn test_ignore_garbage() {
|
||||
for ignore_garbage_param in &["-i", "--ignore-garbage"] {
|
||||
for ignore_garbage_param in &["-i", "--ignore-garbage", "--ig"] {
|
||||
let input = "aGVsbG8sIHdvcmxkIQ==\0"; // spell-checker:disable-line
|
||||
new_ucmd!()
|
||||
.arg("-d")
|
||||
|
@ -61,7 +61,7 @@ fn test_ignore_garbage() {
|
|||
|
||||
#[test]
|
||||
fn test_wrap() {
|
||||
for wrap_param in &["-w", "--wrap"] {
|
||||
for wrap_param in &["-w", "--wrap", "--wr"] {
|
||||
let input = "The quick brown fox jumps over the lazy dog.";
|
||||
new_ucmd!()
|
||||
.arg(wrap_param)
|
||||
|
@ -95,18 +95,12 @@ 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.
|
||||
ts.ucmd()
|
||||
new_ucmd!()
|
||||
.arg("a.txt")
|
||||
.arg("b.txt")
|
||||
.fails()
|
||||
.stderr_only(format!(
|
||||
"{0}: extra operand 'b.txt'\nTry '{1} {0} --help' for more information.",
|
||||
ts.util_name,
|
||||
ts.bin_path.to_string_lossy()
|
||||
));
|
||||
.usage_error("extra operand 'b.txt'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -61,7 +61,7 @@ fn test_do_not_remove_suffix() {
|
|||
|
||||
#[test]
|
||||
fn test_multiple_param() {
|
||||
for &multiple_param in &["-a", "--multiple"] {
|
||||
for &multiple_param in &["-a", "--multiple", "--mul"] {
|
||||
let path = "/foo/bar/baz";
|
||||
new_ucmd!()
|
||||
.args(&[multiple_param, path, path])
|
||||
|
@ -72,7 +72,7 @@ fn test_multiple_param() {
|
|||
|
||||
#[test]
|
||||
fn test_suffix_param() {
|
||||
for &suffix_param in &["-s", "--suffix"] {
|
||||
for &suffix_param in &["-s", "--suffix", "--suf"] {
|
||||
let path = "/foo/bar/baz.exe";
|
||||
new_ucmd!()
|
||||
.args(&[suffix_param, ".exe", path, path])
|
||||
|
@ -83,7 +83,7 @@ fn test_suffix_param() {
|
|||
|
||||
#[test]
|
||||
fn test_zero_param() {
|
||||
for &zero_param in &["-z", "--zero"] {
|
||||
for &zero_param in &["-z", "--zero", "--ze"] {
|
||||
let path = "/foo/bar/baz";
|
||||
new_ucmd!()
|
||||
.args(&[zero_param, "-a", path, path])
|
||||
|
@ -92,9 +92,9 @@ fn test_zero_param() {
|
|||
}
|
||||
}
|
||||
|
||||
fn expect_error(input: Vec<&str>) {
|
||||
fn expect_error(input: &[&str]) {
|
||||
assert!(!new_ucmd!()
|
||||
.args(&input)
|
||||
.args(input)
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_str()
|
||||
|
@ -104,37 +104,30 @@ fn expect_error(input: Vec<&str>) {
|
|||
#[test]
|
||||
fn test_invalid_option() {
|
||||
let path = "/foo/bar/baz";
|
||||
expect_error(vec!["-q", path]);
|
||||
expect_error(&["-q", path]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_no_args() {
|
||||
expect_error(vec![]);
|
||||
expect_error(&[]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_no_args_output() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
ts.ucmd().fails().stderr_is(&format!(
|
||||
"{0}: missing operand\nTry '{1} {0} --help' for more information.",
|
||||
ts.util_name,
|
||||
ts.bin_path.to_string_lossy()
|
||||
));
|
||||
new_ucmd!().fails().usage_error("missing operand");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_too_many_args() {
|
||||
expect_error(vec!["a", "b", "c"]);
|
||||
expect_error(&["a", "b", "c"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_too_many_args_output() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
ts.ucmd().args(&["a", "b", "c"]).fails().stderr_is(format!(
|
||||
"{0}: extra operand 'c'\nTry '{1} {0} --help' for more information.",
|
||||
ts.util_name,
|
||||
ts.bin_path.to_string_lossy()
|
||||
));
|
||||
new_ucmd!()
|
||||
.args(&["a", "b", "c"])
|
||||
.fails()
|
||||
.usage_error("extra operand 'c'");
|
||||
}
|
||||
|
||||
#[cfg(any(unix, target_os = "redox"))]
|
||||
|
|
|
@ -172,7 +172,7 @@ fn test_piped_to_dev_full() {
|
|||
.set_stdout(dev_full)
|
||||
.pipe_in_fixture("alpha.txt")
|
||||
.fails()
|
||||
.stderr_contains(&"No space left on device".to_owned());
|
||||
.stderr_contains("No space left on device");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -264,7 +264,7 @@ fn test_numbered_lines_no_trailing_newline() {
|
|||
|
||||
#[test]
|
||||
fn test_stdin_show_nonprinting() {
|
||||
for same_param in &["-v", "--show-nonprinting"] {
|
||||
for same_param in &["-v", "--show-nonprinting", "--show-non"] {
|
||||
new_ucmd!()
|
||||
.args(&[same_param])
|
||||
.pipe_in("\t\0\n")
|
||||
|
@ -275,7 +275,7 @@ fn test_stdin_show_nonprinting() {
|
|||
|
||||
#[test]
|
||||
fn test_stdin_show_tabs() {
|
||||
for same_param in &["-T", "--show-tabs"] {
|
||||
for same_param in &["-T", "--show-tabs", "--show-ta"] {
|
||||
new_ucmd!()
|
||||
.args(&[same_param])
|
||||
.pipe_in("\t\0\n")
|
||||
|
@ -286,7 +286,7 @@ fn test_stdin_show_tabs() {
|
|||
|
||||
#[test]
|
||||
fn test_stdin_show_ends() {
|
||||
for &same_param in &["-E", "--show-ends"] {
|
||||
for &same_param in &["-E", "--show-ends", "--show-e"] {
|
||||
new_ucmd!()
|
||||
.args(&[same_param, "-"])
|
||||
.pipe_in("\t\0\n\t")
|
||||
|
@ -317,7 +317,7 @@ fn test_show_ends_crlf() {
|
|||
|
||||
#[test]
|
||||
fn test_stdin_show_all() {
|
||||
for same_param in &["-A", "--show-all"] {
|
||||
for same_param in &["-A", "--show-all", "--show-a"] {
|
||||
new_ucmd!()
|
||||
.args(&[same_param])
|
||||
.pipe_in("\t\0\n")
|
||||
|
@ -346,7 +346,7 @@ fn test_stdin_nonprinting_and_tabs() {
|
|||
|
||||
#[test]
|
||||
fn test_stdin_squeeze_blank() {
|
||||
for same_param in &["-s", "--squeeze-blank"] {
|
||||
for same_param in &["-s", "--squeeze-blank", "--squeeze"] {
|
||||
new_ucmd!()
|
||||
.arg(same_param)
|
||||
.pipe_in("\n\na\n\n\n\n\nb\n\n\n")
|
||||
|
@ -358,7 +358,7 @@ fn test_stdin_squeeze_blank() {
|
|||
#[test]
|
||||
fn test_stdin_number_non_blank() {
|
||||
// spell-checker:disable-next-line
|
||||
for same_param in &["-b", "--number-nonblank"] {
|
||||
for same_param in &["-b", "--number-nonblank", "--number-non"] {
|
||||
new_ucmd!()
|
||||
.arg(same_param)
|
||||
.arg("-")
|
||||
|
|
|
@ -461,9 +461,9 @@ fn set_file_context(path: impl AsRef<Path>, context: &str) -> Result<(), selinux
|
|||
context,
|
||||
path.display(),
|
||||
r
|
||||
)
|
||||
);
|
||||
} else {
|
||||
println!("set_file_context: '{}' => '{}'.", context, path.display())
|
||||
println!("set_file_context: '{}' => '{}'.", context, path.display());
|
||||
}
|
||||
r
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ fn test_1() {
|
|||
#[test]
|
||||
fn test_fail_silently() {
|
||||
if get_effective_gid() != 0 {
|
||||
for opt in &["-f", "--silent", "--quiet"] {
|
||||
for opt in &["-f", "--silent", "--quiet", "--sil", "--qui"] {
|
||||
new_ucmd!()
|
||||
.arg(opt)
|
||||
.arg("bin")
|
||||
|
|
|
@ -33,7 +33,7 @@ fn make_file(file: &str, mode: u32) {
|
|||
set_permissions(file, perms).unwrap();
|
||||
}
|
||||
|
||||
fn run_single_test(test: &TestCase, at: AtPath, mut ucmd: UCommand) {
|
||||
fn run_single_test(test: &TestCase, at: &AtPath, mut ucmd: UCommand) {
|
||||
make_file(&at.plus_as_string(TEST_FILE), test.before);
|
||||
let perms = at.metadata(TEST_FILE).permissions().mode();
|
||||
if perms != test.before {
|
||||
|
@ -64,7 +64,7 @@ fn run_single_test(test: &TestCase, at: AtPath, mut ucmd: UCommand) {
|
|||
fn run_tests(tests: Vec<TestCase>) {
|
||||
for test in tests {
|
||||
let (at, ucmd) = at_and_ucmd!();
|
||||
run_single_test(&test, at, ucmd);
|
||||
run_single_test(&test, &at, ucmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -295,7 +295,7 @@ fn test_chmod_reference_file() {
|
|||
];
|
||||
let (at, ucmd) = at_and_ucmd!();
|
||||
make_file(&at.plus_as_string(REFERENCE_FILE), REFERENCE_PERMS);
|
||||
run_single_test(&tests[0], at, ucmd);
|
||||
run_single_test(&tests[0], &at, ucmd);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -334,19 +334,20 @@ fn test_chmod_recursive() {
|
|||
make_file(&at.plus_as_string("a/b/c/c"), 0o100444);
|
||||
make_file(&at.plus_as_string("z/y"), 0o100444);
|
||||
|
||||
// only the permissions of folder `a` and `z` are changed
|
||||
// folder can't be read after read permission is removed
|
||||
ucmd.arg("-R")
|
||||
.arg("--verbose")
|
||||
.arg("-r,a+w")
|
||||
.arg("a")
|
||||
.arg("z")
|
||||
.succeeds()
|
||||
.stdout_contains(&"to 0333 (-wx-wx-wx)")
|
||||
.stdout_contains(&"to 0222 (-w--w--w-)");
|
||||
.fails()
|
||||
.stderr_is("chmod: Permission denied");
|
||||
|
||||
assert_eq!(at.metadata("z/y").permissions().mode(), 0o100222);
|
||||
assert_eq!(at.metadata("a/a").permissions().mode(), 0o100222);
|
||||
assert_eq!(at.metadata("a/b/b").permissions().mode(), 0o100222);
|
||||
assert_eq!(at.metadata("a/b/c/c").permissions().mode(), 0o100222);
|
||||
assert_eq!(at.metadata("z/y").permissions().mode(), 0o100444);
|
||||
assert_eq!(at.metadata("a/a").permissions().mode(), 0o100444);
|
||||
assert_eq!(at.metadata("a/b/b").permissions().mode(), 0o100444);
|
||||
assert_eq!(at.metadata("a/b/c/c").permissions().mode(), 0o100444);
|
||||
println!("mode {:o}", at.metadata("a").permissions().mode());
|
||||
assert_eq!(at.metadata("a").permissions().mode(), 0o40333);
|
||||
assert_eq!(at.metadata("z").permissions().mode(), 0o40333);
|
||||
|
@ -356,6 +357,23 @@ fn test_chmod_recursive() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::unreadable_literal)]
|
||||
fn test_chmod_recursive_read_permission() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.mkdir("a");
|
||||
at.mkdir("a/b");
|
||||
let mut perms = at.metadata("a/b").permissions();
|
||||
perms.set_mode(0o311);
|
||||
set_permissions(at.plus_as_string("a/b"), perms.clone()).unwrap();
|
||||
set_permissions(at.plus_as_string("a"), perms).unwrap();
|
||||
|
||||
ucmd.arg("-R").arg("u+r").arg("a").succeeds();
|
||||
|
||||
assert_eq!(at.metadata("a").permissions().mode(), 0o40711);
|
||||
assert_eq!(at.metadata("a/b").permissions().mode(), 0o40711);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chmod_non_existing_file() {
|
||||
new_ucmd!()
|
||||
|
@ -455,8 +473,8 @@ fn test_chmod_symlink_non_existing_file_recursive() {
|
|||
|
||||
let expected_stdout = &format!(
|
||||
// spell-checker:disable-next-line
|
||||
"mode of '{}' retained as 0755 (rwxr-xr-x)\nneither symbolic link '{}/{}' nor referent has been changed",
|
||||
test_directory, test_directory, test_symlink
|
||||
"mode of '{}' retained as 0755 (rwxr-xr-x)",
|
||||
test_directory
|
||||
);
|
||||
|
||||
// '-v': this should succeed without stderr
|
||||
|
@ -541,7 +559,7 @@ fn test_no_operands() {
|
|||
.arg("777")
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stderr_is("chmod: missing operand");
|
||||
.usage_error("missing operand");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -553,7 +571,7 @@ fn test_mode_after_dash_dash() {
|
|||
before: 0o100777,
|
||||
after: 0o100333,
|
||||
},
|
||||
at,
|
||||
&at,
|
||||
ucmd,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ mod test_passgrp {
|
|||
#[test]
|
||||
fn test_grp2gid() {
|
||||
if cfg!(target_os = "linux") || cfg!(target_os = "android") || cfg!(target_os = "windows") {
|
||||
assert_eq!(0, grp2gid("root").unwrap())
|
||||
assert_eq!(0, grp2gid("root").unwrap());
|
||||
} else {
|
||||
assert_eq!(0, grp2gid("wheel").unwrap());
|
||||
}
|
||||
|
|
|
@ -74,9 +74,8 @@ fn test_invalid_file() {
|
|||
at.mkdir(folder_name);
|
||||
ts.ucmd()
|
||||
.arg(folder_name)
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("cksum: asdf: Is a directory");
|
||||
.succeeds()
|
||||
.stdout_only("4294967295 0 asdf\n");
|
||||
}
|
||||
|
||||
// Make sure crc is correct for files larger than 32 bytes
|
||||
|
|
|
@ -170,3 +170,11 @@ fn no_arguments() {
|
|||
fn one_argument() {
|
||||
new_ucmd!().arg("a").fails().no_stdout().no_stderr();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_no_such_file() {
|
||||
new_ucmd!()
|
||||
.args(&["bogus_file_1", "bogus_file_2"])
|
||||
.fails()
|
||||
.stderr_only("comm: bogus_file_1: No such file or directory");
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// spell-checker:ignore (flags) reflink (fs) tmpfs (linux) rlimit Rlim NOFILE
|
||||
// spell-checker:ignore (flags) reflink (fs) tmpfs (linux) rlimit Rlim NOFILE clob
|
||||
|
||||
use crate::common::util::*;
|
||||
#[cfg(not(windows))]
|
||||
|
@ -29,6 +29,7 @@ static TEST_EXISTING_FILE: &str = "existing_file.txt";
|
|||
static TEST_HELLO_WORLD_SOURCE: &str = "hello_world.txt";
|
||||
static TEST_HELLO_WORLD_SOURCE_SYMLINK: &str = "hello_world.txt.link";
|
||||
static TEST_HELLO_WORLD_DEST: &str = "copy_of_hello_world.txt";
|
||||
static TEST_HELLO_WORLD_DEST_SYMLINK: &str = "copy_of_hello_world.txt.link";
|
||||
static TEST_HOW_ARE_YOU_SOURCE: &str = "how_are_you.txt";
|
||||
static TEST_HOW_ARE_YOU_DEST: &str = "hello_dir/how_are_you.txt";
|
||||
static TEST_COPY_TO_FOLDER: &str = "hello_dir/";
|
||||
|
@ -43,6 +44,8 @@ static TEST_MOUNT_COPY_FROM_FOLDER: &str = "dir_with_mount";
|
|||
static TEST_MOUNT_MOUNTPOINT: &str = "mount";
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||
static TEST_MOUNT_OTHER_FILESYSTEM_FILE: &str = "mount/DO_NOT_copy_me.txt";
|
||||
#[cfg(unix)]
|
||||
static TEST_NONEXISTENT_FILE: &str = "nonexistent_file.txt";
|
||||
|
||||
#[test]
|
||||
fn test_cp_cp() {
|
||||
|
@ -180,6 +183,16 @@ fn test_cp_arg_no_target_directory() {
|
|||
.stderr_contains("cannot overwrite directory");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_target_directory_is_file() {
|
||||
new_ucmd!()
|
||||
.arg("-t")
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.fails()
|
||||
.stderr_contains(format!("'{}' is not a directory", TEST_HOW_ARE_YOU_SOURCE));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_arg_interactive() {
|
||||
new_ucmd!()
|
||||
|
@ -227,6 +240,17 @@ fn test_cp_arg_no_clobber() {
|
|||
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "How are you?\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_arg_no_clobber_inferred_arg() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.arg("--no-clob")
|
||||
.succeeds();
|
||||
|
||||
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "How are you?\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_arg_no_clobber_twice() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
|
@ -372,6 +396,24 @@ fn test_cp_arg_suffix() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_arg_suffix_hyphen_value() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg("-b")
|
||||
.arg("--suffix")
|
||||
.arg("-v")
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.succeeds();
|
||||
|
||||
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n");
|
||||
assert_eq!(
|
||||
at.read(&*format!("{}-v", TEST_HOW_ARE_YOU_SOURCE)),
|
||||
"How are you?\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_custom_backup_suffix_via_env() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
@ -563,17 +605,13 @@ fn test_cp_backup_off() {
|
|||
|
||||
#[test]
|
||||
fn test_cp_backup_no_clobber_conflicting_options() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
ts.ucmd()
|
||||
new_ucmd!()
|
||||
.arg("--backup")
|
||||
.arg("--no-clobber")
|
||||
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.fails().stderr_is(&format!(
|
||||
"{0}: options --backup and --no-clobber are mutually exclusive\nTry '{1} {0} --help' for more information.",
|
||||
ts.util_name,
|
||||
ts.bin_path.to_string_lossy()
|
||||
));
|
||||
.fails()
|
||||
.usage_error("options --backup and --no-clobber are mutually exclusive");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -661,6 +699,51 @@ fn test_cp_no_deref() {
|
|||
assert_eq!(at.read(path_to_check), "Hello, World!\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_no_deref_link_onto_link() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
at.copy(TEST_HELLO_WORLD_SOURCE, TEST_HELLO_WORLD_DEST);
|
||||
|
||||
#[cfg(not(windows))]
|
||||
let _r = fs::symlink(
|
||||
TEST_HELLO_WORLD_SOURCE,
|
||||
at.subdir.join(TEST_HELLO_WORLD_SOURCE_SYMLINK),
|
||||
);
|
||||
#[cfg(windows)]
|
||||
let _r = symlink_file(
|
||||
TEST_HELLO_WORLD_SOURCE,
|
||||
at.subdir.join(TEST_HELLO_WORLD_SOURCE_SYMLINK),
|
||||
);
|
||||
|
||||
#[cfg(not(windows))]
|
||||
let _r = fs::symlink(
|
||||
TEST_HELLO_WORLD_DEST,
|
||||
at.subdir.join(TEST_HELLO_WORLD_DEST_SYMLINK),
|
||||
);
|
||||
#[cfg(windows)]
|
||||
let _r = symlink_file(
|
||||
TEST_HELLO_WORLD_DEST,
|
||||
at.subdir.join(TEST_HELLO_WORLD_DEST_SYMLINK),
|
||||
);
|
||||
|
||||
ucmd.arg("-P")
|
||||
.arg(TEST_HELLO_WORLD_SOURCE_SYMLINK)
|
||||
.arg(TEST_HELLO_WORLD_DEST_SYMLINK)
|
||||
.succeeds();
|
||||
|
||||
// Ensure that the target of the destination was not modified.
|
||||
assert!(!at
|
||||
.symlink_metadata(TEST_HELLO_WORLD_DEST)
|
||||
.file_type()
|
||||
.is_symlink());
|
||||
assert!(at
|
||||
.symlink_metadata(TEST_HELLO_WORLD_DEST_SYMLINK)
|
||||
.file_type()
|
||||
.is_symlink());
|
||||
assert_eq!(at.read(TEST_HELLO_WORLD_DEST_SYMLINK), "Hello, World!\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_strip_trailing_slashes() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
@ -729,6 +812,21 @@ fn test_cp_parents_dest_not_directory() {
|
|||
.stderr_contains("with --parents, the destination must be a directory");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_cp_writable_special_file_permissions() {
|
||||
new_ucmd!().arg("/dev/null").arg("/dev/zero").succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_cp_issue_1665() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.arg("/dev/null").arg("foo").succeeds();
|
||||
assert!(at.file_exists("foo"));
|
||||
assert_eq!(at.read("foo"), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_preserve_no_args() {
|
||||
new_ucmd!()
|
||||
|
@ -1368,3 +1466,163 @@ fn test_canonicalize_symlink() {
|
|||
.no_stderr()
|
||||
.no_stdout();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_copy_through_just_created_symlink() {
|
||||
for &create_t in &[true, false] {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.mkdir("a");
|
||||
at.mkdir("b");
|
||||
at.mkdir("c");
|
||||
#[cfg(unix)]
|
||||
fs::symlink("../t", at.plus("a/1")).unwrap();
|
||||
#[cfg(target_os = "windows")]
|
||||
symlink_file("../t", at.plus("a/1")).unwrap();
|
||||
at.touch("b/1");
|
||||
if create_t {
|
||||
at.touch("t");
|
||||
}
|
||||
ucmd.arg("--no-dereference")
|
||||
.arg("a/1")
|
||||
.arg("b/1")
|
||||
.arg("c")
|
||||
.fails()
|
||||
.stderr_only(if cfg!(not(target_os = "windows")) {
|
||||
"cp: will not copy 'b/1' through just-created symlink 'c/1'"
|
||||
} else {
|
||||
"cp: will not copy 'b/1' through just-created symlink 'c\\1'"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_copy_through_dangling_symlink() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.touch("file");
|
||||
at.symlink_file("nonexistent", "target");
|
||||
ucmd.arg("file")
|
||||
.arg("target")
|
||||
.fails()
|
||||
.stderr_only("cp: not writing through dangling symlink 'target'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_cp_archive_on_nonexistent_file() {
|
||||
new_ucmd!()
|
||||
.arg("-a")
|
||||
.arg(TEST_NONEXISTENT_FILE)
|
||||
.arg(TEST_EXISTING_FILE)
|
||||
.fails()
|
||||
.stderr_only(
|
||||
"cp: cannot stat 'nonexistent_file.txt': No such file or directory (os error 2)",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_link_backup() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.touch("file2");
|
||||
ucmd.arg("-l")
|
||||
.arg("-b")
|
||||
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg("file2")
|
||||
.succeeds();
|
||||
|
||||
assert!(at.file_exists("file2~"));
|
||||
assert_eq!(at.read("file2"), "Hello, World!\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_cp_fifo() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.mkfifo("fifo");
|
||||
ucmd.arg("-r")
|
||||
.arg("fifo")
|
||||
.arg("fifo2")
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.no_stdout();
|
||||
assert!(at.is_fifo("fifo2"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dir_recursive_copy() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
at.mkdir("parent1");
|
||||
at.mkdir("parent2");
|
||||
at.mkdir("parent1/child");
|
||||
at.mkdir("parent2/child1");
|
||||
at.mkdir("parent2/child1/child2");
|
||||
at.mkdir("parent2/child1/child2/child3");
|
||||
|
||||
// case-1: copy parent1 -> parent1: should fail
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-R")
|
||||
.arg("parent1")
|
||||
.arg("parent1")
|
||||
.fails()
|
||||
.stderr_contains("cannot copy a directory");
|
||||
// case-2: copy parent1 -> parent1/child should fail
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-R")
|
||||
.arg("parent1")
|
||||
.arg("parent1/child")
|
||||
.fails()
|
||||
.stderr_contains("cannot copy a directory");
|
||||
// case-3: copy parent1/child -> parent2 should pass
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-R")
|
||||
.arg("parent1/child")
|
||||
.arg("parent2")
|
||||
.succeeds();
|
||||
// case-4: copy parent2/child1/ -> parent2/child1/child2/child3
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-R")
|
||||
.arg("parent2/child1/")
|
||||
.arg("parent2/child1/child2/child3")
|
||||
.fails()
|
||||
.stderr_contains("cannot copy a directory");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_dir_vs_file() {
|
||||
new_ucmd!()
|
||||
.arg("-R")
|
||||
.arg(TEST_COPY_FROM_FOLDER)
|
||||
.arg(TEST_EXISTING_FILE)
|
||||
.fails()
|
||||
.stderr_only("cp: cannot overwrite non-directory with directory");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_overriding_arguments() {
|
||||
let s = TestScenario::new(util_name!());
|
||||
s.fixtures.touch("file1");
|
||||
for (arg1, arg2) in &[
|
||||
#[cfg(not(windows))]
|
||||
("--remove-destination", "--force"),
|
||||
#[cfg(not(windows))]
|
||||
("--force", "--remove-destination"),
|
||||
("--interactive", "--no-clobber"),
|
||||
("--link", "--symbolic-link"),
|
||||
("--symbolic-link", "--link"),
|
||||
("--dereference", "--no-dereference"),
|
||||
("--no-dereference", "--dereference"),
|
||||
] {
|
||||
s.ucmd()
|
||||
.arg(arg1)
|
||||
.arg(arg2)
|
||||
.arg("file1")
|
||||
.arg("file2")
|
||||
.succeeds();
|
||||
s.fixtures.remove("file2");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ static COMPLEX_SEQUENCE: &TestedSequence = &TestedSequence {
|
|||
|
||||
#[test]
|
||||
fn test_byte_sequence() {
|
||||
for ¶m in &["-b", "--bytes"] {
|
||||
for ¶m in &["-b", "--bytes", "--byt"] {
|
||||
for example_seq in EXAMPLE_SEQUENCES {
|
||||
new_ucmd!()
|
||||
.args(&[param, example_seq.sequence, INPUT])
|
||||
|
@ -53,7 +53,7 @@ fn test_byte_sequence() {
|
|||
|
||||
#[test]
|
||||
fn test_char_sequence() {
|
||||
for ¶m in &["-c", "--characters"] {
|
||||
for ¶m in &["-c", "--characters", "--char"] {
|
||||
for example_seq in EXAMPLE_SEQUENCES {
|
||||
//as of coreutils 8.25 a char range is effectively the same as a byte range; there is no distinct treatment of utf8 chars.
|
||||
new_ucmd!()
|
||||
|
@ -66,7 +66,7 @@ fn test_char_sequence() {
|
|||
|
||||
#[test]
|
||||
fn test_field_sequence() {
|
||||
for ¶m in &["-f", "--fields"] {
|
||||
for ¶m in &["-f", "--fields", "--fie"] {
|
||||
for example_seq in EXAMPLE_SEQUENCES {
|
||||
new_ucmd!()
|
||||
.args(&[param, example_seq.sequence, INPUT])
|
||||
|
@ -78,7 +78,7 @@ fn test_field_sequence() {
|
|||
|
||||
#[test]
|
||||
fn test_specify_delimiter() {
|
||||
for ¶m in &["-d", "--delimiter"] {
|
||||
for ¶m in &["-d", "--delimiter", "--del"] {
|
||||
new_ucmd!()
|
||||
.args(&[param, ":", "-f", COMPLEX_SEQUENCE.sequence, INPUT])
|
||||
.succeeds()
|
||||
|
@ -100,29 +100,42 @@ fn test_output_delimiter() {
|
|||
])
|
||||
.succeeds()
|
||||
.stdout_only_fixture("output_delimiter.expected");
|
||||
|
||||
new_ucmd!()
|
||||
.args(&[
|
||||
"-d:",
|
||||
"--output-del=@",
|
||||
"-f",
|
||||
COMPLEX_SEQUENCE.sequence,
|
||||
INPUT,
|
||||
])
|
||||
.succeeds()
|
||||
.stdout_only_fixture("output_delimiter.expected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_complement() {
|
||||
new_ucmd!()
|
||||
.args(&["-d_", "--complement", "-f", "2"])
|
||||
.pipe_in("9_1\n8_2\n7_3")
|
||||
.succeeds()
|
||||
.stdout_only("9\n8\n7\n");
|
||||
for param in &["--complement", "--com"] {
|
||||
new_ucmd!()
|
||||
.args(&["-d_", param, "-f", "2"])
|
||||
.pipe_in("9_1\n8_2\n7_3")
|
||||
.succeeds()
|
||||
.stdout_only("9\n8\n7\n");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero_terminated() {
|
||||
new_ucmd!()
|
||||
.args(&["-d_", "-z", "-f", "1"])
|
||||
.pipe_in("9_1\n8_2\n\07_3")
|
||||
.pipe_in("9_1\n8_2\n\x007_3")
|
||||
.succeeds()
|
||||
.stdout_only("9\07\0");
|
||||
.stdout_only("9\x007\0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_only_delimited() {
|
||||
for param in &["-s", "--only-delimited"] {
|
||||
for param in &["-s", "--only-delimited", "--only-del"] {
|
||||
new_ucmd!()
|
||||
.args(&["-d_", param, "-f", "1"])
|
||||
.pipe_in("91\n82\n7_3")
|
||||
|
|
|
@ -7,12 +7,9 @@ use rust_users::*;
|
|||
|
||||
#[test]
|
||||
fn test_date_email() {
|
||||
new_ucmd!().arg("--rfc-email").succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_date_email2() {
|
||||
new_ucmd!().arg("-R").succeeds();
|
||||
for param in &["--rfc-email", "--rfc-e", "-R"] {
|
||||
new_ucmd!().arg(param).succeeds();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -26,37 +23,40 @@ fn test_date_rfc_3339() {
|
|||
let re = Regex::new(rfc_regexp).unwrap();
|
||||
|
||||
// Check that the output matches the regexp
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--rfc-3339=ns")
|
||||
.succeeds()
|
||||
.stdout_matches(&re);
|
||||
for param in &["--rfc-3339", "--rfc-3"] {
|
||||
scene
|
||||
.ucmd()
|
||||
.arg(format!("{}=ns", param))
|
||||
.succeeds()
|
||||
.stdout_matches(&re);
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--rfc-3339=seconds")
|
||||
.succeeds()
|
||||
.stdout_matches(&re);
|
||||
scene
|
||||
.ucmd()
|
||||
.arg(format!("{}=seconds", param))
|
||||
.succeeds()
|
||||
.stdout_matches(&re);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_date_rfc_8601() {
|
||||
new_ucmd!().arg("--iso-8601=ns").succeeds();
|
||||
for param in &["--iso-8601", "--i"] {
|
||||
new_ucmd!().arg(format!("{}=ns", param)).succeeds();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_date_rfc_8601_second() {
|
||||
new_ucmd!().arg("--iso-8601=second").succeeds();
|
||||
for param in &["--iso-8601", "--i"] {
|
||||
new_ucmd!().arg(format!("{}=second", param)).succeeds();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_date_utc() {
|
||||
new_ucmd!().arg("--utc").succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_date_universal() {
|
||||
new_ucmd!().arg("--universal").succeeds();
|
||||
for param in &["--universal", "--utc", "--uni", "--u"] {
|
||||
new_ucmd!().arg(param).succeeds();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// spell-checker:ignore fname, tname, fpath, specfile, testfile, unspec, ifile, ofile, outfile, fullblock, urand, fileio, atoe, atoibm, availible, behaviour, bmax, bremain, btotal, cflags, creat, ctable, ctty, datastructures, doesnt, etoa, fileout, fname, gnudd, iconvflags, nocache, noctty, noerror, nofollow, nolinks, nonblock, oconvflags, outfile, parseargs, rlen, rmax, rposition, rremain, rsofar, rstat, sigusr, sigval, wlen, wstat
|
||||
// spell-checker:ignore fname, tname, fpath, specfile, testfile, unspec, ifile, ofile, outfile, fullblock, urand, fileio, atoe, atoibm, availible, behaviour, bmax, bremain, btotal, cflags, creat, ctable, ctty, datastructures, doesnt, etoa, fileout, fname, gnudd, iconvflags, iseek, nocache, noctty, noerror, nofollow, nolinks, nonblock, oconvflags, oseek, outfile, parseargs, rlen, rmax, rposition, rremain, rsofar, rstat, sigusr, sigval, wlen, wstat abcdefghijklm abcdefghi nabcde nabcdefg abcdefg
|
||||
|
||||
use crate::common::util::*;
|
||||
|
||||
|
@ -178,12 +178,72 @@ fn test_stdin_stdout_count_w_multiplier() {
|
|||
.success();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_b_multiplier() {
|
||||
// "2b" means 2 * 512, which is 1024.
|
||||
new_ucmd!()
|
||||
.args(&["bs=2b", "count=1"])
|
||||
.pipe_in("a".repeat(1025))
|
||||
.succeeds()
|
||||
.stdout_is("a".repeat(1024));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_x_multiplier() {
|
||||
// "2x3" means 2 * 3, which is 6.
|
||||
new_ucmd!()
|
||||
.args(&["bs=2x3", "count=1"])
|
||||
.pipe_in("abcdefghi")
|
||||
.succeeds()
|
||||
.stdout_is("abcdef");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero_multiplier_warning() {
|
||||
for arg in ["count", "seek", "skip"] {
|
||||
new_ucmd!()
|
||||
.args(&[format!("{}=0", arg).as_str(), "status=none"])
|
||||
.pipe_in("")
|
||||
.succeeds()
|
||||
.no_stdout()
|
||||
.no_stderr();
|
||||
|
||||
new_ucmd!()
|
||||
.args(&[format!("{}=00x1", arg).as_str(), "status=none"])
|
||||
.pipe_in("")
|
||||
.succeeds()
|
||||
.no_stdout()
|
||||
.no_stderr();
|
||||
|
||||
new_ucmd!()
|
||||
.args(&[format!("{}=0x1", arg).as_str(), "status=none"])
|
||||
.pipe_in("")
|
||||
.succeeds()
|
||||
.no_stdout()
|
||||
.stderr_contains("warning: '0x' is a zero multiplier; use '00x' if that is intended");
|
||||
|
||||
new_ucmd!()
|
||||
.args(&[format!("{}=0x0x1", arg).as_str(), "status=none"])
|
||||
.pipe_in("")
|
||||
.succeeds()
|
||||
.no_stdout()
|
||||
.stderr_is("dd: warning: '0x' is a zero multiplier; use '00x' if that is intended\ndd: warning: '0x' is a zero multiplier; use '00x' if that is intended\n");
|
||||
|
||||
new_ucmd!()
|
||||
.args(&[format!("{}=1x0x1", arg).as_str(), "status=none"])
|
||||
.pipe_in("")
|
||||
.succeeds()
|
||||
.no_stdout()
|
||||
.stderr_contains("warning: '0x' is a zero multiplier; use '00x' if that is intended");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_final_stats_noxfer() {
|
||||
new_ucmd!()
|
||||
.args(&["status=noxfer"])
|
||||
.succeeds()
|
||||
.stderr_only("");
|
||||
.stderr_only("0+0 records in\n0+0 records out\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -262,7 +322,9 @@ fn test_nocreat_causes_failure_when_outfile_not_present() {
|
|||
ucmd.args(&["conv=nocreat", of!(&fname)])
|
||||
.pipe_in("")
|
||||
.fails()
|
||||
.stderr_is("dd Error: No such file or directory (os error 2)");
|
||||
.stderr_only(
|
||||
"dd: failed to open 'this-file-does-not-exist.txt': No such file or directory",
|
||||
);
|
||||
assert!(!fix.file_exists(fname));
|
||||
}
|
||||
|
||||
|
@ -357,7 +419,7 @@ fn test_fullblock() {
|
|||
of!(&tmp_fn),
|
||||
"bs=128M",
|
||||
// Note: In order for this test to actually test iflag=fullblock, the bs=VALUE
|
||||
// must be big enough to 'overwhelm' urandom's store of bytes.
|
||||
// must be big enough to 'overwhelm' the urandom store of bytes.
|
||||
// Try executing 'dd if=/dev/urandom bs=128M count=1' (i.e without iflag=fullblock).
|
||||
// The stats should contain the line: '0+1 records in' indicating a partial read.
|
||||
// Since my system only copies 32 MiB without fullblock, I expect 128 MiB to be
|
||||
|
@ -398,6 +460,20 @@ fn test_zeros_to_stdout() {
|
|||
.success();
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
#[test]
|
||||
fn test_oversized_bs_32_bit() {
|
||||
for bs_param in &["bs", "ibs", "obs", "cbs"] {
|
||||
new_ucmd!()
|
||||
.args(&[format!("{}=5GB", bs_param)])
|
||||
.run()
|
||||
.no_stdout()
|
||||
.failure()
|
||||
.status_code(1)
|
||||
.stderr_is(format!("dd: {}=N cannot fit into memory\n", bs_param));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_stdout_with_ibs_obs() {
|
||||
let output: Vec<_> = String::from("y\n").bytes().cycle().take(1024).collect();
|
||||
|
@ -557,5 +633,554 @@ fn test_unicode_filenames() {
|
|||
);
|
||||
}
|
||||
|
||||
// conv=[ascii,ebcdic,ibm], conv=[ucase,lcase], conv=[block,unblock], conv=sync
|
||||
// TODO: Move conv tests from unit test module
|
||||
#[test]
|
||||
fn test_conv_ascii_implies_unblock() {
|
||||
// 0x40 = 0o100 = 64, which gets converted to ' '
|
||||
// 0xc1 = 0o301 = 193, which gets converted to 'A'
|
||||
//
|
||||
// `conv=ascii` implies `conv=unblock`, which means trailing paces
|
||||
// are stripped and a newline is appended at the end of each
|
||||
// block.
|
||||
//
|
||||
// `cbs=4` means use a conversion block size of 4 bytes per block.
|
||||
new_ucmd!()
|
||||
.args(&["conv=ascii", "cbs=4"])
|
||||
.pipe_in(b"\x40\xc1\x40\xc1\x40\xc1\x40\x40".to_vec())
|
||||
.succeeds()
|
||||
.stdout_is(" A A\n A\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conv_ebcdic_implies_block() {
|
||||
// 0x40 = 0o100 = 64, which is the result of converting from ' '
|
||||
// 0xc1 = 0o301 = 193, which is the result of converting from 'A'
|
||||
//
|
||||
// `conv=ebcdic` implies `conv=block`, which means trailing spaces
|
||||
// are added to pad each block.
|
||||
//
|
||||
// `cbs=4` means use a conversion block size of 4 bytes per block.
|
||||
new_ucmd!()
|
||||
.args(&["conv=ebcdic", "cbs=4"])
|
||||
.pipe_in(" A A\n A\n")
|
||||
.succeeds()
|
||||
.stdout_is_bytes(b"\x40\xc1\x40\xc1\x40\xc1\x40\x40");
|
||||
}
|
||||
|
||||
/// Test for seeking forward N bytes in the output file before copying.
|
||||
#[test]
|
||||
fn test_seek_bytes() {
|
||||
// Since the output file is stdout, seeking forward by eight bytes
|
||||
// results in a prefix of eight null bytes.
|
||||
new_ucmd!()
|
||||
.args(&["seek=8", "oflag=seek_bytes"])
|
||||
.pipe_in("abcdefghijklm\n")
|
||||
.succeeds()
|
||||
.stdout_is("\0\0\0\0\0\0\0\0abcdefghijklm\n");
|
||||
}
|
||||
|
||||
/// Test for skipping beyond the number of bytes in a file.
|
||||
#[test]
|
||||
fn test_skip_beyond_file() {
|
||||
new_ucmd!()
|
||||
.args(&["bs=1", "skip=5", "count=0", "status=noxfer"])
|
||||
.pipe_in("abcd")
|
||||
.succeeds()
|
||||
.no_stdout()
|
||||
.stderr_contains(
|
||||
"'standard input': cannot skip to specified offset\n0+0 records in\n0+0 records out\n",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seek_do_not_overwrite() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let mut outfile = at.make_file("outfile");
|
||||
outfile.write_all(b"abc").unwrap();
|
||||
// Skip the first byte of the input, seek past the first byte of
|
||||
// the output, and write only one byte to the output.
|
||||
ucmd.args(&[
|
||||
"bs=1",
|
||||
"skip=1",
|
||||
"seek=1",
|
||||
"count=1",
|
||||
"status=noxfer",
|
||||
"of=outfile",
|
||||
])
|
||||
.pipe_in("123")
|
||||
.succeeds()
|
||||
.stderr_is("1+0 records in\n1+0 records out\n")
|
||||
.no_stdout();
|
||||
assert_eq!(at.read("outfile"), "a2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_partial_records_out() {
|
||||
new_ucmd!()
|
||||
.args(&["bs=2", "status=noxfer"])
|
||||
.pipe_in("abc")
|
||||
.succeeds()
|
||||
.stdout_is("abc")
|
||||
.stderr_is("1+1 records in\n1+1 records out\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_block_cbs16() {
|
||||
new_ucmd!()
|
||||
.args(&["conv=block", "cbs=16"])
|
||||
.pipe_in_fixture("dd-block-cbs16.test")
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("dd-block-cbs16.spec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_block_cbs16_as_cbs8() {
|
||||
new_ucmd!()
|
||||
.args(&["conv=block", "cbs=8"])
|
||||
.pipe_in_fixture("dd-block-cbs16.test")
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("dd-block-cbs8.spec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_block_consecutive_nl() {
|
||||
new_ucmd!()
|
||||
.args(&["conv=block", "cbs=16"])
|
||||
.pipe_in_fixture("dd-block-consecutive-nl.test")
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("dd-block-consecutive-nl-cbs16.spec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unblock_multi_16() {
|
||||
new_ucmd!()
|
||||
.args(&["conv=unblock", "cbs=16"])
|
||||
.pipe_in_fixture("dd-unblock-cbs16.test")
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("dd-unblock-cbs16.spec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unblock_multi_16_as_8() {
|
||||
new_ucmd!()
|
||||
.args(&["conv=unblock", "cbs=8"])
|
||||
.pipe_in_fixture("dd-unblock-cbs16.test")
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("dd-unblock-cbs8.spec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_atoe_conv_spec_test() {
|
||||
new_ucmd!()
|
||||
.args(&["conv=ebcdic"])
|
||||
.pipe_in_fixture("seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test")
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("gnudd-conv-atoe-seq-byte-values.spec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_etoa_conv_spec_test() {
|
||||
new_ucmd!()
|
||||
.args(&["conv=ascii"])
|
||||
.pipe_in_fixture("seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test")
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("gnudd-conv-etoa-seq-byte-values.spec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_atoibm_conv_spec_test() {
|
||||
new_ucmd!()
|
||||
.args(&["conv=ibm"])
|
||||
.pipe_in_fixture("seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test")
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("gnudd-conv-atoibm-seq-byte-values.spec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lcase_ascii_to_ucase_ascii() {
|
||||
new_ucmd!()
|
||||
.args(&["conv=ucase"])
|
||||
.pipe_in_fixture("lcase-ascii.test")
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("ucase-ascii.test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ucase_ascii_to_lcase_ascii() {
|
||||
new_ucmd!()
|
||||
.args(&["conv=lcase"])
|
||||
.pipe_in_fixture("ucase-ascii.test")
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("lcase-ascii.test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_atoe_and_ucase_conv_spec_test() {
|
||||
new_ucmd!()
|
||||
.args(&["conv=ebcdic,ucase"])
|
||||
.pipe_in_fixture("seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test")
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("ucase-ebcdic.test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_atoe_and_lcase_conv_spec_test() {
|
||||
new_ucmd!()
|
||||
.args(&["conv=ebcdic,lcase"])
|
||||
.pipe_in_fixture("seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test")
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("lcase-ebcdic.test");
|
||||
}
|
||||
|
||||
// TODO I think uppercase and lowercase are unintentionally swapped in
|
||||
// the code that parses the command-line arguments. See this line from
|
||||
// `parseargs.rs`:
|
||||
//
|
||||
// (ConvFlag::FmtAtoI, ConvFlag::UCase) => Some(&ASCII_TO_IBM_UCASE_TO_LCASE),
|
||||
// (ConvFlag::FmtAtoI, ConvFlag::LCase) => Some(&ASCII_TO_IBM_LCASE_TO_UCASE),
|
||||
//
|
||||
// If my reading is correct and that is a typo, then the
|
||||
// UCASE_TO_LCASE and LCASE_TO_UCASE in those lines should be swapped,
|
||||
// and the expected output for the following two tests should be
|
||||
// updated accordingly.
|
||||
#[test]
|
||||
fn test_atoibm_and_ucase_conv_spec_test() {
|
||||
new_ucmd!()
|
||||
.args(&["conv=ibm,ucase"])
|
||||
.pipe_in_fixture("seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test")
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("lcase-ibm.test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_atoibm_and_lcase_conv_spec_test() {
|
||||
new_ucmd!()
|
||||
.args(&["conv=ibm,lcase"])
|
||||
.pipe_in_fixture("seq-byte-values-b632a992d3aed5d8d1a59cc5a5a455ba.test")
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("ucase-ibm.test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_swab_256_test() {
|
||||
new_ucmd!()
|
||||
.args(&["conv=swab"])
|
||||
.pipe_in_fixture("seq-byte-values.test")
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("seq-byte-values-swapped.test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_swab_257_test() {
|
||||
new_ucmd!()
|
||||
.args(&["conv=swab"])
|
||||
.pipe_in_fixture("seq-byte-values-odd.test")
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("seq-byte-values-odd.spec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zeros_4k_conv_sync_obs_gt_ibs() {
|
||||
new_ucmd!()
|
||||
.args(&["conv=sync", "ibs=521", "obs=1031"])
|
||||
.pipe_in_fixture("zeros-620f0b67a91f7f74151bc5be745b7110.test")
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("gnudd-conv-sync-ibs-521-obs-1031-zeros.spec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zeros_4k_conv_sync_ibs_gt_obs() {
|
||||
new_ucmd!()
|
||||
.args(&["conv=sync", "ibs=1031", "obs=521"])
|
||||
.pipe_in_fixture("zeros-620f0b67a91f7f74151bc5be745b7110.test")
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("gnudd-conv-sync-ibs-1031-obs-521-zeros.spec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deadbeef_32k_conv_sync_obs_gt_ibs() {
|
||||
new_ucmd!()
|
||||
.args(&[
|
||||
"conv=sync",
|
||||
"ibs=521",
|
||||
"obs=1031",
|
||||
"if=deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test",
|
||||
])
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("gnudd-conv-sync-ibs-521-obs-1031-deadbeef.spec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deadbeef_32k_conv_sync_ibs_gt_obs() {
|
||||
new_ucmd!()
|
||||
.args(&[
|
||||
"conv=sync",
|
||||
"ibs=1031",
|
||||
"obs=521",
|
||||
"if=deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test",
|
||||
])
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("gnudd-conv-sync-ibs-1031-obs-521-deadbeef.spec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_random_73k_test_bs_prime_obs_gt_ibs_sync() {
|
||||
new_ucmd!()
|
||||
.args(&[
|
||||
"conv=sync",
|
||||
"ibs=521",
|
||||
"obs=1031",
|
||||
"if=random-5828891cb1230748e146f34223bbd3b5.test",
|
||||
])
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("gnudd-conv-sync-ibs-521-obs-1031-random.spec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_random_73k_test_bs_prime_ibs_gt_obs_sync() {
|
||||
new_ucmd!()
|
||||
.args(&[
|
||||
"conv=sync",
|
||||
"ibs=1031",
|
||||
"obs=521",
|
||||
"if=random-5828891cb1230748e146f34223bbd3b5.test",
|
||||
])
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("gnudd-conv-sync-ibs-1031-obs-521-random.spec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_identity() {
|
||||
new_ucmd!()
|
||||
.args(&["if=zeros-620f0b67a91f7f74151bc5be745b7110.test"])
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("zeros-620f0b67a91f7f74151bc5be745b7110.test");
|
||||
new_ucmd!()
|
||||
.args(&["if=ones-6ae59e64850377ee5470c854761551ea.test"])
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("ones-6ae59e64850377ee5470c854761551ea.test");
|
||||
new_ucmd!()
|
||||
.args(&["if=deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test"])
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test");
|
||||
new_ucmd!()
|
||||
.args(&["if=random-5828891cb1230748e146f34223bbd3b5.test"])
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("random-5828891cb1230748e146f34223bbd3b5.test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_random_73k_test_not_a_multiple_obs_gt_ibs() {
|
||||
new_ucmd!()
|
||||
.args(&[
|
||||
"ibs=521",
|
||||
"obs=1031",
|
||||
"if=random-5828891cb1230748e146f34223bbd3b5.test",
|
||||
])
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("random-5828891cb1230748e146f34223bbd3b5.test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_random_73k_test_obs_lt_not_a_multiple_ibs() {
|
||||
new_ucmd!()
|
||||
.args(&[
|
||||
"ibs=1031",
|
||||
"obs=521",
|
||||
"if=random-5828891cb1230748e146f34223bbd3b5.test",
|
||||
])
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("random-5828891cb1230748e146f34223bbd3b5.test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deadbeef_all_32k_test_count_reads() {
|
||||
new_ucmd!()
|
||||
.args(&[
|
||||
"bs=1024",
|
||||
"count=32",
|
||||
"if=deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test",
|
||||
])
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deadbeef_all_32k_test_count_bytes() {
|
||||
new_ucmd!()
|
||||
.args(&[
|
||||
"ibs=531",
|
||||
"obs=1031",
|
||||
"count=32x1024",
|
||||
"oflag=count_bytes",
|
||||
"if=deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test",
|
||||
])
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deadbeef_32k_to_16k_test_count_reads() {
|
||||
new_ucmd!()
|
||||
.args(&[
|
||||
"ibs=1024",
|
||||
"obs=1031",
|
||||
"count=16",
|
||||
"if=deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test",
|
||||
])
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("gnudd-deadbeef-first-16k.spec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deadbeef_32k_to_12345_test_count_bytes() {
|
||||
new_ucmd!()
|
||||
.args(&[
|
||||
"ibs=531",
|
||||
"obs=1031",
|
||||
"count=12345",
|
||||
"iflag=count_bytes",
|
||||
"if=deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test",
|
||||
])
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("gnudd-deadbeef-first-12345.spec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_random_73k_test_count_reads() {
|
||||
new_ucmd!()
|
||||
.args(&[
|
||||
"bs=1024",
|
||||
"count=32",
|
||||
"if=random-5828891cb1230748e146f34223bbd3b5.test",
|
||||
])
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("gnudd-random-first-32k.spec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_random_73k_test_count_bytes() {
|
||||
new_ucmd!()
|
||||
.args(&[
|
||||
"ibs=521",
|
||||
"obs=1031",
|
||||
"count=32x1024",
|
||||
"iflag=count_bytes",
|
||||
"if=random-5828891cb1230748e146f34223bbd3b5.test",
|
||||
])
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("gnudd-random-first-32k.spec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_all_valid_ascii_ebcdic_ascii_roundtrip_conv_test() {
|
||||
let tmp = new_ucmd!()
|
||||
.args(&["ibs=128", "obs=1024", "conv=ebcdic"])
|
||||
.pipe_in_fixture("all-valid-ascii-chars-37eff01866ba3f538421b30b7cbefcac.test")
|
||||
.succeeds()
|
||||
.stdout_move_bytes();
|
||||
new_ucmd!()
|
||||
.args(&["ibs=256", "obs=1024", "conv=ascii"])
|
||||
.pipe_in(tmp)
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("all-valid-ascii-chars-37eff01866ba3f538421b30b7cbefcac.test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_skip_zero() {
|
||||
new_ucmd!()
|
||||
.args(&["skip=0", "status=noxfer"])
|
||||
.succeeds()
|
||||
.no_stdout()
|
||||
.stderr_is("0+0 records in\n0+0 records out\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_truncated_record() {
|
||||
new_ucmd!()
|
||||
.args(&["cbs=1", "conv=block", "status=noxfer"])
|
||||
.pipe_in("ab")
|
||||
.succeeds()
|
||||
.stdout_is("a")
|
||||
.stderr_is("0+1 records in\n0+1 records out\n1 truncated record\n");
|
||||
new_ucmd!()
|
||||
.args(&["cbs=1", "conv=block", "status=noxfer"])
|
||||
.pipe_in("ab\ncd\n")
|
||||
.succeeds()
|
||||
.stdout_is("ac")
|
||||
.stderr_is("0+1 records in\n0+1 records out\n2 truncated records\n");
|
||||
}
|
||||
|
||||
/// Test that the output file can be `/dev/null`.
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn test_outfile_dev_null() {
|
||||
new_ucmd!().arg("of=/dev/null").succeeds().no_stdout();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_block_sync() {
|
||||
new_ucmd!()
|
||||
.args(&["ibs=5", "cbs=5", "conv=block,sync", "status=noxfer"])
|
||||
.pipe_in("012\nabcde\n")
|
||||
.succeeds()
|
||||
// blocks: 1 2
|
||||
.stdout_is("012 abcde")
|
||||
.stderr_is("2+0 records in\n0+1 records out\n");
|
||||
|
||||
// It seems that a partial record in is represented as an
|
||||
// all-spaces block at the end of the output. The "1 truncated
|
||||
// record" line is present in the status report due to the line
|
||||
// "abcdefg\n" being truncated to "abcde".
|
||||
new_ucmd!()
|
||||
.args(&["ibs=5", "cbs=5", "conv=block,sync", "status=noxfer"])
|
||||
.pipe_in("012\nabcdefg\n")
|
||||
.succeeds()
|
||||
// blocks: 1 2 3
|
||||
.stdout_is("012 abcde ")
|
||||
.stderr_is("2+1 records in\n0+1 records out\n1 truncated record\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytes_iseek_bytes_iflag() {
|
||||
new_ucmd!()
|
||||
.args(&["iseek=10", "iflag=skip_bytes", "bs=2"])
|
||||
.pipe_in("0123456789abcdefghijklm")
|
||||
.succeeds()
|
||||
.stdout_is("abcdefghijklm");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytes_iseek_skip_additive() {
|
||||
new_ucmd!()
|
||||
.args(&["iseek=5", "skip=5", "iflag=skip_bytes", "bs=2"])
|
||||
.pipe_in("0123456789abcdefghijklm")
|
||||
.succeeds()
|
||||
.stdout_is("abcdefghijklm");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytes_oseek_bytes_oflag() {
|
||||
new_ucmd!()
|
||||
.args(&["oseek=8", "oflag=seek_bytes", "bs=2"])
|
||||
.pipe_in("abcdefghijklm")
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("dd-bytes-alphabet-null.spec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytes_oseek_bytes_trunc_oflag() {
|
||||
new_ucmd!()
|
||||
.args(&["oseek=8", "oflag=seek_bytes", "bs=2", "count=0"])
|
||||
.pipe_in("abcdefghijklm")
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("dd-bytes-null-trunc.spec");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytes_oseek_seek_additive() {
|
||||
new_ucmd!()
|
||||
.args(&["oseek=4", "seek=4", "oflag=seek_bytes", "bs=2"])
|
||||
.pipe_in("abcdefghijklm")
|
||||
.succeeds()
|
||||
.stdout_is_fixture_bytes("dd-bytes-alphabet-null.spec");
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// spell-checker:ignore udev pcent
|
||||
use crate::common::util::*;
|
||||
|
||||
#[test]
|
||||
|
@ -5,6 +6,11 @@ fn test_df_compatible_no_size_arg() {
|
|||
new_ucmd!().arg("-a").succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_df_shortened_long_argument() {
|
||||
new_ucmd!().arg("--a").succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_df_compatible() {
|
||||
new_ucmd!().arg("-ah").succeeds();
|
||||
|
@ -22,6 +28,8 @@ fn test_df_compatible_si() {
|
|||
|
||||
#[test]
|
||||
fn test_df_output() {
|
||||
// TODO These should fail because `-total` should have two dashes,
|
||||
// not just one. But they don't fail.
|
||||
if cfg!(target_os = "macos") {
|
||||
new_ucmd!().arg("-H").arg("-total").succeeds().
|
||||
stdout_only("Filesystem Size Used Available Capacity Use% Mounted on \n");
|
||||
|
@ -32,4 +40,243 @@ fn test_df_output() {
|
|||
}
|
||||
}
|
||||
|
||||
// ToDO: more tests...
|
||||
/// Test that the order of rows in the table does not change across executions.
|
||||
#[test]
|
||||
fn test_order_same() {
|
||||
let output1 = new_ucmd!()
|
||||
.arg("--output=source")
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
let output2 = new_ucmd!()
|
||||
.arg("--output=source")
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
assert_eq!(output1, output2);
|
||||
}
|
||||
|
||||
/// Test of mount point begin repeated
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn test_output_mp_repeat() {
|
||||
let output1 = new_ucmd!().arg("/").arg("/").succeeds().stdout_move_str();
|
||||
let output1: Vec<String> = output1
|
||||
.lines()
|
||||
.map(|l| String::from(l.split_once(' ').unwrap().0))
|
||||
.collect();
|
||||
assert_eq!(3, output1.len());
|
||||
assert_eq!(output1[1], output1[2]);
|
||||
}
|
||||
#[test]
|
||||
fn test_output_conflict_options() {
|
||||
for option in ["-i", "-T", "-P"] {
|
||||
new_ucmd!().arg("--output=source").arg(option).fails();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_output_option() {
|
||||
new_ucmd!().arg("--output").succeeds();
|
||||
new_ucmd!().arg("--output=source,target").succeeds();
|
||||
new_ucmd!().arg("--output=invalid_option").fails();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_output_option_without_equals_sign() {
|
||||
new_ucmd!().arg("--output").arg(".").succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_type_option() {
|
||||
new_ucmd!().args(&["-t", "ext4", "-t", "ext3"]).succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exclude_type_option() {
|
||||
new_ucmd!().args(&["-x", "ext4", "-x", "ext3"]).succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_total() {
|
||||
// Example output:
|
||||
//
|
||||
// Filesystem 1K-blocks Used Available Use% Mounted on
|
||||
// udev 3858016 0 3858016 0% /dev
|
||||
// ...
|
||||
// /dev/loop14 63488 63488 0 100% /snap/core20/1361
|
||||
// total 258775268 98099712 148220200 40% -
|
||||
let output = new_ucmd!().arg("--total").succeeds().stdout_move_str();
|
||||
|
||||
// Skip the header line.
|
||||
let lines: Vec<&str> = output.lines().skip(1).collect();
|
||||
|
||||
// Parse the values from the last row.
|
||||
let last_line = lines.last().unwrap();
|
||||
let mut iter = last_line.split_whitespace();
|
||||
assert_eq!(iter.next().unwrap(), "total");
|
||||
let reported_total_size = iter.next().unwrap().parse().unwrap();
|
||||
let reported_total_used = iter.next().unwrap().parse().unwrap();
|
||||
let reported_total_avail = iter.next().unwrap().parse().unwrap();
|
||||
|
||||
// Loop over each row except the last, computing the sum of each column.
|
||||
let mut computed_total_size = 0;
|
||||
let mut computed_total_used = 0;
|
||||
let mut computed_total_avail = 0;
|
||||
let n = lines.len();
|
||||
for line in &lines[..n - 1] {
|
||||
let mut iter = line.split_whitespace();
|
||||
iter.next().unwrap();
|
||||
computed_total_size += iter.next().unwrap().parse::<u64>().unwrap();
|
||||
computed_total_used += iter.next().unwrap().parse::<u64>().unwrap();
|
||||
computed_total_avail += iter.next().unwrap().parse::<u64>().unwrap();
|
||||
}
|
||||
|
||||
// Check that the sum of each column matches the reported value in
|
||||
// the last row.
|
||||
assert_eq!(computed_total_size, reported_total_size);
|
||||
assert_eq!(computed_total_used, reported_total_used);
|
||||
assert_eq!(computed_total_avail, reported_total_avail);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_use_percentage() {
|
||||
let output = new_ucmd!()
|
||||
.args(&["--total", "--output=used,avail,pcent"])
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
|
||||
// Skip the header line.
|
||||
let lines: Vec<&str> = output.lines().skip(1).collect();
|
||||
|
||||
for line in lines {
|
||||
let mut iter = line.split_whitespace();
|
||||
let reported_used = iter.next().unwrap().parse::<f64>().unwrap();
|
||||
let reported_avail = iter.next().unwrap().parse::<f64>().unwrap();
|
||||
let reported_percentage = iter.next().unwrap();
|
||||
let reported_percentage = reported_percentage[..reported_percentage.len() - 1]
|
||||
.parse::<u8>()
|
||||
.unwrap();
|
||||
let computed_percentage =
|
||||
(100.0 * (reported_used / (reported_used + reported_avail))).ceil() as u8;
|
||||
|
||||
assert_eq!(computed_percentage, reported_percentage);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_block_size_1024() {
|
||||
fn get_header(block_size: u64) -> String {
|
||||
// TODO When #3057 is resolved, we should just use
|
||||
//
|
||||
// new_ucmd!().arg("--output=size").succeeds().stdout_move_str();
|
||||
//
|
||||
// instead of parsing the entire `df` table as a string.
|
||||
let output = new_ucmd!()
|
||||
.args(&["-B", &format!("{}", block_size)])
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
let first_line = output.lines().next().unwrap();
|
||||
let mut column_labels = first_line.split_whitespace();
|
||||
let size_column_label = column_labels.nth(1).unwrap();
|
||||
size_column_label.into()
|
||||
}
|
||||
|
||||
assert_eq!(get_header(1024), "1K-blocks");
|
||||
assert_eq!(get_header(2048), "2K-blocks");
|
||||
assert_eq!(get_header(4096), "4K-blocks");
|
||||
assert_eq!(get_header(1024 * 1024), "1M-blocks");
|
||||
assert_eq!(get_header(2 * 1024 * 1024), "2M-blocks");
|
||||
assert_eq!(get_header(1024 * 1024 * 1024), "1G-blocks");
|
||||
assert_eq!(get_header(34 * 1024 * 1024 * 1024), "34G-blocks");
|
||||
}
|
||||
|
||||
// TODO The spacing does not match GNU df. Also we need to remove
|
||||
// trailing spaces from the heading row.
|
||||
#[test]
|
||||
fn test_output_selects_columns() {
|
||||
let output = new_ucmd!()
|
||||
.args(&["--output=source"])
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
assert_eq!(output.lines().next().unwrap(), "Filesystem ");
|
||||
|
||||
let output = new_ucmd!()
|
||||
.args(&["--output=source,target"])
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
assert_eq!(
|
||||
output.lines().next().unwrap(),
|
||||
"Filesystem Mounted on "
|
||||
);
|
||||
|
||||
let output = new_ucmd!()
|
||||
.args(&["--output=source,target,used"])
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
assert_eq!(
|
||||
output.lines().next().unwrap(),
|
||||
"Filesystem Mounted on Used "
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_output_multiple_occurrences() {
|
||||
let output = new_ucmd!()
|
||||
.args(&["--output=source", "--output=target"])
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
assert_eq!(
|
||||
output.lines().next().unwrap(),
|
||||
"Filesystem Mounted on "
|
||||
);
|
||||
}
|
||||
|
||||
// TODO Fix the spacing.
|
||||
#[test]
|
||||
fn test_output_file_all_filesystems() {
|
||||
// When run with no positional arguments, `df` lets "-" represent
|
||||
// the "File" entry for each row.
|
||||
let output = new_ucmd!()
|
||||
.arg("--output=file")
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
let mut lines = output.lines();
|
||||
assert_eq!(lines.next().unwrap(), "File ");
|
||||
for line in lines {
|
||||
assert_eq!(line, "- ");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Fix the spacing.
|
||||
#[test]
|
||||
fn test_output_file_specific_files() {
|
||||
// Create three files.
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.touch("a");
|
||||
at.touch("b");
|
||||
at.touch("c");
|
||||
|
||||
// When run with positional arguments, the filesystems should
|
||||
// appear in the "File" column.
|
||||
let output = ucmd
|
||||
.args(&["--output=file", "a", "b", "c"])
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
let actual: Vec<&str> = output.lines().collect();
|
||||
assert_eq!(
|
||||
actual,
|
||||
vec![
|
||||
"File ",
|
||||
"a ",
|
||||
"b ",
|
||||
"c "
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_output_field_no_more_than_once() {
|
||||
new_ucmd!()
|
||||
.arg("--output=target,source,target")
|
||||
.fails()
|
||||
.usage_error("option --output: field 'target' used more than once");
|
||||
}
|
||||
|
|
|
@ -179,15 +179,15 @@ fn test_du_hard_link() {
|
|||
|
||||
#[cfg(target_vendor = "apple")]
|
||||
fn _du_hard_link(s: &str) {
|
||||
assert_eq!(s, "12\tsubdir/links\n")
|
||||
assert_eq!(s, "12\tsubdir/links\n");
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
fn _du_hard_link(s: &str) {
|
||||
assert_eq!(s, "8\tsubdir/links\n")
|
||||
assert_eq!(s, "8\tsubdir/links\n");
|
||||
}
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn _du_hard_link(s: &str) {
|
||||
assert_eq!(s, "16\tsubdir/links\n")
|
||||
assert_eq!(s, "16\tsubdir/links\n");
|
||||
}
|
||||
#[cfg(all(
|
||||
not(target_vendor = "apple"),
|
||||
|
|
|
@ -138,11 +138,19 @@ fn test_escape_short_octal() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_no_octal() {
|
||||
fn test_escape_nul() {
|
||||
new_ucmd!()
|
||||
.args(&["-e", "foo\\0 bar"])
|
||||
.succeeds()
|
||||
.stdout_only("foo\\0 bar\n");
|
||||
.stdout_only("foo\0 bar\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_octal_invalid_digit() {
|
||||
new_ucmd!()
|
||||
.args(&["-e", "foo\\08 bar"])
|
||||
.succeeds()
|
||||
.stdout_only("foo\u{0}8 bar\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
// spell-checker:ignore (words) bamf chdir
|
||||
|
||||
#[cfg(not(windows))]
|
||||
use std::fs;
|
||||
// spell-checker:ignore (words) bamf chdir rlimit prlimit COMSPEC
|
||||
|
||||
use crate::common::util::*;
|
||||
use std::env;
|
||||
|
@ -80,6 +77,20 @@ fn test_combined_file_set_unset() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unset_invalid_variables() {
|
||||
use uucore::display::Quotable;
|
||||
|
||||
// Cannot test input with \0 in it, since output will also contain \0. rlimit::prlimit fails
|
||||
// with this error: Error { kind: InvalidInput, message: "nul byte found in provided data" }
|
||||
for var in &["", "a=b"] {
|
||||
new_ucmd!().arg("-u").arg(var).run().stderr_only(format!(
|
||||
"env: cannot unset {}: Invalid argument",
|
||||
var.quote()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_single_name_value_pair() {
|
||||
let out = new_ucmd!().arg("FOO=bar").run();
|
||||
|
@ -108,6 +119,15 @@ fn test_ignore_environment() {
|
|||
scene.ucmd().arg("-").run().no_stdout();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty_name() {
|
||||
new_ucmd!()
|
||||
.arg("-i")
|
||||
.arg("=xyz")
|
||||
.run()
|
||||
.stderr_only("env: warning: no name specified for value 'xyz'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_null_delimiter() {
|
||||
let out = new_ucmd!()
|
||||
|
@ -154,7 +174,7 @@ fn test_fail_null_with_program() {
|
|||
fn test_change_directory() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let temporary_directory = tempdir().unwrap();
|
||||
let temporary_path = fs::canonicalize(temporary_directory.path()).unwrap();
|
||||
let temporary_path = std::fs::canonicalize(temporary_directory.path()).unwrap();
|
||||
assert_ne!(env::current_dir().unwrap(), temporary_path);
|
||||
|
||||
// command to print out current working directory
|
||||
|
@ -167,30 +187,39 @@ fn test_change_directory() {
|
|||
.arg(pwd)
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
assert_eq!(out.trim(), temporary_path.as_os_str())
|
||||
assert_eq!(out.trim(), temporary_path.as_os_str());
|
||||
}
|
||||
|
||||
// no way to consistently get "current working directory", `cd` doesn't work @ CI
|
||||
// instead, we test that the unique temporary directory appears somewhere in the printed variables
|
||||
#[cfg(windows)]
|
||||
#[test]
|
||||
fn test_change_directory() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let temporary_directory = tempdir().unwrap();
|
||||
let temporary_path = temporary_directory.path();
|
||||
|
||||
assert_ne!(env::current_dir().unwrap(), temporary_path);
|
||||
let temporary_path = temporary_directory.path();
|
||||
let temporary_path = temporary_path
|
||||
.strip_prefix(r"\\?\")
|
||||
.unwrap_or(temporary_path);
|
||||
|
||||
let env_cd = env::current_dir().unwrap();
|
||||
let env_cd = env_cd.strip_prefix(r"\\?\").unwrap_or(&env_cd);
|
||||
|
||||
assert_ne!(env_cd, temporary_path);
|
||||
|
||||
// COMSPEC is a variable that contains the full path to cmd.exe
|
||||
let cmd_path = env::var("COMSPEC").unwrap();
|
||||
|
||||
// command to print out current working directory
|
||||
let pwd = [&*cmd_path, "/C", "cd"];
|
||||
|
||||
let out = scene
|
||||
.ucmd()
|
||||
.arg("--chdir")
|
||||
.arg(&temporary_path)
|
||||
.args(&pwd)
|
||||
.succeeds()
|
||||
.stdout_move_str();
|
||||
|
||||
assert!(!out
|
||||
.lines()
|
||||
.any(|line| line.ends_with(temporary_path.file_name().unwrap().to_str().unwrap())));
|
||||
assert_eq!(out.trim(), temporary_path.as_os_str());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// spell-checker:ignore αbcdef
|
||||
|
||||
use crate::common::util::*;
|
||||
|
||||
#[test]
|
||||
|
@ -95,6 +97,27 @@ fn test_and() {
|
|||
new_ucmd!().args(&["", "&", "1"]).run().stdout_is("0\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_length_fail() {
|
||||
new_ucmd!().args(&["length", "αbcdef", "1"]).fails();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_length() {
|
||||
new_ucmd!()
|
||||
.args(&["length", "abcdef"])
|
||||
.succeeds()
|
||||
.stdout_only("6\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_length_mb() {
|
||||
new_ucmd!()
|
||||
.args(&["length", "αbcdef"])
|
||||
.succeeds()
|
||||
.stdout_only("6\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_substr() {
|
||||
new_ucmd!()
|
||||
|
|
|
@ -29,6 +29,8 @@ const NUM_TESTS: usize = 100;
|
|||
|
||||
#[test]
|
||||
fn test_parallel() {
|
||||
use hex_literal::hex;
|
||||
use sha1::{Digest, Sha1};
|
||||
// factor should only flush the buffer at line breaks
|
||||
let n_integers = 100_000;
|
||||
let mut input_string = String::new();
|
||||
|
@ -60,13 +62,20 @@ fn test_parallel() {
|
|||
.ccmd("sort")
|
||||
.arg(tmp_dir.plus("output"))
|
||||
.succeeds();
|
||||
let hash_check = sha1::Sha1::from(result.stdout()).hexdigest();
|
||||
assert_eq!(hash_check, "cc743607c0ff300ff575d92f4ff0c87d5660c393");
|
||||
let mut hasher = Sha1::new();
|
||||
hasher.update(result.stdout());
|
||||
let hash_check = hasher.finalize();
|
||||
assert_eq!(
|
||||
hash_check[..],
|
||||
hex!("cc743607c0ff300ff575d92f4ff0c87d5660c393")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_first_100000_integers() {
|
||||
extern crate sha1;
|
||||
use hex_literal::hex;
|
||||
use sha1::{Digest, Sha1};
|
||||
|
||||
let n_integers = 100_000;
|
||||
let mut input_string = String::new();
|
||||
|
@ -78,8 +87,13 @@ fn test_first_100000_integers() {
|
|||
let result = new_ucmd!().pipe_in(input_string.as_bytes()).succeeds();
|
||||
|
||||
// `seq 0 100000 | factor | sha1sum` => "4ed2d8403934fa1c76fe4b84c5d4b8850299c359"
|
||||
let hash_check = sha1::Sha1::from(result.stdout()).hexdigest();
|
||||
assert_eq!(hash_check, "4ed2d8403934fa1c76fe4b84c5d4b8850299c359");
|
||||
let mut hasher = Sha1::new();
|
||||
hasher.update(result.stdout());
|
||||
let hash_check = hasher.finalize();
|
||||
assert_eq!(
|
||||
hash_check[..],
|
||||
hex!("4ed2d8403934fa1c76fe4b84c5d4b8850299c359")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -115,7 +129,7 @@ fn test_random() {
|
|||
// log distribution---higher probability for lower numbers
|
||||
let factor;
|
||||
loop {
|
||||
let next = rng.gen_range(0_f64, log_num_primes).exp2().floor() as usize;
|
||||
let next = rng.gen_range(0_f64..log_num_primes).exp2().floor() as usize;
|
||||
if next < NUM_PRIMES {
|
||||
factor = primes[next];
|
||||
break;
|
||||
|
|
|
@ -1,6 +1,53 @@
|
|||
use crate::common::util::*;
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
|
||||
use std::fs::OpenOptions;
|
||||
|
||||
#[test]
|
||||
fn test_exit_code() {
|
||||
new_ucmd!().fails();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_version() {
|
||||
new_ucmd!()
|
||||
.args(&["--version"])
|
||||
.fails()
|
||||
.stdout_contains("false");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_help() {
|
||||
new_ucmd!()
|
||||
.args(&["--help"])
|
||||
.fails()
|
||||
.stdout_contains("false");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_short_options() {
|
||||
for option in ["-h", "-V"] {
|
||||
new_ucmd!().arg(option).fails().stdout_is("");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conflict() {
|
||||
new_ucmd!()
|
||||
.args(&["--help", "--version"])
|
||||
.fails()
|
||||
.stdout_is("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
|
||||
fn test_full() {
|
||||
for option in ["--version", "--help"] {
|
||||
let dev_full = OpenOptions::new().write(true).open("/dev/full").unwrap();
|
||||
|
||||
new_ucmd!()
|
||||
.arg(option)
|
||||
.set_stdout(dev_full)
|
||||
.fails()
|
||||
.stderr_contains("No space left on device");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,4 +80,5 @@ test_digest! {
|
|||
shake128_256 shake128 256
|
||||
shake256_512 shake256 512
|
||||
b2sum b2sum 512
|
||||
b3sum b3sum 256
|
||||
}
|
||||
|
|
|
@ -157,11 +157,17 @@ fn test_negative_byte_syntax() {
|
|||
#[test]
|
||||
fn test_negative_zero_lines() {
|
||||
new_ucmd!()
|
||||
.args(&["--lines=-0"])
|
||||
.arg("--lines=-0")
|
||||
.pipe_in("a\nb\n")
|
||||
.succeeds()
|
||||
.stdout_is("a\nb\n");
|
||||
new_ucmd!()
|
||||
.arg("--lines=-0")
|
||||
.pipe_in("a\nb")
|
||||
.succeeds()
|
||||
.stdout_is("a\nb");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_negative_zero_bytes() {
|
||||
new_ucmd!()
|
||||
|
@ -220,9 +226,9 @@ fn test_zero_terminated() {
|
|||
fn test_obsolete_extras() {
|
||||
new_ucmd!()
|
||||
.args(&["-5zv"])
|
||||
.pipe_in("1\02\03\04\05\06")
|
||||
.pipe_in("1\x002\x003\x004\x005\x006")
|
||||
.succeeds()
|
||||
.stdout_is("==> standard input <==\n1\02\03\04\05\0");
|
||||
.stdout_is("==> standard input <==\n1\x002\x003\x004\x005\0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -295,17 +301,24 @@ fn test_head_invalid_num() {
|
|||
#[cfg(target_pointer_width = "32")]
|
||||
{
|
||||
let sizes = ["1000G", "10T"];
|
||||
for size in &sizes {
|
||||
new_ucmd!().args(&["-c", size]).succeeds();
|
||||
}
|
||||
}
|
||||
#[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
|
||||
));
|
||||
.stderr_is("head: out of range integral type conversion attempted: number of bytes is too large");
|
||||
}
|
||||
}
|
||||
new_ucmd!()
|
||||
.args(&["-c", "-³"])
|
||||
.fails()
|
||||
.stderr_is("head: invalid number of bytes: '³'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -329,3 +342,21 @@ fn test_head_num_with_undocumented_sign_bytes() {
|
|||
.succeeds()
|
||||
.stdout_is("abcde");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_presume_input_pipe_default() {
|
||||
new_ucmd!()
|
||||
.args(&["---presume-input-pipe"])
|
||||
.pipe_in_fixture(INPUT)
|
||||
.run()
|
||||
.stdout_is_fixture("lorem_ipsum_default.expected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_presume_input_pipe_5_chars() {
|
||||
new_ucmd!()
|
||||
.args(&["-c", "5", "---presume-input-pipe"])
|
||||
.pipe_in_fixture(INPUT)
|
||||
.run()
|
||||
.stdout_is_fixture("lorem_ipsum_5_chars.expected");
|
||||
}
|
||||
|
|
|
@ -9,16 +9,6 @@ use std::process::Command;
|
|||
#[cfg(target_os = "linux")]
|
||||
use std::thread::sleep;
|
||||
|
||||
#[test]
|
||||
fn test_install_help() {
|
||||
let (_, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
ucmd.arg("--help")
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_contains("FLAGS:");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install_basic() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
@ -493,7 +483,7 @@ fn test_install_copy_then_compare_file() {
|
|||
file2_meta = at.metadata(file2);
|
||||
let after = FileTime::from_last_modification_time(&file2_meta);
|
||||
|
||||
assert!(before == after);
|
||||
assert_eq!(before, after);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -825,6 +815,31 @@ fn test_install_backup_short_custom_suffix() {
|
|||
assert!(at.file_exists(&format!("{}{}", file_b, suffix)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install_backup_short_custom_suffix_hyphen_value() {
|
||||
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 = "-v";
|
||||
|
||||
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!());
|
||||
|
@ -1085,3 +1100,67 @@ fn test_install_backup_off() {
|
|||
assert!(at.file_exists(file_b));
|
||||
assert!(!at.file_exists(&format!("{}~", file_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install_missing_arguments() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.fails()
|
||||
.stderr_contains("install: missing file operand");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install_missing_destination() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file_1 = "source_file1";
|
||||
|
||||
at.touch(file_1);
|
||||
scene.ucmd().arg(file_1).fails().stderr_contains(format!(
|
||||
"install: missing destination file operand after '{}'",
|
||||
file_1
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_install_dir_dot() {
|
||||
// To match tests/install/d-slashdot.sh
|
||||
let scene = TestScenario::new(util_name!());
|
||||
|
||||
scene.ucmd().arg("-d").arg("dir1/.").succeeds();
|
||||
scene.ucmd().arg("-d").arg("dir2/..").succeeds();
|
||||
// Tests that we don't have dir3/. in the output
|
||||
// but only 'dir3'
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-d")
|
||||
.arg("dir3/.")
|
||||
.arg("-v")
|
||||
.succeeds()
|
||||
.stdout_contains("creating directory 'dir3'");
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-d")
|
||||
.arg("dir4/./cal")
|
||||
.arg("-v")
|
||||
.succeeds()
|
||||
.stdout_contains("creating directory 'dir4/./cal'");
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-d")
|
||||
.arg("dir5/./cali/.")
|
||||
.arg("-v")
|
||||
.succeeds()
|
||||
.stdout_contains("creating directory 'dir5/cali'");
|
||||
|
||||
let at = &scene.fixtures;
|
||||
|
||||
assert!(at.dir_exists("dir1"));
|
||||
assert!(at.dir_exists("dir2"));
|
||||
assert!(at.dir_exists("dir3"));
|
||||
assert!(at.dir_exists("dir4/cal"));
|
||||
assert!(at.dir_exists("dir5/cali"));
|
||||
}
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
// spell-checker:ignore (words) autoformat
|
||||
// spell-checker:ignore (words) autoformat nocheck
|
||||
|
||||
use crate::common::util::*;
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
|
||||
use std::fs::OpenOptions;
|
||||
#[cfg(unix)]
|
||||
use std::{ffi::OsStr, os::unix::ffi::OsStrExt};
|
||||
#[cfg(windows)]
|
||||
use std::{ffi::OsString, os::windows::ffi::OsStringExt};
|
||||
|
||||
#[test]
|
||||
fn empty_files() {
|
||||
|
@ -75,6 +81,27 @@ fn different_field() {
|
|||
.stdout_only_fixture("different_field.expected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn out_of_bounds_fields() {
|
||||
new_ucmd!()
|
||||
.arg("fields_1.txt")
|
||||
.arg("fields_4.txt")
|
||||
.arg("-1")
|
||||
.arg("3")
|
||||
.arg("-2")
|
||||
.arg("5")
|
||||
.succeeds()
|
||||
.stdout_only_fixture("out_of_bounds_fields.expected");
|
||||
|
||||
new_ucmd!()
|
||||
.arg("fields_1.txt")
|
||||
.arg("fields_4.txt")
|
||||
.arg("-j")
|
||||
.arg("100000000000000000000") // > usize::MAX for 64 bits
|
||||
.succeeds()
|
||||
.stdout_only_fixture("out_of_bounds_fields.expected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unpaired_lines() {
|
||||
new_ucmd!()
|
||||
|
@ -281,13 +308,66 @@ fn missing_format_fields() {
|
|||
.stdout_only_fixture("missing_format_fields.expected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nocheck_order() {
|
||||
new_ucmd!()
|
||||
.arg("fields_1.txt")
|
||||
.arg("fields_2.txt")
|
||||
.arg("--nocheck-order")
|
||||
.succeeds()
|
||||
.stdout_only_fixture("default.expected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrong_line_order() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
new_ucmd!()
|
||||
.arg("fields_2.txt")
|
||||
.arg("fields_4.txt")
|
||||
.fails()
|
||||
.stderr_is("fields_4.txt:5: is not sorted");
|
||||
.stdout_contains("7 g f 4 fg")
|
||||
.stderr_is(&format!(
|
||||
"{0} {1}: fields_4.txt:5: is not sorted: 11 g 5 gh\n{0} {1}: input is not in sorted order",
|
||||
ts.bin_path.to_string_lossy(),
|
||||
ts.util_name
|
||||
));
|
||||
|
||||
new_ucmd!()
|
||||
.arg("--check-order")
|
||||
.arg("fields_2.txt")
|
||||
.arg("fields_4.txt")
|
||||
.fails()
|
||||
.stdout_does_not_contain("7 g f 4 fg")
|
||||
.stderr_is(&format!(
|
||||
"{0}: fields_4.txt:5: is not sorted: 11 g 5 gh",
|
||||
ts.util_name
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn both_files_wrong_line_order() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
new_ucmd!()
|
||||
.arg("fields_4.txt")
|
||||
.arg("fields_5.txt")
|
||||
.fails()
|
||||
.stdout_contains("5 e 3 ef")
|
||||
.stderr_is(&format!(
|
||||
"{0} {1}: fields_5.txt:4: is not sorted: 3\n{0} {1}: fields_4.txt:5: is not sorted: 11 g 5 gh\n{0} {1}: input is not in sorted order",
|
||||
ts.bin_path.to_string_lossy(),
|
||||
ts.util_name
|
||||
));
|
||||
|
||||
new_ucmd!()
|
||||
.arg("--check-order")
|
||||
.arg("fields_4.txt")
|
||||
.arg("fields_5.txt")
|
||||
.fails()
|
||||
.stdout_does_not_contain("5 e 3 ef")
|
||||
.stderr_is(&format!(
|
||||
"{0}: fields_5.txt:4: is not sorted: 3",
|
||||
ts.util_name
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -328,3 +408,80 @@ fn single_file_with_header() {
|
|||
.succeeds()
|
||||
.stdout_is("A 1\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_line_feeds() {
|
||||
new_ucmd!()
|
||||
.arg("non-line_feeds_1.txt")
|
||||
.arg("non-line_feeds_2.txt")
|
||||
.succeeds()
|
||||
.stdout_only_fixture("non-line_feeds.expected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_unicode() {
|
||||
new_ucmd!()
|
||||
.arg("non-unicode_1.bin")
|
||||
.arg("non-unicode_2.bin")
|
||||
.succeeds()
|
||||
.stdout_only_fixture("non-unicode.expected");
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let invalid_utf8: u8 = 167;
|
||||
new_ucmd!()
|
||||
.arg("-t")
|
||||
.arg(OsStr::from_bytes(&[invalid_utf8]))
|
||||
.arg("non-unicode_1.bin")
|
||||
.arg("non-unicode_2.bin")
|
||||
.succeeds()
|
||||
.stdout_only_fixture("non-unicode_sep.expected");
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let invalid_utf16: OsString = OsStringExt::from_wide(&[0xD800]);
|
||||
new_ucmd!()
|
||||
.arg("-t")
|
||||
.arg(&invalid_utf16)
|
||||
.arg("non-unicode_1.bin")
|
||||
.arg("non-unicode_2.bin")
|
||||
.fails()
|
||||
.stderr_is(
|
||||
"join: unprintable field separators are only supported on unix-like platforms",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn null_field_separators() {
|
||||
new_ucmd!()
|
||||
.arg("-t")
|
||||
.arg("\\0")
|
||||
.arg("non-unicode_1.bin")
|
||||
.arg("non-unicode_2.bin")
|
||||
.succeeds()
|
||||
.stdout_only_fixture("null-sep.expected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn null_line_endings() {
|
||||
new_ucmd!()
|
||||
.arg("-z")
|
||||
.arg("non-unicode_1.bin")
|
||||
.arg("non-unicode_2.bin")
|
||||
.succeeds()
|
||||
.stdout_only_fixture("z.expected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
|
||||
fn test_full() {
|
||||
let dev_full = OpenOptions::new().write(true).open("/dev/full").unwrap();
|
||||
new_ucmd!()
|
||||
.arg("fields_1.txt")
|
||||
.arg("fields_2.txt")
|
||||
.set_stdout(dev_full)
|
||||
.fails()
|
||||
.stderr_contains("No space left on device");
|
||||
}
|
||||
|
|
|
@ -13,8 +13,8 @@ impl Target {
|
|||
// Creates a target that will naturally die after some time if not killed
|
||||
// fast enough.
|
||||
// This timeout avoids hanging failing tests.
|
||||
fn new() -> Target {
|
||||
Target {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
child: Command::new("sleep")
|
||||
.arg("30")
|
||||
.spawn()
|
||||
|
|
|
@ -23,7 +23,7 @@ fn test_link_no_circular() {
|
|||
|
||||
ucmd.args(&[link, link])
|
||||
.fails()
|
||||
.stderr_is("link: No such file or directory (os error 2)\n");
|
||||
.stderr_is("link: cannot create link 'test_link_no_circular' to 'test_link_no_circular': No such file or directory");
|
||||
assert!(!at.file_exists(link));
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ fn test_link_nonexistent_file() {
|
|||
|
||||
ucmd.args(&[file, link])
|
||||
.fails()
|
||||
.stderr_is("link: No such file or directory (os error 2)\n");
|
||||
.stderr_only("link: cannot create link 'test_link_nonexistent_file_link' to 'test_link_nonexistent_file': No such file or directory");
|
||||
assert!(!at.file_exists(file));
|
||||
assert!(!at.file_exists(link));
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ fn test_link_one_argument() {
|
|||
let (_, mut ucmd) = at_and_ucmd!();
|
||||
let file = "test_link_argument";
|
||||
ucmd.args(&[file]).fails().stderr_contains(
|
||||
"error: The argument '<FILES>...' requires at least 2 values, but only 1 was provide",
|
||||
"error: The argument '<FILES>...' requires at least 2 values but only 1 was provided",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -58,6 +58,6 @@ fn test_link_three_arguments() {
|
|||
"test_link_argument3",
|
||||
];
|
||||
ucmd.args(&arguments[..]).fails().stderr_contains(
|
||||
format!("error: The value '{}' was provided to '<FILES>...', but it wasn't expecting any more values", arguments[2]),
|
||||
format!("error: The value '{}' was provided to '<FILES>...' but it wasn't expecting any more values", arguments[2]),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -180,6 +180,33 @@ fn test_symlink_custom_backup_suffix() {
|
|||
assert_eq!(at.resolve_link(backup), file);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_symlink_custom_backup_suffix_hyphen_value() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file = "test_symlink_custom_backup_suffix";
|
||||
let link = "test_symlink_custom_backup_suffix_link";
|
||||
let suffix = "-v";
|
||||
|
||||
at.touch(file);
|
||||
at.symlink_file(file, link);
|
||||
assert!(at.file_exists(file));
|
||||
assert!(at.is_symlink(link));
|
||||
assert_eq!(at.resolve_link(link), file);
|
||||
|
||||
let arg = &format!("--suffix={}", suffix);
|
||||
ucmd.args(&["-b", arg, "-s", file, link])
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
assert!(at.file_exists(file));
|
||||
|
||||
assert!(at.is_symlink(link));
|
||||
assert_eq!(at.resolve_link(link), file);
|
||||
|
||||
let backup = &format!("{}{}", link, suffix);
|
||||
assert!(at.is_symlink(backup));
|
||||
assert_eq!(at.resolve_link(backup), file);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_symlink_backup_numbering() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
@ -588,3 +615,38 @@ fn test_relative_recursive() {
|
|||
ucmd.args(&["-sr", "dir", "dir/recursive"]).succeeds();
|
||||
assert_eq!(at.resolve_link("dir/recursive"), ".");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_backup_same_file() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.touch("file1");
|
||||
ucmd.args(&["--backup", "file1", "./file1"])
|
||||
.fails()
|
||||
.stderr_contains("n: failed to link 'file1' to './file1': Same file");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_backup_force() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
at.write("a", "a\n");
|
||||
at.write("b", "b2\n");
|
||||
|
||||
scene.ucmd().args(&["-s", "b", "b~"]).succeeds().no_stderr();
|
||||
assert!(at.file_exists("a"));
|
||||
assert!(at.file_exists("b"));
|
||||
assert!(at.file_exists("b~"));
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&["-f", "--b=simple", "a", "b"])
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
assert!(at.file_exists("a"));
|
||||
assert!(at.file_exists("b"));
|
||||
assert!(at.file_exists("b~"));
|
||||
assert_eq!(at.read("a"), "a\n");
|
||||
assert_eq!(at.read("b"), "a\n");
|
||||
// we should have the same content as b as we had time to do a backup
|
||||
assert_eq!(at.read("b~"), "b2\n");
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -9,6 +9,10 @@ static TEST_DIR4: &str = "mkdir_test4/mkdir_test4_1";
|
|||
static TEST_DIR5: &str = "mkdir_test5/mkdir_test5_1";
|
||||
static TEST_DIR6: &str = "mkdir_test6";
|
||||
static TEST_FILE7: &str = "mkdir_test7";
|
||||
static TEST_DIR8: &str = "mkdir_test8/mkdir_test8_1/mkdir_test8_2";
|
||||
static TEST_DIR9: &str = "mkdir_test9/../mkdir_test9_1/../mkdir_test9_2";
|
||||
static TEST_DIR10: &str = "mkdir_test10/.";
|
||||
static TEST_DIR11: &str = "mkdir_test11/..";
|
||||
|
||||
#[test]
|
||||
fn test_mkdir_mkdir() {
|
||||
|
@ -75,7 +79,7 @@ fn test_symbolic_mode() {
|
|||
|
||||
ucmd.arg("-m").arg("a=rwx").arg(TEST_DIR1).succeeds();
|
||||
let perms = at.metadata(TEST_DIR1).permissions().mode();
|
||||
assert_eq!(perms, 0o40777)
|
||||
assert_eq!(perms, 0o40777);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -85,7 +89,7 @@ fn test_symbolic_alteration() {
|
|||
|
||||
ucmd.arg("-m").arg("-w").arg(TEST_DIR1).succeeds();
|
||||
let perms = at.metadata(TEST_DIR1).permissions().mode();
|
||||
assert_eq!(perms, 0o40555)
|
||||
assert_eq!(perms, 0o40555);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -98,5 +102,52 @@ fn test_multi_symbolic() {
|
|||
.arg(TEST_DIR1)
|
||||
.succeeds();
|
||||
let perms = at.metadata(TEST_DIR1).permissions().mode();
|
||||
assert_eq!(perms, 0o40750)
|
||||
assert_eq!(perms, 0o40750);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_recursive_reporting() {
|
||||
new_ucmd!()
|
||||
.arg("-p")
|
||||
.arg("-v")
|
||||
.arg(TEST_DIR8)
|
||||
.succeeds()
|
||||
.stdout_contains("created directory 'mkdir_test8'")
|
||||
.stdout_contains("created directory 'mkdir_test8/mkdir_test8_1'")
|
||||
.stdout_contains("created directory 'mkdir_test8/mkdir_test8_1/mkdir_test8_2'");
|
||||
new_ucmd!().arg("-v").arg(TEST_DIR8).fails().no_stdout();
|
||||
new_ucmd!()
|
||||
.arg("-p")
|
||||
.arg("-v")
|
||||
.arg(TEST_DIR9)
|
||||
.succeeds()
|
||||
.stdout_contains("created directory 'mkdir_test9'")
|
||||
.stdout_contains("created directory 'mkdir_test9/../mkdir_test9_1'")
|
||||
.stdout_contains("created directory 'mkdir_test9/../mkdir_test9_1/../mkdir_test9_2'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mkdir_trailing_dot() {
|
||||
let scene2 = TestScenario::new("ls");
|
||||
new_ucmd!()
|
||||
.arg("-p")
|
||||
.arg("-v")
|
||||
.arg("mkdir_test10-2")
|
||||
.succeeds();
|
||||
|
||||
new_ucmd!()
|
||||
.arg("-p")
|
||||
.arg("-v")
|
||||
.arg(TEST_DIR10)
|
||||
.succeeds()
|
||||
.stdout_contains("created directory 'mkdir_test10'");
|
||||
|
||||
new_ucmd!()
|
||||
.arg("-p")
|
||||
.arg("-v")
|
||||
.arg(TEST_DIR11)
|
||||
.succeeds()
|
||||
.stdout_contains("created directory 'mkdir_test11'");
|
||||
let result = scene2.cmd("ls").arg("-al").run();
|
||||
println!("ls dest {}", result.stdout_str());
|
||||
}
|
||||
|
|
|
@ -86,16 +86,14 @@ fn test_mknod_character_device_requires_major_and_minor() {
|
|||
.arg("1")
|
||||
.arg("c")
|
||||
.fails()
|
||||
.status_code(1)
|
||||
.stderr_contains(&"Invalid value for '<MINOR>'");
|
||||
.stderr_contains(&"Invalid value \"c\" for '<MINOR>'");
|
||||
new_ucmd!()
|
||||
.arg("test_file")
|
||||
.arg("c")
|
||||
.arg("c")
|
||||
.arg("1")
|
||||
.fails()
|
||||
.status_code(1)
|
||||
.stderr_contains(&"Invalid value for '<MAJOR>'");
|
||||
.stderr_contains(&"Invalid value \"c\" for '<MAJOR>'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -104,7 +102,6 @@ fn test_mknod_invalid_arg() {
|
|||
new_ucmd!()
|
||||
.arg("--foo")
|
||||
.fails()
|
||||
.status_code(1)
|
||||
.no_stdout()
|
||||
.stderr_contains(&"Found argument '--foo' which wasn't expected");
|
||||
}
|
||||
|
|
|
@ -15,15 +15,10 @@ fn test_more_dir_arg() {
|
|||
// Maybe we could capture the error, i.e. "Device not found" in that case
|
||||
// but I am leaving this for later
|
||||
if atty::is(atty::Stream::Stdout) {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
let result = ts.ucmd().arg(".").run();
|
||||
result.failure();
|
||||
let expected_error_message = &format!(
|
||||
"{0}: '.' is a directory.\nTry '{1} {0} --help' for more information.",
|
||||
ts.util_name,
|
||||
ts.bin_path.to_string_lossy()
|
||||
);
|
||||
assert_eq!(result.stderr_str().trim(), expected_error_message);
|
||||
new_ucmd!()
|
||||
.arg(".")
|
||||
.fails()
|
||||
.usage_error("'.' is a directory.");
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -232,6 +232,40 @@ fn test_mv_force_replace_file() {
|
|||
assert!(at.file_exists(file_b));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_same_file() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file_a = "test_mv_same_file_a";
|
||||
|
||||
at.touch(file_a);
|
||||
ucmd.arg(file_a).arg(file_a).fails().stderr_is(format!(
|
||||
"mv: '{f}' and '{f}' are the same file\n",
|
||||
f = file_a,
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_same_file_not_dot_dir() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let dir = "test_mv_errors_dir";
|
||||
|
||||
at.mkdir(dir);
|
||||
ucmd.arg(dir).arg(dir).fails().stderr_is(format!(
|
||||
"mv: cannot move '{d}' to a subdirectory of itself, '{d}/{d}'",
|
||||
d = dir,
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_same_file_dot_dir() {
|
||||
let (_at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
ucmd.arg(".")
|
||||
.arg(".")
|
||||
.fails()
|
||||
.stderr_is("mv: '.' and '.' are the same file\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_simple_backup() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
@ -306,6 +340,27 @@ fn test_mv_custom_backup_suffix() {
|
|||
assert!(at.file_exists(&format!("{}{}", file_b, suffix)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mv_custom_backup_suffix_hyphen_value() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file_a = "test_mv_custom_backup_suffix_file_a";
|
||||
let file_b = "test_mv_custom_backup_suffix_file_b";
|
||||
let suffix = "-v";
|
||||
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
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_mv_custom_backup_suffix_via_env() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
@ -522,17 +577,13 @@ fn test_mv_backup_off() {
|
|||
|
||||
#[test]
|
||||
fn test_mv_backup_no_clobber_conflicting_options() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
|
||||
ts.ucmd().arg("--backup")
|
||||
new_ucmd!()
|
||||
.arg("--backup")
|
||||
.arg("--no-clobber")
|
||||
.arg("file1")
|
||||
.arg("file2")
|
||||
.fails()
|
||||
.stderr_is(&format!("{0}: options --backup and --no-clobber are mutually exclusive\nTry '{1} {0} --help' for more information.",
|
||||
ts.util_name,
|
||||
ts.bin_path.to_string_lossy()
|
||||
));
|
||||
.usage_error("options --backup and --no-clobber are mutually exclusive");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -22,15 +22,10 @@ fn test_negative_adjustment() {
|
|||
|
||||
#[test]
|
||||
fn test_adjustment_with_no_command_should_error() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
|
||||
ts.ucmd()
|
||||
.args(&["-n", "19"])
|
||||
.run()
|
||||
.stderr_is(&format!("{0}: A command must be given with an adjustment.\nTry '{1} {0} --help' for more information.\n",
|
||||
ts.util_name,
|
||||
ts.bin_path.to_string_lossy()
|
||||
));
|
||||
new_ucmd!()
|
||||
.args(&["-n", "19"])
|
||||
.fails()
|
||||
.usage_error("A command must be given with an adjustment.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// spell-checker:ignore incorrectnumber
|
||||
use crate::common::util::*;
|
||||
|
||||
#[test]
|
||||
|
@ -15,11 +16,11 @@ fn test_nproc_all_omp() {
|
|||
|
||||
let result = TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.env("OMP_NUM_THREADS", "1")
|
||||
.env("OMP_NUM_THREADS", "60")
|
||||
.succeeds();
|
||||
|
||||
let nproc_omp: u8 = result.stdout_str().trim().parse().unwrap();
|
||||
assert!(nproc - 1 == nproc_omp);
|
||||
assert_eq!(nproc_omp, 60);
|
||||
|
||||
let result = TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
|
@ -27,21 +28,141 @@ fn test_nproc_all_omp() {
|
|||
.arg("--all")
|
||||
.succeeds();
|
||||
let nproc_omp: u8 = result.stdout_str().trim().parse().unwrap();
|
||||
assert!(nproc == nproc_omp);
|
||||
assert_eq!(nproc, nproc_omp);
|
||||
|
||||
// If the parsing fails, returns the number of CPU
|
||||
let result = TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.env("OMP_NUM_THREADS", "incorrectnumber") // returns the number CPU
|
||||
.succeeds();
|
||||
let nproc_omp: u8 = result.stdout_str().trim().parse().unwrap();
|
||||
assert_eq!(nproc, nproc_omp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nproc_ignore() {
|
||||
let result = new_ucmd!().succeeds();
|
||||
let nproc: u8 = result.stdout_str().trim().parse().unwrap();
|
||||
if nproc > 1 {
|
||||
let nproc_total: u8 = result.stdout_str().trim().parse().unwrap();
|
||||
if nproc_total > 1 {
|
||||
// Ignore all CPU but one
|
||||
let result = TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.arg("--ignore")
|
||||
.arg((nproc - 1).to_string())
|
||||
.arg((nproc_total - 1).to_string())
|
||||
.succeeds();
|
||||
let nproc: u8 = result.stdout_str().trim().parse().unwrap();
|
||||
assert!(nproc == 1);
|
||||
assert_eq!(nproc, 1);
|
||||
// Ignore all CPU but one with a string
|
||||
let result = TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.arg("--ignore= 1")
|
||||
.succeeds();
|
||||
let nproc: u8 = result.stdout_str().trim().parse().unwrap();
|
||||
assert_eq!(nproc_total - 1, nproc);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nproc_ignore_all_omp() {
|
||||
let result = TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.env("OMP_NUM_THREADS", "42")
|
||||
.arg("--ignore=40")
|
||||
.succeeds();
|
||||
let nproc: u8 = result.stdout_str().trim().parse().unwrap();
|
||||
assert_eq!(nproc, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nproc_omp_limit() {
|
||||
let result = TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.env("OMP_NUM_THREADS", "42")
|
||||
.env("OMP_THREAD_LIMIT", "0")
|
||||
.succeeds();
|
||||
let nproc: u8 = result.stdout_str().trim().parse().unwrap();
|
||||
assert_eq!(nproc, 42);
|
||||
|
||||
let result = TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.env("OMP_NUM_THREADS", "42")
|
||||
.env("OMP_THREAD_LIMIT", "2")
|
||||
.succeeds();
|
||||
let nproc: u8 = result.stdout_str().trim().parse().unwrap();
|
||||
assert_eq!(nproc, 2);
|
||||
|
||||
let result = TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.env("OMP_NUM_THREADS", "42")
|
||||
.env("OMP_THREAD_LIMIT", "2bad")
|
||||
.succeeds();
|
||||
let nproc: u8 = result.stdout_str().trim().parse().unwrap();
|
||||
assert_eq!(nproc, 42);
|
||||
|
||||
let result = new_ucmd!().arg("--all").succeeds();
|
||||
let nproc_system: u8 = result.stdout_str().trim().parse().unwrap();
|
||||
assert!(nproc_system > 0);
|
||||
|
||||
let result = TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.env("OMP_THREAD_LIMIT", "1")
|
||||
.succeeds();
|
||||
let nproc: u8 = result.stdout_str().trim().parse().unwrap();
|
||||
assert_eq!(nproc, 1);
|
||||
|
||||
let result = TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.env("OMP_NUM_THREADS", "0")
|
||||
.env("OMP_THREAD_LIMIT", "")
|
||||
.succeeds();
|
||||
let nproc: u8 = result.stdout_str().trim().parse().unwrap();
|
||||
assert_eq!(nproc, nproc_system);
|
||||
|
||||
let result = TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.env("OMP_NUM_THREADS", "")
|
||||
.env("OMP_THREAD_LIMIT", "")
|
||||
.succeeds();
|
||||
let nproc: u8 = result.stdout_str().trim().parse().unwrap();
|
||||
assert_eq!(nproc, nproc_system);
|
||||
|
||||
let result = TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.env("OMP_NUM_THREADS", "2,2,1")
|
||||
.env("OMP_THREAD_LIMIT", "")
|
||||
.succeeds();
|
||||
let nproc: u8 = result.stdout_str().trim().parse().unwrap();
|
||||
assert_eq!(2, nproc);
|
||||
|
||||
let result = TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.env("OMP_NUM_THREADS", "2,ignored")
|
||||
.env("OMP_THREAD_LIMIT", "")
|
||||
.succeeds();
|
||||
let nproc: u8 = result.stdout_str().trim().parse().unwrap();
|
||||
assert_eq!(2, nproc);
|
||||
|
||||
let result = TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.env("OMP_NUM_THREADS", "2,2,1")
|
||||
.env("OMP_THREAD_LIMIT", "0")
|
||||
.succeeds();
|
||||
let nproc: u8 = result.stdout_str().trim().parse().unwrap();
|
||||
assert_eq!(2, nproc);
|
||||
|
||||
let result = TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.env("OMP_NUM_THREADS", "2,2,1")
|
||||
.env("OMP_THREAD_LIMIT", "1bad")
|
||||
.succeeds();
|
||||
let nproc: u8 = result.stdout_str().trim().parse().unwrap();
|
||||
assert_eq!(2, nproc);
|
||||
|
||||
let result = TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.env("OMP_NUM_THREADS", "29,2,1")
|
||||
.env("OMP_THREAD_LIMIT", "1bad")
|
||||
.succeeds();
|
||||
let nproc: u8 = result.stdout_str().trim().parse().unwrap();
|
||||
assert_eq!(29, nproc);
|
||||
}
|
||||
|
|
|
@ -505,3 +505,91 @@ fn test_round() {
|
|||
.stdout_only(exp.join("\n") + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_suffix_is_added_if_not_supplied() {
|
||||
new_ucmd!()
|
||||
.args(&["--suffix=TEST"])
|
||||
.pipe_in("1000")
|
||||
.succeeds()
|
||||
.stdout_only("1000TEST\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_suffix_is_preserved() {
|
||||
new_ucmd!()
|
||||
.args(&["--suffix=TEST"])
|
||||
.pipe_in("1000TEST")
|
||||
.succeeds()
|
||||
.stdout_only("1000TEST\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_suffix_is_only_applied_to_selected_field() {
|
||||
new_ucmd!()
|
||||
.args(&["--suffix=TEST", "--field=2"])
|
||||
.pipe_in("1000 2000 3000")
|
||||
.succeeds()
|
||||
.stdout_only("1000 2000TEST 3000\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_with_suffix_on_input() {
|
||||
new_ucmd!()
|
||||
.args(&["--suffix=b", "--to=si"])
|
||||
.pipe_in("2000b")
|
||||
.succeeds()
|
||||
.stdout_only("2.0Kb\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_without_suffix_on_input() {
|
||||
new_ucmd!()
|
||||
.args(&["--suffix=b", "--to=si"])
|
||||
.pipe_in("2000")
|
||||
.succeeds()
|
||||
.stdout_only("2.0Kb\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_with_suffix_and_delimiter() {
|
||||
new_ucmd!()
|
||||
.args(&["--suffix=b", "--to=si", "-d=|"])
|
||||
.pipe_in("1000b|2000|3000")
|
||||
.succeeds()
|
||||
.stdout_only("1.0Kb|2000|3000\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_suffix_with_padding() {
|
||||
new_ucmd!()
|
||||
.args(&["--suffix=pad", "--padding=12"])
|
||||
.pipe_in("1000 2000 3000")
|
||||
.succeeds()
|
||||
.stdout_only(" 1000pad 2000 3000\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_stdin_number_returns_status_2() {
|
||||
new_ucmd!().pipe_in("hello").fails().code_is(2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_stdin_number_in_middle_of_input() {
|
||||
new_ucmd!().pipe_in("100\nhello\n200").fails().code_is(2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_argument_number_returns_status_2() {
|
||||
new_ucmd!().args(&["hello"]).fails().code_is(2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_argument_returns_status_1() {
|
||||
new_ucmd!()
|
||||
.args(&["--header=hello"])
|
||||
.pipe_in("53478")
|
||||
.ignore_stdin_write_error()
|
||||
.fails()
|
||||
.code_is(1);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ fn test_file() {
|
|||
let mut f = File::create(&file).unwrap();
|
||||
// spell-checker:disable-next-line
|
||||
assert!(
|
||||
!f.write_all(b"abcdefghijklmnopqrstuvwxyz\n").is_err(),
|
||||
f.write_all(b"abcdefghijklmnopqrstuvwxyz\n").is_ok(),
|
||||
"Test setup failed - could not write file"
|
||||
);
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ fn test_2files() {
|
|||
for &(path, data) in &[(&file1, "abcdefghijklmnop"), (&file2, "qrstuvwxyz\n")] {
|
||||
let mut f = File::create(&path).unwrap();
|
||||
assert!(
|
||||
!f.write_all(data.as_bytes()).is_err(),
|
||||
f.write_all(data.as_bytes()).is_ok(),
|
||||
"Test setup failed - could not write file"
|
||||
);
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ fn test_from_mixed() {
|
|||
for &(path, data) in &[(&file1, data1), (&file3, data3)] {
|
||||
let mut f = File::create(&path).unwrap();
|
||||
assert!(
|
||||
!f.write_all(data.as_bytes()).is_err(),
|
||||
f.write_all(data.as_bytes()).is_ok(),
|
||||
"Test setup failed - could not write file"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -60,6 +60,24 @@ static EXAMPLE_DATA: &[TestData] = &[
|
|||
ins: &["1\na\n", "2\nb\n"],
|
||||
out: "1 2\na b\n",
|
||||
},
|
||||
TestData {
|
||||
name: "multibyte-delim",
|
||||
args: &["-d", "💣"],
|
||||
ins: &["1\na\n", "2\nb\n"],
|
||||
out: "1💣2\na💣b\n",
|
||||
},
|
||||
TestData {
|
||||
name: "multibyte-delim-serial",
|
||||
args: &["-d", "💣", "-s"],
|
||||
ins: &["1\na\n", "2\nb\n"],
|
||||
out: "1💣a\n2💣b\n",
|
||||
},
|
||||
TestData {
|
||||
name: "trailing whitespace",
|
||||
args: &["-d", "|"],
|
||||
ins: &["1 \na \n", "2\t\nb\t\n"],
|
||||
out: "1 |2\t\na |b\t\n",
|
||||
},
|
||||
];
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -24,14 +24,11 @@ fn test_capitalize() {
|
|||
fn test_long_format() {
|
||||
let login = "root";
|
||||
let pw: Passwd = Passwd::locate(login).unwrap();
|
||||
let real_name = pw.user_info().replace("&", &pw.name().capitalize());
|
||||
let real_name = pw.user_info.replace('&', &pw.name.capitalize());
|
||||
let ts = TestScenario::new(util_name!());
|
||||
ts.ucmd().arg("-l").arg(login).succeeds().stdout_is(format!(
|
||||
"Login name: {:<28}In real life: {}\nDirectory: {:<29}Shell: {}\n\n",
|
||||
login,
|
||||
real_name,
|
||||
pw.user_dir(),
|
||||
pw.user_shell()
|
||||
login, real_name, pw.user_dir, pw.user_shell
|
||||
));
|
||||
|
||||
ts.ucmd()
|
||||
|
@ -47,7 +44,14 @@ fn test_long_format() {
|
|||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn test_long_format_multiple_users() {
|
||||
let args = ["-l", "root", "root", "root"];
|
||||
// multiple instances of one account we know exists,
|
||||
// the account of the test runner,
|
||||
// and an account that (probably) doesn't exist
|
||||
let runner = match std::env::var("USER") {
|
||||
Ok(user) => user,
|
||||
Err(_) => "".to_string(),
|
||||
};
|
||||
let args = ["-l", "root", "root", "root", &runner, "no_such_user"];
|
||||
let ts = TestScenario::new(util_name!());
|
||||
let expect = unwrap_or_return!(expected_result(&ts, &args));
|
||||
|
||||
|
@ -61,7 +65,7 @@ fn test_long_format_multiple_users() {
|
|||
#[test]
|
||||
fn test_long_format_wo_user() {
|
||||
// "no username specified; at least one must be specified when using -l"
|
||||
new_ucmd!().arg("-l").fails().code_is(1);
|
||||
new_ucmd!().arg("-l").fails();
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
|
|
|
@ -448,3 +448,16 @@ fn test_with_join_lines_option() {
|
|||
&valid_last_modified_template_vars(start),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_value_for_number_lines() {
|
||||
// *5 is of the form [SEP[NUMBER]] so is accepted and succeeds
|
||||
new_ucmd!().args(&["-n", "*5", "test.log"]).succeeds();
|
||||
|
||||
// a is of the form [SEP[NUMBER]] so is accepted and succeeds
|
||||
new_ucmd!().args(&["-n", "a", "test.log"]).succeeds();
|
||||
|
||||
// foo5.txt is of not the form [SEP[NUMBER]] so is not used as value.
|
||||
// Therefore, pr tries to access the file, which does not exist.
|
||||
new_ucmd!().args(&["-n", "foo5.txt", "test.log"]).fails();
|
||||
}
|
||||
|
|
|
@ -26,5 +26,5 @@ fn test_get_var() {
|
|||
.succeeds();
|
||||
|
||||
assert!(!result.stdout_str().is_empty());
|
||||
assert!(result.stdout_str().trim() == "VALUE");
|
||||
assert_eq!(result.stdout_str().trim(), "VALUE");
|
||||
}
|
||||
|
|
|
@ -228,6 +228,22 @@ fn sub_num_float() {
|
|||
.stdout_only("twenty is 20.000000");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_num_float_e_round() {
|
||||
new_ucmd!()
|
||||
.args(&["%e", "99999999"])
|
||||
.succeeds()
|
||||
.stdout_only("1.000000e+08");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_num_float_e_no_round() {
|
||||
new_ucmd!()
|
||||
.args(&["%e", "99999994"])
|
||||
.succeeds()
|
||||
.stdout_only("9.999999e+07");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_num_float_round() {
|
||||
new_ucmd!()
|
||||
|
@ -236,6 +252,14 @@ fn sub_num_float_round() {
|
|||
.stdout_only("two is 2.000000");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_num_float_round_nines_dec() {
|
||||
new_ucmd!()
|
||||
.args(&["%f", "0.99999999"])
|
||||
.succeeds()
|
||||
.stdout_only("1.000000");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_num_sci_lower() {
|
||||
new_ucmd!()
|
||||
|
@ -265,7 +289,7 @@ fn sub_num_dec_trunc() {
|
|||
new_ucmd!()
|
||||
.args(&["pi is ~ %g", "3.1415926535"])
|
||||
.succeeds()
|
||||
.stdout_only("pi is ~ 3.141593");
|
||||
.stdout_only("pi is ~ 3.14159");
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "test_unimplemented"), ignore)]
|
||||
|
@ -429,3 +453,72 @@ fn sub_any_specifiers_after_second_param() {
|
|||
.succeeds()
|
||||
.stdout_only("3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stop_after_additional_escape() {
|
||||
new_ucmd!()
|
||||
.args(&["A%sC\\cD%sF", "B", "E"]) //spell-checker:disable-line
|
||||
.succeeds()
|
||||
.stdout_only("ABC");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_float_leading_zeroes() {
|
||||
new_ucmd!()
|
||||
.args(&["%010f", "1"])
|
||||
.succeeds()
|
||||
.stdout_only("001.000000");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_general_float() {
|
||||
new_ucmd!()
|
||||
.args(&["%g", "1.1"])
|
||||
.succeeds()
|
||||
.stdout_only("1.1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_general_truncate_to_integer() {
|
||||
new_ucmd!().args(&["%g", "1.0"]).succeeds().stdout_only("1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_general_scientific_notation() {
|
||||
new_ucmd!()
|
||||
.args(&["%g", "1000010"])
|
||||
.succeeds()
|
||||
.stdout_only("1.00001e+06");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_general_round_scientific_notation() {
|
||||
new_ucmd!()
|
||||
.args(&["%g", "123456789"])
|
||||
.succeeds()
|
||||
.stdout_only("1.23457e+08");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_general_round_float() {
|
||||
new_ucmd!()
|
||||
.args(&["%g", "12345.6789"])
|
||||
.succeeds()
|
||||
.stdout_only("12345.7");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_general_round_float_to_integer() {
|
||||
new_ucmd!()
|
||||
.args(&["%g", "123456.7"])
|
||||
.succeeds()
|
||||
.stdout_only("123457");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_general_round_float_leading_zeroes() {
|
||||
new_ucmd!()
|
||||
.args(&["%g", "1.000009"])
|
||||
.succeeds()
|
||||
.stdout_only("1.00001");
|
||||
}
|
||||
|
|
|
@ -149,8 +149,8 @@ fn test_realpath_dangling() {
|
|||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.symlink_file("nonexistent-file", "link");
|
||||
ucmd.arg("link")
|
||||
.succeeds()
|
||||
.stdout_only(at.plus_as_string("nonexistent-file\n"));
|
||||
.fails()
|
||||
.stderr_contains("realpath: link: No such file or directory");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -202,3 +202,34 @@ fn test_realpath_missing() {
|
|||
.succeeds()
|
||||
.stdout_only(expect);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_realpath_when_symlink_is_absolute_and_enoent() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
at.mkdir("dir2");
|
||||
at.touch("dir2/bar");
|
||||
|
||||
at.mkdir("dir1");
|
||||
at.symlink_file("dir2/bar", "dir1/foo1");
|
||||
at.symlink_file("/dir2/bar", "dir1/foo2");
|
||||
at.relative_symlink_file("dir2/baz", at.plus("dir1/foo3").to_str().unwrap());
|
||||
|
||||
#[cfg(unix)]
|
||||
ucmd.arg("dir1/foo1")
|
||||
.arg("dir1/foo2")
|
||||
.arg("dir1/foo3")
|
||||
.run()
|
||||
.stdout_contains("/dir2/bar\n")
|
||||
.stdout_contains("/dir2/baz\n")
|
||||
.stderr_is("realpath: dir1/foo2: No such file or directory");
|
||||
|
||||
#[cfg(windows)]
|
||||
ucmd.arg("dir1/foo1")
|
||||
.arg("dir1/foo2")
|
||||
.arg("dir1/foo3")
|
||||
.run()
|
||||
.stdout_contains("\\dir2\\bar\n")
|
||||
.stdout_contains("\\dir2\\baz\n")
|
||||
.stderr_is("realpath: dir1/foo2: No such file or directory");
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ const TESTS: [TestCase; 10] = [
|
|||
#[allow(clippy::needless_lifetimes)]
|
||||
fn convert_path<'a>(path: &'a str) -> Cow<'a, str> {
|
||||
#[cfg(windows)]
|
||||
return path.replace("/", "\\").into();
|
||||
return path.replace('/', "\\").into();
|
||||
#[cfg(not(windows))]
|
||||
return path.into();
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ fn test_relpath_with_from_no_d() {
|
|||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
for test in TESTS.iter() {
|
||||
for test in &TESTS {
|
||||
let from: &str = &convert_path(test.from);
|
||||
let to: &str = &convert_path(test.to);
|
||||
let expected: &str = &convert_path(test.expected);
|
||||
|
@ -96,7 +96,7 @@ fn test_relpath_with_from_with_d() {
|
|||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
for test in TESTS.iter() {
|
||||
for test in &TESTS {
|
||||
let from: &str = &convert_path(test.from);
|
||||
let to: &str = &convert_path(test.to);
|
||||
let pwd = at.as_string();
|
||||
|
@ -132,7 +132,7 @@ fn test_relpath_no_from_no_d() {
|
|||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
for test in TESTS.iter() {
|
||||
for test in &TESTS {
|
||||
let to: &str = &convert_path(test.to);
|
||||
at.mkdir_all(to);
|
||||
|
||||
|
@ -150,7 +150,7 @@ fn test_relpath_no_from_with_d() {
|
|||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
for test in TESTS.iter() {
|
||||
for test in &TESTS {
|
||||
let to: &str = &convert_path(test.to);
|
||||
let pwd = at.as_string();
|
||||
at.mkdir_all(to);
|
||||
|
|
|
@ -169,6 +169,29 @@ fn test_rm_recursive() {
|
|||
assert!(!at.file_exists(file_b));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rm_recursive_multiple() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let dir = "test_rm_recursive_directory";
|
||||
let file_a = "test_rm_recursive_directory/test_rm_recursive_file_a";
|
||||
let file_b = "test_rm_recursive_directory/test_rm_recursive_file_b";
|
||||
|
||||
at.mkdir(dir);
|
||||
at.touch(file_a);
|
||||
at.touch(file_b);
|
||||
|
||||
ucmd.arg("-r")
|
||||
.arg("-r")
|
||||
.arg("-r")
|
||||
.arg(dir)
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
assert!(!at.dir_exists(dir));
|
||||
assert!(!at.file_exists(file_a));
|
||||
assert!(!at.file_exists(file_b));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rm_directory_without_flag() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
@ -257,7 +280,7 @@ fn test_rm_force_no_operand() {
|
|||
fn test_rm_no_operand() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
ts.ucmd().fails().stderr_is(&format!(
|
||||
"{0}: missing an argument\n{0}: for help, try '{1} {0} --help'\n",
|
||||
"{0}: missing operand\nTry '{1} {0} --help' for more information.\n",
|
||||
ts.util_name,
|
||||
ts.bin_path.to_string_lossy()
|
||||
));
|
||||
|
@ -291,3 +314,36 @@ fn test_rm_verbose_slash() {
|
|||
assert!(!at.dir_exists(dir));
|
||||
assert!(!at.file_exists(file_a));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rm_silently_accepts_presume_input_tty2() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file_2 = "test_rm_silently_accepts_presume_input_tty2";
|
||||
|
||||
at.touch(file_2);
|
||||
|
||||
ucmd.arg("---presume-input-tty").arg(file_2).succeeds();
|
||||
|
||||
assert!(!at.file_exists(file_2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rm_interactive_never() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file_2 = "test_rm_interactive";
|
||||
|
||||
at.touch(file_2);
|
||||
#[cfg(feature = "chmod")]
|
||||
scene.ccmd("chmod").arg("0").arg(file_2).succeeds();
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--interactive=never")
|
||||
.arg(file_2)
|
||||
.succeeds()
|
||||
.stdout_is("");
|
||||
|
||||
assert!(!at.file_exists(file_2));
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// spell-checker:ignore lmnop xlmnop
|
||||
use crate::common::util::*;
|
||||
use std::io::Read;
|
||||
|
||||
|
@ -7,26 +8,26 @@ fn test_hex_rejects_sign_after_identifier() {
|
|||
.args(&["0x-123ABC"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("invalid hexadecimal argument: '0x-123ABC'")
|
||||
.stderr_contains("invalid floating point 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("invalid floating point 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.");
|
||||
.stderr_contains("which wasn't expected, or isn't valid in this context")
|
||||
.stderr_contains("For more information try --help");
|
||||
new_ucmd!()
|
||||
.args(&["-0x+123ABC"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("invalid hexadecimal argument: '-0x+123ABC'")
|
||||
.stderr_contains("for more information.");
|
||||
.stderr_contains("which wasn't expected, or isn't valid in this context")
|
||||
.stderr_contains("For more information try --help");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -60,30 +61,51 @@ fn test_hex_identifier_in_wrong_place() {
|
|||
.args(&["1234ABCD0x"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("invalid hexadecimal argument: '1234ABCD0x'")
|
||||
.stderr_contains("invalid floating point argument: '1234ABCD0x'")
|
||||
.stderr_contains("for more information.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rejects_nan() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
|
||||
ts.ucmd().args(&["NaN"]).fails().stderr_only(format!(
|
||||
"{0}: invalid 'not-a-number' argument: 'NaN'\nTry '{1} {0} --help' for more information.",
|
||||
ts.util_name,
|
||||
ts.bin_path.to_string_lossy()
|
||||
));
|
||||
new_ucmd!()
|
||||
.arg("NaN")
|
||||
.fails()
|
||||
.usage_error("invalid 'not-a-number' argument: 'NaN'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rejects_non_floats() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
new_ucmd!()
|
||||
.arg("foo")
|
||||
.fails()
|
||||
.usage_error("invalid floating point argument: 'foo'");
|
||||
}
|
||||
|
||||
ts.ucmd().args(&["foo"]).fails().stderr_only(&format!(
|
||||
"{0}: invalid floating point argument: 'foo'\nTry '{1} {0} --help' for more information.",
|
||||
ts.util_name,
|
||||
ts.bin_path.to_string_lossy()
|
||||
));
|
||||
#[test]
|
||||
fn test_accepts_option_argument_directly() {
|
||||
new_ucmd!()
|
||||
.arg("-s,")
|
||||
.arg("2")
|
||||
.succeeds()
|
||||
.stdout_is("1,2\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_option_with_detected_negative_argument() {
|
||||
new_ucmd!()
|
||||
.arg("-s,")
|
||||
.args(&["-1", "2"])
|
||||
.succeeds()
|
||||
.stdout_is("-1,0,1,2\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_negative_number_as_separator() {
|
||||
new_ucmd!()
|
||||
.arg("-s")
|
||||
.args(&["-1", "2"])
|
||||
.succeeds()
|
||||
.stdout_is("1-12\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -479,6 +501,72 @@ fn test_width_decimal_scientific_notation_trailing_zeros_increment() {
|
|||
.no_stderr();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_width_negative_decimal_notation() {
|
||||
new_ucmd!()
|
||||
.args(&["-w", "-.1", ".1", ".11"])
|
||||
.succeeds()
|
||||
.stdout_is("-0.1\n00.0\n00.1\n")
|
||||
.no_stderr();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_width_negative_scientific_notation() {
|
||||
new_ucmd!()
|
||||
.args(&["-w", "-1e-3", "1"])
|
||||
.succeeds()
|
||||
.stdout_is("-0.001\n00.999\n")
|
||||
.no_stderr();
|
||||
new_ucmd!()
|
||||
.args(&["-w", "-1.e-3", "1"])
|
||||
.succeeds()
|
||||
.stdout_is("-0.001\n00.999\n")
|
||||
.no_stderr();
|
||||
new_ucmd!()
|
||||
.args(&["-w", "-1.0e-4", "1"])
|
||||
.succeeds()
|
||||
.stdout_is("-0.00010\n00.99990\n")
|
||||
.no_stderr();
|
||||
new_ucmd!()
|
||||
.args(&["-w", "-.1e2", "10", "100"])
|
||||
.succeeds()
|
||||
.stdout_is(
|
||||
"-010
|
||||
0000
|
||||
0010
|
||||
0020
|
||||
0030
|
||||
0040
|
||||
0050
|
||||
0060
|
||||
0070
|
||||
0080
|
||||
0090
|
||||
0100
|
||||
",
|
||||
)
|
||||
.no_stderr();
|
||||
new_ucmd!()
|
||||
.args(&["-w", "-0.1e2", "10", "100"])
|
||||
.succeeds()
|
||||
.stdout_is(
|
||||
"-010
|
||||
0000
|
||||
0010
|
||||
0020
|
||||
0030
|
||||
0040
|
||||
0050
|
||||
0060
|
||||
0070
|
||||
0080
|
||||
0090
|
||||
0100
|
||||
",
|
||||
)
|
||||
.no_stderr();
|
||||
}
|
||||
|
||||
/// Test that trailing zeros in the end argument do not contribute to width.
|
||||
#[test]
|
||||
fn test_width_decimal_scientific_notation_trailing_zeros_end() {
|
||||
|
@ -521,6 +609,22 @@ fn test_inf() {
|
|||
run(&["inf"], b"1\n2\n3\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inf_width() {
|
||||
run(
|
||||
&["-w", "1.000", "inf", "inf"],
|
||||
b"1.000\n inf\n inf\n inf\n",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_neg_inf_width() {
|
||||
run(
|
||||
&["-w", "1.000", "-inf", "-inf"],
|
||||
b"1.000\n -inf\n -inf\n -inf\n",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ignore_leading_whitespace() {
|
||||
new_ucmd!()
|
||||
|
@ -538,9 +642,99 @@ fn test_trailing_whitespace_error() {
|
|||
new_ucmd!()
|
||||
.arg("1 ")
|
||||
.fails()
|
||||
.usage_error("invalid floating point argument: '1 '");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_negative_zero_int_start_float_increment() {
|
||||
new_ucmd!()
|
||||
.args(&["-0", "0.1", "0.1"])
|
||||
.succeeds()
|
||||
.stdout_is("-0.0\n0.1\n")
|
||||
.no_stderr();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_float_precision_increment() {
|
||||
new_ucmd!()
|
||||
.args(&["999", "0.1", "1000.1"])
|
||||
.succeeds()
|
||||
.stdout_is(
|
||||
"999.0
|
||||
999.1
|
||||
999.2
|
||||
999.3
|
||||
999.4
|
||||
999.5
|
||||
999.6
|
||||
999.7
|
||||
999.8
|
||||
999.9
|
||||
1000.0
|
||||
1000.1
|
||||
",
|
||||
)
|
||||
.no_stderr();
|
||||
}
|
||||
|
||||
/// Test for floating point precision issues.
|
||||
#[test]
|
||||
fn test_negative_increment_decimal() {
|
||||
new_ucmd!()
|
||||
.args(&["0.1", "-0.1", "-0.2"])
|
||||
.succeeds()
|
||||
.stdout_is("0.1\n0.0\n-0.1\n-0.2\n")
|
||||
.no_stderr();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero_not_first() {
|
||||
new_ucmd!()
|
||||
.args(&["-w", "-0.1", "0.1", "0.1"])
|
||||
.succeeds()
|
||||
.stdout_is("-0.1\n00.0\n00.1\n")
|
||||
.no_stderr();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rounding_end() {
|
||||
new_ucmd!()
|
||||
.args(&["1", "-1", "0.1"])
|
||||
.succeeds()
|
||||
.stdout_is("1\n")
|
||||
.no_stderr();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_error_float() {
|
||||
new_ucmd!()
|
||||
.arg("lmnop")
|
||||
.fails()
|
||||
.usage_error("invalid floating point argument: 'lmnop'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_error_hex() {
|
||||
new_ucmd!()
|
||||
.arg("0xlmnop")
|
||||
.fails()
|
||||
.usage_error("invalid hexadecimal argument: '0xlmnop'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_option() {
|
||||
new_ucmd!()
|
||||
.args(&["-f", "%.2f", "0.0", "0.1", "0.5"])
|
||||
.succeeds()
|
||||
.stdout_only("0.00\n0.10\n0.20\n0.30\n0.40\n0.50\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_zero_increment_value() {
|
||||
new_ucmd!()
|
||||
.args(&["0", "0", "1"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("seq: invalid floating point argument: '1 '")
|
||||
// FIXME The second line of the error message is "Try 'seq
|
||||
// --help' for more information."
|
||||
.stderr_contains("invalid Zero increment value: '0'")
|
||||
.stderr_contains("for more information.");
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ fn test_head_count() {
|
|||
result_seq.iter().all(|x| input_seq.contains(x)),
|
||||
"Output includes element not from input: {}",
|
||||
result.stdout_str()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -129,7 +129,7 @@ fn test_repeat() {
|
|||
.iter()
|
||||
.filter(|x| !input_seq.contains(x))
|
||||
.collect::<Vec<&i32>>()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -154,9 +154,7 @@ fn test_shuf_echo_and_input_range_not_allowed() {
|
|||
new_ucmd!()
|
||||
.args(&["-e", "0", "-i", "0-2"])
|
||||
.fails()
|
||||
.stderr_contains(
|
||||
"The argument '--input-range <LO-HI>' cannot be used with '--echo <ARG>...'",
|
||||
);
|
||||
.stderr_contains("cannot be used with");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -164,7 +162,7 @@ fn test_shuf_input_range_and_file_not_allowed() {
|
|||
new_ucmd!()
|
||||
.args(&["-i", "0-9", "file"])
|
||||
.fails()
|
||||
.stderr_contains("The argument '<file>' cannot be used with '--input-range <LO-HI>'");
|
||||
.stderr_contains("cannot be used with");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -198,3 +196,19 @@ fn test_shuf_invalid_input_line_count() {
|
|||
.fails()
|
||||
.stderr_contains("invalid line count: 'a'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shuf_multiple_input_line_count() {
|
||||
let result = new_ucmd!()
|
||||
.args(&["-i10-200", "-n", "10", "-n", "5"])
|
||||
.succeeds();
|
||||
|
||||
result.no_stderr();
|
||||
|
||||
let result_count = result
|
||||
.stdout_str()
|
||||
.split('\n')
|
||||
.filter(|x| !x.is_empty())
|
||||
.count();
|
||||
assert_eq!(result_count, 5, "Output should have 5 items");
|
||||
}
|
||||
|
|
|
@ -1,7 +1,16 @@
|
|||
// spell-checker:ignore dont
|
||||
use crate::common::util::*;
|
||||
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
#[test]
|
||||
fn test_invalid_time_interval() {
|
||||
new_ucmd!()
|
||||
.arg("xyz")
|
||||
.fails()
|
||||
.usage_error("invalid time interval 'xyz'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sleep_no_suffix() {
|
||||
let millis_100 = Duration::from_millis(100);
|
||||
|
@ -115,3 +124,36 @@ fn test_sleep_sum_duration_many() {
|
|||
fn test_sleep_wrong_time() {
|
||||
new_ucmd!().args(&["0.1s", "abc"]).fails();
|
||||
}
|
||||
|
||||
// TODO These tests would obviously block for a very long time. We
|
||||
// only want to verify that there is no error here, so we could just
|
||||
// figure out a way to terminate the child process after a short
|
||||
// period of time.
|
||||
|
||||
// #[test]
|
||||
#[allow(dead_code)]
|
||||
fn test_dont_overflow() {
|
||||
new_ucmd!()
|
||||
.arg("9223372036854775808d")
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.no_stdout();
|
||||
}
|
||||
|
||||
// #[test]
|
||||
#[allow(dead_code)]
|
||||
fn test_sum_overflow() {
|
||||
new_ucmd!()
|
||||
.args(&["100000000000000d", "100000000000000d", "100000000000000d"])
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.no_stdout();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_negative_interval() {
|
||||
new_ucmd!()
|
||||
.args(&["--", "-1"])
|
||||
.fails()
|
||||
.usage_error("invalid time interval '-1'");
|
||||
}
|
||||
|
|
|
@ -155,7 +155,7 @@ fn test_multiple_decimals_general() {
|
|||
test_helper(
|
||||
"multiple_decimals_general",
|
||||
&["-g", "--general-numeric-sort", "--sort=general-numeric"],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -163,7 +163,7 @@ fn test_multiple_decimals_numeric() {
|
|||
test_helper(
|
||||
"multiple_decimals_numeric",
|
||||
&["-n", "--numeric-sort", "--sort=numeric"],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -171,7 +171,7 @@ fn test_numeric_with_trailing_invalid_chars() {
|
|||
test_helper(
|
||||
"numeric_trailing_chars",
|
||||
&["-n", "--numeric-sort", "--sort=numeric"],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -338,24 +338,20 @@ fn test_dictionary_order() {
|
|||
|
||||
#[test]
|
||||
fn test_dictionary_order2() {
|
||||
for non_dictionary_order2_param in &["-d"] {
|
||||
new_ucmd!()
|
||||
.pipe_in("a👦🏻aa b\naaaa b") // spell-checker:disable-line
|
||||
.arg(non_dictionary_order2_param) // spell-checker:disable-line
|
||||
.succeeds()
|
||||
.stdout_only("a👦🏻aa b\naaaa b\n"); // spell-checker:disable-line
|
||||
}
|
||||
new_ucmd!()
|
||||
.pipe_in("a👦🏻aa\tb\naaaa\tb") // spell-checker:disable-line
|
||||
.arg("-d")
|
||||
.succeeds()
|
||||
.stdout_only("a👦🏻aa\tb\naaaa\tb\n"); // spell-checker:disable-line
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_non_printing_chars() {
|
||||
for non_printing_chars_param in &["-i"] {
|
||||
new_ucmd!()
|
||||
.pipe_in("a👦🏻aa\naaaa") // spell-checker:disable-line
|
||||
.arg(non_printing_chars_param) // spell-checker:disable-line
|
||||
.succeeds()
|
||||
.stdout_only("a👦🏻aa\naaaa\n"); // spell-checker:disable-line
|
||||
}
|
||||
new_ucmd!()
|
||||
.pipe_in("a👦🏻aa\naaaa") // spell-checker:disable-line
|
||||
.arg("-i")
|
||||
.succeeds()
|
||||
.stdout_only("a👦🏻aa\naaaa\n"); // spell-checker:disable-line
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -486,14 +482,12 @@ fn test_default_unsorted_ints2() {
|
|||
|
||||
#[test]
|
||||
fn test_numeric_unique_ints2() {
|
||||
for numeric_unique_sort_param in &["-nu"] {
|
||||
let input = "9\n9\n8\n1\n";
|
||||
new_ucmd!()
|
||||
.arg(numeric_unique_sort_param)
|
||||
.pipe_in(input)
|
||||
.succeeds()
|
||||
.stdout_only("1\n8\n9\n");
|
||||
}
|
||||
let input = "9\n9\n8\n1\n";
|
||||
new_ucmd!()
|
||||
.arg("-nu")
|
||||
.pipe_in(input)
|
||||
.succeeds()
|
||||
.stdout_only("1\n8\n9\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -588,7 +582,7 @@ fn test_keys_with_options_blanks_start() {
|
|||
|
||||
#[test]
|
||||
fn test_keys_blanks_with_char_idx() {
|
||||
test_helper("keys_blanks", &["-k 1.2b"])
|
||||
test_helper("keys_blanks", &["-k 1.2b"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -648,7 +642,7 @@ fn test_keys_negative_size_match() {
|
|||
|
||||
#[test]
|
||||
fn test_keys_ignore_flag() {
|
||||
test_helper("keys_ignore_flag", &["-k 1n -b"])
|
||||
test_helper("keys_ignore_flag", &["-k 1n -b"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -918,6 +912,7 @@ fn test_compress_merge() {
|
|||
|
||||
#[test]
|
||||
fn test_compress_fail() {
|
||||
#[cfg(not(windows))]
|
||||
TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.args(&[
|
||||
|
@ -930,6 +925,21 @@ fn test_compress_fail() {
|
|||
])
|
||||
.fails()
|
||||
.stderr_only("sort: couldn't execute compress program: errno 2");
|
||||
// With coverage, it fails with a different error:
|
||||
// "thread 'main' panicked at 'called `Option::unwrap()` on ...
|
||||
// So, don't check the output
|
||||
#[cfg(windows)]
|
||||
TestScenario::new(util_name!())
|
||||
.ucmd_keepenv()
|
||||
.args(&[
|
||||
"ext_sort.txt",
|
||||
"-n",
|
||||
"--compress-program",
|
||||
"nonexistent-program",
|
||||
"-S",
|
||||
"10",
|
||||
])
|
||||
.fails();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -980,7 +990,8 @@ fn test_conflict_check_out() {
|
|||
.arg("-o=/dev/null")
|
||||
.fails()
|
||||
.stderr_contains(
|
||||
"error: The argument '--output <FILENAME>' cannot be used with '--check",
|
||||
// the rest of the message might be subject to change
|
||||
"error: The argument",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1049,10 +1060,13 @@ fn test_separator_null() {
|
|||
#[test]
|
||||
fn test_output_is_input() {
|
||||
let input = "a\nb\nc\n";
|
||||
let (at, mut cmd) = at_and_ucmd!();
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
at.touch("file");
|
||||
at.append("file", input);
|
||||
cmd.args(&["-m", "-u", "-o", "file", "file", "file", "file"])
|
||||
scene
|
||||
.ucmd_keepenv()
|
||||
.args(&["-m", "-u", "-o", "file", "file", "file", "file"])
|
||||
.succeeds();
|
||||
assert_eq!(at.read("file"), input);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// *
|
||||
// * For the full copyright and license information, please view the LICENSE
|
||||
// * file that was distributed with this source code.
|
||||
|
||||
// spell-checker:ignore xzaaa sixhundredfiftyonebytes ninetyonebytes threebytes asciilowercase fghij klmno pqrst uvwxyz fivelines twohundredfortyonebytes onehundredlines nbbbb
|
||||
extern crate rand;
|
||||
extern crate regex;
|
||||
|
||||
|
@ -12,16 +12,16 @@ use crate::common::util::*;
|
|||
use rand::SeedableRng;
|
||||
#[cfg(not(windows))]
|
||||
use std::env;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::{
|
||||
fs::{read_dir, File},
|
||||
io::BufWriter,
|
||||
io::{BufWriter, Read, Write},
|
||||
};
|
||||
|
||||
fn random_chars(n: usize) -> String {
|
||||
thread_rng()
|
||||
.sample_iter(&rand::distributions::Alphanumeric)
|
||||
.map(char::from)
|
||||
.take(n)
|
||||
.collect::<String>()
|
||||
}
|
||||
|
@ -32,8 +32,8 @@ struct Glob {
|
|||
}
|
||||
|
||||
impl Glob {
|
||||
fn new(at: &AtPath, directory: &str, regex: &str) -> Glob {
|
||||
Glob {
|
||||
fn new(at: &AtPath, directory: &str, regex: &str) -> Self {
|
||||
Self {
|
||||
directory: AtPath::new(Path::new(&at.plus_as_string(directory))),
|
||||
regex: Regex::new(regex).unwrap(),
|
||||
}
|
||||
|
@ -83,8 +83,8 @@ impl RandomFile {
|
|||
const LINESIZE: usize = 32;
|
||||
|
||||
/// `create()` file handle located at `at` / `name`
|
||||
fn new(at: &AtPath, name: &str) -> RandomFile {
|
||||
RandomFile {
|
||||
fn new(at: &AtPath, name: &str) -> Self {
|
||||
Self {
|
||||
inner: File::create(&at.plus(name)).unwrap(),
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ impl RandomFile {
|
|||
fn add_lines(&mut self, lines: usize) {
|
||||
let mut n = lines;
|
||||
while n > 0 {
|
||||
writeln!(self.inner, "{}", random_chars(RandomFile::LINESIZE)).unwrap();
|
||||
writeln!(self.inner, "{}", random_chars(Self::LINESIZE)).unwrap();
|
||||
n -= 1;
|
||||
}
|
||||
}
|
||||
|
@ -228,6 +228,14 @@ fn test_split_additional_suffix() {
|
|||
assert_eq!(glob.collate(), at.read_bytes(name));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_additional_suffix_no_slash() {
|
||||
new_ucmd!()
|
||||
.args(&["--additional-suffix", "a/b"])
|
||||
.fails()
|
||||
.usage_error("invalid suffix 'a/b', contains directory separator");
|
||||
}
|
||||
|
||||
// note: the test_filter* tests below are unix-only
|
||||
// windows support has been waived for now because of the difficulty of getting
|
||||
// the `cmd` call right
|
||||
|
@ -329,14 +337,321 @@ fn test_split_invalid_bytes_size() {
|
|||
{
|
||||
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
|
||||
));
|
||||
new_ucmd!().args(&["-b", size]).succeeds();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_chunks_num_chunks_oversized_32() {
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
{
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
at.touch("file");
|
||||
scene
|
||||
.ucmd()
|
||||
.args(&["--number", "5000000000", "file"])
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stderr_only("split: Number of chunks too big");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_stdin_num_chunks() {
|
||||
new_ucmd!()
|
||||
.args(&["--number=1"])
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stderr_only("split: -: cannot determine file size");
|
||||
}
|
||||
|
||||
fn file_read(at: &AtPath, filename: &str) -> String {
|
||||
let mut s = String::new();
|
||||
at.open(filename).read_to_string(&mut s).unwrap();
|
||||
s
|
||||
}
|
||||
|
||||
// TODO Use char::from_digit() in Rust v1.51.0 or later.
|
||||
fn char_from_digit(n: usize) -> char {
|
||||
(b'a' + n as u8) as char
|
||||
}
|
||||
|
||||
/// Test for the default suffix length behavior: dynamically increasing size.
|
||||
#[test]
|
||||
fn test_alphabetic_dynamic_suffix_length() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
// Split into chunks of one byte each.
|
||||
//
|
||||
// The input file has (26^2) - 26 + 1 = 651 bytes. This is just
|
||||
// enough to force `split` to dynamically increase the length of
|
||||
// the filename for the very last chunk.
|
||||
//
|
||||
// We expect the output files to be named
|
||||
//
|
||||
// xaa, xab, xac, ..., xyx, xyy, xyz, xzaaa
|
||||
//
|
||||
ucmd.args(&["-b", "1", "sixhundredfiftyonebytes.txt"])
|
||||
.succeeds();
|
||||
for i in 0..25 {
|
||||
for j in 0..26 {
|
||||
let filename = format!("x{}{}", char_from_digit(i), char_from_digit(j),);
|
||||
let contents = file_read(&at, &filename);
|
||||
assert_eq!(contents, "a");
|
||||
}
|
||||
}
|
||||
assert_eq!(file_read(&at, "xzaaa"), "a");
|
||||
}
|
||||
|
||||
/// Test for the default suffix length behavior: dynamically increasing size.
|
||||
#[test]
|
||||
fn test_numeric_dynamic_suffix_length() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
// Split into chunks of one byte each, use numbers instead of
|
||||
// letters as file suffixes.
|
||||
//
|
||||
// The input file has (10^2) - 10 + 1 = 91 bytes. This is just
|
||||
// enough to force `split` to dynamically increase the length of
|
||||
// the filename for the very last chunk.
|
||||
//
|
||||
// x00, x01, x02, ..., x87, x88, x89, x9000
|
||||
//
|
||||
ucmd.args(&["-d", "-b", "1", "ninetyonebytes.txt"])
|
||||
.succeeds();
|
||||
for i in 0..90 {
|
||||
let filename = format!("x{:02}", i);
|
||||
let contents = file_read(&at, &filename);
|
||||
assert_eq!(contents, "a");
|
||||
}
|
||||
assert_eq!(file_read(&at, "x9000"), "a");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hex_dynamic_suffix_length() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
// Split into chunks of one byte each, use hexadecimal digits
|
||||
// instead of letters as file suffixes.
|
||||
//
|
||||
// The input file has (16^2) - 16 + 1 = 241 bytes. This is just
|
||||
// enough to force `split` to dynamically increase the length of
|
||||
// the filename for the very last chunk.
|
||||
//
|
||||
// x00, x01, x02, ..., xed, xee, xef, xf000
|
||||
//
|
||||
ucmd.args(&["-x", "-b", "1", "twohundredfortyonebytes.txt"])
|
||||
.succeeds();
|
||||
for i in 0..240 {
|
||||
let filename = format!("x{:02x}", i);
|
||||
let contents = file_read(&at, &filename);
|
||||
assert_eq!(contents, "a");
|
||||
}
|
||||
assert_eq!(file_read(&at, "xf000"), "a");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_suffixes_exhausted() {
|
||||
new_ucmd!()
|
||||
.args(&["-b", "1", "-a", "1", "asciilowercase.txt"])
|
||||
.fails()
|
||||
.stderr_only("split: output file suffixes exhausted");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_verbose() {
|
||||
new_ucmd!()
|
||||
.args(&["-b", "5", "--verbose", "asciilowercase.txt"])
|
||||
.succeeds()
|
||||
.stdout_only(
|
||||
"creating file 'xaa'
|
||||
creating file 'xab'
|
||||
creating file 'xac'
|
||||
creating file 'xad'
|
||||
creating file 'xae'
|
||||
creating file 'xaf'
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_number() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file_read = |f| {
|
||||
let mut s = String::new();
|
||||
at.open(f).read_to_string(&mut s).unwrap();
|
||||
s
|
||||
};
|
||||
ucmd.args(&["-n", "5", "asciilowercase.txt"]).succeeds();
|
||||
assert_eq!(file_read("xaa"), "abcde");
|
||||
assert_eq!(file_read("xab"), "fghij");
|
||||
assert_eq!(file_read("xac"), "klmno");
|
||||
assert_eq!(file_read("xad"), "pqrst");
|
||||
assert_eq!(file_read("xae"), "uvwxyz\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_number_with_io_blksize() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file_read = |f| {
|
||||
let mut s = String::new();
|
||||
at.open(f).read_to_string(&mut s).unwrap();
|
||||
s
|
||||
};
|
||||
ucmd.args(&["-n", "5", "asciilowercase.txt", "---io-blksize", "1024"])
|
||||
.succeeds();
|
||||
assert_eq!(file_read("xaa"), "abcde");
|
||||
assert_eq!(file_read("xab"), "fghij");
|
||||
assert_eq!(file_read("xac"), "klmno");
|
||||
assert_eq!(file_read("xad"), "pqrst");
|
||||
assert_eq!(file_read("xae"), "uvwxyz\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_default_with_io_blksize() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let name = "split_default_with_io_blksize";
|
||||
RandomFile::new(&at, name).add_lines(2000);
|
||||
ucmd.args(&[name, "---io-blksize", "2M"]).succeeds();
|
||||
|
||||
let glob = Glob::new(&at, ".", r"x[[:alpha:]][[:alpha:]]$");
|
||||
assert_eq!(glob.count(), 2);
|
||||
assert_eq!(glob.collate(), at.read_bytes(name));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_suffix_length() {
|
||||
new_ucmd!()
|
||||
.args(&["-a", "xyz"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("invalid suffix length: 'xyz'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_include_newlines() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["-l", "2", "fivelines.txt"]).succeeds();
|
||||
|
||||
let mut s = String::new();
|
||||
at.open("xaa").read_to_string(&mut s).unwrap();
|
||||
assert_eq!(s, "1\n2\n");
|
||||
|
||||
let mut s = String::new();
|
||||
at.open("xab").read_to_string(&mut s).unwrap();
|
||||
assert_eq!(s, "3\n4\n");
|
||||
|
||||
let mut s = String::new();
|
||||
at.open("xac").read_to_string(&mut s).unwrap();
|
||||
assert_eq!(s, "5\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_allow_empty_files() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["-n", "4", "threebytes.txt"])
|
||||
.succeeds()
|
||||
.no_stdout()
|
||||
.no_stderr();
|
||||
assert_eq!(at.read("xaa"), "a");
|
||||
assert_eq!(at.read("xab"), "b");
|
||||
assert_eq!(at.read("xac"), "c");
|
||||
assert_eq!(at.read("xad"), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_elide_empty_files() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["-e", "-n", "4", "threebytes.txt"])
|
||||
.succeeds()
|
||||
.no_stdout()
|
||||
.no_stderr();
|
||||
assert_eq!(at.read("xaa"), "a");
|
||||
assert_eq!(at.read("xab"), "b");
|
||||
assert_eq!(at.read("xac"), "c");
|
||||
assert!(!at.plus("xad").exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_elide_dev_null() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["-e", "-n", "3", "/dev/null"])
|
||||
.succeeds()
|
||||
.no_stdout()
|
||||
.no_stderr();
|
||||
assert!(!at.plus("xaa").exists());
|
||||
assert!(!at.plus("xab").exists());
|
||||
assert!(!at.plus("xac").exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lines() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
let file_read = |f| {
|
||||
let mut s = String::new();
|
||||
at.open(f).read_to_string(&mut s).unwrap();
|
||||
s
|
||||
};
|
||||
|
||||
// Split into two files without splitting up lines.
|
||||
ucmd.args(&["-n", "l/2", "fivelines.txt"]).succeeds();
|
||||
|
||||
assert_eq!(file_read("xaa"), "1\n2\n3\n");
|
||||
assert_eq!(file_read("xab"), "4\n5\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lines_kth() {
|
||||
new_ucmd!()
|
||||
.args(&["-n", "l/3/10", "onehundredlines.txt"])
|
||||
.succeeds()
|
||||
.stdout_only("20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_line_bytes() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["-C", "8", "letters.txt"]).succeeds();
|
||||
assert_eq!(at.read("xaa"), "aaaaaaaa");
|
||||
assert_eq!(at.read("xab"), "a\nbbbb\n");
|
||||
assert_eq!(at.read("xac"), "cccc\ndd\n");
|
||||
assert_eq!(at.read("xad"), "ee\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_line_bytes_no_final_newline() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["-C", "2"])
|
||||
.pipe_in("1\n2222\n3\n4")
|
||||
.succeeds()
|
||||
.no_stdout()
|
||||
.no_stderr();
|
||||
assert_eq!(at.read("xaa"), "1\n");
|
||||
assert_eq!(at.read("xab"), "22");
|
||||
assert_eq!(at.read("xac"), "22");
|
||||
assert_eq!(at.read("xad"), "\n");
|
||||
assert_eq!(at.read("xae"), "3\n");
|
||||
assert_eq!(at.read("xaf"), "4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_line_bytes_no_empty_file() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["-C", "1"])
|
||||
.pipe_in("1\n2222\n3\n4")
|
||||
.succeeds()
|
||||
.no_stdout()
|
||||
.no_stderr();
|
||||
assert_eq!(at.read("xaa"), "1");
|
||||
assert_eq!(at.read("xab"), "\n");
|
||||
assert_eq!(at.read("xac"), "2");
|
||||
assert_eq!(at.read("xad"), "2");
|
||||
assert_eq!(at.read("xae"), "2");
|
||||
assert_eq!(at.read("xaf"), "2");
|
||||
assert_eq!(at.read("xag"), "\n");
|
||||
assert_eq!(at.read("xah"), "3");
|
||||
assert_eq!(at.read("xai"), "\n");
|
||||
assert_eq!(at.read("xaj"), "4");
|
||||
assert!(!at.plus("xak").exists());
|
||||
}
|
||||
|
|
|
@ -34,6 +34,14 @@ fn test_group_num() {
|
|||
assert_eq!("24", group_num("24"));
|
||||
assert_eq!("4", group_num("4"));
|
||||
assert_eq!("", group_num(""));
|
||||
assert_eq!("-5", group_num("-5"));
|
||||
assert_eq!("-1,234", group_num("-1234"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_group_num_panic_if_invalid_numeric_characters() {
|
||||
group_num("³³³³³");
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -29,9 +29,9 @@ fn test_stdbuf_no_buffer_option_fails() {
|
|||
|
||||
ts.ucmd().args(&["head"]).fails().stderr_is(&format!(
|
||||
"error: The following required arguments were not provided:\n \
|
||||
--error <MODE>\n \
|
||||
--input <MODE>\n \
|
||||
--output <MODE>\n\n\
|
||||
--output <MODE>\n \
|
||||
--error <MODE>\n\n\
|
||||
USAGE:\n \
|
||||
{1} {0} OPTION... COMMAND\n\n\
|
||||
For more information try --help",
|
||||
|
@ -53,16 +53,10 @@ fn test_stdbuf_trailing_var_arg() {
|
|||
#[cfg(not(target_os = "windows"))]
|
||||
#[test]
|
||||
fn test_stdbuf_line_buffering_stdin_fails() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
|
||||
ts.ucmd()
|
||||
new_ucmd!()
|
||||
.args(&["-i", "L", "head"])
|
||||
.fails()
|
||||
.stderr_is(&format!(
|
||||
"{0}: line buffering stdin is meaningless\nTry '{1} {0} --help' for more information.",
|
||||
ts.util_name,
|
||||
ts.bin_path.to_string_lossy()
|
||||
));
|
||||
.usage_error("line buffering stdin is meaningless");
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
|
@ -81,5 +75,15 @@ fn test_stdbuf_invalid_mode_fails() {
|
|||
.fails()
|
||||
.code_is(125)
|
||||
.stderr_contains("stdbuf: invalid mode '1Y': Value too large for defined data type");
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
{
|
||||
new_ucmd!()
|
||||
.args(&[*option, "5GB", "head"])
|
||||
.fails()
|
||||
.code_is(125)
|
||||
.stderr_contains(
|
||||
"stdbuf: invalid mode '5GB': Value too large for defined data type",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// * 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 logfile
|
||||
// spell-checker:ignore (ToDO) abcdefghijklmnopqrstuvwxyz efghijklmnopqrstuvwxyz vwxyz emptyfile logfile bogusfile siette ocho nueve diez
|
||||
// spell-checker:ignore (libs) kqueue
|
||||
// spell-checker:ignore (jargon) tailable untailable
|
||||
|
||||
|
@ -92,6 +92,34 @@ fn test_follow_single() {
|
|||
child.kill().unwrap();
|
||||
}
|
||||
|
||||
/// Test for following when bytes are written that are not valid UTF-8.
|
||||
#[test]
|
||||
fn test_follow_non_utf8_bytes() {
|
||||
// Tail the test file and start following it.
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let mut child = ucmd.arg("-f").arg(FOOBAR_TXT).run_no_wait();
|
||||
let expected = at.read("foobar_single_default.expected");
|
||||
assert_eq!(read_size(&mut child, expected.len()), expected);
|
||||
|
||||
// Now append some bytes that are not valid UTF-8.
|
||||
//
|
||||
// The binary integer "10000000" is *not* a valid UTF-8 encoding
|
||||
// of a character: https://en.wikipedia.org/wiki/UTF-8#Encoding
|
||||
//
|
||||
// We also write the newline character because our implementation
|
||||
// of `tail` is attempting to read a line of input, so the
|
||||
// presence of a newline character will force the `follow()`
|
||||
// function to conclude reading input bytes and start writing them
|
||||
// to output. The newline character is not fundamental to this
|
||||
// test, it is just a requirement of the current implementation.
|
||||
let expected = [0b10000000, b'\n'];
|
||||
at.append_bytes(FOOBAR_TXT, &expected);
|
||||
let actual = read_size_bytes(&mut child, expected.len());
|
||||
assert_eq!(actual, expected.to_vec());
|
||||
|
||||
child.kill().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_follow_multiple() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
@ -217,13 +245,13 @@ fn test_single_big_args() {
|
|||
|
||||
let mut big_input = at.make_file(FILE);
|
||||
for i in 0..LINES {
|
||||
writeln!(&mut big_input, "Line {}", i).expect("Could not write to FILE");
|
||||
writeln!(big_input, "Line {}", i).expect("Could not write to FILE");
|
||||
}
|
||||
big_input.flush().expect("Could not flush FILE");
|
||||
|
||||
let mut big_expected = at.make_file(EXPECTED_FILE);
|
||||
for i in (LINES - N_ARG)..LINES {
|
||||
writeln!(&mut big_expected, "Line {}", i).expect("Could not write to EXPECTED_FILE");
|
||||
writeln!(big_expected, "Line {}", i).expect("Could not write to EXPECTED_FILE");
|
||||
}
|
||||
big_expected.flush().expect("Could not flush EXPECTED_FILE");
|
||||
|
||||
|
@ -266,14 +294,14 @@ fn test_bytes_big() {
|
|||
let mut big_input = at.make_file(FILE);
|
||||
for i in 0..BYTES {
|
||||
let digit = from_digit((i % 10) as u32, 10).unwrap();
|
||||
write!(&mut big_input, "{}", digit).expect("Could not write to FILE");
|
||||
write!(big_input, "{}", digit).expect("Could not write to FILE");
|
||||
}
|
||||
big_input.flush().expect("Could not flush FILE");
|
||||
|
||||
let mut big_expected = at.make_file(EXPECTED_FILE);
|
||||
for i in (BYTES - N_ARG)..BYTES {
|
||||
let digit = from_digit((i % 10) as u32, 10).unwrap();
|
||||
write!(&mut big_expected, "{}", digit).expect("Could not write to EXPECTED_FILE");
|
||||
write!(big_expected, "{}", digit).expect("Could not write to EXPECTED_FILE");
|
||||
}
|
||||
big_expected.flush().expect("Could not flush EXPECTED_FILE");
|
||||
|
||||
|
@ -302,13 +330,13 @@ fn test_lines_with_size_suffix() {
|
|||
|
||||
let mut big_input = at.make_file(FILE);
|
||||
for i in 0..LINES {
|
||||
writeln!(&mut big_input, "Line {}", i).expect("Could not write to FILE");
|
||||
writeln!(big_input, "Line {}", i).expect("Could not write to FILE");
|
||||
}
|
||||
big_input.flush().expect("Could not flush FILE");
|
||||
|
||||
let mut big_expected = at.make_file(EXPECTED_FILE);
|
||||
for i in (LINES - N_ARG)..LINES {
|
||||
writeln!(&mut big_expected, "Line {}", i).expect("Could not write to EXPECTED_FILE");
|
||||
writeln!(big_expected, "Line {}", i).expect("Could not write to EXPECTED_FILE");
|
||||
}
|
||||
big_expected.flush().expect("Could not flush EXPECTED_FILE");
|
||||
|
||||
|
@ -512,6 +540,67 @@ fn test_positive_lines() {
|
|||
.stdout_is("c\nd\ne\n");
|
||||
}
|
||||
|
||||
/// Test for reading all but the first NUM lines of a file: `tail -n +3 infile`.
|
||||
#[test]
|
||||
fn test_positive_lines_file() {
|
||||
new_ucmd!()
|
||||
.args(&["-n", "+7", "foobar.txt"])
|
||||
.succeeds()
|
||||
.stdout_is(
|
||||
"siette
|
||||
ocho
|
||||
nueve
|
||||
diez
|
||||
once
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
/// Test for reading all but the first NUM bytes of a file: `tail -c +3 infile`.
|
||||
#[test]
|
||||
fn test_positive_bytes_file() {
|
||||
new_ucmd!()
|
||||
.args(&["-c", "+42", "foobar.txt"])
|
||||
.succeeds()
|
||||
.stdout_is(
|
||||
"ho
|
||||
nueve
|
||||
diez
|
||||
once
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
/// Test for reading all but the first NUM lines: `tail -3`.
|
||||
#[test]
|
||||
fn test_obsolete_syntax_positive_lines() {
|
||||
new_ucmd!()
|
||||
.args(&["-3"])
|
||||
.pipe_in("a\nb\nc\nd\ne\n")
|
||||
.succeeds()
|
||||
.stdout_is("c\nd\ne\n");
|
||||
}
|
||||
|
||||
/// Test for reading all but the first NUM lines: `tail -n -10`.
|
||||
#[test]
|
||||
fn test_small_file() {
|
||||
new_ucmd!()
|
||||
.args(&["-n -10"])
|
||||
.pipe_in("a\nb\nc\nd\ne\n")
|
||||
.succeeds()
|
||||
.stdout_is("a\nb\nc\nd\ne\n");
|
||||
}
|
||||
|
||||
/// Test for reading all but the first NUM lines: `tail -10`.
|
||||
#[test]
|
||||
fn test_obsolete_syntax_small_file() {
|
||||
new_ucmd!()
|
||||
.args(&["-10"])
|
||||
.pipe_in("a\nb\nc\nd\ne\n")
|
||||
.succeeds()
|
||||
.stdout_is("a\nb\nc\nd\ne\n");
|
||||
}
|
||||
|
||||
/// Test for reading all lines, specified by `tail -n +0`.
|
||||
#[test]
|
||||
fn test_positive_zero_lines() {
|
||||
|
@ -550,12 +639,13 @@ fn test_invalid_num() {
|
|||
.args(&["-c", size])
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stderr_only(format!(
|
||||
"tail: invalid number of bytes: '{}': Value too large for defined data type",
|
||||
size
|
||||
));
|
||||
.stderr_only("tail: Insufficient addressable memory");
|
||||
}
|
||||
}
|
||||
new_ucmd!()
|
||||
.args(&["-c", "-³"])
|
||||
.fails()
|
||||
.stderr_is("tail: invalid number of bytes: '³'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1326,3 +1416,40 @@ fn take_stdout_stderr(p: &mut std::process::Child) -> (String, String) {
|
|||
p_stderr.read_to_string(&mut buf_stderr).unwrap();
|
||||
(buf_stdout, buf_stderr)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_no_such_file() {
|
||||
new_ucmd!()
|
||||
.arg("bogusfile")
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("cannot open 'bogusfile' for reading: No such file or directory");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_no_trailing_newline() {
|
||||
new_ucmd!().pipe_in("x").succeeds().stdout_only("x");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lines_zero_terminated() {
|
||||
new_ucmd!()
|
||||
.args(&["-z", "-n", "2"])
|
||||
.pipe_in("a\0b\0c\0d\0e\0")
|
||||
.succeeds()
|
||||
.stdout_only("d\0e\0");
|
||||
new_ucmd!()
|
||||
.args(&["-z", "-n", "+2"])
|
||||
.pipe_in("a\0b\0c\0d\0e\0")
|
||||
.succeeds()
|
||||
.stdout_only("b\0c\0d\0e\0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_presume_input_pipe_default() {
|
||||
new_ucmd!()
|
||||
.arg("---presume-input-pipe")
|
||||
.pipe_in_fixture(FOOBAR_TXT)
|
||||
.run()
|
||||
.stdout_is_fixture("foobar_stdin_default.expected");
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ fn test_tee_processing_multiple_operands() {
|
|||
// POSIX says: "Processing of at least 13 file operands shall be supported."
|
||||
|
||||
let content = "tee_sample_content";
|
||||
for &n in [1, 2, 12, 13].iter() {
|
||||
for &n in &[1, 2, 12, 13] {
|
||||
let files = (1..=n).map(|x| x.to_string()).collect::<Vec<_>>();
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
|
@ -18,7 +18,7 @@ fn test_tee_processing_multiple_operands() {
|
|||
.succeeds()
|
||||
.stdout_is(content);
|
||||
|
||||
for file in files.iter() {
|
||||
for file in &files {
|
||||
assert!(at.file_exists(file));
|
||||
assert_eq!(at.read(file), content);
|
||||
}
|
||||
|
@ -63,9 +63,7 @@ fn test_tee_append() {
|
|||
fn test_tee_no_more_writeable_1() {
|
||||
// equals to 'tee /dev/full out2 <multi_read' call
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let content = (1..=10)
|
||||
.map(|x| format!("{}\n", x.to_string()))
|
||||
.collect::<String>();
|
||||
let content = (1..=10).map(|x| format!("{}\n", x)).collect::<String>();
|
||||
let file_out = "tee_file_out";
|
||||
|
||||
ucmd.arg("/dev/full")
|
||||
|
@ -85,9 +83,7 @@ fn test_tee_no_more_writeable_2() {
|
|||
// but currently there is no way to redirect stdout to /dev/full
|
||||
// so this test is disabled
|
||||
let (_at, mut ucmd) = at_and_ucmd!();
|
||||
let _content = (1..=10)
|
||||
.map(|x| format!("{}\n", x.to_string()))
|
||||
.collect::<String>();
|
||||
let _content = (1..=10).map(|x| format!("{}\n", x)).collect::<String>();
|
||||
let file_out_a = "tee_file_out_a";
|
||||
let file_out_b = "tee_file_out_b";
|
||||
|
||||
|
|
|
@ -440,7 +440,27 @@ fn test_file_is_not_writable() {
|
|||
|
||||
#[test]
|
||||
fn test_file_is_not_executable() {
|
||||
new_ucmd!().args(&["!", "-x", "regular_file"]).succeeds();
|
||||
#[cfg(unix)]
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
#[cfg(not(unix))]
|
||||
let (_, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
// WSL creates executable files by default, so if we are on unix, make sure
|
||||
// to set make it non-executable.
|
||||
// Files on other targets are non-executable by default.
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let metadata = std::fs::metadata(at.plus("regular_file")).unwrap();
|
||||
let mut permissions = metadata.permissions();
|
||||
|
||||
// The conversion is useless on some platforms and casts from u16 to
|
||||
// u32 on others
|
||||
#[allow(clippy::useless_conversion)]
|
||||
permissions.set_mode(permissions.mode() & !u32::from(libc::S_IXUSR));
|
||||
std::fs::set_permissions(at.plus("regular_file"), permissions).unwrap();
|
||||
}
|
||||
ucmd.args(&["!", "-x", "regular_file"]).succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// spell-checker:ignore dont
|
||||
use crate::common::util::*;
|
||||
|
||||
// FIXME: this depends on the system having true and false in PATH
|
||||
|
@ -10,6 +11,24 @@ fn test_subcommand_return_code() {
|
|||
new_ucmd!().arg("1").arg("false").run().status_code(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_time_interval() {
|
||||
new_ucmd!()
|
||||
.args(&["xyz", "sleep", "0"])
|
||||
.fails()
|
||||
.code_is(125)
|
||||
.usage_error("invalid time interval 'xyz'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_kill_after() {
|
||||
new_ucmd!()
|
||||
.args(&["-k", "xyz", "1", "sleep", "0"])
|
||||
.fails()
|
||||
.code_is(125)
|
||||
.usage_error("invalid time interval 'xyz'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_command_with_args() {
|
||||
new_ucmd!()
|
||||
|
@ -45,3 +64,64 @@ fn test_zero_timeout() {
|
|||
.no_stderr()
|
||||
.no_stdout();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_command_empty_args() {
|
||||
new_ucmd!()
|
||||
.args(&["", ""])
|
||||
.fails()
|
||||
.stderr_contains("timeout: empty string");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_preserve_status() {
|
||||
new_ucmd!()
|
||||
.args(&["--preserve-status", ".1", "sleep", "10"])
|
||||
.fails()
|
||||
// 128 + SIGTERM = 128 + 15
|
||||
.code_is(128 + 15)
|
||||
.no_stderr()
|
||||
.no_stdout();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dont_overflow() {
|
||||
new_ucmd!()
|
||||
.args(&["9223372036854775808d", "sleep", "0"])
|
||||
.succeeds()
|
||||
.code_is(0)
|
||||
.no_stderr()
|
||||
.no_stdout();
|
||||
new_ucmd!()
|
||||
.args(&["-k", "9223372036854775808d", "10", "sleep", "0"])
|
||||
.succeeds()
|
||||
.code_is(0)
|
||||
.no_stderr()
|
||||
.no_stdout();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_negative_interval() {
|
||||
new_ucmd!()
|
||||
.args(&["--", "-1", "sleep", "0"])
|
||||
.fails()
|
||||
.usage_error("invalid time interval '-1'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_signal() {
|
||||
new_ucmd!()
|
||||
.args(&["-s", "invalid", "1", "sleep", "0"])
|
||||
.fails()
|
||||
.usage_error("'invalid': invalid signal");
|
||||
}
|
||||
|
||||
/// Test that the long form of the `--kill-after` argument is recognized.
|
||||
#[test]
|
||||
fn test_kill_after_long() {
|
||||
new_ucmd!()
|
||||
.args(&["--kill-after=1", "1", "sleep", "0"])
|
||||
.succeeds()
|
||||
.no_stdout()
|
||||
.no_stderr();
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ fn get_symlink_times(at: &AtPath, path: &str) -> (FileTime, FileTime) {
|
|||
}
|
||||
|
||||
fn set_file_times(at: &AtPath, path: &str, atime: FileTime, mtime: FileTime) {
|
||||
filetime::set_file_times(&at.plus_as_string(path), atime, mtime).unwrap()
|
||||
filetime::set_file_times(&at.plus_as_string(path), atime, mtime).unwrap();
|
||||
}
|
||||
|
||||
// Adjusts for local timezone
|
||||
|
@ -427,7 +427,7 @@ fn test_touch_mtime_dst_succeeds() {
|
|||
|
||||
let target_time = str_to_filetime("%Y%m%d%H%M", "202103140300");
|
||||
let (_, mtime) = get_file_times(&at, file);
|
||||
assert!(target_time == mtime);
|
||||
assert_eq!(target_time, mtime);
|
||||
}
|
||||
|
||||
// is_dst_switch_hour returns true if timespec ts is just before the switch
|
||||
|
@ -510,6 +510,27 @@ fn test_touch_no_such_file_error_msg() {
|
|||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_touch_changes_time_of_file_in_stdout() {
|
||||
// command like: `touch - 1< ./c`
|
||||
// should change the timestamp of c
|
||||
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file = "test_touch_changes_time_of_file_in_stdout";
|
||||
|
||||
at.touch(file);
|
||||
assert!(at.file_exists(file));
|
||||
let (_, mtime) = get_file_times(&at, file);
|
||||
|
||||
ucmd.args(&["-"])
|
||||
.set_stdout(at.make_file(file))
|
||||
.succeeds()
|
||||
.no_stderr();
|
||||
|
||||
let (_, mtime_after) = get_file_times(&at, file);
|
||||
assert!(mtime_after != mtime);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_touch_permission_denied_error_msg() {
|
||||
|
@ -530,3 +551,25 @@ fn test_touch_permission_denied_error_msg() {
|
|||
&full_path
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_touch_no_args() {
|
||||
let mut ucmd = new_ucmd!();
|
||||
ucmd.fails().stderr_only(
|
||||
r##"touch: missing file operand
|
||||
Try 'touch --help' for more information."##,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_no_dereference_no_file() {
|
||||
new_ucmd!()
|
||||
.args(&["-h", "not-a-file"])
|
||||
.fails()
|
||||
.stderr_contains("setting times of 'not-a-file': No such file or directory");
|
||||
new_ucmd!()
|
||||
.args(&["-h", "not-a-file-1", "not-a-file-2"])
|
||||
.fails()
|
||||
.stderr_contains("setting times of 'not-a-file-1': No such file or directory")
|
||||
.stderr_contains("setting times of 'not-a-file-2': No such file or directory");
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// spell-checker:ignore aabbaa aabbcc aabc abbb abcc abcdefabcdef abcdefghijk abcdefghijklmn abcdefghijklmnop ABCDEFGHIJKLMNOPQRS abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFZZ abcxyz ABCXYZ abcxyzabcxyz ABCXYZABCXYZ acbdef alnum amzamz AMZXAMZ bbbd cclass cefgm cntrl compl dabcdef dncase Gzabcdefg PQRST upcase wxyzz xdigit xycde xyyye xyyz xyzzzzxyzzzz ZABCDEF Zamz Cdefghijkl Cdefghijklmn
|
||||
use crate::common::util::*;
|
||||
|
||||
#[test]
|
||||
|
@ -98,12 +99,11 @@ fn test_complement4() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "fixme: GNU tr returns '0a1b2c3' instead of '0~1~2~3', see #2158"]
|
||||
fn test_complement5() {
|
||||
// $ echo '0x1y2z3' | tr -c '\0-@' '*-~'
|
||||
// $ echo -n '0x1y2z3' | tr -c '\0-@' '*-~'
|
||||
// 0a1b2c3
|
||||
new_ucmd!()
|
||||
.args(&["-c", "\\0-@", "*-~"])
|
||||
.args(&["-c", r"\0-@", "*-~"])
|
||||
.pipe_in("0x1y2z3")
|
||||
.run()
|
||||
.stdout_is("0a1b2c3");
|
||||
|
@ -192,6 +192,7 @@ fn test_set1_shorter_than_set2() {
|
|||
|
||||
#[test]
|
||||
fn test_truncate() {
|
||||
// echo -n "abcde" | tr -t "abc" "xy"
|
||||
new_ucmd!()
|
||||
.args(&["-t", "abc", "xy"])
|
||||
.pipe_in("abcde")
|
||||
|
@ -286,11 +287,835 @@ fn test_interpret_backslash_at_eol_literally() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
// FixME: panicked at 'failed to write to stdin of child: Broken pipe (os error 32)
|
||||
#[cfg(not(target_os = "freebsd"))]
|
||||
fn test_more_than_2_sets() {
|
||||
new_ucmd!()
|
||||
.args(&["'abcdefgh'", "'a", "'b'"])
|
||||
.pipe_in("hello world")
|
||||
.fails();
|
||||
new_ucmd!().args(&["'abcdef'", "'a'", "'b'"]).fails();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_translation_works() {
|
||||
// echo -n "abcdefabcdef" | tr "dabcdef" "xyz"
|
||||
new_ucmd!()
|
||||
.args(&["abcdef", "xyz"])
|
||||
.pipe_in("abcdefabcdef")
|
||||
.succeeds()
|
||||
.stdout_is("xyzzzzxyzzzz");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alnum_overrides_translation_to_fallback_1() {
|
||||
// echo -n "abcdefghijklmnopqrstuvwxyz" | tr "abc[:alpha:]" "xyz"
|
||||
new_ucmd!()
|
||||
.args(&["abc[:alpha:]", "xyz"])
|
||||
.pipe_in("abcdefghijklmnopqrstuvwxyz")
|
||||
.succeeds()
|
||||
.stdout_is("zzzzzzzzzzzzzzzzzzzzzzzzzz");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alnum_overrides_translation_to_fallback_2() {
|
||||
// echo -n "abcdefghijklmnopqrstuvwxyz" | tr "[:alpha:]abc" "xyz"
|
||||
new_ucmd!()
|
||||
.args(&["[:alpha:]abc", "xyz"])
|
||||
.pipe_in("abcdefghijklmnopqrstuvwxyz")
|
||||
.succeeds()
|
||||
.stdout_is("zzzzzzzzzzzzzzzzzzzzzzzzzz");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn overrides_translation_pair_if_repeats() {
|
||||
// echo -n 'aaa' | tr "aaa" "xyz"
|
||||
new_ucmd!()
|
||||
.args(&["aaa", "xyz"])
|
||||
.pipe_in("aaa")
|
||||
.succeeds()
|
||||
.stdout_is("zzz");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uppercase_conversion_works_1() {
|
||||
// echo -n 'abcdefghijklmnopqrstuvwxyz' | tr "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
new_ucmd!()
|
||||
.args(&["abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"])
|
||||
.pipe_in("abcdefghijklmnopqrstuvwxyz")
|
||||
.succeeds()
|
||||
.stdout_is("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uppercase_conversion_works_2() {
|
||||
// echo -n 'abcdefghijklmnopqrstuvwxyz' | tr "a-z" "A-Z"
|
||||
new_ucmd!()
|
||||
.args(&["a-z", "A-Z"])
|
||||
.pipe_in("abcdefghijklmnopqrstuvwxyz")
|
||||
.succeeds()
|
||||
.stdout_is("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uppercase_conversion_works_3() {
|
||||
// echo -n 'abcdefghijklmnopqrstuvwxyz' | tr "[:lower:]" "[:upper:]"
|
||||
new_ucmd!()
|
||||
.args(&["[:lower:]", "[:upper:]"])
|
||||
.pipe_in("abcdefghijklmnopqrstuvwxyz")
|
||||
.succeeds()
|
||||
.stdout_is("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn translate_complement_set_in_order() {
|
||||
// echo -n '01234' | tr -c '@-~' ' -^'
|
||||
new_ucmd!()
|
||||
.args(&["-c", "@-~", " -^"])
|
||||
.pipe_in("01234")
|
||||
.succeeds()
|
||||
.stdout_is("PQRST");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alpha_expands_uppercase_lowercase() {
|
||||
// echo -n "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" | tr "[:alpha:]" " -_"
|
||||
new_ucmd!()
|
||||
.args(&["[:alpha:]", " -_"])
|
||||
.pipe_in("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
|
||||
.succeeds()
|
||||
.stdout_is(r##" !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRS"##);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alnum_expands_number_uppercase_lowercase() {
|
||||
// echo -n "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" | tr "[:alnum:]" " -_"
|
||||
new_ucmd!()
|
||||
.args(&["[:alnum:]", " -_"])
|
||||
.pipe_in("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
|
||||
.succeeds()
|
||||
.stdout_is(r##" !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]"##);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests() {
|
||||
// ['1', qw(abcd '[]*]'), {IN=>'abcd'}, {OUT=>']]]]'}],
|
||||
new_ucmd!()
|
||||
.args(&["abcd", "[]*]"])
|
||||
.pipe_in("abcd")
|
||||
.succeeds()
|
||||
.stdout_is("]]]]");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_2() {
|
||||
// ['2', qw(abc '[%*]xyz'), {IN=>'abc'}, {OUT=>'xyz'}],
|
||||
new_ucmd!()
|
||||
.args(&["abc", "[%*]xyz"])
|
||||
.pipe_in("abc")
|
||||
.succeeds()
|
||||
.stdout_is("xyz");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_3() {
|
||||
// ['3', qw('' '[.*]'), {IN=>'abc'}, {OUT=>'abc'}],
|
||||
new_ucmd!()
|
||||
.args(&["", "[.*]"])
|
||||
.pipe_in("abc")
|
||||
.succeeds()
|
||||
.stdout_is("abc");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_4() {
|
||||
// # Test --truncate-set1 behavior when string1 is longer than string2
|
||||
// ['4', qw(-t abcd xy), {IN=>'abcde'}, {OUT=>'xycde'}],
|
||||
new_ucmd!()
|
||||
.args(&["-t", "abcd", "xy"])
|
||||
.pipe_in("abcde")
|
||||
.succeeds()
|
||||
.stdout_is("xycde");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_5() {
|
||||
// # Test bsd behavior (the default) when string1 is longer than string2
|
||||
// ['5', qw(abcd xy), {IN=>'abcde'}, {OUT=>'xyyye'}],
|
||||
new_ucmd!()
|
||||
.args(&["abcd", "xy"])
|
||||
.pipe_in("abcde")
|
||||
.succeeds()
|
||||
.stdout_is("xyyye");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_6() {
|
||||
// # Do it the posix way
|
||||
// ['6', qw(abcd 'x[y*]'), {IN=>'abcde'}, {OUT=>'xyyye'}],
|
||||
new_ucmd!()
|
||||
.args(&["abcd", "x[y*]"])
|
||||
.pipe_in("abcde")
|
||||
.succeeds()
|
||||
.stdout_is("xyyye");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_7() {
|
||||
// ['7', qw(-s a-p '%[.*]$'), {IN=>'abcdefghijklmnop'}, {OUT=>'%.$'}],
|
||||
new_ucmd!()
|
||||
.args(&["-s", "a-p", "%[.*]$"])
|
||||
.pipe_in("abcdefghijklmnop")
|
||||
.succeeds()
|
||||
.stdout_is("%.$");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_8() {
|
||||
// ['8', qw(-s a-p '[.*]$'), {IN=>'abcdefghijklmnop'}, {OUT=>'.$'}],
|
||||
new_ucmd!()
|
||||
.args(&["-s", "a-p", "[.*]$"])
|
||||
.pipe_in("abcdefghijklmnop")
|
||||
.succeeds()
|
||||
.stdout_is(".$");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_9() {
|
||||
// ['9', qw(-s a-p '%[.*]'), {IN=>'abcdefghijklmnop'}, {OUT=>'%.'}],
|
||||
new_ucmd!()
|
||||
.args(&["-s", "a-p", "%[.*]"])
|
||||
.pipe_in("abcdefghijklmnop")
|
||||
.succeeds()
|
||||
.stdout_is("%.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_a() {
|
||||
// ['a', qw(-s '[a-z]'), {IN=>'aabbcc'}, {OUT=>'abc'}],
|
||||
new_ucmd!()
|
||||
.args(&["-s", "[a-z]"])
|
||||
.pipe_in("aabbcc")
|
||||
.succeeds()
|
||||
.stdout_is("abc");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_b() {
|
||||
// ['b', qw(-s '[a-c]'), {IN=>'aabbcc'}, {OUT=>'abc'}],
|
||||
new_ucmd!()
|
||||
.args(&["-s", "[a-c]"])
|
||||
.pipe_in("aabbcc")
|
||||
.succeeds()
|
||||
.stdout_is("abc");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_c() {
|
||||
// ['c', qw(-s '[a-b]'), {IN=>'aabbcc'}, {OUT=>'abcc'}],
|
||||
new_ucmd!()
|
||||
.args(&["-s", "[a-b]"])
|
||||
.pipe_in("aabbcc")
|
||||
.succeeds()
|
||||
.stdout_is("abcc");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_d() {
|
||||
// ['d', qw(-s '[b-c]'), {IN=>'aabbcc'}, {OUT=>'aabc'}],
|
||||
new_ucmd!()
|
||||
.args(&["-s", "[b-c]"])
|
||||
.pipe_in("aabbcc")
|
||||
.succeeds()
|
||||
.stdout_is("aabc");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "I cannot tell if this means that tr preserve the octal representation?"]
|
||||
fn check_against_gnu_tr_tests_e() {
|
||||
// ['e', qw(-s '[\0-\5]'), {IN=>"\0\0a\1\1b\2\2\2c\3\3\3d\4\4\4\4e\5\5"}, {OUT=>"\0a\1b\2c\3d\4e\5"}],
|
||||
new_ucmd!()
|
||||
.args(&["-s", r"[\0-\5]"])
|
||||
.pipe_in(
|
||||
"\u{0}\u{0}a\u{1}\u{1}b\u{2}\u{2}\u{2}c\u{3}\u{3}\u{3}d\u{4}\u{4}\u{4}\u{4}e\u{5}\u{5}",
|
||||
)
|
||||
.succeeds()
|
||||
.stdout_is("\u{0}a\u{1}b\u{2}c\u{3}d\u{4}e\u{5}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_f() {
|
||||
// # tests of delete
|
||||
// ['f', qw(-d '[=[=]'), {IN=>'[[[[[[[]]]]]]]]'}, {OUT=>']]]]]]]]'}],
|
||||
new_ucmd!()
|
||||
.args(&["-d", "[=[=]"])
|
||||
.pipe_in("[[[[[[[]]]]]]]]")
|
||||
.succeeds()
|
||||
.stdout_is("]]]]]]]]");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_g() {
|
||||
// ['g', qw(-d '[=]=]'), {IN=>'[[[[[[[]]]]]]]]'}, {OUT=>'[[[[[[['}],
|
||||
new_ucmd!()
|
||||
.args(&["-d", "[=]=]"])
|
||||
.pipe_in("[[[[[[[]]]]]]]]")
|
||||
.succeeds()
|
||||
.stdout_is("[[[[[[[");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_h() {
|
||||
// ['h', qw(-d '[:xdigit:]'), {IN=>'0123456789acbdefABCDEF'}, {OUT=>''}],
|
||||
new_ucmd!()
|
||||
.args(&["-d", "[:xdigit:]"])
|
||||
.pipe_in("0123456789acbdefABCDEF")
|
||||
.succeeds()
|
||||
.stdout_is("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_i() {
|
||||
// ['i', qw(-d '[:xdigit:]'), {IN=>'w0x1y2z3456789acbdefABCDEFz'}, {OUT=>'wxyzz'}],
|
||||
new_ucmd!()
|
||||
.args(&["-d", "[:xdigit:]"])
|
||||
.pipe_in("w0x1y2z3456789acbdefABCDEFz")
|
||||
.succeeds()
|
||||
.stdout_is("wxyzz");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_j() {
|
||||
// ['j', qw(-d '[:digit:]'), {IN=>'0123456789'}, {OUT=>''}],
|
||||
new_ucmd!()
|
||||
.args(&["-d", "[:digit:]"])
|
||||
.pipe_in("0123456789")
|
||||
.succeeds()
|
||||
.stdout_is("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_k() {
|
||||
// ['k', qw(-d '[:digit:]'), {IN=>'a0b1c2d3e4f5g6h7i8j9k'}, {OUT=>'abcdefghijk'}],
|
||||
new_ucmd!()
|
||||
.args(&["-d", "[:digit:]"])
|
||||
.pipe_in("a0b1c2d3e4f5g6h7i8j9k")
|
||||
.succeeds()
|
||||
.stdout_is("abcdefghijk");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_l() {
|
||||
// ['l', qw(-d '[:lower:]'), {IN=>'abcdefghijklmnopqrstuvwxyz'}, {OUT=>''}],
|
||||
new_ucmd!()
|
||||
.args(&["-d", "[:lower:]"])
|
||||
.pipe_in("abcdefghijklmnopqrstuvwxyz")
|
||||
.succeeds()
|
||||
.stdout_is("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_m() {
|
||||
// ['m', qw(-d '[:upper:]'), {IN=>'ABCDEFGHIJKLMNOPQRSTUVWXYZ'}, {OUT=>''}],
|
||||
new_ucmd!()
|
||||
.args(&["-d", "[:upper:]"])
|
||||
.pipe_in("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
.succeeds()
|
||||
.stdout_is("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_n() {
|
||||
// ['n', qw(-d '[:lower:][:upper:]'), {IN=>'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'}, {OUT=>''}],
|
||||
new_ucmd!()
|
||||
.args(&["-d", "[:lower:][:upper:]"])
|
||||
.pipe_in("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
.succeeds()
|
||||
.stdout_is("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_o() {
|
||||
// ['o', qw(-d '[:alpha:]'), {IN=>'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'}, {OUT=>''}],
|
||||
new_ucmd!()
|
||||
.args(&["-d", "[:alpha:]"])
|
||||
.pipe_in("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
.succeeds()
|
||||
.stdout_is("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_p() {
|
||||
// ['p', qw(-d '[:alnum:]'), {IN=>'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'}, {OUT=>''}],
|
||||
new_ucmd!()
|
||||
.args(&["-d", "[:alnum:]"])
|
||||
.pipe_in("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
|
||||
.succeeds()
|
||||
.stdout_is("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_q() {
|
||||
// ['q', qw(-d '[:alnum:]'), {IN=>'.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.'}, {OUT=>'..'}],
|
||||
new_ucmd!()
|
||||
.args(&["-d", "[:alnum:]"])
|
||||
.pipe_in(".abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.")
|
||||
.succeeds()
|
||||
.stdout_is("..");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_r() {
|
||||
// ['r', qw(-ds '[:alnum:]' .),
|
||||
// {IN=>'.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.'},
|
||||
// {OUT=>'.'}],
|
||||
new_ucmd!()
|
||||
.args(&["-ds", "[:alnum:]", "."])
|
||||
.pipe_in(".abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.")
|
||||
.succeeds()
|
||||
.stdout_is(".");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_s() {
|
||||
// # The classic example, with string2 BSD-style
|
||||
// ['s', qw(-cs '[:alnum:]' '\n'),
|
||||
// {IN=>'The big black fox jumped over the fence.'},
|
||||
// {OUT=>"The\nbig\nblack\nfox\njumped\nover\nthe\nfence\n"}],
|
||||
new_ucmd!()
|
||||
.args(&["-cs", "[:alnum:]", "\n"])
|
||||
.pipe_in("The big black fox jumped over the fence.")
|
||||
.succeeds()
|
||||
.stdout_is("The\nbig\nblack\nfox\njumped\nover\nthe\nfence\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_t() {
|
||||
// # The classic example, POSIX-style
|
||||
// ['t', qw(-cs '[:alnum:]' '[\n*]'),
|
||||
// {IN=>'The big black fox jumped over the fence.'},
|
||||
// {OUT=>"The\nbig\nblack\nfox\njumped\nover\nthe\nfence\n"}],
|
||||
new_ucmd!()
|
||||
.args(&["-cs", "[:alnum:]", "[\n*]"])
|
||||
.pipe_in("The big black fox jumped over the fence.")
|
||||
.succeeds()
|
||||
.stdout_is("The\nbig\nblack\nfox\njumped\nover\nthe\nfence\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_u() {
|
||||
// ['u', qw(-ds b a), {IN=>'aabbaa'}, {OUT=>'a'}],
|
||||
new_ucmd!()
|
||||
.args(&["-ds", "b", "a"])
|
||||
.pipe_in("aabbaa")
|
||||
.succeeds()
|
||||
.stdout_is("a");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_v() {
|
||||
// ['v', qw(-ds '[:xdigit:]' Z), {IN=>'ZZ0123456789acbdefABCDEFZZ'}, {OUT=>'Z'}],
|
||||
new_ucmd!()
|
||||
.args(&["-ds", "[:xdigit:]", "Z"])
|
||||
.pipe_in("ZZ0123456789acbdefABCDEFZZ")
|
||||
.succeeds()
|
||||
.stdout_is("Z");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_w() {
|
||||
// # Try some data with 8th bit set in case something is mistakenly
|
||||
// # sign-extended.
|
||||
// ['w', qw(-ds '\350' '\345'),
|
||||
// {IN=>"\300\301\377\345\345\350\345"},
|
||||
// {OUT=>"\300\301\377\345"}],
|
||||
new_ucmd!()
|
||||
.args(&["-ds", "\u{350}", "\u{345}"])
|
||||
.pipe_in("\u{300}\u{301}\u{377}\u{345}\u{345}\u{350}\u{345}")
|
||||
.succeeds()
|
||||
.stdout_is("\u{300}\u{301}\u{377}\u{345}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_x() {
|
||||
// ['x', qw(-s abcdefghijklmn '[:*016]'),
|
||||
// {IN=>'abcdefghijklmnop'}, {OUT=>':op'}],
|
||||
new_ucmd!()
|
||||
.args(&["-s", "abcdefghijklmn", "[:*016]"])
|
||||
.pipe_in("abcdefghijklmnop")
|
||||
.succeeds()
|
||||
.stdout_is(":op");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_y() {
|
||||
// ['y', qw(-d a-z), {IN=>'abc $code'}, {OUT=>' $'}],
|
||||
new_ucmd!()
|
||||
.args(&["-d", "a-z"])
|
||||
.pipe_in("abc $code")
|
||||
.succeeds()
|
||||
.stdout_is(" $");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_z() {
|
||||
// ['z', qw(-ds a-z '$.'), {IN=>'a.b.c $$$$code\\'}, {OUT=>'. $\\'}],
|
||||
new_ucmd!()
|
||||
.args(&["-ds", "a-z", "$."])
|
||||
.pipe_in("a.b.c $$$$code\\")
|
||||
.succeeds()
|
||||
.stdout_is(". $\\");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_range_a_a() {
|
||||
// # Make sure that a-a is accepted.
|
||||
// ['range-a-a', qw(a-a z), {IN=>'abc'}, {OUT=>'zbc'}],
|
||||
new_ucmd!()
|
||||
.args(&["a-a", "z"])
|
||||
.pipe_in("abc")
|
||||
.succeeds()
|
||||
.stdout_is("zbc");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_null() {
|
||||
// ['null', qw(a ''), {IN=>''}, {OUT=>''}, {EXIT=>1},
|
||||
// {ERR=>"$prog: when not truncating set1, string2 must be non-empty\n"}],
|
||||
new_ucmd!()
|
||||
.args(&["a", ""])
|
||||
.pipe_in("")
|
||||
.fails()
|
||||
.stderr_is("tr: when not truncating set1, string2 must be non-empty\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_upcase() {
|
||||
// ['upcase', qw('[:lower:]' '[:upper:]'),
|
||||
// {IN=>'abcxyzABCXYZ'},
|
||||
// {OUT=>'ABCXYZABCXYZ'}],
|
||||
new_ucmd!()
|
||||
.args(&["[:lower:]", "[:upper:]"])
|
||||
.pipe_in("abcxyzABCXYZ")
|
||||
.succeeds()
|
||||
.stdout_is("ABCXYZABCXYZ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_dncase() {
|
||||
// ['dncase', qw('[:upper:]' '[:lower:]'),
|
||||
// {IN=>'abcxyzABCXYZ'},
|
||||
// {OUT=>'abcxyzabcxyz'}],
|
||||
new_ucmd!()
|
||||
.args(&["[:upper:]", "[:lower:]"])
|
||||
.pipe_in("abcxyzABCXYZ")
|
||||
.succeeds()
|
||||
.stdout_is("abcxyzabcxyz");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_rep_cclass() {
|
||||
// ['rep-cclass', qw('a[=*2][=c=]' xyyz), {IN=>'a=c'}, {OUT=>'xyz'}],
|
||||
new_ucmd!()
|
||||
.args(&["a[=*2][=c=]", "xyyz"])
|
||||
.pipe_in("a=c")
|
||||
.succeeds()
|
||||
.stdout_is("xyz");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_rep_1() {
|
||||
// ['rep-1', qw('[:*3][:digit:]' a-m), {IN=>':1239'}, {OUT=>'cefgm'}],
|
||||
new_ucmd!()
|
||||
.args(&["[:*3][:digit:]", "a-m"])
|
||||
.pipe_in(":1239")
|
||||
.succeeds()
|
||||
.stdout_is("cefgm");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_rep_2() {
|
||||
// ['rep-2', qw('a[b*512]c' '1[x*]2'), {IN=>'abc'}, {OUT=>'1x2'}],
|
||||
new_ucmd!()
|
||||
.args(&["a[b*512]c", "1[x*]2"])
|
||||
.pipe_in("abc")
|
||||
.succeeds()
|
||||
.stdout_is("1x2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_rep_3() {
|
||||
// ['rep-3', qw('a[b*513]c' '1[x*]2'), {IN=>'abc'}, {OUT=>'1x2'}],
|
||||
new_ucmd!()
|
||||
.args(&["a[b*513]c", "1[x*]2"])
|
||||
.pipe_in("abc")
|
||||
.succeeds()
|
||||
.stdout_is("1x2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_o_rep_1() {
|
||||
// # Another couple octal repeat count tests.
|
||||
// ['o-rep-1', qw('[b*08]' '[x*]'), {IN=>''}, {OUT=>''}, {EXIT=>1},
|
||||
// {ERR=>"$prog: invalid repeat count '08' in [c*n] construct\n"}],
|
||||
new_ucmd!()
|
||||
.args(&["[b*08]", "[x*]"])
|
||||
.pipe_in("")
|
||||
.fails()
|
||||
.stderr_is("tr: invalid repeat count '08' in [c*n] construct\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_o_rep_2() {
|
||||
// ['o-rep-2', qw('[b*010]cd' '[a*7]BC[x*]'), {IN=>'bcd'}, {OUT=>'BCx'}],
|
||||
new_ucmd!()
|
||||
.args(&["[b*010]cd", "[a*7]BC[x*]"])
|
||||
.pipe_in("bcd")
|
||||
.succeeds()
|
||||
.stdout_is("BCx");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn octal_repeat_count_test() {
|
||||
//below will result in 8'x' and 4'y' as octal 010 = decimal 8
|
||||
new_ucmd!()
|
||||
.args(&["ABCdefghijkl", "[x*010]Y"])
|
||||
.pipe_in("ABCdefghijklmn12")
|
||||
.succeeds()
|
||||
.stdout_is("xxxxxxxxYYYYmn12");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_octal_repeat_count_test() {
|
||||
//below will result in 10'x' and 2'y' as the 10 does not have 0 prefix
|
||||
new_ucmd!()
|
||||
.args(&["ABCdefghijkl", "[x*10]Y"])
|
||||
.pipe_in("ABCdefghijklmn12")
|
||||
.succeeds()
|
||||
.stdout_is("xxxxxxxxxxYYmn12");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_esc() {
|
||||
// ['esc', qw('a\-z' A-Z), {IN=>'abc-z'}, {OUT=>'AbcBC'}],
|
||||
new_ucmd!()
|
||||
.args(&[r"a\-z", "A-Z"])
|
||||
.pipe_in("abc-z")
|
||||
.succeeds()
|
||||
.stdout_is("AbcBC");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_bs_055() {
|
||||
// ['bs-055', qw('a\055b' def), {IN=>"a\055b"}, {OUT=>'def'}],
|
||||
new_ucmd!()
|
||||
.args(&["a\u{055}b", "def"])
|
||||
.pipe_in("a\u{055}b")
|
||||
.succeeds()
|
||||
.stdout_is("def");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "Failing in Windows because it will not separate '\' and 'x' as separate arguments"]
|
||||
fn check_against_gnu_tr_tests_bs_at_end() {
|
||||
// ['bs-at-end', qw('\\' x), {IN=>"\\"}, {OUT=>'x'},
|
||||
// {ERR=>"$prog: warning: an unescaped backslash at end of "
|
||||
// . "string is not portable\n"}],
|
||||
new_ucmd!()
|
||||
.args(&[r"\", "x"])
|
||||
.pipe_in(r"\")
|
||||
.succeeds()
|
||||
.stdout_is("x")
|
||||
.stderr_is("tr: warning: an unescaped backslash at end of string is not portable");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "not sure why GNU bails here. `[Y*]` should be able to generate all the mapping"]
|
||||
fn check_against_gnu_tr_tests_ross_0a() {
|
||||
// # From Ross
|
||||
// ['ross-0a', qw(-cs '[:upper:]' 'X[Y*]'), {IN=>''}, {OUT=>''}, {EXIT=>1},
|
||||
// {ERR=>$map_all_to_1}],
|
||||
new_ucmd!()
|
||||
.args(&["-cs", "[:upper:]", "X[Y*]"])
|
||||
.pipe_in("")
|
||||
.fails()
|
||||
.stderr_is("tr: when translating with complemented character classes,\nstring2 must map all characters in the domain to one");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "not sure why GNU bails here. `[Y*]` should be able to generate all the mapping"]
|
||||
fn check_against_gnu_tr_tests_ross_0b() {
|
||||
// ['ross-0b', qw(-cs '[:cntrl:]' 'X[Y*]'), {IN=>''}, {OUT=>''}, {EXIT=>1},
|
||||
// {ERR=>$map_all_to_1}],
|
||||
new_ucmd!()
|
||||
.args(&["-cs", "[:cntrl:]", "X[Y*]"])
|
||||
.pipe_in("")
|
||||
.fails()
|
||||
.stderr_is("tr: when translating with complemented character classes,\nstring2 must map all characters in the domain to one");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_ross_1a() {
|
||||
// ['ross-1a', qw(-cs '[:upper:]' '[X*]'),
|
||||
// {IN=>'AMZamz123.-+AMZ'}, {OUT=>'AMZXAMZ'}],
|
||||
new_ucmd!()
|
||||
.args(&["-cs", "[:upper:]", "[X*]"])
|
||||
.pipe_in("AMZamz123.-+AMZ")
|
||||
.succeeds()
|
||||
.stdout_is("AMZXAMZ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_ross_1b() {
|
||||
// ['ross-1b', qw(-cs '[:upper:][:digit:]' '[Z*]'), {IN=>''}, {OUT=>''}],
|
||||
new_ucmd!()
|
||||
.args(&["-cs", "[:upper:][:digit:]", "[Z*]"])
|
||||
.pipe_in("")
|
||||
.succeeds()
|
||||
.stdout_is("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_ross_2() {
|
||||
// ['ross-2', qw(-dcs '[:lower:]' n-rs-z),
|
||||
// {IN=>'amzAMZ123.-+amz'}, {OUT=>'amzamz'}],
|
||||
new_ucmd!()
|
||||
.args(&["-dcs", "[:lower:]", "n-rs-z"])
|
||||
.pipe_in("amzAMZ123.-+amz")
|
||||
.succeeds()
|
||||
.stdout_is("amzamz");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_ross_3() {
|
||||
// ['ross-3', qw(-ds '[:xdigit:]' '[:alnum:]'),
|
||||
// {IN=>'.ZABCDEFGzabcdefg.0123456788899.GG'}, {OUT=>'.ZGzg..G'}],
|
||||
new_ucmd!()
|
||||
.args(&["-ds", "[:xdigit:]", "[:alnum:]"])
|
||||
.pipe_in(".ZABCDEFGzabcdefg.0123456788899.GG")
|
||||
.succeeds()
|
||||
.stdout_is(".ZGzg..G");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_ross_4() {
|
||||
// ['ross-4', qw(-dcs '[:alnum:]' '[:digit:]'), {IN=>''}, {OUT=>''}],
|
||||
new_ucmd!()
|
||||
.args(&["-dcs", "[:alnum:]", "[:digit:]"])
|
||||
.pipe_in("")
|
||||
.succeeds()
|
||||
.stdout_is("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_ross_5() {
|
||||
// ['ross-5', qw(-dc '[:lower:]'), {IN=>''}, {OUT=>''}],
|
||||
new_ucmd!()
|
||||
.args(&["-dc", "[:lower:]"])
|
||||
.pipe_in("")
|
||||
.succeeds()
|
||||
.stdout_is("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_ross_6() {
|
||||
// ['ross-6', qw(-dc '[:upper:]'), {IN=>''}, {OUT=>''}],
|
||||
new_ucmd!()
|
||||
.args(&["-dc", "[:upper:]"])
|
||||
.pipe_in("")
|
||||
.succeeds()
|
||||
.stdout_is("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_empty_eq() {
|
||||
// # Ensure that these fail.
|
||||
// # Prior to 2.0.20, each would evoke a failed assertion.
|
||||
// ['empty-eq', qw('[==]' x), {IN=>''}, {OUT=>''}, {EXIT=>1},
|
||||
// {ERR=>"$prog: missing equivalence class character '[==]'\n"}],
|
||||
new_ucmd!()
|
||||
.args(&["[==]", "x"])
|
||||
.pipe_in("")
|
||||
.fails()
|
||||
.stderr_is("tr: missing equivalence class character '[==]'\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_empty_cc() {
|
||||
// ['empty-cc', qw('[::]' x), {IN=>''}, {OUT=>''}, {EXIT=>1},
|
||||
// {ERR=>"$prog: missing character class name '[::]'\n"}],
|
||||
new_ucmd!()
|
||||
.args(&["[::]", "x"])
|
||||
.pipe_in("")
|
||||
.fails()
|
||||
.stderr_is("tr: missing character class name '[::]'\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_repeat_bs_9() {
|
||||
// # Weird repeat counts.
|
||||
// ['repeat-bs-9', qw(abc '[b*\9]'), {IN=>'abcd'}, {OUT=>'[b*d'}],
|
||||
new_ucmd!()
|
||||
.args(&["abc", r"[b*\9]"])
|
||||
.pipe_in("abcd")
|
||||
.succeeds()
|
||||
.stdout_is("[b*d");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_repeat_0() {
|
||||
// ['repeat-0', qw(abc '[b*0]'), {IN=>'abcd'}, {OUT=>'bbbd'}],
|
||||
new_ucmd!()
|
||||
.args(&["abc", "[b*0]"])
|
||||
.pipe_in("abcd")
|
||||
.succeeds()
|
||||
.stdout_is("bbbd");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_repeat_zeros() {
|
||||
// ['repeat-zeros', qw(abc '[b*00000000000000000000]'),
|
||||
// {IN=>'abcd'}, {OUT=>'bbbd'}],
|
||||
new_ucmd!()
|
||||
.args(&["abc", "[b*00000000000000000000]"])
|
||||
.pipe_in("abcd")
|
||||
.succeeds()
|
||||
.stdout_is("bbbd");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_repeat_compl() {
|
||||
// ['repeat-compl', qw(-c '[a*65536]\n' '[b*]'), {IN=>'abcd'}, {OUT=>'abbb'}],
|
||||
new_ucmd!()
|
||||
.args(&["-c", "[a*65536]\n", "[b*]"])
|
||||
.pipe_in("abcd")
|
||||
.succeeds()
|
||||
.stdout_is("abbb");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_repeat_x_c() {
|
||||
// ['repeat-xC', qw(-C '[a*65536]\n' '[b*]'), {IN=>'abcd'}, {OUT=>'abbb'}],
|
||||
new_ucmd!()
|
||||
.args(&["-C", "[a*65536]\n", "[b*]"])
|
||||
.pipe_in("abcd")
|
||||
.succeeds()
|
||||
.stdout_is("abbb");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "I think either clap-rs or uutils is parsing the '-H' as an argument..."]
|
||||
fn check_against_gnu_tr_tests_fowler_1() {
|
||||
// # From Glenn Fowler.
|
||||
// ['fowler-1', qw(ah -H), {IN=>'aha'}, {OUT=>'-H-'}],
|
||||
new_ucmd!()
|
||||
.args(&["ah", "-H"])
|
||||
.pipe_in("aha")
|
||||
.succeeds()
|
||||
.stdout_is("-H-");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_against_gnu_tr_tests_no_abort_1() {
|
||||
// # Up to coreutils-6.9, this would provoke a failed assertion.
|
||||
// ['no-abort-1', qw(-c a '[b*256]'), {IN=>'abc'}, {OUT=>'abb'}],
|
||||
new_ucmd!()
|
||||
.args(&["-c", "a", "[b*256]"])
|
||||
.pipe_in("abc")
|
||||
.succeeds()
|
||||
.stdout_is("abb");
|
||||
}
|
||||
|
|
|
@ -1,6 +1,53 @@
|
|||
use crate::common::util::*;
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
|
||||
use std::fs::OpenOptions;
|
||||
|
||||
#[test]
|
||||
fn test_exit_code() {
|
||||
new_ucmd!().succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_version() {
|
||||
new_ucmd!()
|
||||
.args(&["--version"])
|
||||
.succeeds()
|
||||
.stdout_contains("true");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_help() {
|
||||
new_ucmd!()
|
||||
.args(&["--help"])
|
||||
.succeeds()
|
||||
.stdout_contains("true");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_short_options() {
|
||||
for option in ["-h", "-V"] {
|
||||
new_ucmd!().arg(option).succeeds().stdout_is("");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conflict() {
|
||||
new_ucmd!()
|
||||
.args(&["--help", "--version"])
|
||||
.succeeds()
|
||||
.stdout_is("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
|
||||
fn test_full() {
|
||||
for option in ["--version", "--help"] {
|
||||
let dev_full = OpenOptions::new().write(true).open("/dev/full").unwrap();
|
||||
|
||||
new_ucmd!()
|
||||
.arg(option)
|
||||
.set_stdout(dev_full)
|
||||
.fails()
|
||||
.stderr_contains("No space left on device");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -250,11 +250,24 @@ 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:
|
||||
new_ucmd!()
|
||||
.args(&["file"])
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stderr_contains(
|
||||
"error: The following required arguments were not provided:
|
||||
--reference <RFILE>
|
||||
--size <SIZE>",
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_option() {
|
||||
// truncate: cli parsing error returns 1
|
||||
new_ucmd!()
|
||||
.args(&["--this-arg-does-not-exist"])
|
||||
.fails()
|
||||
.code_is(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -306,18 +319,116 @@ fn test_truncate_bytes_size() {
|
|||
.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
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Test that truncating a non-existent file creates that file.
|
||||
#[test]
|
||||
fn test_new_file() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let filename = "new_file_that_does_not_exist_yet";
|
||||
ucmd.args(&["-s", "8", filename])
|
||||
.succeeds()
|
||||
.no_stdout()
|
||||
.no_stderr();
|
||||
assert!(at.file_exists(filename));
|
||||
assert_eq!(at.read_bytes(filename), vec![b'\0'; 8]);
|
||||
}
|
||||
|
||||
/// Test for not creating a non-existent file.
|
||||
#[test]
|
||||
fn test_new_file_no_create() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let filename = "new_file_that_does_not_exist_yet";
|
||||
ucmd.args(&["-s", "8", "-c", filename])
|
||||
.succeeds()
|
||||
.no_stdout()
|
||||
.no_stderr();
|
||||
assert!(!at.file_exists(filename));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_division_by_zero_size_only() {
|
||||
new_ucmd!()
|
||||
.args(&["-s", "/0", "file"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("division by zero");
|
||||
new_ucmd!()
|
||||
.args(&["-s", "%0", "file"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("division by zero");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_division_by_zero_reference_and_size() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.make_file(FILE1);
|
||||
ucmd.args(&["-r", FILE1, "-s", "/0", "file"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("division by zero");
|
||||
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.make_file(FILE1);
|
||||
ucmd.args(&["-r", FILE1, "-s", "%0", "file"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("division by zero");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_no_such_dir() {
|
||||
new_ucmd!()
|
||||
.args(&["-s", "0", "a/b"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("cannot open 'a/b' for writing: No such file or directory");
|
||||
}
|
||||
|
||||
/// Test that truncate with a relative size less than 0 is not an error.
|
||||
#[test]
|
||||
fn test_underflow_relative_size() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["-s-1", FILE1])
|
||||
.succeeds()
|
||||
.no_stdout()
|
||||
.no_stderr();
|
||||
assert!(at.file_exists(FILE1));
|
||||
assert!(at.read_bytes(FILE1).is_empty());
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
#[test]
|
||||
fn test_fifo_error_size_only() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.mkfifo("fifo");
|
||||
ucmd.args(&["-s", "0", "fifo"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("cannot open 'fifo' for writing: No such device or address");
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
#[test]
|
||||
fn test_fifo_error_reference_file_only() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.mkfifo("fifo");
|
||||
at.make_file("reference_file");
|
||||
ucmd.args(&["-r", "reference_file", "fifo"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("cannot open 'fifo' for writing: No such device or address");
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
#[test]
|
||||
fn test_fifo_error_reference_and_size() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.mkfifo("fifo");
|
||||
at.make_file("reference_file");
|
||||
ucmd.args(&["-r", "reference_file", "-s", "+0", "fifo"])
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("cannot open 'fifo' for writing: No such device or address");
|
||||
}
|
||||
|
|
|
@ -64,6 +64,11 @@ fn test_wrong_argument() {
|
|||
new_ucmd!().args(&["a"]).fails().code_is(2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_help() {
|
||||
new_ucmd!().args(&["--help"]).succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
// FixME: freebsd panic
|
||||
#[cfg(all(unix, not(target_os = "freebsd")))]
|
||||
|
|
|
@ -7,6 +7,7 @@ fn test_users_no_arg() {
|
|||
|
||||
#[test]
|
||||
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
|
||||
#[ignore = "issue #3219"]
|
||||
fn test_users_check_name() {
|
||||
#[cfg(target_os = "linux")]
|
||||
let util_name = util_name!();
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#[cfg(all(unix, not(target_os = "macos")))]
|
||||
use pretty_assertions::assert_ne;
|
||||
|
||||
use crate::common::util::*;
|
||||
|
||||
// spell-checker:ignore (flags) lwmcL clmwL ; (path) bogusfile emptyfile manyemptylines moby notrailingnewline onelongemptyline onelongword weirdchars
|
||||
|
@ -178,7 +181,8 @@ fn test_file_one_long_word() {
|
|||
.stdout_is(" 1 1 10001 10001 10000 onelongword.txt\n");
|
||||
}
|
||||
|
||||
/// Test that the number of bytes in the file dictate the display width.
|
||||
/// Test that the total size of all the files in the input dictates
|
||||
/// the display width.
|
||||
///
|
||||
/// The width in digits of any count is the width in digits of the
|
||||
/// number of bytes in the file, regardless of whether the number of
|
||||
|
@ -200,6 +204,27 @@ fn test_file_bytes_dictate_width() {
|
|||
.args(&["-lw", "emptyfile.txt"])
|
||||
.run()
|
||||
.stdout_is("0 0 emptyfile.txt\n");
|
||||
|
||||
// lorem_ipsum.txt contains 772 bytes, and alice_in_wonderland.txt contains
|
||||
// 302 bytes. The total is 1074 bytes, which has a width of 4
|
||||
new_ucmd!()
|
||||
.args(&["-lwc", "alice_in_wonderland.txt", "lorem_ipsum.txt"])
|
||||
.run()
|
||||
.stdout_is(
|
||||
" 5 57 302 alice_in_wonderland.txt\n 13 109 772 \
|
||||
lorem_ipsum.txt\n 18 166 1074 total\n",
|
||||
);
|
||||
|
||||
// . is a directory, so minimum_width should get set to 7
|
||||
#[cfg(not(windows))]
|
||||
const STDOUT: &str = " 0 0 0 emptyfile.txt\n 0 0 0 \
|
||||
.\n 0 0 0 total\n";
|
||||
#[cfg(windows)]
|
||||
const STDOUT: &str = " 0 0 0 emptyfile.txt\n 0 0 0 total\n";
|
||||
new_ucmd!()
|
||||
.args(&["-lwc", "emptyfile.txt", "."])
|
||||
.run()
|
||||
.stdout_is(STDOUT);
|
||||
}
|
||||
|
||||
/// Test that getting counts from a directory is an error.
|
||||
|
@ -235,3 +260,64 @@ fn test_read_from_nonexistent_file() {
|
|||
.stderr_contains(MSG)
|
||||
.stdout_is("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(unix, not(target_os = "macos")))]
|
||||
fn test_files_from_pseudo_filesystem() {
|
||||
let result = new_ucmd!().arg("-c").arg("/proc/version").succeeds();
|
||||
assert_ne!(result.stdout_str(), "0 /proc/version\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_files0_disabled_files_argument() {
|
||||
const MSG: &str = "file operands cannot be combined with --files0-from";
|
||||
new_ucmd!()
|
||||
.args(&["--files0-from=files0_list.txt"])
|
||||
.arg("lorem_ipsum.txt")
|
||||
.fails()
|
||||
.stderr_contains(MSG)
|
||||
.stdout_is("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_files0_from() {
|
||||
new_ucmd!()
|
||||
.args(&["--files0-from=files0_list.txt"])
|
||||
.run()
|
||||
.stdout_is(
|
||||
" 13 109 772 lorem_ipsum.txt\n 18 204 1115 moby_dick.txt\n 5 57 302 \
|
||||
alice_in_wonderland.txt\n 36 370 2189 total\n",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_files0_from_with_stdin() {
|
||||
new_ucmd!()
|
||||
.args(&["--files0-from=-"])
|
||||
.pipe_in("lorem_ipsum.txt")
|
||||
.run()
|
||||
.stdout_is(" 13 109 772 lorem_ipsum.txt\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_files0_from_with_stdin_in_file() {
|
||||
new_ucmd!()
|
||||
.args(&["--files0-from=files0_list_with_stdin.txt"])
|
||||
.pipe_in_fixture("alice_in_wonderland.txt")
|
||||
.run()
|
||||
.stdout_is(
|
||||
" 13 109 772 lorem_ipsum.txt\n 18 204 1115 moby_dick.txt\n 5 57 302 \
|
||||
-\n 36 370 2189 total\n",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_files0_from_with_stdin_try_read_from_stdin() {
|
||||
const MSG: &str = "when reading file names from stdin, no file name of '-' allowed";
|
||||
new_ucmd!()
|
||||
.args(&["--files0-from=-"])
|
||||
.pipe_in("-")
|
||||
.fails()
|
||||
.stderr_contains(MSG)
|
||||
.stdout_is("");
|
||||
}
|
||||
|
|
|
@ -9,9 +9,10 @@ use crate::common::util::*;
|
|||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
#[ignore = "issue #3219"]
|
||||
fn test_count() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
for opt in &["-q", "--count"] {
|
||||
for opt in &["-q", "--count", "--c"] {
|
||||
let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str();
|
||||
ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout);
|
||||
}
|
||||
|
@ -21,7 +22,7 @@ fn test_count() {
|
|||
#[test]
|
||||
fn test_boot() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
for opt in &["-b", "--boot"] {
|
||||
for opt in &["-b", "--boot", "--b"] {
|
||||
let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str();
|
||||
ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout);
|
||||
}
|
||||
|
@ -29,9 +30,10 @@ fn test_boot() {
|
|||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
#[ignore = "issue #3219"]
|
||||
fn test_heading() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
for opt in &["-H", "--heading"] {
|
||||
for opt in &["-H", "--heading", "--head"] {
|
||||
// allow whitespace variation
|
||||
// * minor whitespace differences occur between platform built-in outputs;
|
||||
// specifically number of TABs between "TIME" and "COMMENT" may be variant
|
||||
|
@ -47,9 +49,10 @@ fn test_heading() {
|
|||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
#[ignore = "issue #3219"]
|
||||
fn test_short() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
for opt in &["-s", "--short"] {
|
||||
for opt in &["-s", "--short", "--s"] {
|
||||
let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str();
|
||||
ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout);
|
||||
}
|
||||
|
@ -59,7 +62,7 @@ fn test_short() {
|
|||
#[test]
|
||||
fn test_login() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
for opt in &["-l", "--login"] {
|
||||
for opt in &["-l", "--login", "--log"] {
|
||||
let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str();
|
||||
ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout);
|
||||
}
|
||||
|
@ -69,17 +72,15 @@ fn test_login() {
|
|||
#[test]
|
||||
fn test_m() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
for opt in &["-m"] {
|
||||
let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str();
|
||||
ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout);
|
||||
}
|
||||
let expected_stdout = unwrap_or_return!(expected_result(&ts, &["-m"])).stdout_move_str();
|
||||
ts.ucmd().arg("-m").succeeds().stdout_is(expected_stdout);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn test_process() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
for opt in &["-p", "--process"] {
|
||||
for opt in &["-p", "--process", "--p"] {
|
||||
let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str();
|
||||
ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout);
|
||||
}
|
||||
|
@ -89,7 +90,7 @@ fn test_process() {
|
|||
#[test]
|
||||
fn test_runlevel() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
for opt in &["-r", "--runlevel"] {
|
||||
for opt in &["-r", "--runlevel", "--r"] {
|
||||
let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str();
|
||||
ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout);
|
||||
|
||||
|
@ -102,7 +103,7 @@ fn test_runlevel() {
|
|||
#[test]
|
||||
fn test_time() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
for opt in &["-t", "--time"] {
|
||||
for opt in &["-t", "--time", "--t"] {
|
||||
let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str();
|
||||
ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout);
|
||||
}
|
||||
|
@ -110,6 +111,7 @@ fn test_time() {
|
|||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
#[ignore = "issue #3219"]
|
||||
fn test_mesg() {
|
||||
// -T, -w, --mesg
|
||||
// add user's message status as +, - or ?
|
||||
|
@ -118,7 +120,15 @@ fn test_mesg() {
|
|||
// --writable
|
||||
// same as -T
|
||||
let ts = TestScenario::new(util_name!());
|
||||
for opt in &["-T", "-w", "--mesg", "--message", "--writable"] {
|
||||
for opt in &[
|
||||
"-T",
|
||||
"-w",
|
||||
"--mesg",
|
||||
"--m",
|
||||
"--message",
|
||||
"--writable",
|
||||
"--w",
|
||||
] {
|
||||
let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str();
|
||||
ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout);
|
||||
}
|
||||
|
@ -136,7 +146,7 @@ fn test_arg1_arg2() {
|
|||
#[test]
|
||||
fn test_too_many_args() {
|
||||
const EXPECTED: &str =
|
||||
"error: The value 'u' was provided to '<FILE>...', but it wasn't expecting any more values";
|
||||
"error: The value 'u' was provided to '<FILE>...' but it wasn't expecting any more values";
|
||||
|
||||
let args = ["am", "i", "u"];
|
||||
new_ucmd!().args(&args).fails().stderr_contains(EXPECTED);
|
||||
|
@ -144,9 +154,10 @@ fn test_too_many_args() {
|
|||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
#[ignore = "issue #3219"]
|
||||
fn test_users() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
for opt in &["-u", "--users"] {
|
||||
for opt in &["-u", "--users", "--us"] {
|
||||
let actual = ts.ucmd().arg(opt).succeeds().stdout_move_str();
|
||||
let expect = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str();
|
||||
println!("actual: {:?}", actual);
|
||||
|
@ -169,6 +180,7 @@ fn test_users() {
|
|||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
#[ignore = "issue #3219"]
|
||||
fn test_lookup() {
|
||||
let opt = "--lookup";
|
||||
let ts = TestScenario::new(util_name!());
|
||||
|
@ -180,7 +192,7 @@ fn test_lookup() {
|
|||
#[test]
|
||||
fn test_dead() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
for opt in &["-d", "--dead"] {
|
||||
for opt in &["-d", "--dead", "--de"] {
|
||||
let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str();
|
||||
ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout);
|
||||
}
|
||||
|
@ -188,6 +200,7 @@ fn test_dead() {
|
|||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
#[ignore = "issue #3219"]
|
||||
fn test_all_separately() {
|
||||
if cfg!(target_os = "macos") {
|
||||
// TODO: fix `-u`, see: test_users
|
||||
|
@ -205,6 +218,7 @@ fn test_all_separately() {
|
|||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
#[ignore = "issue #3219"]
|
||||
fn test_all() {
|
||||
if cfg!(target_os = "macos") {
|
||||
// TODO: fix `-u`, see: test_users
|
||||
|
@ -212,7 +226,7 @@ fn test_all() {
|
|||
}
|
||||
|
||||
let ts = TestScenario::new(util_name!());
|
||||
for opt in &["-a", "--all"] {
|
||||
for opt in &["-a", "--all", "--a"] {
|
||||
let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str();
|
||||
ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout);
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ fn test_long_input() {
|
|||
// try something long.
|
||||
#[cfg(windows)]
|
||||
const TIMES: usize = 500;
|
||||
let arg = "abcdefg".repeat(TIMES) + "\n";
|
||||
let arg = "abcdef".repeat(TIMES) + "\n";
|
||||
let expected_out = arg.repeat(30);
|
||||
run(&[&arg[..arg.len() - 1]], expected_out.as_bytes());
|
||||
}
|
||||
|
|
|
@ -62,6 +62,10 @@ fn read_scenario_fixture<S: AsRef<OsStr>>(tmpd: &Option<Rc<TempDir>>, file_rel_p
|
|||
/// within a struct which has convenience assertion functions about those outputs
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CmdResult {
|
||||
/// bin_path provided by `TestScenario` or `UCommand`
|
||||
bin_path: String,
|
||||
/// util_name provided by `TestScenario` or `UCommand`
|
||||
util_name: Option<String>,
|
||||
//tmpd is used for convenience functions for asserts against fixtures
|
||||
tmpd: Option<Rc<TempDir>>,
|
||||
/// exit status for command (if there is one)
|
||||
|
@ -77,13 +81,17 @@ pub struct CmdResult {
|
|||
|
||||
impl CmdResult {
|
||||
pub fn new(
|
||||
bin_path: String,
|
||||
util_name: Option<String>,
|
||||
tmpd: Option<Rc<TempDir>>,
|
||||
code: Option<i32>,
|
||||
success: bool,
|
||||
stdout: &[u8],
|
||||
stderr: &[u8],
|
||||
) -> CmdResult {
|
||||
CmdResult {
|
||||
) -> Self {
|
||||
Self {
|
||||
bin_path,
|
||||
util_name,
|
||||
tmpd,
|
||||
code,
|
||||
success,
|
||||
|
@ -142,7 +150,7 @@ impl CmdResult {
|
|||
self.code.expect("Program must be run first")
|
||||
}
|
||||
|
||||
pub fn code_is(&self, expected_code: i32) -> &CmdResult {
|
||||
pub fn code_is(&self, expected_code: i32) -> &Self {
|
||||
assert_eq!(self.code(), expected_code);
|
||||
self
|
||||
}
|
||||
|
@ -162,7 +170,7 @@ impl CmdResult {
|
|||
}
|
||||
|
||||
/// asserts that the command resulted in a success (zero) status code
|
||||
pub fn success(&self) -> &CmdResult {
|
||||
pub fn success(&self) -> &Self {
|
||||
assert!(
|
||||
self.success,
|
||||
"Command was expected to succeed.\nstdout = {}\n stderr = {}",
|
||||
|
@ -173,7 +181,7 @@ impl CmdResult {
|
|||
}
|
||||
|
||||
/// asserts that the command resulted in a failure (non-zero) status code
|
||||
pub fn failure(&self) -> &CmdResult {
|
||||
pub fn failure(&self) -> &Self {
|
||||
assert!(
|
||||
!self.success,
|
||||
"Command was expected to fail.\nstdout = {}\n stderr = {}",
|
||||
|
@ -184,7 +192,7 @@ impl CmdResult {
|
|||
}
|
||||
|
||||
/// asserts that the command's exit code is the same as the given one
|
||||
pub fn status_code(&self, code: i32) -> &CmdResult {
|
||||
pub fn status_code(&self, code: i32) -> &Self {
|
||||
assert_eq!(self.code, Some(code));
|
||||
self
|
||||
}
|
||||
|
@ -194,7 +202,7 @@ impl CmdResult {
|
|||
/// but you might find yourself using this function if
|
||||
/// 1. you can not know exactly what stdout will be or
|
||||
/// 2. you know that stdout will also be empty
|
||||
pub fn no_stderr(&self) -> &CmdResult {
|
||||
pub fn no_stderr(&self) -> &Self {
|
||||
assert!(
|
||||
self.stderr.is_empty(),
|
||||
"Expected stderr to be empty, but it's:\n{}",
|
||||
|
@ -209,7 +217,7 @@ impl CmdResult {
|
|||
/// but you might find yourself using this function if
|
||||
/// 1. you can not know exactly what stderr will be or
|
||||
/// 2. you know that stderr will also be empty
|
||||
pub fn no_stdout(&self) -> &CmdResult {
|
||||
pub fn no_stdout(&self) -> &Self {
|
||||
assert!(
|
||||
self.stdout.is_empty(),
|
||||
"Expected stdout to be empty, but it's:\n{}",
|
||||
|
@ -221,25 +229,25 @@ impl CmdResult {
|
|||
/// asserts that the command resulted in stdout stream output that equals the
|
||||
/// passed in value, trailing whitespace are kept to force strict comparison (#1235)
|
||||
/// stdout_only is a better choice unless stderr may or will be non-empty
|
||||
pub fn stdout_is<T: AsRef<str>>(&self, msg: T) -> &CmdResult {
|
||||
pub fn stdout_is<T: AsRef<str>>(&self, msg: T) -> &Self {
|
||||
assert_eq!(self.stdout_str(), String::from(msg.as_ref()));
|
||||
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 {
|
||||
pub fn stdout_is_any<T: AsRef<str> + std::fmt::Debug>(&self, expected: &[T]) -> &Self {
|
||||
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 {
|
||||
pub fn normalized_newlines_stdout_is<T: AsRef<str>>(&self, msg: T) -> &Self {
|
||||
let msg = msg.as_ref().replace("\r\n", "\n");
|
||||
assert_eq!(self.stdout_str().replace("\r\n", "\n"), msg);
|
||||
self
|
||||
|
@ -247,23 +255,45 @@ impl CmdResult {
|
|||
|
||||
/// asserts that the command resulted in stdout stream output,
|
||||
/// whose bytes equal those of the passed in slice
|
||||
pub fn stdout_is_bytes<T: AsRef<[u8]>>(&self, msg: T) -> &CmdResult {
|
||||
pub fn stdout_is_bytes<T: AsRef<[u8]>>(&self, msg: T) -> &Self {
|
||||
assert_eq!(self.stdout, msg.as_ref());
|
||||
self
|
||||
}
|
||||
|
||||
/// like stdout_is(...), but expects the contents of the file at the provided relative path
|
||||
pub fn stdout_is_fixture<T: AsRef<OsStr>>(&self, file_rel_path: T) -> &CmdResult {
|
||||
pub fn stdout_is_fixture<T: AsRef<OsStr>>(&self, file_rel_path: T) -> &Self {
|
||||
let contents = read_scenario_fixture(&self.tmpd, file_rel_path);
|
||||
self.stdout_is(String::from_utf8(contents).unwrap())
|
||||
}
|
||||
|
||||
/// Assert that the bytes of stdout exactly match those of the given file.
|
||||
///
|
||||
/// Contrast this with [`CmdResult::stdout_is_fixture`], which
|
||||
/// decodes the contents of the file as a UTF-8 [`String`] before
|
||||
/// comparison with stdout.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Use this method in a unit test like this:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// #[test]
|
||||
/// fn test_something() {
|
||||
/// new_ucmd!().succeeds().stdout_is_fixture_bytes("expected.bin");
|
||||
/// }
|
||||
/// ```
|
||||
pub fn stdout_is_fixture_bytes<T: AsRef<OsStr>>(&self, file_rel_path: T) -> &Self {
|
||||
let contents = read_scenario_fixture(&self.tmpd, file_rel_path);
|
||||
self.stdout_is_bytes(contents)
|
||||
}
|
||||
|
||||
/// like stdout_is_fixture(...), but replaces the data in fixture file based on values provided in template_vars
|
||||
/// command output
|
||||
pub fn stdout_is_templated_fixture<T: AsRef<OsStr>>(
|
||||
&self,
|
||||
file_rel_path: T,
|
||||
template_vars: &[(&str, &str)],
|
||||
) -> &CmdResult {
|
||||
) -> &Self {
|
||||
let mut contents =
|
||||
String::from_utf8(read_scenario_fixture(&self.tmpd, file_rel_path)).unwrap();
|
||||
for kv in template_vars {
|
||||
|
@ -286,13 +316,13 @@ impl CmdResult {
|
|||
}
|
||||
contents
|
||||
});
|
||||
self.stdout_is_any(possible_values.collect());
|
||||
self.stdout_is_any(&possible_values.collect::<Vec<_>>());
|
||||
}
|
||||
|
||||
/// 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
|
||||
pub fn stderr_is<T: AsRef<str>>(&self, msg: T) -> &CmdResult {
|
||||
pub fn stderr_is<T: AsRef<str>>(&self, msg: T) -> &Self {
|
||||
assert_eq!(
|
||||
self.stderr_str().trim_end(),
|
||||
String::from(msg.as_ref()).trim_end()
|
||||
|
@ -302,13 +332,13 @@ impl CmdResult {
|
|||
|
||||
/// asserts that the command resulted in stderr stream output,
|
||||
/// whose bytes equal those of the passed in slice
|
||||
pub fn stderr_is_bytes<T: AsRef<[u8]>>(&self, msg: T) -> &CmdResult {
|
||||
pub fn stderr_is_bytes<T: AsRef<[u8]>>(&self, msg: T) -> &Self {
|
||||
assert_eq!(self.stderr, msg.as_ref());
|
||||
self
|
||||
}
|
||||
|
||||
/// Like stdout_is_fixture, but for stderr
|
||||
pub fn stderr_is_fixture<T: AsRef<OsStr>>(&self, file_rel_path: T) -> &CmdResult {
|
||||
pub fn stderr_is_fixture<T: AsRef<OsStr>>(&self, file_rel_path: T) -> &Self {
|
||||
let contents = read_scenario_fixture(&self.tmpd, file_rel_path);
|
||||
self.stderr_is(String::from_utf8(contents).unwrap())
|
||||
}
|
||||
|
@ -317,7 +347,7 @@ impl CmdResult {
|
|||
/// 1. the command resulted in stdout stream output that equals the
|
||||
/// passed in value
|
||||
/// 2. the command resulted in empty (zero-length) stderr stream output
|
||||
pub fn stdout_only<T: AsRef<str>>(&self, msg: T) -> &CmdResult {
|
||||
pub fn stdout_only<T: AsRef<str>>(&self, msg: T) -> &Self {
|
||||
self.no_stderr().stdout_is(msg)
|
||||
}
|
||||
|
||||
|
@ -325,12 +355,12 @@ impl CmdResult {
|
|||
/// 1. the command resulted in a stdout stream whose bytes
|
||||
/// equal those of the passed in value
|
||||
/// 2. the command resulted in an empty stderr stream
|
||||
pub fn stdout_only_bytes<T: AsRef<[u8]>>(&self, msg: T) -> &CmdResult {
|
||||
pub fn stdout_only_bytes<T: AsRef<[u8]>>(&self, msg: T) -> &Self {
|
||||
self.no_stderr().stdout_is_bytes(msg)
|
||||
}
|
||||
|
||||
/// like stdout_only(...), but expects the contents of the file at the provided relative path
|
||||
pub fn stdout_only_fixture<T: AsRef<OsStr>>(&self, file_rel_path: T) -> &CmdResult {
|
||||
pub fn stdout_only_fixture<T: AsRef<OsStr>>(&self, file_rel_path: T) -> &Self {
|
||||
let contents = read_scenario_fixture(&self.tmpd, file_rel_path);
|
||||
self.stdout_only_bytes(contents)
|
||||
}
|
||||
|
@ -339,7 +369,7 @@ impl CmdResult {
|
|||
/// 1. the command resulted in stderr stream output that equals the
|
||||
/// passed in value, when both are trimmed of trailing whitespace
|
||||
/// 2. the command resulted in empty (zero-length) stdout stream output
|
||||
pub fn stderr_only<T: AsRef<str>>(&self, msg: T) -> &CmdResult {
|
||||
pub fn stderr_only<T: AsRef<str>>(&self, msg: T) -> &Self {
|
||||
self.no_stdout().stderr_is(msg)
|
||||
}
|
||||
|
||||
|
@ -347,17 +377,34 @@ impl CmdResult {
|
|||
/// 1. the command resulted in a stderr stream whose bytes equal the ones
|
||||
/// of the passed value
|
||||
/// 2. the command resulted in an empty stdout stream
|
||||
pub fn stderr_only_bytes<T: AsRef<[u8]>>(&self, msg: T) -> &CmdResult {
|
||||
self.no_stderr().stderr_is_bytes(msg)
|
||||
pub fn stderr_only_bytes<T: AsRef<[u8]>>(&self, msg: T) -> &Self {
|
||||
self.no_stdout().stderr_is_bytes(msg)
|
||||
}
|
||||
|
||||
pub fn fails_silently(&self) -> &CmdResult {
|
||||
pub fn fails_silently(&self) -> &Self {
|
||||
assert!(!self.success);
|
||||
assert!(self.stderr.is_empty());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn stdout_contains<T: AsRef<str>>(&self, cmp: T) -> &CmdResult {
|
||||
/// asserts that
|
||||
/// 1. the command resulted in stderr stream output that equals the
|
||||
/// the following format when both are trimmed of trailing whitespace
|
||||
/// `"{util_name}: {msg}\nTry '{bin_path} {util_name} --help' for more information."`
|
||||
/// This the expected format when a UUsageError is returned or when show_error! is called
|
||||
/// `msg` should be the same as the one provided to UUsageError::new or show_error!
|
||||
///
|
||||
/// 2. the command resulted in empty (zero-length) stdout stream output
|
||||
pub fn usage_error<T: AsRef<str>>(&self, msg: T) -> &Self {
|
||||
self.stderr_only(format!(
|
||||
"{0}: {2}\nTry '{1} {0} --help' for more information.",
|
||||
self.util_name.as_ref().unwrap(), // This shouldn't be called using a normal command
|
||||
self.bin_path,
|
||||
msg.as_ref()
|
||||
))
|
||||
}
|
||||
|
||||
pub fn stdout_contains<T: AsRef<str>>(&self, cmp: T) -> &Self {
|
||||
assert!(
|
||||
self.stdout_str().contains(cmp.as_ref()),
|
||||
"'{}' does not contain '{}'",
|
||||
|
@ -367,7 +414,7 @@ impl CmdResult {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn stderr_contains<T: AsRef<str>>(&self, cmp: T) -> &CmdResult {
|
||||
pub fn stderr_contains<T: AsRef<str>>(&self, cmp: T) -> &Self {
|
||||
assert!(
|
||||
self.stderr_str().contains(cmp.as_ref()),
|
||||
"'{}' does not contain '{}'",
|
||||
|
@ -377,7 +424,7 @@ impl CmdResult {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn stdout_does_not_contain<T: AsRef<str>>(&self, cmp: T) -> &CmdResult {
|
||||
pub fn stdout_does_not_contain<T: AsRef<str>>(&self, cmp: T) -> &Self {
|
||||
assert!(
|
||||
!self.stdout_str().contains(cmp.as_ref()),
|
||||
"'{}' contains '{}' but should not",
|
||||
|
@ -387,21 +434,21 @@ impl CmdResult {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn stderr_does_not_contain<T: AsRef<str>>(&self, cmp: T) -> &CmdResult {
|
||||
pub fn stderr_does_not_contain<T: AsRef<str>>(&self, cmp: T) -> &Self {
|
||||
assert!(!self.stderr_str().contains(cmp.as_ref()));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn stdout_matches(&self, regex: ®ex::Regex) -> &CmdResult {
|
||||
pub fn stdout_matches(&self, regex: ®ex::Regex) -> &Self {
|
||||
if !regex.is_match(self.stdout_str().trim()) {
|
||||
panic!("Stdout does not match regex:\n{}", self.stdout_str())
|
||||
panic!("Stdout does not match regex:\n{}", self.stdout_str());
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn stdout_does_not_match(&self, regex: ®ex::Regex) -> &CmdResult {
|
||||
pub fn stdout_does_not_match(&self, regex: ®ex::Regex) -> &Self {
|
||||
if regex.is_match(self.stdout_str().trim()) {
|
||||
panic!("Stdout matches regex:\n{}", self.stdout_str())
|
||||
panic!("Stdout matches regex:\n{}", self.stdout_str());
|
||||
}
|
||||
self
|
||||
}
|
||||
|
@ -444,8 +491,8 @@ pub struct AtPath {
|
|||
}
|
||||
|
||||
impl AtPath {
|
||||
pub fn new(subdir: &Path) -> AtPath {
|
||||
AtPath {
|
||||
pub fn new(subdir: &Path) -> Self {
|
||||
Self {
|
||||
subdir: PathBuf::from(subdir),
|
||||
}
|
||||
}
|
||||
|
@ -654,6 +701,11 @@ impl AtPath {
|
|||
symlink_file(&self.plus(original), &self.plus(link)).unwrap();
|
||||
}
|
||||
|
||||
pub fn relative_symlink_file(&self, original: &str, link: &str) {
|
||||
log_info("symlink", &format!("{},{}", original, link));
|
||||
symlink_file(original, link).unwrap();
|
||||
}
|
||||
|
||||
pub fn symlink_dir(&self, original: &str, link: &str) {
|
||||
log_info(
|
||||
"symlink",
|
||||
|
@ -728,20 +780,12 @@ 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()..])
|
||||
|
||||
if let Some(stripped) = s.strip_prefix(prefix) {
|
||||
String::from(stripped)
|
||||
} else {
|
||||
s
|
||||
}
|
||||
// ... with ...
|
||||
// if let Some(stripped) = s.strip_prefix(prefix) {
|
||||
// String::from(stripped)
|
||||
// } else {
|
||||
// s
|
||||
// }
|
||||
// ... when using MSRV with stabilized `strip_prefix()`
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -759,9 +803,9 @@ pub struct TestScenario {
|
|||
}
|
||||
|
||||
impl TestScenario {
|
||||
pub fn new(util_name: &str) -> TestScenario {
|
||||
pub fn new(util_name: &str) -> Self {
|
||||
let tmpd = Rc::new(TempDir::new().unwrap());
|
||||
let ts = TestScenario {
|
||||
let ts = Self {
|
||||
bin_path: {
|
||||
// Instead of hard coding the path relative to the current
|
||||
// directory, use Cargo's OUT_DIR to find path to executable.
|
||||
|
@ -788,31 +832,36 @@ impl TestScenario {
|
|||
/// Returns builder for invoking the target uutils binary. Paths given are
|
||||
/// treated relative to the environment's unique temporary test directory.
|
||||
pub fn ucmd(&self) -> UCommand {
|
||||
let mut cmd = self.cmd(&self.bin_path);
|
||||
cmd.arg(&self.util_name);
|
||||
cmd
|
||||
self.composite_cmd(&self.bin_path, &self.util_name, true)
|
||||
}
|
||||
|
||||
/// Returns builder for invoking the target uutils binary. Paths given are
|
||||
/// treated relative to the environment's unique temporary test directory.
|
||||
pub fn composite_cmd<S: AsRef<OsStr>, T: AsRef<OsStr>>(
|
||||
&self,
|
||||
bin: S,
|
||||
util_name: T,
|
||||
env_clear: bool,
|
||||
) -> UCommand {
|
||||
UCommand::new_from_tmp(bin, &Some(util_name), self.tmpd.clone(), env_clear)
|
||||
}
|
||||
|
||||
/// Returns builder for invoking any system command. Paths given are treated
|
||||
/// relative to the environment's unique temporary test directory.
|
||||
pub fn cmd<S: AsRef<OsStr>>(&self, bin: S) -> UCommand {
|
||||
UCommand::new_from_tmp(bin, self.tmpd.clone(), true)
|
||||
UCommand::new_from_tmp::<S, S>(bin, &None, self.tmpd.clone(), true)
|
||||
}
|
||||
|
||||
/// Returns builder for invoking any uutils command. Paths given are treated
|
||||
/// relative to the environment's unique temporary test directory.
|
||||
pub fn ccmd<S: AsRef<OsStr>>(&self, bin: S) -> UCommand {
|
||||
let mut cmd = self.cmd(&self.bin_path);
|
||||
cmd.arg(bin);
|
||||
cmd
|
||||
self.composite_cmd(&self.bin_path, bin, true)
|
||||
}
|
||||
|
||||
// different names are used rather than an argument
|
||||
// because the need to keep the environment is exceedingly rare.
|
||||
pub fn ucmd_keepenv(&self) -> UCommand {
|
||||
let mut cmd = self.cmd_keepenv(&self.bin_path);
|
||||
cmd.arg(&self.util_name);
|
||||
cmd
|
||||
self.composite_cmd(&self.bin_path, &self.util_name, false)
|
||||
}
|
||||
|
||||
/// Returns builder for invoking any system command. Paths given are treated
|
||||
|
@ -820,7 +869,7 @@ impl TestScenario {
|
|||
/// Differs from the builder returned by `cmd` in that `cmd_keepenv` does not call
|
||||
/// `Command::env_clear` (Clears the entire environment map for the child process.)
|
||||
pub fn cmd_keepenv<S: AsRef<OsStr>>(&self, bin: S) -> UCommand {
|
||||
UCommand::new_from_tmp(bin, self.tmpd.clone(), false)
|
||||
UCommand::new_from_tmp::<S, S>(bin, &None, self.tmpd.clone(), false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -834,6 +883,8 @@ impl TestScenario {
|
|||
pub struct UCommand {
|
||||
pub raw: Command,
|
||||
comm_string: String,
|
||||
bin_path: String,
|
||||
util_name: Option<String>,
|
||||
tmpd: Option<Rc<TempDir>>,
|
||||
has_run: bool,
|
||||
ignore_stdin_write_error: bool,
|
||||
|
@ -846,12 +897,20 @@ pub struct UCommand {
|
|||
}
|
||||
|
||||
impl UCommand {
|
||||
pub fn new<T: AsRef<OsStr>, U: AsRef<OsStr>>(arg: T, curdir: U, env_clear: bool) -> UCommand {
|
||||
UCommand {
|
||||
pub fn new<T: AsRef<OsStr>, S: AsRef<OsStr>, U: AsRef<OsStr>>(
|
||||
bin_path: T,
|
||||
util_name: &Option<S>,
|
||||
curdir: U,
|
||||
env_clear: bool,
|
||||
) -> Self {
|
||||
let bin_path = bin_path.as_ref();
|
||||
let util_name = util_name.as_ref().map(|un| un.as_ref());
|
||||
|
||||
let mut ucmd = Self {
|
||||
tmpd: None,
|
||||
has_run: false,
|
||||
raw: {
|
||||
let mut cmd = Command::new(arg.as_ref());
|
||||
let mut cmd = Command::new(bin_path);
|
||||
cmd.current_dir(curdir.as_ref());
|
||||
if env_clear {
|
||||
if cfg!(windows) {
|
||||
|
@ -871,7 +930,9 @@ impl UCommand {
|
|||
}
|
||||
cmd
|
||||
},
|
||||
comm_string: String::from(arg.as_ref().to_str().unwrap()),
|
||||
comm_string: String::from(bin_path.to_str().unwrap()),
|
||||
bin_path: bin_path.to_str().unwrap().to_string(),
|
||||
util_name: util_name.map(|un| un.to_str().unwrap().to_string()),
|
||||
ignore_stdin_write_error: false,
|
||||
bytes_into_stdin: None,
|
||||
stdin: None,
|
||||
|
@ -879,34 +940,45 @@ impl UCommand {
|
|||
stderr: None,
|
||||
#[cfg(target_os = "linux")]
|
||||
limits: vec![],
|
||||
};
|
||||
|
||||
if let Some(un) = util_name {
|
||||
ucmd.arg(un);
|
||||
}
|
||||
|
||||
ucmd
|
||||
}
|
||||
|
||||
pub fn new_from_tmp<T: AsRef<OsStr>>(arg: T, tmpd: Rc<TempDir>, env_clear: bool) -> UCommand {
|
||||
pub fn new_from_tmp<T: AsRef<OsStr>, S: AsRef<OsStr>>(
|
||||
bin_path: T,
|
||||
util_name: &Option<S>,
|
||||
tmpd: Rc<TempDir>,
|
||||
env_clear: bool,
|
||||
) -> Self {
|
||||
let tmpd_path_buf = String::from(&(*tmpd.as_ref().path().to_str().unwrap()));
|
||||
let mut ucmd: UCommand = UCommand::new(arg.as_ref(), tmpd_path_buf, env_clear);
|
||||
let mut ucmd: Self = Self::new(bin_path, util_name, tmpd_path_buf, env_clear);
|
||||
ucmd.tmpd = Some(tmpd);
|
||||
ucmd
|
||||
}
|
||||
|
||||
pub fn set_stdin<T: Into<Stdio>>(&mut self, stdin: T) -> &mut UCommand {
|
||||
pub fn set_stdin<T: Into<Stdio>>(&mut self, stdin: T) -> &mut Self {
|
||||
self.stdin = Some(stdin.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_stdout<T: Into<Stdio>>(&mut self, stdout: T) -> &mut UCommand {
|
||||
pub fn set_stdout<T: Into<Stdio>>(&mut self, stdout: T) -> &mut Self {
|
||||
self.stdout = Some(stdout.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_stderr<T: Into<Stdio>>(&mut self, stderr: T) -> &mut UCommand {
|
||||
pub fn set_stderr<T: Into<Stdio>>(&mut self, stderr: T) -> &mut Self {
|
||||
self.stderr = Some(stderr.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a parameter to the invocation. Path arguments are treated relative
|
||||
/// to the test environment directory.
|
||||
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut UCommand {
|
||||
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self {
|
||||
assert!(!self.has_run, "{}", ALREADY_RUN);
|
||||
self.comm_string.push(' ');
|
||||
self.comm_string
|
||||
|
@ -917,7 +989,7 @@ impl UCommand {
|
|||
|
||||
/// Add multiple parameters to the invocation. Path arguments are treated relative
|
||||
/// to the test environment directory.
|
||||
pub fn args<S: AsRef<OsStr>>(&mut self, args: &[S]) -> &mut UCommand {
|
||||
pub fn args<S: AsRef<OsStr>>(&mut self, args: &[S]) -> &mut Self {
|
||||
assert!(!self.has_run, "{}", MULTIPLE_STDIN_MEANINGLESS);
|
||||
let strings = args
|
||||
.iter()
|
||||
|
@ -935,9 +1007,9 @@ impl UCommand {
|
|||
}
|
||||
|
||||
/// provides standard input to feed in to the command when spawned
|
||||
pub fn pipe_in<T: Into<Vec<u8>>>(&mut self, input: T) -> &mut UCommand {
|
||||
pub fn pipe_in<T: Into<Vec<u8>>>(&mut self, input: T) -> &mut Self {
|
||||
assert!(
|
||||
!self.bytes_into_stdin.is_some(),
|
||||
self.bytes_into_stdin.is_none(),
|
||||
"{}",
|
||||
MULTIPLE_STDIN_MEANINGLESS
|
||||
);
|
||||
|
@ -946,7 +1018,7 @@ impl UCommand {
|
|||
}
|
||||
|
||||
/// like pipe_in(...), but uses the contents of the file at the provided relative path as the piped in data
|
||||
pub fn pipe_in_fixture<S: AsRef<OsStr>>(&mut self, file_rel_path: S) -> &mut UCommand {
|
||||
pub fn pipe_in_fixture<S: AsRef<OsStr>>(&mut self, file_rel_path: S) -> &mut Self {
|
||||
let contents = read_scenario_fixture(&self.tmpd, file_rel_path);
|
||||
self.pipe_in(contents)
|
||||
}
|
||||
|
@ -954,13 +1026,13 @@ impl UCommand {
|
|||
/// Ignores error caused by feeding stdin to the command.
|
||||
/// This is typically useful to test non-standard workflows
|
||||
/// like feeding something to a command that does not read it
|
||||
pub fn ignore_stdin_write_error(&mut self) -> &mut UCommand {
|
||||
assert!(!self.bytes_into_stdin.is_none(), "{}", NO_STDIN_MEANINGLESS);
|
||||
pub fn ignore_stdin_write_error(&mut self) -> &mut Self {
|
||||
assert!(self.bytes_into_stdin.is_some(), "{}", NO_STDIN_MEANINGLESS);
|
||||
self.ignore_stdin_write_error = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn env<K, V>(&mut self, key: K, val: V) -> &mut UCommand
|
||||
pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Self
|
||||
where
|
||||
K: AsRef<OsStr>,
|
||||
V: AsRef<OsStr>,
|
||||
|
@ -1014,7 +1086,7 @@ impl UCommand {
|
|||
.write_all(input);
|
||||
if !self.ignore_stdin_write_error {
|
||||
if let Err(e) = write_result {
|
||||
panic!("failed to write to stdin of child: {}", e)
|
||||
panic!("failed to write to stdin of child: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1029,6 +1101,8 @@ impl UCommand {
|
|||
let prog = self.run_no_wait().wait_with_output().unwrap();
|
||||
|
||||
CmdResult {
|
||||
bin_path: self.bin_path.clone(),
|
||||
util_name: self.util_name.clone(),
|
||||
tmpd: self.tmpd.clone(),
|
||||
code: prog.status.code(),
|
||||
success: prog.status.success(),
|
||||
|
@ -1070,6 +1144,13 @@ impl UCommand {
|
|||
/// Wrapper for `child.stdout.read_exact()`.
|
||||
/// Careful, this blocks indefinitely if `size` bytes is never reached.
|
||||
pub fn read_size(child: &mut Child, size: usize) -> String {
|
||||
String::from_utf8(read_size_bytes(child, size)).unwrap()
|
||||
}
|
||||
|
||||
/// Read the specified number of bytes from the stdout of the child process.
|
||||
///
|
||||
/// Careful, this blocks indefinitely if `size` bytes is never reached.
|
||||
pub fn read_size_bytes(child: &mut Child, size: usize) -> Vec<u8> {
|
||||
let mut output = Vec::new();
|
||||
output.resize(size, 0);
|
||||
sleep(Duration::from_secs(1));
|
||||
|
@ -1079,7 +1160,7 @@ pub fn read_size(child: &mut Child, size: usize) -> String {
|
|||
.unwrap()
|
||||
.read_exact(output.as_mut_slice())
|
||||
.unwrap();
|
||||
String::from_utf8(output).unwrap()
|
||||
output
|
||||
}
|
||||
|
||||
pub fn vec_of_size(n: usize) -> Vec<u8> {
|
||||
|
@ -1119,13 +1200,13 @@ pub fn host_name_for(util_name: &str) -> Cow<str> {
|
|||
{
|
||||
// make call to `host_name_for` idempotent
|
||||
if util_name.starts_with('g') && util_name != "groups" {
|
||||
return util_name.into();
|
||||
util_name.into()
|
||||
} else {
|
||||
return format!("g{}", util_name).into();
|
||||
format!("g{}", util_name).into()
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
return util_name.into();
|
||||
util_name.into()
|
||||
}
|
||||
|
||||
// GNU coreutils version 8.32 is the reference version since it is the latest version and the
|
||||
|
@ -1183,14 +1264,7 @@ pub fn check_coreutil_version(
|
|||
.output()
|
||||
{
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
return Err(format!(
|
||||
"{}: '{}' {}",
|
||||
UUTILS_WARNING,
|
||||
util_name,
|
||||
e.to_string()
|
||||
))
|
||||
}
|
||||
Err(e) => return Err(format!("{}: '{}' {}", UUTILS_WARNING, util_name, e)),
|
||||
};
|
||||
std::str::from_utf8(&version_check.stdout).unwrap()
|
||||
.split('\n')
|
||||
|
@ -1200,7 +1274,7 @@ pub fn check_coreutil_version(
|
|||
|| Err(format!("{}: unexpected output format for reference coreutil: '{} --version'", UUTILS_WARNING, util_name)),
|
||||
|s| {
|
||||
if s.contains(&format!("(GNU coreutils) {}", version_expected)) {
|
||||
Ok(format!("{}: {}", UUTILS_INFO, s.to_string()))
|
||||
Ok(format!("{}: {}", UUTILS_INFO, s))
|
||||
} else if s.contains("(GNU coreutils)") {
|
||||
let version_found = parse_coreutil_version(s);
|
||||
let version_expected = version_expected.parse::<f32>().unwrap_or_default();
|
||||
|
@ -1276,6 +1350,8 @@ pub fn expected_result(ts: &TestScenario, args: &[&str]) -> std::result::Result<
|
|||
};
|
||||
|
||||
Ok(CmdResult::new(
|
||||
ts.bin_path.as_os_str().to_str().unwrap().to_string(),
|
||||
Some(ts.util_name.clone()),
|
||||
Some(result.tmpd()),
|
||||
Some(result.code()),
|
||||
result.succeeded(),
|
||||
|
@ -1293,6 +1369,8 @@ mod tests {
|
|||
#[test]
|
||||
fn test_code_is() {
|
||||
let res = CmdResult {
|
||||
bin_path: "".into(),
|
||||
util_name: None,
|
||||
tmpd: None,
|
||||
code: Some(32),
|
||||
success: false,
|
||||
|
@ -1306,6 +1384,8 @@ mod tests {
|
|||
#[should_panic]
|
||||
fn test_code_is_fail() {
|
||||
let res = CmdResult {
|
||||
bin_path: "".into(),
|
||||
util_name: None,
|
||||
tmpd: None,
|
||||
code: Some(32),
|
||||
success: false,
|
||||
|
@ -1318,6 +1398,8 @@ mod tests {
|
|||
#[test]
|
||||
fn test_failure() {
|
||||
let res = CmdResult {
|
||||
bin_path: "".into(),
|
||||
util_name: None,
|
||||
tmpd: None,
|
||||
code: None,
|
||||
success: false,
|
||||
|
@ -1331,6 +1413,8 @@ mod tests {
|
|||
#[should_panic]
|
||||
fn test_failure_fail() {
|
||||
let res = CmdResult {
|
||||
bin_path: "".into(),
|
||||
util_name: None,
|
||||
tmpd: None,
|
||||
code: None,
|
||||
success: true,
|
||||
|
@ -1343,6 +1427,8 @@ mod tests {
|
|||
#[test]
|
||||
fn test_success() {
|
||||
let res = CmdResult {
|
||||
bin_path: "".into(),
|
||||
util_name: None,
|
||||
tmpd: None,
|
||||
code: None,
|
||||
success: true,
|
||||
|
@ -1356,6 +1442,8 @@ mod tests {
|
|||
#[should_panic]
|
||||
fn test_success_fail() {
|
||||
let res = CmdResult {
|
||||
bin_path: "".into(),
|
||||
util_name: None,
|
||||
tmpd: None,
|
||||
code: None,
|
||||
success: false,
|
||||
|
@ -1368,6 +1456,8 @@ mod tests {
|
|||
#[test]
|
||||
fn test_no_stderr_output() {
|
||||
let res = CmdResult {
|
||||
bin_path: "".into(),
|
||||
util_name: None,
|
||||
tmpd: None,
|
||||
code: None,
|
||||
success: true,
|
||||
|
@ -1382,6 +1472,8 @@ mod tests {
|
|||
#[should_panic]
|
||||
fn test_no_stderr_fail() {
|
||||
let res = CmdResult {
|
||||
bin_path: "".into(),
|
||||
util_name: None,
|
||||
tmpd: None,
|
||||
code: None,
|
||||
success: true,
|
||||
|
@ -1396,6 +1488,8 @@ mod tests {
|
|||
#[should_panic]
|
||||
fn test_no_stdout_fail() {
|
||||
let res = CmdResult {
|
||||
bin_path: "".into(),
|
||||
util_name: None,
|
||||
tmpd: None,
|
||||
code: None,
|
||||
success: true,
|
||||
|
@ -1409,6 +1503,8 @@ mod tests {
|
|||
#[test]
|
||||
fn test_std_does_not_contain() {
|
||||
let res = CmdResult {
|
||||
bin_path: "".into(),
|
||||
util_name: None,
|
||||
tmpd: None,
|
||||
code: None,
|
||||
success: true,
|
||||
|
@ -1423,6 +1519,8 @@ mod tests {
|
|||
#[should_panic]
|
||||
fn test_stdout_does_not_contain_fail() {
|
||||
let res = CmdResult {
|
||||
bin_path: "".into(),
|
||||
util_name: None,
|
||||
tmpd: None,
|
||||
code: None,
|
||||
success: true,
|
||||
|
@ -1437,6 +1535,8 @@ mod tests {
|
|||
#[should_panic]
|
||||
fn test_stderr_does_not_contain_fail() {
|
||||
let res = CmdResult {
|
||||
bin_path: "".into(),
|
||||
util_name: None,
|
||||
tmpd: None,
|
||||
code: None,
|
||||
success: true,
|
||||
|
@ -1450,6 +1550,8 @@ mod tests {
|
|||
#[test]
|
||||
fn test_stdout_matches() {
|
||||
let res = CmdResult {
|
||||
bin_path: "".into(),
|
||||
util_name: None,
|
||||
tmpd: None,
|
||||
code: None,
|
||||
success: true,
|
||||
|
@ -1466,6 +1568,8 @@ mod tests {
|
|||
#[should_panic]
|
||||
fn test_stdout_matches_fail() {
|
||||
let res = CmdResult {
|
||||
bin_path: "".into(),
|
||||
util_name: None,
|
||||
tmpd: None,
|
||||
code: None,
|
||||
success: true,
|
||||
|
@ -1481,6 +1585,8 @@ mod tests {
|
|||
#[should_panic]
|
||||
fn test_stdout_not_matches_fail() {
|
||||
let res = CmdResult {
|
||||
bin_path: "".into(),
|
||||
util_name: None,
|
||||
tmpd: None,
|
||||
code: None,
|
||||
success: true,
|
||||
|
@ -1495,6 +1601,8 @@ mod tests {
|
|||
#[test]
|
||||
fn test_normalized_newlines_stdout_is() {
|
||||
let res = CmdResult {
|
||||
bin_path: "".into(),
|
||||
util_name: None,
|
||||
tmpd: None,
|
||||
code: None,
|
||||
success: true,
|
||||
|
@ -1511,6 +1619,8 @@ mod tests {
|
|||
#[should_panic]
|
||||
fn test_normalized_newlines_stdout_is_fail() {
|
||||
let res = CmdResult {
|
||||
bin_path: "".into(),
|
||||
util_name: None,
|
||||
tmpd: None,
|
||||
code: None,
|
||||
success: true,
|
||||
|
|
BIN
tests/fixtures/dd/all-valid-ascii-chars-37eff01866ba3f538421b30b7cbefcac.test
vendored
Normal file
BIN
tests/fixtures/dd/all-valid-ascii-chars-37eff01866ba3f538421b30b7cbefcac.test
vendored
Normal file
Binary file not shown.
16
tests/fixtures/dd/dd-block-cbs16-win.test
vendored
Normal file
16
tests/fixtures/dd/dd-block-cbs16-win.test
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
0
|
||||
01
|
||||
012
|
||||
0123
|
||||
01234
|
||||
012345
|
||||
0123456
|
||||
01234567
|
||||
012345678
|
||||
0123456789
|
||||
0123456789a
|
||||
0123456789ab
|
||||
0123456789abc
|
||||
0123456789abcd
|
||||
0123456789abcde
|
||||
0123456789abcdef
|
1
tests/fixtures/dd/dd-block-cbs16.spec
vendored
Normal file
1
tests/fixtures/dd/dd-block-cbs16.spec
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
0 01 012 0123 01234 012345 0123456 01234567 012345678 0123456789 0123456789a 0123456789ab 0123456789abc 0123456789abcd 0123456789abcde 0123456789abcdef
|
16
tests/fixtures/dd/dd-block-cbs16.test
vendored
Normal file
16
tests/fixtures/dd/dd-block-cbs16.test
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
0
|
||||
01
|
||||
012
|
||||
0123
|
||||
01234
|
||||
012345
|
||||
0123456
|
||||
01234567
|
||||
012345678
|
||||
0123456789
|
||||
0123456789a
|
||||
0123456789ab
|
||||
0123456789abc
|
||||
0123456789abcd
|
||||
0123456789abcde
|
||||
0123456789abcdef
|
1
tests/fixtures/dd/dd-block-cbs8.spec
vendored
Normal file
1
tests/fixtures/dd/dd-block-cbs8.spec
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
0 01 012 0123 01234 012345 0123456 012345670123456701234567012345670123456701234567012345670123456701234567
|
1
tests/fixtures/dd/dd-block-consecutive-nl-cbs16.spec
vendored
Normal file
1
tests/fixtures/dd/dd-block-consecutive-nl-cbs16.spec
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
pre post
|
4
tests/fixtures/dd/dd-block-consecutive-nl-win.test
vendored
Normal file
4
tests/fixtures/dd/dd-block-consecutive-nl-win.test
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
pre
|
||||
|
||||
|
||||
post
|
4
tests/fixtures/dd/dd-block-consecutive-nl.test
vendored
Normal file
4
tests/fixtures/dd/dd-block-consecutive-nl.test
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
pre
|
||||
|
||||
|
||||
post
|
BIN
tests/fixtures/dd/dd-bytes-alphabet-null.spec
vendored
Normal file
BIN
tests/fixtures/dd/dd-bytes-alphabet-null.spec
vendored
Normal file
Binary file not shown.
BIN
tests/fixtures/dd/dd-bytes-null-trunc.spec
vendored
Normal file
BIN
tests/fixtures/dd/dd-bytes-null-trunc.spec
vendored
Normal file
Binary file not shown.
16
tests/fixtures/dd/dd-unblock-cbs16-win.spec
vendored
Normal file
16
tests/fixtures/dd/dd-unblock-cbs16-win.spec
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
0
|
||||
01
|
||||
012
|
||||
0123
|
||||
01234
|
||||
012345
|
||||
0123456
|
||||
01234567
|
||||
012345678
|
||||
0123456789
|
||||
0123456789a
|
||||
0123456789ab
|
||||
0123456789abc
|
||||
0123456789abcd
|
||||
0123456789abcde
|
||||
0123456789abcdef
|
16
tests/fixtures/dd/dd-unblock-cbs16.spec
vendored
Normal file
16
tests/fixtures/dd/dd-unblock-cbs16.spec
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
0
|
||||
01
|
||||
012
|
||||
0123
|
||||
01234
|
||||
012345
|
||||
0123456
|
||||
01234567
|
||||
012345678
|
||||
0123456789
|
||||
0123456789a
|
||||
0123456789ab
|
||||
0123456789abc
|
||||
0123456789abcd
|
||||
0123456789abcde
|
||||
0123456789abcdef
|
1
tests/fixtures/dd/dd-unblock-cbs16.test
vendored
Normal file
1
tests/fixtures/dd/dd-unblock-cbs16.test
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
0 01 012 0123 01234 012345 0123456 01234567 012345678 0123456789 0123456789a 0123456789ab 0123456789abc 0123456789abcd 0123456789abcde 0123456789abcdef
|
32
tests/fixtures/dd/dd-unblock-cbs8-win.spec
vendored
Normal file
32
tests/fixtures/dd/dd-unblock-cbs8-win.spec
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
0
|
||||
|
||||
01
|
||||
|
||||
012
|
||||
|
||||
0123
|
||||
|
||||
01234
|
||||
|
||||
012345
|
||||
|
||||
0123456
|
||||
|
||||
01234567
|
||||
|
||||
01234567
|
||||
8
|
||||
01234567
|
||||
89
|
||||
01234567
|
||||
89a
|
||||
01234567
|
||||
89ab
|
||||
01234567
|
||||
89abc
|
||||
01234567
|
||||
89abcd
|
||||
01234567
|
||||
89abcde
|
||||
01234567
|
||||
89abcdef
|
32
tests/fixtures/dd/dd-unblock-cbs8.spec
vendored
Normal file
32
tests/fixtures/dd/dd-unblock-cbs8.spec
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
0
|
||||
|
||||
01
|
||||
|
||||
012
|
||||
|
||||
0123
|
||||
|
||||
01234
|
||||
|
||||
012345
|
||||
|
||||
0123456
|
||||
|
||||
01234567
|
||||
|
||||
01234567
|
||||
8
|
||||
01234567
|
||||
89
|
||||
01234567
|
||||
89a
|
||||
01234567
|
||||
89ab
|
||||
01234567
|
||||
89abc
|
||||
01234567
|
||||
89abcd
|
||||
01234567
|
||||
89abcde
|
||||
01234567
|
||||
89abcdef
|
BIN
tests/fixtures/dd/deadbeef-16.spec
vendored
Normal file
BIN
tests/fixtures/dd/deadbeef-16.spec
vendored
Normal file
Binary file not shown.
1
tests/fixtures/dd/deadbeef-16.test
vendored
Normal file
1
tests/fixtures/dd/deadbeef-16.test
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
1
tests/fixtures/dd/deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test
vendored
Normal file
1
tests/fixtures/dd/deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test
vendored
Normal file
File diff suppressed because one or more lines are too long
1
tests/fixtures/dd/gnudd-conv-sync-ibs-1031-obs-521-deadbeef.spec
vendored
Normal file
1
tests/fixtures/dd/gnudd-conv-sync-ibs-1031-obs-521-deadbeef.spec
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
tests/fixtures/dd/gnudd-conv-sync-ibs-1031-obs-521-random.spec
vendored
Normal file
BIN
tests/fixtures/dd/gnudd-conv-sync-ibs-1031-obs-521-random.spec
vendored
Normal file
Binary file not shown.
BIN
tests/fixtures/dd/gnudd-conv-sync-ibs-1031-obs-521-zeros.spec
vendored
Normal file
BIN
tests/fixtures/dd/gnudd-conv-sync-ibs-1031-obs-521-zeros.spec
vendored
Normal file
Binary file not shown.
1
tests/fixtures/dd/gnudd-conv-sync-ibs-521-obs-1031-deadbeef.spec
vendored
Normal file
1
tests/fixtures/dd/gnudd-conv-sync-ibs-521-obs-1031-deadbeef.spec
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
tests/fixtures/dd/gnudd-conv-sync-ibs-521-obs-1031-random.spec
vendored
Normal file
BIN
tests/fixtures/dd/gnudd-conv-sync-ibs-521-obs-1031-random.spec
vendored
Normal file
Binary file not shown.
BIN
tests/fixtures/dd/gnudd-conv-sync-ibs-521-obs-1031-zeros.spec
vendored
Normal file
BIN
tests/fixtures/dd/gnudd-conv-sync-ibs-521-obs-1031-zeros.spec
vendored
Normal file
Binary file not shown.
1
tests/fixtures/dd/gnudd-deadbeef-first-12345.spec
vendored
Normal file
1
tests/fixtures/dd/gnudd-deadbeef-first-12345.spec
vendored
Normal file
File diff suppressed because one or more lines are too long
1
tests/fixtures/dd/gnudd-deadbeef-first-16k.spec
vendored
Normal file
1
tests/fixtures/dd/gnudd-deadbeef-first-16k.spec
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
tests/fixtures/dd/gnudd-random-first-32k.spec
vendored
Normal file
BIN
tests/fixtures/dd/gnudd-random-first-32k.spec
vendored
Normal file
Binary file not shown.
BIN
tests/fixtures/dd/lcase-ascii.test
vendored
Normal file
BIN
tests/fixtures/dd/lcase-ascii.test
vendored
Normal file
Binary file not shown.
BIN
tests/fixtures/dd/lcase-ebcdic.spec
vendored
Normal file
BIN
tests/fixtures/dd/lcase-ebcdic.spec
vendored
Normal file
Binary file not shown.
BIN
tests/fixtures/dd/lcase-ebcdic.test
vendored
Normal file
BIN
tests/fixtures/dd/lcase-ebcdic.test
vendored
Normal file
Binary file not shown.
BIN
tests/fixtures/dd/lcase-ibm.spec
vendored
Normal file
BIN
tests/fixtures/dd/lcase-ibm.spec
vendored
Normal file
Binary file not shown.
BIN
tests/fixtures/dd/lcase-ibm.test
vendored
Normal file
BIN
tests/fixtures/dd/lcase-ibm.test
vendored
Normal file
Binary file not shown.
1
tests/fixtures/dd/ones-6ae59e64850377ee5470c854761551ea.test
vendored
Normal file
1
tests/fixtures/dd/ones-6ae59e64850377ee5470c854761551ea.test
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue