coreutils/tests/by-util/test_yes.rs
Jed Denlea 3870ee252a yes: support non-UTF-8 args
Also, tighten the creation of the output buffer.  Rather than copy "y\n"
8192 times, or any other input some number of times, it can be doubled
in place using Vec::extend_from_within.
2023-05-15 11:29:14 -07:00

110 lines
2.8 KiB
Rust

use std::ffi::OsStr;
use std::process::{ExitStatus, Stdio};
#[cfg(unix)]
use std::os::unix::process::ExitStatusExt;
use crate::common::util::TestScenario;
#[cfg(unix)]
fn check_termination(result: ExitStatus) {
assert_eq!(result.signal(), Some(libc::SIGPIPE));
}
#[cfg(not(unix))]
fn check_termination(result: ExitStatus) {
assert!(result.success(), "yes did not exit successfully");
}
const NO_ARGS: &[&str] = &[];
/// Run `yes`, capture some of the output, close the pipe, and verify it.
fn run(args: &[impl AsRef<OsStr>], expected: &[u8]) {
let mut cmd = new_ucmd!();
let mut child = cmd.args(args).set_stdout(Stdio::piped()).run_no_wait();
let buf = child.stdout_exact_bytes(expected.len());
child.close_stdout();
#[allow(deprecated)]
check_termination(child.wait_with_output().unwrap().status);
assert_eq!(buf.as_slice(), expected);
}
#[test]
fn test_invalid_arg() {
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
}
#[test]
fn test_simple() {
run(NO_ARGS, b"y\ny\ny\ny\n");
}
#[test]
fn test_args() {
run(&["a", "bar", "c"], b"a bar c\na bar c\na ba");
}
#[test]
fn test_long_output() {
run(NO_ARGS, "y\n".repeat(512 * 1024).as_bytes());
}
/// Test with an output that seems likely to get mangled in case of incomplete writes.
#[test]
fn test_long_odd_output() {
run(&["abcdef"], "abcdef\n".repeat(1024 * 1024).as_bytes());
}
/// Test with an input that doesn't fit in the standard buffer.
#[test]
fn test_long_input() {
#[cfg(not(windows))]
const TIMES: usize = 14000;
// On Windows the command line is limited to 8191 bytes.
// This is not actually enough to fill the buffer, but it's still nice to
// try something long.
#[cfg(windows)]
const TIMES: usize = 500;
let arg = "abcdef".repeat(TIMES) + "\n";
let expected_out = arg.repeat(30);
run(&[&arg[..arg.len() - 1]], expected_out.as_bytes());
}
#[test]
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
fn test_piped_to_dev_full() {
use std::fs::OpenOptions;
for append in [true, false] {
{
let dev_full = OpenOptions::new()
.write(true)
.append(append)
.open("/dev/full")
.unwrap();
new_ucmd!()
.set_stdout(dev_full)
.fails()
.stderr_contains("No space left on device");
}
}
}
#[test]
#[cfg(any(unix, target_os = "wasi"))]
fn test_non_utf8() {
#[cfg(unix)]
use std::os::unix::ffi::OsStrExt;
#[cfg(target_os = "wasi")]
use std::os::wasi::ffi::OsStrExt;
run(
&[
OsStr::from_bytes(b"\xbf\xff\xee"),
OsStr::from_bytes(b"bar"),
],
&b"\xbf\xff\xee bar\n".repeat(5000),
);
}