From 9246751e90d48d67965d08bda94e643d98841ba5 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 8 Sep 2017 07:18:33 -0600 Subject: [PATCH 1/4] Add negative versions of string matches - `.doesnt_print`, `.doesnt_print_exactly` - `.doesnt_print_error`, `.doesnt_print_error_exactly` Fixes #31 --- src/lib.rs | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/output.rs | 35 ++++++++++++++----- 2 files changed, 123 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 215c1fe..2edd454 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -309,6 +309,7 @@ impl Assert { self.expect_stdout = Some(OutputAssertion { expect: output.into(), fuzzy: true, + expected_result: true, kind: StdOut, }); self @@ -329,6 +330,7 @@ impl Assert { self.expect_stdout = Some(OutputAssertion { expect: output.into(), fuzzy: false, + expected_result: true, kind: StdOut, }); self @@ -351,6 +353,7 @@ impl Assert { self.expect_stderr = Some(OutputAssertion { expect: output.into(), fuzzy: true, + expected_result: true, kind: StdErr, }); self @@ -373,6 +376,99 @@ impl Assert { self.expect_stderr = Some(OutputAssertion { expect: output.into(), fuzzy: false, + expected_result: true, + kind: StdErr, + }); + self + } + + /// Expect the command's output to not **contain** `output`. + /// + /// # Examples + /// + /// ```rust + /// extern crate assert_cli; + /// + /// assert_cli::Assert::command(&["echo", "42"]) + /// .doesnt_print("73") + /// .execute() + /// .unwrap(); + /// ``` + pub fn doesnt_print>(mut self, output: O) -> Self { + self.expect_stdout = Some(OutputAssertion { + expect: output.into(), + fuzzy: true, + expected_result: false, + kind: StdOut, + }); + self + } + + /// Expect the command to output to not be **exactly** this `output`. + /// + /// # Examples + /// + /// ```rust + /// extern crate assert_cli; + /// + /// assert_cli::Assert::command(&["echo", "42"]) + /// .doesnt_print_exactly("73") + /// .execute() + /// .unwrap(); + /// ``` + pub fn doesnt_print_exactly>(mut self, output: O) -> Self { + self.expect_stdout = Some(OutputAssertion { + expect: output.into(), + fuzzy: false, + expected_result: false, + kind: StdOut, + }); + self + } + + /// Expect the command's stderr output to not **contain** `output`. + /// + /// # Examples + /// + /// ```rust + /// extern crate assert_cli; + /// + /// assert_cli::Assert::command(&["cat", "non-existing-file"]) + /// .fails() + /// .and() + /// .doesnt_print_error("content") + /// .execute() + /// .unwrap(); + /// ``` + pub fn doesnt_print_error>(mut self, output: O) -> Self { + self.expect_stderr = Some(OutputAssertion { + expect: output.into(), + fuzzy: true, + expected_result: false, + kind: StdErr, + }); + self + } + + /// Expect the command to output to not be **exactly** this `output` to stderr. + /// + /// # Examples + /// + /// ```rust + /// extern crate assert_cli; + /// + /// assert_cli::Assert::command(&["cat", "non-existing-file"]) + /// .fails_with(1) + /// .and() + /// .doesnt_print_error_exactly("content") + /// .execute() + /// .unwrap(); + /// ``` + pub fn doesnt_print_error_exactly>(mut self, output: O) -> Self { + self.expect_stderr = Some(OutputAssertion { + expect: output.into(), + fuzzy: false, + expected_result: false, kind: StdErr, }); self diff --git a/src/output.rs b/src/output.rs index 34c975c..b95fee2 100644 --- a/src/output.rs +++ b/src/output.rs @@ -11,13 +11,19 @@ use diff; pub struct OutputAssertion { pub expect: String, pub fuzzy: bool, + pub expected_result: bool, pub kind: T, } impl OutputAssertion { fn matches_fuzzy(&self, got: &str) -> Result<()> { - if !got.contains(&self.expect) { - bail!(ErrorKind::OutputMismatch(self.expect.clone(), got.into())); + let result = got.contains(&self.expect); + if result != self.expected_result { + if self.expected_result { + bail!(ErrorKind::OutputDoesntContain(self.expect.clone(), got.into())); + } else { + bail!(ErrorKind::OutputContains(self.expect.clone(), got.into())); + } } Ok(()) @@ -25,10 +31,15 @@ impl OutputAssertion { fn matches_exact(&self, got: &str) -> Result<()> { let differences = Changeset::new(self.expect.trim(), got.trim(), "\n"); - - if differences.distance > 0 { - let nice_diff = diff::render(&differences)?; - bail!(ErrorKind::ExactOutputMismatch(nice_diff)); + let result = differences.distance == 0; + + if result != self.expected_result { + if self.expected_result { + let nice_diff = diff::render(&differences)?; + bail!(ErrorKind::OutputDoesntMatch(nice_diff)); + } else { + bail!(ErrorKind::OutputMatches(got.to_owned())); + } } Ok(()) @@ -88,14 +99,22 @@ mod errors { Fmt(::std::fmt::Error); } errors { - OutputMismatch(expected: String, got: String) { + OutputDoesntContain(expected: String, got: String) { description("Output was not as expected") display("expected to contain {:?}, got {:?}", expected, got) } - ExactOutputMismatch(diff: String) { + OutputContains(expected: String, got: String) { + description("Output was not as expected") + display("expected to not contain {:?}, got {:?}", expected, got) + } + OutputDoesntMatch(diff: String) { description("Output was not as expected") display("{}", diff) } + OutputMatches(got: String) { + description("Output was not as expected") + display("{}", got) + } } } } From 69c8c858cad98421fc56699274f35672d2da9618 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 8 Sep 2017 20:50:21 -0600 Subject: [PATCH 2/4] Split assert code into distinct module --- src/assert.rs | 431 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 431 +------------------------------------------------- 2 files changed, 433 insertions(+), 429 deletions(-) create mode 100644 src/assert.rs diff --git a/src/assert.rs b/src/assert.rs new file mode 100644 index 0000000..4a70290 --- /dev/null +++ b/src/assert.rs @@ -0,0 +1,431 @@ +use std::default; +use std::process::Command; +use std::path::PathBuf; + +use errors::*; +use output::{OutputAssertion, StdErr, StdOut}; + +/// Assertions for a specific command. +#[derive(Debug)] +pub struct Assert { + cmd: Vec, + current_dir: Option, + expect_success: Option, + expect_exit_code: Option, + expect_stdout: Option>, + expect_stderr: Option>, +} + +impl default::Default for Assert { + /// Construct an assert using `cargo run --` as command. + /// + /// Defaults to asserting _successful_ execution. + fn default() -> Self { + Assert { + cmd: vec!["cargo", "run", "--"] + .into_iter().map(String::from).collect(), + current_dir: None, + expect_success: Some(true), + expect_exit_code: None, + expect_stdout: None, + expect_stderr: None, + } + } +} + +impl Assert { + /// Run the crate's main binary. + /// + /// Defaults to asserting _successful_ execution. + pub fn main_binary() -> Self { + Assert::default() + } + + /// Run a specific binary of the current crate. + /// + /// Defaults to asserting _successful_ execution. + pub fn cargo_binary(name: &str) -> Self { + Assert { + cmd: vec!["cargo", "run", "--bin", name, "--"] + .into_iter().map(String::from).collect(), + ..Self::default() + } + } + + /// Run a custom command. + /// + /// Defaults to asserting _successful_ execution. + /// + /// # Examples + /// + /// ```rust + /// extern crate assert_cli; + /// + /// assert_cli::Assert::command(&["echo", "1337"]) + /// .unwrap(); + /// ``` + pub fn command(cmd: &[&str]) -> Self { + Assert { + cmd: cmd.into_iter().cloned().map(String::from).collect(), + ..Self::default() + } + } + + /// Add arguments to the command. + /// + /// # Examples + /// + /// ```rust + /// extern crate assert_cli; + /// + /// assert_cli::Assert::command(&["echo"]) + /// .with_args(&["42"]) + /// .prints("42") + /// .unwrap(); + /// ``` + pub fn with_args(mut self, args: &[&str]) -> Self { + self.cmd.extend(args.into_iter().cloned().map(String::from)); + self + } + + /// Sets the working directory for the command. + /// + /// # Examples + /// + /// ```rust + /// extern crate assert_cli; + /// + /// assert_cli::Assert::command(&["wc", "lib.rs"]) + /// .current_dir(std::path::Path::new("src")) + /// .prints("lib.rs") + /// .execute() + /// .unwrap(); + /// ``` + pub fn current_dir>(mut self, dir: P) -> Self { + self.current_dir = Some(dir.into()); + self + } + + /// Small helper to make chains more readable. + /// + /// # Examples + /// + /// ```rust + /// extern crate assert_cli; + /// + /// assert_cli::Assert::command(&["echo", "42"]) + /// .prints("42") + /// .unwrap(); + /// ``` + pub fn and(self) -> Self { + self + } + + /// Expect the command to be executed successfully. + /// + /// # Examples + /// + /// ```rust + /// extern crate assert_cli; + /// + /// assert_cli::Assert::command(&["echo", "42"]) + /// .unwrap(); + /// ``` + pub fn succeeds(mut self) -> Self { + self.expect_exit_code = None; + self.expect_success = Some(true); + self + } + + /// Expect the command to fail. + /// + /// Note: This does not include shell failures like `command not found`. I.e. the + /// command must _run_ and fail for this assertion to pass. + /// + /// # Examples + /// + /// ```rust + /// extern crate assert_cli; + /// + /// assert_cli::Assert::command(&["cat", "non-existing-file"]) + /// .fails() + /// .and() + /// .prints_error("non-existing-file") + /// .unwrap(); + /// ``` + pub fn fails(mut self) -> Self { + self.expect_success = Some(false); + self + } + + /// Expect the command to fail and return a specific error code. + /// + /// # 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(); + /// ``` + pub fn fails_with(mut self, expect_exit_code: i32) -> Self { + self.expect_success = Some(false); + self.expect_exit_code = Some(expect_exit_code); + self + } + + /// Expect the command's output to **contain** `output`. + /// + /// # Examples + /// + /// ```rust + /// extern crate assert_cli; + /// + /// assert_cli::Assert::command(&["echo", "42"]) + /// .prints("42") + /// .unwrap(); + /// ``` + pub fn prints>(mut self, output: O) -> Self { + self.expect_stdout = Some(OutputAssertion { + expect: output.into(), + fuzzy: true, + expected_result: true, + kind: 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_stdout = Some(OutputAssertion { + expect: output.into(), + fuzzy: false, + expected_result: true, + kind: StdOut, + }); + self + } + + /// Expect the command's stderr output to **contain** `output`. + /// + /// # Examples + /// + /// ```rust + /// extern crate assert_cli; + /// + /// assert_cli::Assert::command(&["cat", "non-existing-file"]) + /// .fails() + /// .and() + /// .prints_error("non-existing-file") + /// .unwrap(); + /// ``` + pub fn prints_error>(mut self, output: O) -> Self { + self.expect_stderr = Some(OutputAssertion { + expect: output.into(), + fuzzy: true, + expected_result: true, + kind: StdErr, + }); + self + } + + /// Expect the command to output **exactly** this `output` to stderr. + /// + /// # 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(); + /// ``` + pub fn prints_error_exactly>(mut self, output: O) -> Self { + self.expect_stderr = Some(OutputAssertion { + expect: output.into(), + fuzzy: false, + expected_result: true, + kind: StdErr, + }); + self + } + + /// Expect the command's output to not **contain** `output`. + /// + /// # Examples + /// + /// ```rust + /// extern crate assert_cli; + /// + /// assert_cli::Assert::command(&["echo", "42"]) + /// .doesnt_print("73") + /// .execute() + /// .unwrap(); + /// ``` + pub fn doesnt_print>(mut self, output: O) -> Self { + self.expect_stdout = Some(OutputAssertion { + expect: output.into(), + fuzzy: true, + expected_result: false, + kind: StdOut, + }); + self + } + + /// Expect the command to output to not be **exactly** this `output`. + /// + /// # Examples + /// + /// ```rust + /// extern crate assert_cli; + /// + /// assert_cli::Assert::command(&["echo", "42"]) + /// .doesnt_print_exactly("73") + /// .execute() + /// .unwrap(); + /// ``` + pub fn doesnt_print_exactly>(mut self, output: O) -> Self { + self.expect_stdout = Some(OutputAssertion { + expect: output.into(), + fuzzy: false, + expected_result: false, + kind: StdOut, + }); + self + } + + /// Expect the command's stderr output to not **contain** `output`. + /// + /// # Examples + /// + /// ```rust + /// extern crate assert_cli; + /// + /// assert_cli::Assert::command(&["cat", "non-existing-file"]) + /// .fails() + /// .and() + /// .doesnt_print_error("content") + /// .execute() + /// .unwrap(); + /// ``` + pub fn doesnt_print_error>(mut self, output: O) -> Self { + self.expect_stderr = Some(OutputAssertion { + expect: output.into(), + fuzzy: true, + expected_result: false, + kind: StdErr, + }); + self + } + + /// Expect the command to output to not be **exactly** this `output` to stderr. + /// + /// # Examples + /// + /// ```rust + /// extern crate assert_cli; + /// + /// assert_cli::Assert::command(&["cat", "non-existing-file"]) + /// .fails_with(1) + /// .and() + /// .doesnt_print_error_exactly("content") + /// .execute() + /// .unwrap(); + /// ``` + pub fn doesnt_print_error_exactly>(mut self, output: O) -> Self { + self.expect_stderr = Some(OutputAssertion { + expect: output.into(), + fuzzy: false, + expected_result: false, + kind: StdErr, + }); + self + } + + /// Execute the command and check the assertions. + /// + /// # Examples + /// + /// ```rust + /// extern crate assert_cli; + /// + /// let test = assert_cli::Assert::command(&["echo", "42"]) + /// .prints("42") + /// .execute(); + /// assert!(test.is_ok()); + /// ``` + 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(), + )); + } + + if let Some(ref ouput_assertion) = self.expect_stdout { + ouput_assertion.execute(&output) + .map_err(|e| ErrorKind::StdoutMismatch(self.cmd.clone(), e))?; + } + + if let Some(ref ouput_assertion) = self.expect_stderr { + ouput_assertion.execute(&output) + .map_err(|e| ErrorKind::StderrMismatch(self.cmd.clone(), e))?; + } + + Ok(()) + } + + /// Execute the command, check the assertions, and panic when they fail. + /// + /// # Examples + /// + /// ```rust,should_panic="Assert CLI failure" + /// extern crate assert_cli; + /// + /// assert_cli::Assert::command(&["echo", "42"]) + /// .fails() + /// .unwrap(); // panics + /// ``` + pub fn unwrap(self) { + if let Err(err) = self.execute() { + panic!("{}", err); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 2edd454..81636be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -108,441 +108,14 @@ extern crate difference; #[macro_use] extern crate error_chain; extern crate rustc_serialize; -use std::process::Command; -use std::path::PathBuf; - mod errors; -use errors::*; #[macro_use] mod macros; pub use macros::flatten_escaped_string; mod output; -use output::{OutputAssertion, StdErr, StdOut}; mod diff; -/// Assertions for a specific command. -#[derive(Debug)] -pub struct Assert { - cmd: Vec, - current_dir: Option, - expect_success: Option, - expect_exit_code: Option, - expect_stdout: Option>, - expect_stderr: Option>, -} - -impl std::default::Default for Assert { - /// Construct an assert using `cargo run --` as command. - /// - /// Defaults to asserting _successful_ execution. - fn default() -> Self { - Assert { - cmd: vec!["cargo", "run", "--"] - .into_iter().map(String::from).collect(), - current_dir: None, - expect_success: Some(true), - expect_exit_code: None, - expect_stdout: None, - expect_stderr: None, - } - } -} - -impl Assert { - /// Run the crate's main binary. - /// - /// Defaults to asserting _successful_ execution. - pub fn main_binary() -> Self { - Assert::default() - } - - /// Run a specific binary of the current crate. - /// - /// Defaults to asserting _successful_ execution. - pub fn cargo_binary(name: &str) -> Self { - Assert { - cmd: vec!["cargo", "run", "--bin", name, "--"] - .into_iter().map(String::from).collect(), - ..Self::default() - } - } - - /// Run a custom command. - /// - /// Defaults to asserting _successful_ execution. - /// - /// # Examples - /// - /// ```rust - /// extern crate assert_cli; - /// - /// assert_cli::Assert::command(&["echo", "1337"]) - /// .unwrap(); - /// ``` - pub fn command(cmd: &[&str]) -> Self { - Assert { - cmd: cmd.into_iter().cloned().map(String::from).collect(), - ..Self::default() - } - } - - /// Add arguments to the command. - /// - /// # Examples - /// - /// ```rust - /// extern crate assert_cli; - /// - /// assert_cli::Assert::command(&["echo"]) - /// .with_args(&["42"]) - /// .prints("42") - /// .unwrap(); - /// ``` - pub fn with_args(mut self, args: &[&str]) -> Self { - self.cmd.extend(args.into_iter().cloned().map(String::from)); - self - } - - /// Sets the working directory for the command. - /// - /// # Examples - /// - /// ```rust - /// extern crate assert_cli; - /// - /// assert_cli::Assert::command(&["wc", "lib.rs"]) - /// .current_dir(std::path::Path::new("src")) - /// .prints("lib.rs") - /// .execute() - /// .unwrap(); - /// ``` - pub fn current_dir>(mut self, dir: P) -> Self { - self.current_dir = Some(dir.into()); - self - } - - /// Small helper to make chains more readable. - /// - /// # Examples - /// - /// ```rust - /// extern crate assert_cli; - /// - /// assert_cli::Assert::command(&["echo", "42"]) - /// .prints("42") - /// .unwrap(); - /// ``` - pub fn and(self) -> Self { - self - } - - /// Expect the command to be executed successfully. - /// - /// # Examples - /// - /// ```rust - /// extern crate assert_cli; - /// - /// assert_cli::Assert::command(&["echo", "42"]) - /// .unwrap(); - /// ``` - pub fn succeeds(mut self) -> Self { - self.expect_exit_code = None; - self.expect_success = Some(true); - self - } - - /// Expect the command to fail. - /// - /// Note: This does not include shell failures like `command not found`. I.e. the - /// command must _run_ and fail for this assertion to pass. - /// - /// # Examples - /// - /// ```rust - /// extern crate assert_cli; - /// - /// assert_cli::Assert::command(&["cat", "non-existing-file"]) - /// .fails() - /// .and() - /// .prints_error("non-existing-file") - /// .unwrap(); - /// ``` - pub fn fails(mut self) -> Self { - self.expect_success = Some(false); - self - } - - /// Expect the command to fail and return a specific error code. - /// - /// # 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(); - /// ``` - pub fn fails_with(mut self, expect_exit_code: i32) -> Self { - self.expect_success = Some(false); - self.expect_exit_code = Some(expect_exit_code); - self - } - - /// Expect the command's output to **contain** `output`. - /// - /// # Examples - /// - /// ```rust - /// extern crate assert_cli; - /// - /// assert_cli::Assert::command(&["echo", "42"]) - /// .prints("42") - /// .unwrap(); - /// ``` - pub fn prints>(mut self, output: O) -> Self { - self.expect_stdout = Some(OutputAssertion { - expect: output.into(), - fuzzy: true, - expected_result: true, - kind: 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_stdout = Some(OutputAssertion { - expect: output.into(), - fuzzy: false, - expected_result: true, - kind: StdOut, - }); - self - } - - /// Expect the command's stderr output to **contain** `output`. - /// - /// # Examples - /// - /// ```rust - /// extern crate assert_cli; - /// - /// assert_cli::Assert::command(&["cat", "non-existing-file"]) - /// .fails() - /// .and() - /// .prints_error("non-existing-file") - /// .unwrap(); - /// ``` - pub fn prints_error>(mut self, output: O) -> Self { - self.expect_stderr = Some(OutputAssertion { - expect: output.into(), - fuzzy: true, - expected_result: true, - kind: StdErr, - }); - self - } - - /// Expect the command to output **exactly** this `output` to stderr. - /// - /// # 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(); - /// ``` - pub fn prints_error_exactly>(mut self, output: O) -> Self { - self.expect_stderr = Some(OutputAssertion { - expect: output.into(), - fuzzy: false, - expected_result: true, - kind: StdErr, - }); - self - } - - /// Expect the command's output to not **contain** `output`. - /// - /// # Examples - /// - /// ```rust - /// extern crate assert_cli; - /// - /// assert_cli::Assert::command(&["echo", "42"]) - /// .doesnt_print("73") - /// .execute() - /// .unwrap(); - /// ``` - pub fn doesnt_print>(mut self, output: O) -> Self { - self.expect_stdout = Some(OutputAssertion { - expect: output.into(), - fuzzy: true, - expected_result: false, - kind: StdOut, - }); - self - } - - /// Expect the command to output to not be **exactly** this `output`. - /// - /// # Examples - /// - /// ```rust - /// extern crate assert_cli; - /// - /// assert_cli::Assert::command(&["echo", "42"]) - /// .doesnt_print_exactly("73") - /// .execute() - /// .unwrap(); - /// ``` - pub fn doesnt_print_exactly>(mut self, output: O) -> Self { - self.expect_stdout = Some(OutputAssertion { - expect: output.into(), - fuzzy: false, - expected_result: false, - kind: StdOut, - }); - self - } - - /// Expect the command's stderr output to not **contain** `output`. - /// - /// # Examples - /// - /// ```rust - /// extern crate assert_cli; - /// - /// assert_cli::Assert::command(&["cat", "non-existing-file"]) - /// .fails() - /// .and() - /// .doesnt_print_error("content") - /// .execute() - /// .unwrap(); - /// ``` - pub fn doesnt_print_error>(mut self, output: O) -> Self { - self.expect_stderr = Some(OutputAssertion { - expect: output.into(), - fuzzy: true, - expected_result: false, - kind: StdErr, - }); - self - } - - /// Expect the command to output to not be **exactly** this `output` to stderr. - /// - /// # Examples - /// - /// ```rust - /// extern crate assert_cli; - /// - /// assert_cli::Assert::command(&["cat", "non-existing-file"]) - /// .fails_with(1) - /// .and() - /// .doesnt_print_error_exactly("content") - /// .execute() - /// .unwrap(); - /// ``` - pub fn doesnt_print_error_exactly>(mut self, output: O) -> Self { - self.expect_stderr = Some(OutputAssertion { - expect: output.into(), - fuzzy: false, - expected_result: false, - kind: StdErr, - }); - self - } - - /// Execute the command and check the assertions. - /// - /// # Examples - /// - /// ```rust - /// extern crate assert_cli; - /// - /// let test = assert_cli::Assert::command(&["echo", "42"]) - /// .prints("42") - /// .execute(); - /// assert!(test.is_ok()); - /// ``` - 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(), - )); - } - - if let Some(ref ouput_assertion) = self.expect_stdout { - ouput_assertion.execute(&output) - .map_err(|e| ErrorKind::StdoutMismatch(self.cmd.clone(), e))?; - } - - if let Some(ref ouput_assertion) = self.expect_stderr { - ouput_assertion.execute(&output) - .map_err(|e| ErrorKind::StderrMismatch(self.cmd.clone(), e))?; - } - - Ok(()) - } - - /// Execute the command, check the assertions, and panic when they fail. - /// - /// # Examples - /// - /// ```rust,should_panic="Assert CLI failure" - /// extern crate assert_cli; - /// - /// assert_cli::Assert::command(&["echo", "42"]) - /// .fails() - /// .unwrap(); // panics - /// ``` - pub fn unwrap(self) { - if let Err(err) = self.execute() { - panic!("{}", err); - } - } -} +mod assert; +pub use assert::Assert; From 0404ec0e5b1cd94f305f99928347d9bd2bd422c1 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 8 Sep 2017 21:06:02 -0600 Subject: [PATCH 3/4] Upgrade dependencies --- Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5d53d06..8b92925 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,16 +13,16 @@ keywords = ["cli", "testing", "assert"] build = "build.rs" [dependencies] -colored = "1.4" +colored = "1.5" difference = "1.0" -error-chain = "0.10.0" +error-chain = "0.11" rustc-serialize = "0.3" [build-dependencies] -skeptic = "0.5" +skeptic = "0.13" [dev-dependencies] -skeptic = "0.5" +skeptic = "0.13" [badges] travis-ci = { repository = "killercup/assert_cli" } From 433bbc2ff14c9848033fdb7600fffab3bf182c32 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 8 Sep 2017 21:17:21 -0600 Subject: [PATCH 4/4] Remove dependency on rustc_serialize --- Cargo.toml | 2 +- src/lib.rs | 2 +- src/macros.rs | 37 ++++++++++++++++++++++++++++++++----- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8b92925..4444670 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ build = "build.rs" colored = "1.5" difference = "1.0" error-chain = "0.11" -rustc-serialize = "0.3" +serde_json = "1.0" [build-dependencies] skeptic = "0.13" diff --git a/src/lib.rs b/src/lib.rs index 81636be..425ceae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -106,7 +106,7 @@ extern crate difference; #[macro_use] extern crate error_chain; -extern crate rustc_serialize; +extern crate serde_json; mod errors; diff --git a/src/macros.rs b/src/macros.rs index 7377ce7..1c92529 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,5 +1,5 @@ use std::borrow::Cow; -use rustc_serialize::json::Json; +use serde_json; /// Easily construct an `Assert` with a custom command. /// @@ -50,10 +50,8 @@ macro_rules! assert_cmd { /// If `x` can not be decoded as `String`. #[doc(hidden)] fn deserialize_json_string(x: &str) -> String { - match Json::from_str(x).expect(&format!("Unable to deserialize `{:?}` as string.", x)) { - Json::String(deserialized) => deserialized, - _ => panic!("Unable to deserialize `{:?}` as string.", x), - } + serde_json::from_str(x) + .expect(&format!("Unable to deserialize `{:?}` as string.", x)) } /// Deserialize a JSON-encoded `String`. @@ -99,3 +97,32 @@ macro_rules! __assert_single_token_expression { // little helper (@DENY) => { }; } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn flatten_unquoted() + { + assert_eq!( + flatten_escaped_string("hello world"), + "hello world"); + } + + #[test] + fn flatten_quoted() + { + assert_eq!( + flatten_escaped_string(r#""hello world""#), + "hello world"); + } + + #[test] + fn flatten_escaped() + { + assert_eq!( + flatten_escaped_string(r#""hello world \u0042 A""#), + "hello world B A"); + } +}