diff --git a/src/assert.rs b/src/assert.rs index 6824930..42dacab 100644 --- a/src/assert.rs +++ b/src/assert.rs @@ -7,7 +7,7 @@ use std::str; use predicates; use predicates::str::PredicateStrExt; -use cmd::dump_buffer; +use errors::dump_buffer; use errors::output_fmt; /// Assert the state of an `Output`. @@ -51,7 +51,7 @@ impl OutputAssertExt for process::Output { impl<'c> OutputAssertExt for &'c mut process::Command { fn assert(self) -> Assert { let output = self.output().unwrap(); - Assert::new(output).set_cmd(format!("{:?}", self)) + Assert::new(output).append_context("command", format!("{:?}", self)) } } @@ -71,11 +71,9 @@ impl<'c> OutputAssertExt for &'c mut process::Command { /// .assert() /// .success(); /// ``` -#[derive(Debug)] pub struct Assert { output: process::Output, - cmd: Option, - stdin: Option>, + context: Vec<(&'static str, Box)>, } impl Assert { @@ -83,20 +81,16 @@ impl Assert { pub fn new(output: process::Output) -> Self { Self { output, - cmd: None, - stdin: None, + context: vec![], } } - /// Add the command line for additional context. - pub fn set_cmd(mut self, cmd: String) -> Self { - self.cmd = Some(cmd); - self - } - - /// Add the `stdn` for additional context. - pub fn set_stdin(mut self, stdin: Vec) -> Self { - self.stdin = Some(stdin); + /// Clarify failures with additional context. + pub fn append_context(mut self, name: &'static str, context: D) -> Self + where + D: fmt::Display + 'static, + { + self.context.push((name, Box::new(context))); self } @@ -298,20 +292,21 @@ impl Assert { impl fmt::Display for Assert { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(ref cmd) = self.cmd { - writeln!(f, "command=`{}`", cmd)?; - } - if let Some(ref stdin) = self.stdin { - if let Ok(stdin) = str::from_utf8(stdin) { - writeln!(f, "stdin=```{}```", stdin)?; - } else { - writeln!(f, "stdin=```{:?}```", stdin)?; - } + for (name, context) in &self.context { + writeln!(f, "{}=`{}`", name, context)?; } output_fmt(&self.output, f) } } +impl fmt::Debug for Assert { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Assert") + .field("output", &self.output) + .finish() + } +} + /// Used by `Assert::code` to convert `Self` into the needed `Predicate`. /// /// # Examples diff --git a/src/cmd.rs b/src/cmd.rs index df39c46..c814687 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -1,6 +1,6 @@ use std::process; -use std::str; +use errors::dump_buffer; use errors::OutputError; use errors::OutputResult; @@ -116,11 +116,3 @@ impl<'c> OutputOkExt for &'c mut process::Command { } } } - -pub(crate) fn dump_buffer(buffer: &[u8]) -> String { - if let Ok(buffer) = str::from_utf8(buffer) { - buffer.to_string() - } else { - format!("{:?}", buffer) - } -} diff --git a/src/errors.rs b/src/errors.rs index 46dbb4e..fc173f7 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -162,16 +162,47 @@ pub(crate) fn output_fmt(output: &process::Output, f: &mut fmt::Formatter) -> fm } else { writeln!(f, "code=")?; } - if let Ok(stdout) = str::from_utf8(&output.stdout) { - writeln!(f, "stdout=```{}```", stdout)?; + + write!(f, "stdout=```")?; + write_buffer(&output.stdout, f)?; + writeln!(f, "```")?; + + write!(f, "stderr=```")?; + write_buffer(&output.stderr, f)?; + writeln!(f, "```")?; + + Ok(()) +} + +pub(crate) fn dump_buffer(buffer: &[u8]) -> String { + if let Ok(buffer) = str::from_utf8(buffer) { + buffer.to_string() } else { - writeln!(f, "stdout=```{:?}```", output.stdout)?; + format!("{:?}", buffer) } - if let Ok(stderr) = str::from_utf8(&output.stderr) { - writeln!(f, "stderr=```{}```", stderr)?; +} + +pub(crate) fn write_buffer(buffer: &[u8], f: &mut fmt::Formatter) -> fmt::Result { + if let Ok(buffer) = str::from_utf8(buffer) { + write!(f, "{}", buffer) } else { - writeln!(f, "stderr=```{:?}```", output.stderr)?; + write!(f, "{:?}", buffer) + } +} + +#[derive(Debug)] +pub(crate) struct DebugBuffer { + buffer: Vec, +} + +impl DebugBuffer { + pub(crate) fn new(buffer: Vec) -> Self { + DebugBuffer { buffer } } +} - Ok(()) +impl fmt::Display for DebugBuffer { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write_buffer(&self.buffer, f) + } } diff --git a/src/stdin.rs b/src/stdin.rs index df5ecea..ff71988 100644 --- a/src/stdin.rs +++ b/src/stdin.rs @@ -7,8 +7,9 @@ use std::process; use assert::Assert; use assert::OutputAssertExt; -use cmd::dump_buffer; use cmd::OutputOkExt; +use errors::dump_buffer; +use errors::DebugBuffer; use errors::OutputError; use errors::OutputResult; @@ -189,7 +190,7 @@ impl<'c> OutputAssertExt for &'c mut StdInCommand<'c> { fn assert(self) -> Assert { let output = self.output().unwrap(); Assert::new(output) - .set_cmd(format!("{:?}", self.cmd)) - .set_stdin(self.stdin.clone()) + .append_context("command", format!("{:?}", self.cmd)) + .append_context("stdin", DebugBuffer::new(self.stdin.clone())) } }