This repository was archived by the owner on Dec 29, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 19
fix(output): Re-work API to work with rustfmt #74
Closed
+262
−241
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,67 +2,169 @@ use self::errors::*; | |
pub use self::errors::{Error, ErrorKind}; | ||
use diff; | ||
use difference::Changeset; | ||
use std::ffi::OsString; | ||
use std::process::Output; | ||
use std::process; | ||
|
||
#[derive(Debug, Clone)] | ||
pub struct OutputAssertion { | ||
|
||
#[derive(Debug, Clone, PartialEq, Eq)] | ||
struct IsPredicate { | ||
pub expect: String, | ||
pub fuzzy: bool, | ||
pub expected_result: bool, | ||
pub kind: OutputKind, | ||
} | ||
|
||
impl OutputAssertion { | ||
fn matches_fuzzy(&self, got: &str) -> Result<()> { | ||
let result = got.contains(&self.expect); | ||
impl IsPredicate { | ||
pub fn verify_str(&self, got: &str) -> Result<()> { | ||
let differences = Changeset::new(self.expect.trim(), got.trim(), "\n"); | ||
let result = differences.distance == 0; | ||
|
||
if result != self.expected_result { | ||
if self.expected_result { | ||
bail!(ErrorKind::OutputDoesntContain( | ||
let nice_diff = diff::render(&differences)?; | ||
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. Do we really want to early-return this error? I think I'd |
||
bail!(ErrorKind::OutputDoesntMatch( | ||
self.expect.clone(), | ||
got.into() | ||
got.to_owned(), | ||
nice_diff | ||
)); | ||
} else { | ||
bail!(ErrorKind::OutputContains(self.expect.clone(), got.into())); | ||
bail!(ErrorKind::OutputMatches(got.to_owned())); | ||
} | ||
} | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
fn matches_exact(&self, got: &str) -> Result<()> { | ||
let differences = Changeset::new(self.expect.trim(), got.trim(), "\n"); | ||
let result = differences.distance == 0; | ||
#[derive(Debug, Clone, PartialEq, Eq)] | ||
struct ContainsPredicate { | ||
pub expect: String, | ||
pub expected_result: bool, | ||
} | ||
|
||
impl ContainsPredicate { | ||
pub fn verify_str(&self, got: &str) -> Result<()> { | ||
let result = got.contains(&self.expect); | ||
if result != self.expected_result { | ||
if self.expected_result { | ||
let nice_diff = diff::render(&differences)?; | ||
bail!(ErrorKind::OutputDoesntMatch( | ||
bail!(ErrorKind::OutputDoesntContain( | ||
self.expect.clone(), | ||
got.to_owned(), | ||
nice_diff | ||
got.into() | ||
)); | ||
} else { | ||
bail!(ErrorKind::OutputMatches(got.to_owned())); | ||
bail!(ErrorKind::OutputContains(self.expect.clone(), got.into())); | ||
} | ||
} | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
#[derive(Debug, Clone)] | ||
enum StrPredicate { | ||
Is(IsPredicate), | ||
Contains(ContainsPredicate), | ||
} | ||
|
||
impl StrPredicate { | ||
pub fn verify_str(&self, got: &str) -> Result<()> { | ||
match *self { | ||
StrPredicate::Is(ref pred) => pred.verify_str(got), | ||
StrPredicate::Contains(ref pred) => pred.verify_str(got), | ||
} | ||
} | ||
} | ||
|
||
pub fn execute(&self, output: &Output, cmd: &[OsString]) -> super::errors::Result<()> { | ||
let observed = String::from_utf8_lossy(self.kind.select(output)); | ||
/// Assertions for command output. | ||
#[derive(Debug, Clone)] | ||
pub struct Output { | ||
pred: StrPredicate, | ||
} | ||
|
||
let result = if self.fuzzy { | ||
self.matches_fuzzy(&observed) | ||
} else { | ||
self.matches_exact(&observed) | ||
impl Output { | ||
/// Expect the command's output to **contain** `output`. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ```rust | ||
/// extern crate assert_cli; | ||
/// | ||
/// assert_cli::Assert::command(&["echo"]) | ||
/// .with_args(&["42"]) | ||
/// .stdout(assert_cli::Output::contains("42")) | ||
/// .unwrap(); | ||
/// ``` | ||
pub fn contains<O: Into<String>>(output: O) -> Self { | ||
let pred = ContainsPredicate { | ||
expect: output.into(), | ||
expected_result: true, | ||
}; | ||
result.map_err(|e| { | ||
super::errors::ErrorKind::OutputMismatch(cmd.to_vec(), e, self.kind) | ||
})?; | ||
Self::new(StrPredicate::Contains(pred)) | ||
} | ||
|
||
Ok(()) | ||
/// Expect the command to output **exactly** this `output`. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ```rust | ||
/// extern crate assert_cli; | ||
/// | ||
/// assert_cli::Assert::command(&["echo"]) | ||
/// .with_args(&["42"]) | ||
/// .stdout(assert_cli::Output::is("42")) | ||
/// .unwrap(); | ||
/// ``` | ||
pub fn is<O: Into<String>>(output: O) -> Self { | ||
let pred = IsPredicate { | ||
expect: output.into(), | ||
expected_result: true, | ||
}; | ||
Self::new(StrPredicate::Is(pred)) | ||
} | ||
|
||
/// Expect the command's output to not **contain** `output`. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ```rust | ||
/// extern crate assert_cli; | ||
/// | ||
/// assert_cli::Assert::command(&["echo"]) | ||
/// .with_args(&["42"]) | ||
/// .stdout(assert_cli::Output::doesnt_contain("73")) | ||
/// .unwrap(); | ||
/// ``` | ||
pub fn doesnt_contain<O: Into<String>>(output: O) -> Self { | ||
let pred = ContainsPredicate { | ||
expect: output.into(), | ||
expected_result: false, | ||
}; | ||
Self::new(StrPredicate::Contains(pred)) | ||
} | ||
|
||
/// Expect the command to output to not be **exactly** this `output`. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ```rust | ||
/// extern crate assert_cli; | ||
/// | ||
/// assert_cli::Assert::command(&["echo"]) | ||
/// .with_args(&["42"]) | ||
/// .stdout(assert_cli::Output::isnt("73")) | ||
/// .unwrap(); | ||
/// ``` | ||
pub fn isnt<O: Into<String>>(output: O) -> Self { | ||
let pred = IsPredicate { | ||
expect: output.into(), | ||
expected_result: false, | ||
}; | ||
Self::new(StrPredicate::Is(pred)) | ||
} | ||
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. After reading for of these I fell the need to write a macro for this… which would probably not make the code much clearer 😅 |
||
|
||
fn new(pred: StrPredicate) -> Self { | ||
Self { pred } | ||
} | ||
|
||
pub(crate) fn verify_str(&self, got: &str) -> Result<()> { | ||
self.pred.verify_str(got) | ||
} | ||
} | ||
|
||
|
@@ -73,14 +175,48 @@ pub enum OutputKind { | |
} | ||
|
||
impl OutputKind { | ||
pub fn select(self, o: &Output) -> &[u8] { | ||
pub fn select(self, o: &process::Output) -> &[u8] { | ||
match self { | ||
OutputKind::StdOut => &o.stdout, | ||
OutputKind::StdErr => &o.stderr, | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug, Clone)] | ||
pub struct OutputPredicate { | ||
kind: OutputKind, | ||
pred: Output, | ||
} | ||
|
||
impl OutputPredicate { | ||
pub fn stdout(pred: Output) -> Self { | ||
Self { | ||
kind: OutputKind::StdOut, | ||
pred: pred, | ||
} | ||
} | ||
|
||
pub fn stderr(pred: Output) -> Self { | ||
Self { | ||
kind: OutputKind::StdErr, | ||
pred: pred, | ||
} | ||
} | ||
|
||
pub(crate) fn verify_str(&self, got: &str) -> Result<()> { | ||
let kind = self.kind; | ||
self.pred | ||
.verify_str(got) | ||
.chain_err(|| ErrorKind::OutputMismatch(kind)) | ||
} | ||
|
||
pub(crate) fn verify_output(&self, got: &process::Output) -> Result<()> { | ||
let got = String::from_utf8_lossy(self.kind.select(got)); | ||
self.verify_str(&got) | ||
} | ||
} | ||
|
||
mod errors { | ||
error_chain! { | ||
foreign_links { | ||
|
@@ -103,6 +239,13 @@ mod errors { | |
description("Output was not as expected") | ||
display("expected to not match\noutput=```{}```", got) | ||
} | ||
OutputMismatch(kind: super::OutputKind) { | ||
description("Output was not as expected") | ||
display( | ||
"Unexpected {:?}", | ||
kind | ||
) | ||
} | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
I'd probably
use assert_cli::{Assert, Output};
in most examples.