-
Notifications
You must be signed in to change notification settings - Fork 21
Review/feedback #16
Review/feedback #16
Changes from 1 commit
5681d0b
ed19a66
cc2d7be
cdf0d1e
0ee479c
fcd20f1
1f29f4f
f45db85
8a01125
e307b80
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -76,7 +76,8 @@ | |
extern crate difference; | ||
#[macro_use] extern crate error_chain; | ||
|
||
use std::process::Command; | ||
use std::process::{Command, Output}; | ||
use std::fmt; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are there any style recommendations how to order use and mod statements? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When I think about it, I do it like
and sort the individual blocks alphanumerically There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, that sounds good. But when
But I've also seen |
||
|
||
use difference::Changeset; | ||
|
||
|
@@ -101,6 +102,30 @@ struct OutputAssertion { | |
fuzzy: bool, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like the way you split out this struct, it's very neat. Seeing how the code below with the matches on fuzziness etc. is pretty much duplicated, I'm wondering if maybe it can become a method on this type, like At one point I was thinking about introducing an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest we start a separate discussion about future refactoring, e.g. in the ticket #20 you created, or yet another general architecture discussion ticket? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, I think I'll just open a new PR where I try that design after this one gets merged. Issues that are not about bugs or features but contain a ton of quoted code are kinda hard to keep track of :) |
||
} | ||
|
||
#[derive(Debug, Copy, Clone)] | ||
enum OutputType { | ||
StdOut, | ||
StdErr, | ||
} | ||
|
||
impl OutputType { | ||
fn select<'a>(&self, o: &'a Output) -> &'a [u8] { | ||
match *self { | ||
OutputType::StdOut => &o.stdout, | ||
OutputType::StdErr => &o.stderr, | ||
} | ||
} | ||
} | ||
|
||
impl fmt::Display for OutputType { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
match *self { | ||
OutputType::StdOut => write!(f, "stdout"), | ||
OutputType::StdErr => write!(f, "stderr"), | ||
} | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of doing this – an enum with two impl blocks – we could also use two unit structs and introduce a trait This way (as alluded to above) we can add a field I'm not sure this is a truly nicer design; I got the idea from wanting to encapsulate the whole output comparison business. Maybe it's totally over engineered 😄 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I generally tend to prefer traits too. Hm, maybe we keep that idea in mind for the 'general architecture' discussion? |
||
|
||
impl std::default::Default for Assert { | ||
/// Construct an assert using `cargo run --` as command. | ||
/// | ||
|
@@ -357,57 +382,52 @@ impl Assert { | |
)); | ||
} | ||
|
||
let stdout = String::from_utf8_lossy(&output.stdout); | ||
match self.expect_stdout { | ||
self.assert_output(OutputType::StdOut, &output)?; | ||
self.assert_output(OutputType::StdErr, &output)?; | ||
|
||
Ok(()) | ||
} | ||
|
||
/// Perform the appropriate output assertion. | ||
fn assert_output(&self, output_type: OutputType, output: &Output) -> Result<()> { | ||
let observed = String::from_utf8_lossy(output_type.select(output)); | ||
match *self.expect_output(output_type) { | ||
Some(OutputAssertion { | ||
expect: ref expected_output, | ||
fuzzy: true, | ||
}) if !stdout.contains(expected_output) => { | ||
}) if !observed.contains(expected_output) => { | ||
bail!(ErrorKind::OutputMismatch( | ||
output_type.to_string(), | ||
self.cmd.clone(), | ||
expected_output.clone(), | ||
stdout.into(), | ||
observed.into(), | ||
)); | ||
}, | ||
Some(OutputAssertion { | ||
expect: ref expected_output, | ||
fuzzy: false, | ||
}) => { | ||
let differences = Changeset::new(expected_output.trim(), stdout.trim(), "\n"); | ||
let differences = Changeset::new(expected_output.trim(), observed.trim(), "\n"); | ||
if differences.distance > 0 { | ||
let nice_diff = diff::render(&differences)?; | ||
bail!(ErrorKind::ExactOutputMismatch(self.cmd.clone(), nice_diff)); | ||
bail!(ErrorKind::ExactOutputMismatch( | ||
output_type.to_string(), | ||
self.cmd.clone(), | ||
nice_diff | ||
)); | ||
} | ||
}, | ||
_ => {}, | ||
} | ||
Ok(()) | ||
} | ||
|
||
let stderr = String::from_utf8_lossy(&output.stderr); | ||
match self.expect_stderr { | ||
Some(OutputAssertion { | ||
expect: ref expected_output, | ||
fuzzy: true, | ||
}) if !stderr.contains(expected_output) => { | ||
bail!(ErrorKind::ErrorOutputMismatch( | ||
self.cmd.clone(), | ||
expected_output.clone(), | ||
stderr.into(), | ||
)); | ||
}, | ||
Some(OutputAssertion { | ||
expect: ref expected_output, | ||
fuzzy: false, | ||
}) => { | ||
let differences = Changeset::new(expected_output.trim(), stderr.trim(), "\n"); | ||
if differences.distance > 0 { | ||
let nice_diff = diff::render(&differences)?; | ||
bail!(ErrorKind::ExactErrorOutputMismatch(self.cmd.clone(),nice_diff)); | ||
} | ||
}, | ||
_ => {}, | ||
/// Return a reference to the appropriate output assertion. | ||
fn expect_output(&self, output_type: OutputType) -> &Option<OutputAssertion> { | ||
match output_type { | ||
OutputType::StdOut => &self.expect_stdout, | ||
OutputType::StdErr => &self.expect_stderr, | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
/// Execute the command, check the assertions, and panic when they fail. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could also embed the
OutputType
enum directly - but then it must be public and would appear in the docs.