From 1f042baec10060f46c4222860929235bc206c68e Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 13 Sep 2017 11:33:01 -0600 Subject: [PATCH] Change stdout/sterr asseertion API BREAKING CHANGE: - `.prints` -> `.stdout().contains` - `.prints_exactly` -> `.stdout().is` - `.prints_error` -> `.stderr().contains` - `.prints_error_exactly` -> `.stderr().is` --- README.md | 10 +- src/assert.rs | 259 +++++++++++++++++++++----------------------------- src/lib.rs | 12 +-- src/macros.rs | 2 +- 4 files changed, 120 insertions(+), 163 deletions(-) diff --git a/README.md b/README.md index ae97974..796d975 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Here's a trivial example: extern crate assert_cli; fn main() { - assert_cli::Assert::command(&["echo", "42"]).prints("42").unwrap(); + assert_cli::Assert::command(&["echo", "42"]).stdout().contains("42").unwrap(); } ``` @@ -31,7 +31,7 @@ Or if you'd rather use the macro, to save you some writing: #[macro_use] extern crate assert_cli; fn main() { - assert_cmd!(echo "42").prints("42").unwrap(); + assert_cmd!(echo "42").stdout().contains("42").unwrap(); } ``` @@ -45,21 +45,21 @@ fn main() { let test = assert_cmd!(ls "foo-bar-foo") .fails() .and() - .prints_error("foo-bar-foo") + .stderr().contains("foo-bar-foo") .execute(); assert!(test.is_ok()); } ``` If you want to match the program's output _exactly_, you can use -`prints_exactly`: +`stdout().is`: ```rust,should_panic #[macro_use] extern crate assert_cli; fn main() { assert_cmd!(wc "README.md") - .prints_exactly("1337 README.md") + .stdout().is("1337 README.md") .unwrap(); } ``` diff --git a/src/assert.rs b/src/assert.rs index e4a43f4..ca03e26 100644 --- a/src/assert.rs +++ b/src/assert.rs @@ -79,7 +79,7 @@ impl Assert { /// /// assert_cli::Assert::command(&["echo"]) /// .with_args(&["42"]) - /// .prints("42") + /// .stdout().contains("42") /// .unwrap(); /// ``` pub fn with_args(mut self, args: &[&str]) -> Self { @@ -96,7 +96,7 @@ impl Assert { /// /// assert_cli::Assert::command(&["wc", "lib.rs"]) /// .current_dir(std::path::Path::new("src")) - /// .prints("lib.rs") + /// .stdout().contains("lib.rs") /// .execute() /// .unwrap(); /// ``` @@ -113,7 +113,7 @@ impl Assert { /// extern crate assert_cli; /// /// assert_cli::Assert::command(&["echo", "42"]) - /// .prints("42") + /// .stdout().contains("42") /// .unwrap(); /// ``` pub fn and(self) -> Self { @@ -149,7 +149,7 @@ impl Assert { /// assert_cli::Assert::command(&["cat", "non-existing-file"]) /// .fails() /// .and() - /// .prints_error("non-existing-file") + /// .stderr().contains("non-existing-file") /// .unwrap(); /// ``` pub fn fails(mut self) -> Self { @@ -167,7 +167,7 @@ impl Assert { /// assert_cli::Assert::command(&["cat", "non-existing-file"]) /// .fails_with(1) /// .and() - /// .prints_error_exactly("cat: non-existing-file: No such file or directory") + /// .stderr().is("cat: non-existing-file: No such file or directory") /// .unwrap(); /// ``` pub fn fails_with(mut self, expect_exit_code: i32) -> Self { @@ -176,7 +176,7 @@ impl Assert { self } - /// Expect the command's output to **contain** `output`. + /// Create an assertion for stdout's contents /// /// # Examples /// @@ -184,41 +184,18 @@ impl Assert { /// extern crate assert_cli; /// /// assert_cli::Assert::command(&["echo", "42"]) - /// .prints("42") + /// .stdout().contains("42") /// .unwrap(); /// ``` - pub fn prints>(mut self, output: O) -> Self { - self.expect_output.push(OutputAssertion { - expect: output.into(), - fuzzy: true, - expected_result: true, + pub fn stdout(self) -> OutputAssertionBuilder { + OutputAssertionBuilder { + assertion: self, kind: OutputKind::StdOut, - }); - self - } - - /// Expect the command to output **exactly** this `output`. - /// - /// # Examples - /// - /// ```rust - /// extern crate assert_cli; - /// - /// assert_cli::Assert::command(&["echo", "42"]) - /// .prints_exactly("42") - /// .unwrap(); - /// ``` - pub fn prints_exactly>(mut self, output: O) -> Self { - self.expect_output.push(OutputAssertion { - expect: output.into(), - fuzzy: false, expected_result: true, - kind: OutputKind::StdOut, - }); - self + } } - /// Expect the command's stderr output to **contain** `output`. + /// Create an assertion for stdout's contents /// /// # Examples /// @@ -226,67 +203,95 @@ impl Assert { /// extern crate assert_cli; /// /// assert_cli::Assert::command(&["cat", "non-existing-file"]) - /// .fails() + /// .fails_with(1) /// .and() - /// .prints_error("non-existing-file") + /// .stderr().is("cat: non-existing-file: No such file or directory") /// .unwrap(); /// ``` - pub fn prints_error>(mut self, output: O) -> Self { - self.expect_output.push(OutputAssertion { - expect: output.into(), - fuzzy: true, - expected_result: true, + pub fn stderr(self) -> OutputAssertionBuilder { + OutputAssertionBuilder { + assertion: self, kind: OutputKind::StdErr, - }); - self + expected_result: true, + } } - /// Expect the command to output **exactly** this `output` to stderr. + /// Execute the command and check the assertions. /// /// # Examples /// /// ```rust /// extern crate assert_cli; /// - /// assert_cli::Assert::command(&["cat", "non-existing-file"]) - /// .fails_with(1) - /// .and() - /// .prints_error_exactly("cat: non-existing-file: No such file or directory") - /// .unwrap(); + /// let test = assert_cli::Assert::command(&["echo", "42"]) + /// .stdout().contains("42") + /// .execute(); + /// assert!(test.is_ok()); /// ``` - pub fn prints_error_exactly>(mut self, output: O) -> Self { - self.expect_output.push(OutputAssertion { - expect: output.into(), - fuzzy: false, - expected_result: true, - kind: OutputKind::StdErr, - }); - self + pub fn execute(self) -> Result<()> { + let cmd = &self.cmd[0]; + let args: Vec<_> = self.cmd.iter().skip(1).collect(); + let mut command = Command::new(cmd); + let command = command.args(&args); + let command = match self.current_dir { + Some(ref dir) => command.current_dir(dir), + None => command, + }; + let output = command.output()?; + + if let Some(expect_success) = self.expect_success { + if expect_success != output.status.success() { + bail!(ErrorKind::StatusMismatch( + self.cmd.clone(), + expect_success, + )); + } + } + + if self.expect_exit_code.is_some() && + self.expect_exit_code != output.status.code() { + bail!(ErrorKind::ExitCodeMismatch( + self.cmd.clone(), + self.expect_exit_code, + output.status.code(), + )); + } + + self.expect_output + .iter() + .map(|a| a.execute(&output, &self.cmd)) + .collect::>>()?; + + Ok(()) } - /// Expect the command's output to not **contain** `output`. + /// Execute the command, check the assertions, and panic when they fail. /// /// # Examples /// - /// ```rust + /// ```rust,should_panic="Assert CLI failure" /// extern crate assert_cli; /// /// assert_cli::Assert::command(&["echo", "42"]) - /// .doesnt_print("73") - /// .execute() - /// .unwrap(); + /// .fails() + /// .unwrap(); // panics /// ``` - pub fn doesnt_print>(mut self, output: O) -> Self { - self.expect_output.push(OutputAssertion { - expect: output.into(), - fuzzy: true, - expected_result: false, - kind: OutputKind::StdOut, - }); - self + pub fn unwrap(self) { + if let Err(err) = self.execute() { + panic!("{}", err); + } } +} - /// Expect the command to output to not be **exactly** this `output`. +#[derive(Debug)] +pub struct OutputAssertionBuilder { + pub assertion: Assert, + pub kind: OutputKind, + pub expected_result: bool, +} + +impl OutputAssertionBuilder { + /// Negate the assertion predicate /// /// # Examples /// @@ -294,131 +299,83 @@ impl Assert { /// extern crate assert_cli; /// /// assert_cli::Assert::command(&["echo", "42"]) - /// .doesnt_print_exactly("73") - /// .execute() + /// .stdout().not().contains("73") /// .unwrap(); /// ``` - pub fn doesnt_print_exactly>(mut self, output: O) -> Self { - self.expect_output.push(OutputAssertion { - expect: output.into(), - fuzzy: false, - expected_result: false, - kind: OutputKind::StdOut, - }); + pub fn not(mut self) -> Self { + self.expected_result = ! self.expected_result; self } - /// Expect the command's stderr output to not **contain** `output`. + /// Expect the command's output to **contain** `output`. /// /// # Examples /// /// ```rust /// extern crate assert_cli; /// - /// assert_cli::Assert::command(&["cat", "non-existing-file"]) - /// .fails() - /// .and() - /// .doesnt_print_error("content") - /// .execute() + /// assert_cli::Assert::command(&["echo", "42"]) + /// .stdout().contains("42") /// .unwrap(); /// ``` - pub fn doesnt_print_error>(mut self, output: O) -> Self { - self.expect_output.push(OutputAssertion { + pub fn contains>(mut self, output: O) -> Assert { + self.assertion.expect_output.push(OutputAssertion { expect: output.into(), fuzzy: true, - expected_result: false, - kind: OutputKind::StdErr, + expected_result: self.expected_result, + kind: self.kind, }); - self + self.assertion } - /// Expect the command to output to not be **exactly** this `output` to stderr. + /// Expect the command to output **exactly** this `output`. /// /// # Examples /// /// ```rust /// extern crate assert_cli; /// - /// assert_cli::Assert::command(&["cat", "non-existing-file"]) - /// .fails_with(1) - /// .and() - /// .doesnt_print_error_exactly("content") - /// .execute() + /// assert_cli::Assert::command(&["echo", "42"]) + /// .stdout().is("42") /// .unwrap(); /// ``` - pub fn doesnt_print_error_exactly>(mut self, output: O) -> Self { - self.expect_output.push(OutputAssertion { + pub fn is>(mut self, output: O) -> Assert { + self.assertion.expect_output.push(OutputAssertion { expect: output.into(), fuzzy: false, - expected_result: false, - kind: OutputKind::StdErr, + expected_result: self.expected_result, + kind: self.kind, }); - self + self.assertion } - /// Execute the command and check the assertions. + /// Expect the command's output to not **contain** `output`. /// /// # Examples /// /// ```rust /// extern crate assert_cli; /// - /// let test = assert_cli::Assert::command(&["echo", "42"]) - /// .prints("42") - /// .execute(); - /// assert!(test.is_ok()); + /// assert_cli::Assert::command(&["echo", "42"]) + /// .stdout().doesnt_contain("73") + /// .unwrap(); /// ``` - pub fn execute(self) -> Result<()> { - let cmd = &self.cmd[0]; - let args: Vec<_> = self.cmd.iter().skip(1).collect(); - let mut command = Command::new(cmd); - let command = command.args(&args); - let command = match self.current_dir { - Some(ref dir) => command.current_dir(dir), - None => command, - }; - let output = command.output()?; - - if let Some(expect_success) = self.expect_success { - if expect_success != output.status.success() { - bail!(ErrorKind::StatusMismatch( - self.cmd.clone(), - expect_success, - )); - } - } - - if self.expect_exit_code.is_some() && - self.expect_exit_code != output.status.code() { - bail!(ErrorKind::ExitCodeMismatch( - self.cmd.clone(), - self.expect_exit_code, - output.status.code(), - )); - } - - self.expect_output - .iter() - .map(|a| a.execute(&output, &self.cmd)) - .collect::>>()?; - - Ok(()) + pub fn doesnt_contain>(self, output: O) -> Assert { + self.not().contains(output) } - /// Execute the command, check the assertions, and panic when they fail. + /// Expect the command to output to not be **exactly** this `output`. /// /// # Examples /// - /// ```rust,should_panic="Assert CLI failure" + /// ```rust /// extern crate assert_cli; /// /// assert_cli::Assert::command(&["echo", "42"]) - /// .fails() - /// .unwrap(); // panics + /// .stdout().isnt("73") + /// .unwrap(); /// ``` - pub fn unwrap(self) { - if let Err(err) = self.execute() { - panic!("{}", err); - } + pub fn isnt>(self, output: O) -> Assert { + self.not().is(output) } } diff --git a/src/lib.rs b/src/lib.rs index 425ceae..f36cbc7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ //! //! ```rust //! assert_cli::Assert::command(&["echo", "42"]) -//! .prints("42") +//! .stdout().contains("42") //! .unwrap(); //! ``` //! @@ -26,7 +26,7 @@ //! //! ```rust,should_panic //! assert_cli::Assert::command(&["echo", "42"]) -//! .prints_exactly("1337") +//! .stdout().is("1337") //! .unwrap(); //! ``` //! @@ -45,7 +45,7 @@ //! ```rust //! # #[macro_use] extern crate assert_cli; //! # fn main() { -//! assert_cmd!(echo "42").prints("42").unwrap(); +//! assert_cmd!(echo "42").stdout().contains("42").unwrap(); //! # } //! ``` //! @@ -68,7 +68,7 @@ //! assert_cmd!(cat "non-existing-file") //! .fails() //! .and() -//! .prints_error("non-existing-file") +//! .stderr().contains("non-existing-file") //! .unwrap(); //! # } //! ``` @@ -78,7 +78,7 @@ //! - Use `fails_with` to assert a specific exit status. //! - There is also a `succeeds` method, but this is already the implicit default //! and can usually be omitted. -//! - We can inspect the output of **stderr** with `prints_error` and `prints_error_exactly`. +//! - We can inspect the output of **stderr** with `stderr().contains` and `stderr().is`. //! - The `and` method has no effect, other than to make everything more readable. //! Feel free to use it. :-) //! @@ -97,7 +97,7 @@ //! ```rust //! # #[macro_use] extern crate assert_cli; //! # fn main() { -//! let x = assert_cmd!(echo "1337").prints_exactly("42").execute(); +//! let x = assert_cmd!(echo "1337").stdout().is("42").execute(); //! assert!(x.is_err()); //! # } //! ``` diff --git a/src/macros.rs b/src/macros.rs index 1c92529..1078032 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -22,7 +22,7 @@ use serde_json; /// # fn main() { /// assert_cmd!(echo "Launch sequence initiated.\nNo errors whatsoever!\n") /// .succeeds() -/// .prints("No errors whatsoever") +/// .stdout().contains("No errors whatsoever") /// .unwrap(); /// # } /// ```