1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 03:27:44 +00:00

wc: more tests and fixes

My previous commits meant to bring our wc's output and behavior in line
with GNU's. There should be tests that check for these changes!

I found a stupid bug in my own changes, I was not adding 1 to the
indexes produced by .enumerate() when printing errors.
This commit is contained in:
Jed Denlea 2023-04-29 19:47:49 -07:00
parent c4b53a44b5
commit e5b46ea3eb
5 changed files with 199 additions and 35 deletions

View file

@ -268,12 +268,16 @@ fn test_multiple_default() {
"lorem_ipsum.txt",
"moby_dick.txt",
"alice_in_wonderland.txt",
"alice in wonderland.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",
);
.stdout_is(concat!(
" 13 109 772 lorem_ipsum.txt\n",
" 18 204 1115 moby_dick.txt\n",
" 5 57 302 alice_in_wonderland.txt\n",
" 5 57 302 alice in wonderland.txt\n",
" 41 427 2491 total\n",
));
}
/// Test for an empty file.
@ -352,17 +356,24 @@ fn test_file_bytes_dictate_width() {
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",
);
.stdout_is(concat!(
" 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";
const STDOUT: &str = concat!(
" 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";
const STDOUT: &str = concat!(
" 0 0 0 emptyfile.txt\n",
" 0 0 0 total\n",
);
new_ucmd!()
.args(&["-lwc", "emptyfile.txt", "."])
.run()
@ -392,12 +403,10 @@ fn test_read_from_directory_error() {
/// Test that getting counts from nonexistent file is an error.
#[test]
fn test_read_from_nonexistent_file() {
const MSG: &str = "bogusfile: No such file or directory";
new_ucmd!()
.args(&["bogusfile"])
.fails()
.stderr_contains(MSG)
.stdout_is("");
.stderr_only("wc: bogusfile: No such file or directory\n");
}
#[test]
@ -421,15 +430,30 @@ fn test_files0_disabled_files_argument() {
#[test]
fn test_files0_from() {
// file
new_ucmd!()
.args(&["--files0-from=files0_list.txt"])
.run()
.success()
.stdout_is(concat!(
" 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",
));
// stream
new_ucmd!()
.args(&["--files0-from=-"])
.pipe_in_fixture("files0_list.txt")
.run()
.success()
.stdout_is(concat!(
"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]
@ -450,7 +474,7 @@ fn test_files0_from_with_stdin_in_file() {
.stdout_is(concat!(
" 13 109 772 lorem_ipsum.txt\n",
" 18 204 1115 moby_dick.txt\n",
" 5 57 302 -\n",
" 5 57 302 -\n", // alice_in_wonderland.txt
" 36 370 2189 total\n",
));
}
@ -531,3 +555,152 @@ fn test_total_only() {
.run()
.stdout_is("31 313 1887\n");
}
#[test]
fn test_zero_length_files() {
// A trailing zero is ignored, but otherwise empty file names are an error...
const LIST: &str = "\0moby_dick.txt\0\0alice_in_wonderland.txt\0\0lorem_ipsum.txt\0";
// Try with and without the last \0
for l in [LIST.len(), LIST.len() - 1] {
new_ucmd!()
.args(&["--files0-from=-"])
.pipe_in(&LIST[..l])
.run()
.failure()
.stdout_is(concat!(
"18 204 1115 moby_dick.txt\n",
"5 57 302 alice_in_wonderland.txt\n",
"13 109 772 lorem_ipsum.txt\n",
"36 370 2189 total\n",
))
.stderr_is(concat!(
"wc: -:1: invalid zero-length file name\n",
"wc: -:3: invalid zero-length file name\n",
"wc: -:5: invalid zero-length file name\n",
));
}
// But, just as important, a zero-length file name may still be at the end...
new_ucmd!()
.args(&["--files0-from=-"])
.pipe_in(
LIST.as_bytes()
.iter()
.chain(b"\0")
.copied()
.collect::<Vec<_>>(),
)
.run()
.failure()
.stdout_is(concat!(
"18 204 1115 moby_dick.txt\n",
"5 57 302 alice_in_wonderland.txt\n",
"13 109 772 lorem_ipsum.txt\n",
"36 370 2189 total\n",
))
.stderr_is(concat!(
"wc: -:1: invalid zero-length file name\n",
"wc: -:3: invalid zero-length file name\n",
"wc: -:5: invalid zero-length file name\n",
"wc: -:7: invalid zero-length file name\n",
));
}
#[test]
fn test_files0_errors_quoting() {
new_ucmd!()
.args(&["--files0-from=files0 with nonexistent.txt"])
.run()
.failure()
.stderr_is(concat!(
"wc: this_file_does_not_exist.txt: No such file or directory\n",
"wc: 'files0 with nonexistent.txt':2: invalid zero-length file name\n",
"wc: 'this file does not exist.txt': No such file or directory\n",
"wc: \"this files doesn't exist either.txt\": No such file or directory\n",
))
.stdout_is("0 0 0 total\n");
}
#[test]
fn test_files0_progressive_stream() {
use std::process::Stdio;
// You should be able to run wc and have a back-and-forth exchange with wc...
let mut child = new_ucmd!()
.args(&["--files0-from=-"])
.set_stdin(Stdio::piped())
.set_stdout(Stdio::piped())
.set_stderr(Stdio::piped())
.run_no_wait();
macro_rules! chk {
($fn:ident, $exp:literal) => {
assert_eq!(child.$fn($exp.len()), $exp.as_bytes());
};
}
// File in, count out...
child.write_in("moby_dick.txt\0");
chk!(stdout_exact_bytes, "18 204 1115 moby_dick.txt\n");
child.write_in("lorem_ipsum.txt\0");
chk!(stdout_exact_bytes, "13 109 772 lorem_ipsum.txt\n");
// Introduce an error!
child.write_in("\0");
chk!(
stderr_exact_bytes,
"wc: -:3: invalid zero-length file name\n"
);
// wc is quick to forgive, let's move on...
child.write_in("alice_in_wonderland.txt\0");
chk!(stdout_exact_bytes, "5 57 302 alice_in_wonderland.txt\n");
// Fin.
child
.wait()
.expect("wc should finish")
.failure()
.stdout_only("36 370 2189 total\n");
}
#[test]
fn files0_from_dir() {
// On Unix, `read(open("."))` fails. On Windows, `open(".")` fails. Thus, the errors happen in
// different contexts.
#[cfg(not(windows))]
macro_rules! dir_err {
($p:literal) => {
concat!("wc: ", $p, ": read error: Is a directory\n")
};
}
#[cfg(windows)]
macro_rules! dir_err {
($p:literal) => {
concat!("wc: cannot open ", $p, " for reading: Permission denied\n")
};
}
new_ucmd!()
.args(&["--files0-from=dir with spaces"])
.fails()
.stderr_only(dir_err!("'dir with spaces'"));
// Those contexts have different rules about quoting in errors...
#[cfg(windows)]
const DOT_ERR: &str = dir_err!("'.'");
#[cfg(not(windows))]
const DOT_ERR: &str = dir_err!(".");
new_ucmd!()
.args(&["--files0-from=."])
.fails()
.stderr_only(DOT_ERR);
// That also means you cannot `< . wc --files0-from=-` on Windows.
#[cfg(not(windows))]
new_ucmd!()
.args(&["--files0-from=-"])
.set_stdin(std::fs::File::open(".").unwrap())
.fails()
.stderr_only(dir_err!("-"));
}