mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
tests(cat,stdbuf): Add broken-pipe robustness tests (#4627)
Add test coverage for cat and stdbuf broken pipe handling: **cat tests:** - test_cat_broken_pipe_nonzero_and_message: Verify cat handles SIGPIPE without hanging or crashing and exits with nonzero status **stdbuf tests:** - test_permission_external_missing_lib: Handle missing external libstdbuf - test_no_such_external_missing_lib: Error handling in external lib mode - Guard existing tests with #[cfg(not(feature = "feat_external_libstdbuf"))] These tests address write-errors.sh from GNU test suite (#4627) and improve cross-platform robustness for stdbuf feat_external_libstdbuf builds.
This commit is contained in:
@@ -18,6 +18,32 @@ use uutests::util::TestScenario;
|
||||
use uutests::util::vec_of_size;
|
||||
use uutests::util_name;
|
||||
|
||||
#[cfg(unix)]
|
||||
// Verify cat handles a broken pipe on stdout without hanging or crashing and exits nonzero
|
||||
#[test]
|
||||
fn test_cat_broken_pipe_nonzero_and_message() {
|
||||
use std::fs::File;
|
||||
use std::os::unix::io::FromRawFd;
|
||||
use uutests::new_ucmd;
|
||||
|
||||
unsafe {
|
||||
let mut fds: [libc::c_int; 2] = [0, 0];
|
||||
assert_eq!(libc::pipe(fds.as_mut_ptr()), 0, "Failed to create pipe");
|
||||
// Close the read end to simulate a broken pipe on stdout
|
||||
let read_end = File::from_raw_fd(fds[0]);
|
||||
// Explicitly drop the read-end so writers see EPIPE instead of blocking on a full pipe
|
||||
std::mem::drop(read_end);
|
||||
let write_end = File::from_raw_fd(fds[1]);
|
||||
|
||||
let content = (0..10000).map(|_| "x").collect::<String>();
|
||||
// On Unix, SIGPIPE should lead to a non-zero exit; ensure process exits and fails
|
||||
new_ucmd!()
|
||||
.set_stdout(write_end)
|
||||
.pipe_in(content.as_bytes())
|
||||
.fails();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_output_simple() {
|
||||
new_ucmd!()
|
||||
|
||||
@@ -15,6 +15,7 @@ fn invalid_input() {
|
||||
new_ucmd!().arg("-/").fails_with_code(125);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "feat_external_libstdbuf"))]
|
||||
#[test]
|
||||
fn test_permission() {
|
||||
new_ucmd!()
|
||||
@@ -24,6 +25,23 @@ fn test_permission() {
|
||||
.stderr_contains("Permission denied");
|
||||
}
|
||||
|
||||
// TODO: Tests below are brittle when feat_external_libstdbuf is enabled and libstdbuf is not installed.
|
||||
// Align stdbuf with GNU search order to enable deterministic testing without installation:
|
||||
// 1) search for libstdbuf next to the stdbuf binary, 2) then in LIBSTDBUF_DIR, 3) then system locations.
|
||||
// After implementing this, rework tests to provide a temporary symlink rather than depending on system state.
|
||||
|
||||
#[cfg(feature = "feat_external_libstdbuf")]
|
||||
#[test]
|
||||
fn test_permission_external_missing_lib() {
|
||||
// When built with external libstdbuf, running stdbuf fails early if lib is not installed
|
||||
new_ucmd!()
|
||||
.arg("-o1")
|
||||
.arg(".")
|
||||
.fails_with_code(1)
|
||||
.stderr_contains("External libstdbuf not found");
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "feat_external_libstdbuf"))]
|
||||
#[test]
|
||||
fn test_no_such() {
|
||||
new_ucmd!()
|
||||
@@ -33,6 +51,17 @@ fn test_no_such() {
|
||||
.stderr_contains("No such file or directory");
|
||||
}
|
||||
|
||||
#[cfg(feature = "feat_external_libstdbuf")]
|
||||
#[test]
|
||||
fn test_no_such_external_missing_lib() {
|
||||
// With external lib mode and missing installation, stdbuf fails before spawning the command
|
||||
new_ucmd!()
|
||||
.arg("-o1")
|
||||
.arg("no_such")
|
||||
.fails_with_code(1)
|
||||
.stderr_contains("External libstdbuf not found");
|
||||
}
|
||||
|
||||
// Disabled on x86_64-unknown-linux-musl because the cross-rs Docker image for this target
|
||||
// does not provide musl-compiled system utilities (like head), leading to dynamic linker errors
|
||||
// when preloading musl-compiled libstdbuf.so into glibc-compiled binaries. Same thing for FreeBSD.
|
||||
|
||||
Reference in New Issue
Block a user