mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 19:47:45 +00:00
allow ignoring stdin write errors in tests
* if we want to test an irregular scenario, ignoring errors caused by writing to stdin of the command can be uselful. * for example, when writing some text to stdin of cksum in a scenario where it doesn't consume this input, the child process might have exited before the text was written. therefore, this test sometimes fails with a 'Broken pipe'.
This commit is contained in:
parent
9ae4928b7b
commit
d51ca40986
2 changed files with 31 additions and 7 deletions
|
@ -35,14 +35,19 @@ fn test_empty() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_arg_overrides_stdin() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let input = "foobarfoobar";
|
||||
|
||||
at.touch("a");
|
||||
|
||||
let result = ucmd.arg("a").pipe_in(input.as_bytes()).run();
|
||||
let result = ucmd
|
||||
.arg("a")
|
||||
.pipe_in(input.as_bytes())
|
||||
// the command might have exited before all bytes have been pipe in.
|
||||
// in that case, we don't care about the error (broken pipe)
|
||||
.ignore_stdin_write_error()
|
||||
.run();
|
||||
|
||||
println!("{}, {}", result.stdout, result.stderr);
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@ static ALREADY_RUN: &str = " you have already run this UCommand, if you want to
|
|||
testing();";
|
||||
static MULTIPLE_STDIN_MEANINGLESS: &str = "Ucommand is designed around a typical use case of: provide args and input stream -> spawn process -> block until completion -> return output streams. For verifying that a particular section of the input stream is what causes a particular behavior, use the Command type directly.";
|
||||
|
||||
static NO_STDIN_MEANINGLESS: &str = "Setting this flag has no effect if there is no stdin";
|
||||
|
||||
/// Test if the program is running under CI
|
||||
pub fn is_ci() -> bool {
|
||||
std::env::var("CI")
|
||||
|
@ -624,6 +626,7 @@ pub struct UCommand {
|
|||
tmpd: Option<Rc<TempDir>>,
|
||||
has_run: bool,
|
||||
stdin: Option<Vec<u8>>,
|
||||
ignore_stdin_write_error: bool,
|
||||
}
|
||||
|
||||
impl UCommand {
|
||||
|
@ -653,6 +656,7 @@ impl UCommand {
|
|||
},
|
||||
comm_string: String::from(arg.as_ref().to_str().unwrap()),
|
||||
stdin: None,
|
||||
ignore_stdin_write_error: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -705,6 +709,17 @@ impl UCommand {
|
|||
self.pipe_in(contents)
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
if self.stdin.is_none() {
|
||||
panic!("{}", NO_STDIN_MEANINGLESS);
|
||||
}
|
||||
self.ignore_stdin_write_error = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn env<K, V>(&mut self, key: K, val: V) -> &mut UCommand
|
||||
where
|
||||
K: AsRef<OsStr>,
|
||||
|
@ -725,7 +740,7 @@ impl UCommand {
|
|||
}
|
||||
self.has_run = true;
|
||||
log_info("run", &self.comm_string);
|
||||
let mut result = self
|
||||
let mut child = self
|
||||
.raw
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
|
@ -734,15 +749,19 @@ impl UCommand {
|
|||
.unwrap();
|
||||
|
||||
if let Some(ref input) = self.stdin {
|
||||
result
|
||||
let write_result = child
|
||||
.stdin
|
||||
.take()
|
||||
.unwrap_or_else(|| panic!("Could not take child process stdin"))
|
||||
.write_all(input)
|
||||
.unwrap_or_else(|e| panic!("{}", e));
|
||||
.write_all(input);
|
||||
if !self.ignore_stdin_write_error {
|
||||
if let Err(e) = write_result {
|
||||
panic!("failed to write to stdin of child: {}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
child
|
||||
}
|
||||
|
||||
/// Spawns the command, feeds the stdin if any, waits for the result
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue