Skip to content
This repository was archived by the owner on Dec 29, 2021. It is now read-only.

Commit f7a7f64

Browse files
committed
refactor(output): Make implementation more expanable.
Move from a `bool` to track the type of output predicate to a stateful enum.
1 parent 3cca64e commit f7a7f64

File tree

4 files changed

+207
-107
lines changed

4 files changed

+207
-107
lines changed

src/assert.rs

Lines changed: 25 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use environment::Environment;
22
use error_chain::ChainedError;
33
use errors::*;
4-
use output::{OutputAssertion, OutputKind};
4+
use output::{Output, OutputKind, OutputPredicate};
55
use std::default;
66
use std::ffi::{OsStr, OsString};
77
use std::io::Write;
@@ -18,7 +18,7 @@ pub struct Assert {
1818
current_dir: Option<PathBuf>,
1919
expect_success: Option<bool>,
2020
expect_exit_code: Option<i32>,
21-
expect_output: Vec<OutputAssertion>,
21+
expect_output: Vec<OutputPredicate>,
2222
stdin_contents: Option<String>,
2323
}
2424

@@ -289,7 +289,6 @@ impl Assert {
289289
OutputAssertionBuilder {
290290
assertion: self,
291291
kind: OutputKind::StdOut,
292-
expected_result: true,
293292
}
294293
}
295294

@@ -310,7 +309,6 @@ impl Assert {
310309
OutputAssertionBuilder {
311310
assertion: self,
312311
kind: OutputKind::StdErr,
313-
expected_result: true,
314312
}
315313
}
316314

@@ -327,10 +325,10 @@ impl Assert {
327325
/// assert!(test.is_ok());
328326
/// ```
329327
pub fn execute(self) -> Result<()> {
330-
let cmd = &self.cmd[0];
328+
let bin = &self.cmd[0];
331329

332330
let args: Vec<_> = self.cmd.iter().skip(1).collect();
333-
let mut command = Command::new(cmd);
331+
let mut command = Command::new(bin);
334332
let command = command
335333
.stdin(Stdio::piped())
336334
.stdout(Stdio::piped())
@@ -361,30 +359,23 @@ impl Assert {
361359
if expect_success != output.status.success() {
362360
let out = String::from_utf8_lossy(&output.stdout).to_string();
363361
let err = String::from_utf8_lossy(&output.stderr).to_string();
364-
bail!(ErrorKind::StatusMismatch(
365-
self.cmd.clone(),
366-
expect_success,
367-
out,
368-
err,
369-
));
362+
let err: Error = ErrorKind::StatusMismatch(expect_success, out, err).into();
363+
bail!(err.chain_err(|| ErrorKind::AssertionFailed(self.cmd.clone())));
370364
}
371365
}
372366

373367
if self.expect_exit_code.is_some() && self.expect_exit_code != output.status.code() {
374368
let out = String::from_utf8_lossy(&output.stdout).to_string();
375369
let err = String::from_utf8_lossy(&output.stderr).to_string();
376-
bail!(ErrorKind::ExitCodeMismatch(
377-
self.cmd.clone(),
378-
self.expect_exit_code,
379-
output.status.code(),
380-
out,
381-
err,
382-
));
370+
let err: Error =
371+
ErrorKind::ExitCodeMismatch(self.expect_exit_code, output.status.code(), out, err)
372+
.into();
373+
bail!(err.chain_err(|| ErrorKind::AssertionFailed(self.cmd.clone())));
383374
}
384375

385376
self.expect_output
386377
.iter()
387-
.map(|a| a.execute(&output, &self.cmd))
378+
.map(|a| a.verify_output(&output).chain_err(|| ErrorKind::AssertionFailed(self.cmd.clone())))
388379
.collect::<Result<Vec<()>>>()?;
389380

390381
Ok(())
@@ -414,28 +405,9 @@ impl Assert {
414405
pub struct OutputAssertionBuilder {
415406
assertion: Assert,
416407
kind: OutputKind,
417-
expected_result: bool,
418408
}
419409

420410
impl OutputAssertionBuilder {
421-
/// Negate the assertion predicate
422-
///
423-
/// # Examples
424-
///
425-
/// ```rust
426-
/// extern crate assert_cli;
427-
///
428-
/// assert_cli::Assert::command(&["echo", "42"])
429-
/// .stdout().not().contains("73")
430-
/// .unwrap();
431-
/// ```
432-
// No clippy, we don't want to implement std::ops::Not :)
433-
#[cfg_attr(feature = "cargo-clippy", allow(should_implement_trait))]
434-
pub fn not(mut self) -> Self {
435-
self.expected_result = !self.expected_result;
436-
self
437-
}
438-
439411
/// Expect the command's output to **contain** `output`.
440412
///
441413
/// # Examples
@@ -448,12 +420,8 @@ impl OutputAssertionBuilder {
448420
/// .unwrap();
449421
/// ```
450422
pub fn contains<O: Into<String>>(mut self, output: O) -> Assert {
451-
self.assertion.expect_output.push(OutputAssertion {
452-
expect: output.into(),
453-
fuzzy: true,
454-
expected_result: self.expected_result,
455-
kind: self.kind,
456-
});
423+
let pred = OutputPredicate::new(self.kind, Output::contains(output));
424+
self.assertion.expect_output.push(pred);
457425
self.assertion
458426
}
459427

@@ -469,12 +437,8 @@ impl OutputAssertionBuilder {
469437
/// .unwrap();
470438
/// ```
471439
pub fn is<O: Into<String>>(mut self, output: O) -> Assert {
472-
self.assertion.expect_output.push(OutputAssertion {
473-
expect: output.into(),
474-
fuzzy: false,
475-
expected_result: self.expected_result,
476-
kind: self.kind,
477-
});
440+
let pred = OutputPredicate::new(self.kind, Output::is(output));
441+
self.assertion.expect_output.push(pred);
478442
self.assertion
479443
}
480444

@@ -489,8 +453,10 @@ impl OutputAssertionBuilder {
489453
/// .stdout().doesnt_contain("73")
490454
/// .unwrap();
491455
/// ```
492-
pub fn doesnt_contain<O: Into<String>>(self, output: O) -> Assert {
493-
self.not().contains(output)
456+
pub fn doesnt_contain<O: Into<String>>(mut self, output: O) -> Assert {
457+
let pred = OutputPredicate::new(self.kind, Output::doesnt_contain(output));
458+
self.assertion.expect_output.push(pred);
459+
self.assertion
494460
}
495461

496462
/// Expect the command to output to not be **exactly** this `output`.
@@ -504,8 +470,10 @@ impl OutputAssertionBuilder {
504470
/// .stdout().isnt("73")
505471
/// .unwrap();
506472
/// ```
507-
pub fn isnt<O: Into<String>>(self, output: O) -> Assert {
508-
self.not().is(output)
473+
pub fn isnt<O: Into<String>>(mut self, output: O) -> Assert {
474+
let pred = OutputPredicate::new(self.kind, Output::isnt(output));
475+
self.assertion.expect_output.push(pred);
476+
self.assertion
509477
}
510478
}
511479

@@ -522,7 +490,7 @@ mod test {
522490
fn take_ownership() {
523491
let x = Environment::inherit();
524492

525-
command().with_env(x.clone()).with_env(&x).with_env(x);
493+
command().with_env(x.clone()).with_env(&x).with_env(x).unwrap();
526494
}
527495

528496
#[test]
@@ -564,8 +532,7 @@ mod test {
564532
command()
565533
.with_env(y)
566534
.stdout()
567-
.not()
568-
.contains("key=value")
535+
.doesnt_contain("key=value")
569536
.execute()
570537
.unwrap();
571538
}

src/errors.rs

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ fn format_cmd(cmd: &[OsString]) -> String {
1111
}
1212

1313
error_chain! {
14+
links {
15+
Output(output::Error, output::ErrorKind);
16+
}
1417
foreign_links {
1518
Io(::std::io::Error);
1619
Fmt(::std::fmt::Error);
@@ -24,46 +27,41 @@ error_chain! {
2427
format_cmd(cmd),
2528
)
2629
}
27-
StatusMismatch(cmd: Vec<OsString>, expected: bool, out: String, err: String) {
28-
description("Wrong status")
30+
AssertionFailed(cmd: Vec<OsString>) {
31+
description("Assertion failed")
2932
display(
30-
"{}: (command `{}` expected to {})\nstatus={}\nstdout=```{}```\nstderr=```{}```",
33+
"{}: (command `{}` failed)",
3134
ERROR_PREFIX,
3235
format_cmd(cmd),
36+
)
37+
}
38+
StatusMismatch(expected: bool, out: String, err: String) {
39+
description("Wrong status")
40+
display(
41+
"Expected to {}\nstatus={}\nstdout=```{}```\nstderr=```{}```",
3342
expected = if *expected { "succeed" } else { "fail" },
3443
got = if *expected { "failed" } else { "succeeded" },
3544
out = out,
3645
err = err,
3746
)
3847
}
3948
ExitCodeMismatch(
40-
cmd: Vec<OsString>,
4149
expected: Option<i32>,
4250
got: Option<i32>,
4351
out: String,
4452
err: String
4553
) {
4654
description("Wrong exit code")
4755
display(
48-
"{prefix}: (exit code of `{cmd}` expected to be `{expected:?}`)\n\
56+
"Expected exit code to be `{expected:?}`)\n\
4957
exit code=`{code:?}`\n\
5058
stdout=```{stdout}```\n\
5159
stderr=```{stderr}```",
52-
prefix=ERROR_PREFIX,
53-
cmd=format_cmd(cmd),
5460
expected=expected,
5561
code=got,
5662
stdout=out,
5763
stderr=err,
5864
)
5965
}
60-
OutputMismatch(cmd: Vec<OsString>, output_err: output::Error, kind: output::OutputKind) {
61-
description("Output was not as expected")
62-
display(
63-
"{}: `{}` {:?} mismatch: {}",
64-
ERROR_PREFIX, format_cmd(cmd), kind, output_err,
65-
)
66-
}
67-
6866
}
6967
}

src/lib.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,10 @@ mod errors;
129129
mod macros;
130130
pub use macros::flatten_escaped_string;
131131

132-
mod output;
133-
132+
mod assert;
134133
mod diff;
134+
mod output;
135135

136-
mod assert;
137136
pub use assert::Assert;
138137
pub use assert::OutputAssertionBuilder;
139138
/// Environment is a re-export of the Environment crate

0 commit comments

Comments
 (0)