From bf1d0204eb93274ebd00b0f3a0d412e91f15641e Mon Sep 17 00:00:00 2001 From: chrysn Date: Fri, 14 Jun 2024 13:18:55 +0200 Subject: [PATCH] feat(trycmd): Support `echo text | command` Closes: https://github.com/assert-rs/snapbox/issues/172 --- crates/trycmd/src/bin/bin-fixture.rs | 6 ++++++ crates/trycmd/src/schema.rs | 25 ++++++++++++++++++++++- crates/trycmd/tests/cmd/echo-stdin.trycmd | 6 ++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 crates/trycmd/tests/cmd/echo-stdin.trycmd diff --git a/crates/trycmd/src/bin/bin-fixture.rs b/crates/trycmd/src/bin/bin-fixture.rs index 89a49f53..8b006338 100644 --- a/crates/trycmd/src/bin/bin-fixture.rs +++ b/crates/trycmd/src/bin/bin-fixture.rs @@ -5,6 +5,12 @@ use std::io::Write; use std::process; fn run() -> Result<(), Box> { + if env::var("lines-from-stdin").as_deref() == Ok("1") { + for line in std::io::stdin().lines() { + println!("read line from stdin: {}", line.unwrap()); + } + } + if let Ok(text) = env::var("stdout") { println!("{}", text); } diff --git a/crates/trycmd/src/schema.rs b/crates/trycmd/src/schema.rs index 2c17e533..a889cbbf 100644 --- a/crates/trycmd/src/schema.rs +++ b/crates/trycmd/src/schema.rs @@ -292,6 +292,29 @@ impl TryCmd { stdout.pop(); } + let mut stdin = None; + if cmdline.first().is_some_and(|s| s == "echo") { + // No full piping / POSIX shell implemented, but this is a frequent and + // important tool + // + // If no pipe is found, this is not processed any further: echo is then treated + // as the binary, as it would have been if there were no special handling. + if let Some(index) = cmdline.iter().position(|s| s == &"|") { + let (echo_part, actual_command) = cmdline.split_at(index); + let echo_args = &echo_part[1..]; + if echo_args.first().is_some_and(|f| f == "-n") + || echo_args.iter().any(|s| s.contains("\\")) + { + return Err( + "Behavior of echo with -n or backslashes is not defined in POSIX" + .into(), + ); + } + stdin = Some(crate::Data::text(format!("{}\n", echo_args.join(" ")))); + cmdline = actual_command[1..].into(); + } + }; + let mut env = Env::default(); let bin = loop { @@ -310,7 +333,7 @@ impl TryCmd { bin: Some(Bin::Name(bin)), args: cmdline, env, - stdin: None, + stdin, stderr_to_stdout: true, expected_status_source, expected_status, diff --git a/crates/trycmd/tests/cmd/echo-stdin.trycmd b/crates/trycmd/tests/cmd/echo-stdin.trycmd new file mode 100644 index 00000000..210973f2 --- /dev/null +++ b/crates/trycmd/tests/cmd/echo-stdin.trycmd @@ -0,0 +1,6 @@ +``` +$ echo "hello" "second argument" | \ +> lines-from-stdin=1 bin-fixture +read line from stdin: hello second argument + +```