1 //! [`std::process::Output`] assertions.
2 
3 use std::borrow::Cow;
4 use std::error::Error;
5 use std::fmt;
6 use std::process;
7 use std::str;
8 
9 use predicates::str::PredicateStrExt;
10 use predicates_tree::CaseTreeExt;
11 
12 use crate::output::output_fmt;
13 use crate::output::DebugBytes;
14 
15 /// Assert the state of an [`Output`].
16 ///
17 /// # Examples
18 ///
19 /// ```rust,no_run
20 /// use assert_cmd::prelude::*;
21 ///
22 /// use std::process::Command;
23 ///
24 /// let mut cmd = Command::cargo_bin("bin_fixture")
25 ///     .unwrap();
26 /// cmd.assert()
27 ///     .success();
28 /// ```
29 ///
30 /// [`Output`]: std::process::Output
31 pub trait OutputAssertExt {
32     /// Wrap with an interface for that provides assertions on the [`Output`].
33     ///
34     /// # Examples
35     ///
36     /// ```rust,no_run
37     /// use assert_cmd::prelude::*;
38     ///
39     /// use std::process::Command;
40     ///
41     /// let mut cmd = Command::cargo_bin("bin_fixture")
42     ///     .unwrap();
43     /// cmd.assert()
44     ///     .success();
45     /// ```
46     ///
47     /// [`Output`]: std::process::Output
assert(self) -> Assert48     fn assert(self) -> Assert;
49 }
50 
51 impl OutputAssertExt for process::Output {
assert(self) -> Assert52     fn assert(self) -> Assert {
53         Assert::new(self)
54     }
55 }
56 
57 impl<'c> OutputAssertExt for &'c mut process::Command {
assert(self) -> Assert58     fn assert(self) -> Assert {
59         let output = match self.output() {
60             Ok(output) => output,
61             Err(err) => {
62                 panic!("Failed to spawn {:?}: {}", self, err);
63             }
64         };
65         Assert::new(output).append_context("command", format!("{:?}", self))
66     }
67 }
68 
69 /// [`Assert`] represented as a [`Result`].
70 ///
71 /// Produced by the `try_` variants the [`Assert`] methods.
72 ///
73 /// # Example
74 ///
75 /// ```rust
76 /// use assert_cmd::prelude::*;
77 ///
78 /// use std::process::Command;
79 ///
80 /// let result = Command::new("echo")
81 ///     .assert()
82 ///     .try_success();
83 /// assert!(result.is_ok());
84 /// ```
85 ///
86 /// [`Result`]: std::result::Result
87 pub type AssertResult = Result<Assert, AssertError>;
88 
89 /// [`Assert`] error (see [`AssertResult`]).
90 #[derive(Debug)]
91 pub struct AssertError {
92     assert: Assert,
93     reason: AssertReason,
94 }
95 
96 #[derive(Debug)]
97 enum AssertReason {
98     UnexpectedFailure { actual_code: Option<i32> },
99     UnexpectedSuccess,
100     UnexpectedCompletion,
101     CommandInterrupted,
102     UnexpectedReturnCode { case_tree: CaseTree },
103     UnexpectedStdout { case_tree: CaseTree },
104     UnexpectedStderr { case_tree: CaseTree },
105 }
106 
107 struct CaseTree(predicates_tree::CaseTree);
108 
109 impl fmt::Display for CaseTree {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result110     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111         <predicates_tree::CaseTree as fmt::Display>::fmt(&self.0, f)
112     }
113 }
114 
115 // Work around `Debug` not being implemented for `predicates_tree::CaseTree`.
116 impl fmt::Debug for CaseTree {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result117     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118         <predicates_tree::CaseTree as fmt::Display>::fmt(&self.0, f)
119     }
120 }
121 
122 impl AssertError {
panic<T>(self) -> T123     fn panic<T>(self) -> T {
124         panic!("{}", self.to_string())
125     }
126 }
127 
128 impl Error for AssertError {}
129 
130 impl fmt::Display for AssertError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result131     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132         match &self.reason {
133             AssertReason::UnexpectedFailure { actual_code } => writeln!(
134                 f,
135                 "Unexpected failure.\ncode-{}\nstderr=```{}```",
136                 actual_code.map_or("<interrupted>".to_owned(), |actual_code| actual_code
137                     .to_string()),
138                 DebugBytes::new(&self.assert.output.stderr),
139             ),
140             AssertReason::UnexpectedSuccess => {
141                 writeln!(f, "Unexpected success")
142             }
143             AssertReason::UnexpectedCompletion => {
144                 writeln!(f, "Unexpected completion")
145             }
146             AssertReason::CommandInterrupted => {
147                 writeln!(f, "Command interrupted")
148             }
149             AssertReason::UnexpectedReturnCode { case_tree } => {
150                 writeln!(f, "Unexpected return code, failed {}", case_tree)
151             }
152             AssertReason::UnexpectedStdout { case_tree } => {
153                 writeln!(f, "Unexpected stdout, failed {}", case_tree)
154             }
155             AssertReason::UnexpectedStderr { case_tree } => {
156                 writeln!(f, "Unexpected stderr, failed {}", case_tree)
157             }
158         }?;
159         write!(f, "{}", self.assert)
160     }
161 }
162 
163 /// Assert the state of an [`Output`].
164 ///
165 /// Create an `Assert` through the [`OutputAssertExt`] trait.
166 ///
167 /// # Examples
168 ///
169 /// ```rust,no_run
170 /// use assert_cmd::prelude::*;
171 ///
172 /// use std::process::Command;
173 ///
174 /// let mut cmd = Command::cargo_bin("bin_fixture")
175 ///     .unwrap();
176 /// cmd.assert()
177 ///     .success();
178 /// ```
179 ///
180 /// [`Output`]: std::process::Output
181 pub struct Assert {
182     output: process::Output,
183     context: Vec<(&'static str, Box<dyn fmt::Display>)>,
184 }
185 
186 impl Assert {
187     /// Create an `Assert` for a given [`Output`].
188     ///
189     /// [`Output`]: std::process::Output
new(output: process::Output) -> Self190     pub fn new(output: process::Output) -> Self {
191         Self {
192             output,
193             context: vec![],
194         }
195     }
196 
into_error(self, reason: AssertReason) -> AssertError197     fn into_error(self, reason: AssertReason) -> AssertError {
198         AssertError {
199             assert: self,
200             reason,
201         }
202     }
203 
204     /// Clarify failures with additional context.
205     ///
206     /// # Examples
207     ///
208     /// ```rust,no_run
209     /// use assert_cmd::prelude::*;
210     ///
211     /// use std::process::Command;
212     ///
213     /// Command::cargo_bin("bin_fixture")
214     ///     .unwrap()
215     ///     .assert()
216     ///     .append_context("main", "no args")
217     ///     .success();
218     /// ```
append_context<D>(mut self, name: &'static str, context: D) -> Self where D: fmt::Display + 'static,219     pub fn append_context<D>(mut self, name: &'static str, context: D) -> Self
220     where
221         D: fmt::Display + 'static,
222     {
223         self.context.push((name, Box::new(context)));
224         self
225     }
226 
227     /// Access the contained [`Output`].
228     ///
229     /// [`Output`]: std::process::Output
get_output(&self) -> &process::Output230     pub fn get_output(&self) -> &process::Output {
231         &self.output
232     }
233 
234     /// Ensure the command succeeded.
235     ///
236     /// # Examples
237     ///
238     /// ```rust,no_run
239     /// use assert_cmd::prelude::*;
240     ///
241     /// use std::process::Command;
242     ///
243     /// Command::cargo_bin("bin_fixture")
244     ///     .unwrap()
245     ///     .assert()
246     ///     .success();
247     /// ```
success(self) -> Self248     pub fn success(self) -> Self {
249         self.try_success().unwrap_or_else(AssertError::panic)
250     }
251 
252     /// `try_` variant of [`Assert::success`].
try_success(self) -> AssertResult253     pub fn try_success(self) -> AssertResult {
254         if !self.output.status.success() {
255             let actual_code = self.output.status.code();
256             return Err(self.into_error(AssertReason::UnexpectedFailure { actual_code }));
257         }
258         Ok(self)
259     }
260 
261     /// Ensure the command failed.
262     ///
263     /// # Examples
264     ///
265     /// ```rust,no_run
266     /// use assert_cmd::prelude::*;
267     ///
268     /// use std::process::Command;
269     ///
270     /// Command::cargo_bin("bin_fixture")
271     ///     .unwrap()
272     ///     .env("exit", "1")
273     ///     .assert()
274     ///     .failure();
275     /// ```
failure(self) -> Self276     pub fn failure(self) -> Self {
277         self.try_failure().unwrap_or_else(AssertError::panic)
278     }
279 
280     /// Variant of [`Assert::failure`] that returns an [`AssertResult`].
try_failure(self) -> AssertResult281     pub fn try_failure(self) -> AssertResult {
282         if self.output.status.success() {
283             return Err(self.into_error(AssertReason::UnexpectedSuccess));
284         }
285         Ok(self)
286     }
287 
288     /// Ensure the command aborted before returning a code.
interrupted(self) -> Self289     pub fn interrupted(self) -> Self {
290         self.try_interrupted().unwrap_or_else(AssertError::panic)
291     }
292 
293     /// Variant of [`Assert::interrupted`] that returns an [`AssertResult`].
try_interrupted(self) -> AssertResult294     pub fn try_interrupted(self) -> AssertResult {
295         if self.output.status.code().is_some() {
296             return Err(self.into_error(AssertReason::UnexpectedCompletion));
297         }
298         Ok(self)
299     }
300 
301     /// Ensure the command returned the expected code.
302     ///
303     /// This uses [`IntoCodePredicate`] to provide short-hands for common cases.
304     ///
305     /// See [`predicates`] for more predicates.
306     ///
307     /// # Examples
308     ///
309     /// Accepting a predicate:
310     /// ```rust,no_run
311     /// use assert_cmd::prelude::*;
312     ///
313     /// use std::process::Command;
314     /// use predicates::prelude::*;
315     ///
316     /// Command::cargo_bin("bin_fixture")
317     ///     .unwrap()
318     ///     .env("exit", "42")
319     ///     .assert()
320     ///     .code(predicate::eq(42));
321     /// ```
322     ///
323     /// Accepting an exit code:
324     /// ```rust,no_run
325     /// use assert_cmd::prelude::*;
326     ///
327     /// use std::process::Command;
328     ///
329     /// Command::cargo_bin("bin_fixture")
330     ///     .unwrap()
331     ///     .env("exit", "42")
332     ///     .assert()
333     ///     .code(42);
334     /// ```
335     ///
336     /// Accepting multiple exit codes:
337     /// ```rust,no_run
338     /// use assert_cmd::prelude::*;
339     ///
340     /// use std::process::Command;
341     ///
342     /// Command::cargo_bin("bin_fixture")
343     ///     .unwrap()
344     ///     .env("exit", "42")
345     ///     .assert()
346     ///     .code(&[2, 42] as &[i32]);
347     /// ```
348     ///
code<I, P>(self, pred: I) -> Self where I: IntoCodePredicate<P>, P: predicates_core::Predicate<i32>,349     pub fn code<I, P>(self, pred: I) -> Self
350     where
351         I: IntoCodePredicate<P>,
352         P: predicates_core::Predicate<i32>,
353     {
354         self.try_code(pred).unwrap_or_else(AssertError::panic)
355     }
356 
357     /// Variant of [`Assert::code`] that returns an [`AssertResult`].
try_code<I, P>(self, pred: I) -> AssertResult where I: IntoCodePredicate<P>, P: predicates_core::Predicate<i32>,358     pub fn try_code<I, P>(self, pred: I) -> AssertResult
359     where
360         I: IntoCodePredicate<P>,
361         P: predicates_core::Predicate<i32>,
362     {
363         self.code_impl(&pred.into_code())
364     }
365 
code_impl(self, pred: &dyn predicates_core::Predicate<i32>) -> AssertResult366     fn code_impl(self, pred: &dyn predicates_core::Predicate<i32>) -> AssertResult {
367         let actual_code = if let Some(actual_code) = self.output.status.code() {
368             actual_code
369         } else {
370             return Err(self.into_error(AssertReason::CommandInterrupted));
371         };
372         if let Some(case) = pred.find_case(false, &actual_code) {
373             return Err(self.into_error(AssertReason::UnexpectedReturnCode {
374                 case_tree: CaseTree(case.tree()),
375             }));
376         }
377         Ok(self)
378     }
379 
380     /// Ensure the command wrote the expected data to `stdout`.
381     ///
382     /// This uses [`IntoOutputPredicate`] to provide short-hands for common cases.
383     ///
384     /// See [`predicates`] for more predicates.
385     ///
386     /// # Examples
387     ///
388     /// Accepting a bytes predicate:
389     /// ```rust,no_run
390     /// use assert_cmd::prelude::*;
391     ///
392     /// use std::process::Command;
393     /// use predicates::prelude::*;
394     ///
395     /// Command::cargo_bin("bin_fixture")
396     ///     .unwrap()
397     ///     .env("stdout", "hello")
398     ///     .env("stderr", "world")
399     ///     .assert()
400     ///     .stdout(predicate::eq(b"hello\n" as &[u8]));
401     /// ```
402     ///
403     /// Accepting a `str` predicate:
404     /// ```rust,no_run
405     /// use assert_cmd::prelude::*;
406     ///
407     /// use std::process::Command;
408     /// use predicates::prelude::*;
409     ///
410     /// Command::cargo_bin("bin_fixture")
411     ///     .unwrap()
412     ///     .env("stdout", "hello")
413     ///     .env("stderr", "world")
414     ///     .assert()
415     ///     .stdout(predicate::str::diff("hello\n"));
416     /// ```
417     ///
418     /// Accepting bytes:
419     /// ```rust,no_run
420     /// use assert_cmd::prelude::*;
421     ///
422     /// use std::process::Command;
423     ///
424     /// Command::cargo_bin("bin_fixture")
425     ///     .unwrap()
426     ///     .env("stdout", "hello")
427     ///     .env("stderr", "world")
428     ///     .assert()
429     ///     .stdout(b"hello\n" as &[u8]);
430     /// ```
431     ///
432     /// Accepting a `str`:
433     /// ```rust,no_run
434     /// use assert_cmd::prelude::*;
435     ///
436     /// use std::process::Command;
437     ///
438     /// Command::cargo_bin("bin_fixture")
439     ///     .unwrap()
440     ///     .env("stdout", "hello")
441     ///     .env("stderr", "world")
442     ///     .assert()
443     ///     .stdout("hello\n");
444     /// ```
445     ///
stdout<I, P>(self, pred: I) -> Self where I: IntoOutputPredicate<P>, P: predicates_core::Predicate<[u8]>,446     pub fn stdout<I, P>(self, pred: I) -> Self
447     where
448         I: IntoOutputPredicate<P>,
449         P: predicates_core::Predicate<[u8]>,
450     {
451         self.try_stdout(pred).unwrap_or_else(AssertError::panic)
452     }
453 
454     /// Variant of [`Assert::stdout`] that returns an [`AssertResult`].
try_stdout<I, P>(self, pred: I) -> AssertResult where I: IntoOutputPredicate<P>, P: predicates_core::Predicate<[u8]>,455     pub fn try_stdout<I, P>(self, pred: I) -> AssertResult
456     where
457         I: IntoOutputPredicate<P>,
458         P: predicates_core::Predicate<[u8]>,
459     {
460         self.stdout_impl(&pred.into_output())
461     }
462 
stdout_impl(self, pred: &dyn predicates_core::Predicate<[u8]>) -> AssertResult463     fn stdout_impl(self, pred: &dyn predicates_core::Predicate<[u8]>) -> AssertResult {
464         {
465             let actual = &self.output.stdout;
466             if let Some(case) = pred.find_case(false, &actual) {
467                 return Err(self.into_error(AssertReason::UnexpectedStdout {
468                     case_tree: CaseTree(case.tree()),
469                 }));
470             }
471         }
472         Ok(self)
473     }
474 
475     /// Ensure the command wrote the expected data to `stderr`.
476     ///
477     /// This uses [`IntoOutputPredicate`] to provide short-hands for common cases.
478     ///
479     /// See [`predicates`] for more predicates.
480     ///
481     /// # Examples
482     ///
483     /// Accepting a bytes predicate:
484     /// ```rust,no_run
485     /// use assert_cmd::prelude::*;
486     ///
487     /// use std::process::Command;
488     /// use predicates::prelude::*;
489     ///
490     /// Command::cargo_bin("bin_fixture")
491     ///     .unwrap()
492     ///     .env("stdout", "hello")
493     ///     .env("stderr", "world")
494     ///     .assert()
495     ///     .stderr(predicate::eq(b"world\n" as &[u8]));
496     /// ```
497     ///
498     /// Accepting a `str` predicate:
499     /// ```rust,no_run
500     /// use assert_cmd::prelude::*;
501     ///
502     /// use std::process::Command;
503     /// use predicates::prelude::*;
504     ///
505     /// Command::cargo_bin("bin_fixture")
506     ///     .unwrap()
507     ///     .env("stdout", "hello")
508     ///     .env("stderr", "world")
509     ///     .assert()
510     ///     .stderr(predicate::str::diff("world\n"));
511     /// ```
512     ///
513     /// Accepting bytes:
514     /// ```rust,no_run
515     /// use assert_cmd::prelude::*;
516     ///
517     /// use std::process::Command;
518     ///
519     /// Command::cargo_bin("bin_fixture")
520     ///     .unwrap()
521     ///     .env("stdout", "hello")
522     ///     .env("stderr", "world")
523     ///     .assert()
524     ///     .stderr(b"world\n" as &[u8]);
525     /// ```
526     ///
527     /// Accepting a `str`:
528     /// ```rust,no_run
529     /// use assert_cmd::prelude::*;
530     ///
531     /// use std::process::Command;
532     ///
533     /// Command::cargo_bin("bin_fixture")
534     ///     .unwrap()
535     ///     .env("stdout", "hello")
536     ///     .env("stderr", "world")
537     ///     .assert()
538     ///     .stderr("world\n");
539     /// ```
540     ///
stderr<I, P>(self, pred: I) -> Self where I: IntoOutputPredicate<P>, P: predicates_core::Predicate<[u8]>,541     pub fn stderr<I, P>(self, pred: I) -> Self
542     where
543         I: IntoOutputPredicate<P>,
544         P: predicates_core::Predicate<[u8]>,
545     {
546         self.try_stderr(pred).unwrap_or_else(AssertError::panic)
547     }
548 
549     /// Variant of [`Assert::stderr`] that returns an [`AssertResult`].
try_stderr<I, P>(self, pred: I) -> AssertResult where I: IntoOutputPredicate<P>, P: predicates_core::Predicate<[u8]>,550     pub fn try_stderr<I, P>(self, pred: I) -> AssertResult
551     where
552         I: IntoOutputPredicate<P>,
553         P: predicates_core::Predicate<[u8]>,
554     {
555         self.stderr_impl(&pred.into_output())
556     }
557 
stderr_impl(self, pred: &dyn predicates_core::Predicate<[u8]>) -> AssertResult558     fn stderr_impl(self, pred: &dyn predicates_core::Predicate<[u8]>) -> AssertResult {
559         {
560             let actual = &self.output.stderr;
561             if let Some(case) = pred.find_case(false, &actual) {
562                 return Err(self.into_error(AssertReason::UnexpectedStderr {
563                     case_tree: CaseTree(case.tree()),
564                 }));
565             }
566         }
567         Ok(self)
568     }
569 }
570 
571 impl fmt::Display for Assert {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result572     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
573         for &(ref name, ref context) in &self.context {
574             writeln!(f, "{}=`{}`", name, context)?;
575         }
576         output_fmt(&self.output, f)
577     }
578 }
579 
580 impl fmt::Debug for Assert {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result581     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
582         f.debug_struct("Assert")
583             .field("output", &self.output)
584             .finish()
585     }
586 }
587 
588 /// Used by [`Assert::code`] to convert `Self` into the needed
589 /// [`predicates_core::Predicate<i32>`].
590 ///
591 /// # Examples
592 ///
593 /// ```rust,no_run
594 /// use assert_cmd::prelude::*;
595 ///
596 /// use std::process::Command;
597 /// use predicates::prelude::*;
598 ///
599 /// Command::cargo_bin("bin_fixture")
600 ///     .unwrap()
601 ///     .env("exit", "42")
602 ///     .assert()
603 ///     .code(predicate::eq(42));
604 ///
605 /// // which can be shortened to:
606 /// Command::cargo_bin("bin_fixture")
607 ///     .unwrap()
608 ///     .env("exit", "42")
609 ///     .assert()
610 ///     .code(42);
611 /// ```
612 pub trait IntoCodePredicate<P>
613 where
614     P: predicates_core::Predicate<i32>,
615 {
616     /// The type of the predicate being returned.
617     type Predicate;
618 
619     /// Convert to a predicate for testing a program's exit code.
into_code(self) -> P620     fn into_code(self) -> P;
621 }
622 
623 impl<P> IntoCodePredicate<P> for P
624 where
625     P: predicates_core::Predicate<i32>,
626 {
627     type Predicate = P;
628 
into_code(self) -> Self::Predicate629     fn into_code(self) -> Self::Predicate {
630         self
631     }
632 }
633 
634 /// Keep `predicates` concrete Predicates out of our public API.
635 /// [predicates_core::Predicate] used by [`IntoCodePredicate`] for code.
636 ///
637 /// # Example
638 ///
639 /// ```rust,no_run
640 /// use assert_cmd::prelude::*;
641 ///
642 /// use std::process::Command;
643 ///
644 /// Command::cargo_bin("bin_fixture")
645 ///     .unwrap()
646 ///     .env("exit", "42")
647 ///     .assert()
648 ///     .code(42);
649 /// ```
650 #[derive(Debug)]
651 pub struct EqCodePredicate(predicates::ord::EqPredicate<i32>);
652 
653 impl EqCodePredicate {
new(value: i32) -> Self654     pub(crate) fn new(value: i32) -> Self {
655         let pred = predicates::ord::eq(value);
656         EqCodePredicate(pred)
657     }
658 }
659 
660 impl predicates_core::reflection::PredicateReflection for EqCodePredicate {
parameters<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a>661     fn parameters<'a>(
662         &'a self,
663     ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a> {
664         self.0.parameters()
665     }
666 
667     /// Nested `Predicate`s of the current `Predicate`.
children<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a>668     fn children<'a>(
669         &'a self,
670     ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a> {
671         self.0.children()
672     }
673 }
674 
675 impl predicates_core::Predicate<i32> for EqCodePredicate {
eval(&self, item: &i32) -> bool676     fn eval(&self, item: &i32) -> bool {
677         self.0.eval(item)
678     }
679 
find_case<'a>( &'a self, expected: bool, variable: &i32, ) -> Option<predicates_core::reflection::Case<'a>>680     fn find_case<'a>(
681         &'a self,
682         expected: bool,
683         variable: &i32,
684     ) -> Option<predicates_core::reflection::Case<'a>> {
685         self.0.find_case(expected, variable)
686     }
687 }
688 
689 impl fmt::Display for EqCodePredicate {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result690     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
691         self.0.fmt(f)
692     }
693 }
694 
695 impl IntoCodePredicate<EqCodePredicate> for i32 {
696     type Predicate = EqCodePredicate;
697 
into_code(self) -> Self::Predicate698     fn into_code(self) -> Self::Predicate {
699         Self::Predicate::new(self)
700     }
701 }
702 
703 /// Keep `predicates` concrete Predicates out of our public API.
704 /// [predicates_core::Predicate] used by [`IntoCodePredicate`] for iterables of codes.
705 ///
706 /// # Example
707 ///
708 /// ```rust,no_run
709 /// use assert_cmd::prelude::*;
710 ///
711 /// use std::process::Command;
712 ///
713 /// Command::cargo_bin("bin_fixture")
714 ///     .unwrap()
715 ///     .env("exit", "42")
716 ///     .assert()
717 ///     .code(&[2, 42] as &[i32]);
718 /// ```
719 #[derive(Debug)]
720 pub struct InCodePredicate(predicates::iter::InPredicate<i32>);
721 
722 impl InCodePredicate {
new<I: IntoIterator<Item = i32>>(value: I) -> Self723     pub(crate) fn new<I: IntoIterator<Item = i32>>(value: I) -> Self {
724         let pred = predicates::iter::in_iter(value);
725         InCodePredicate(pred)
726     }
727 }
728 
729 impl predicates_core::reflection::PredicateReflection for InCodePredicate {
parameters<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a>730     fn parameters<'a>(
731         &'a self,
732     ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a> {
733         self.0.parameters()
734     }
735 
736     /// Nested `Predicate`s of the current `Predicate`.
children<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a>737     fn children<'a>(
738         &'a self,
739     ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a> {
740         self.0.children()
741     }
742 }
743 
744 impl predicates_core::Predicate<i32> for InCodePredicate {
eval(&self, item: &i32) -> bool745     fn eval(&self, item: &i32) -> bool {
746         self.0.eval(item)
747     }
748 
find_case<'a>( &'a self, expected: bool, variable: &i32, ) -> Option<predicates_core::reflection::Case<'a>>749     fn find_case<'a>(
750         &'a self,
751         expected: bool,
752         variable: &i32,
753     ) -> Option<predicates_core::reflection::Case<'a>> {
754         self.0.find_case(expected, variable)
755     }
756 }
757 
758 impl fmt::Display for InCodePredicate {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result759     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
760         self.0.fmt(f)
761     }
762 }
763 
764 impl IntoCodePredicate<InCodePredicate> for Vec<i32> {
765     type Predicate = InCodePredicate;
766 
into_code(self) -> Self::Predicate767     fn into_code(self) -> Self::Predicate {
768         Self::Predicate::new(self)
769     }
770 }
771 
772 impl IntoCodePredicate<InCodePredicate> for &'static [i32] {
773     type Predicate = InCodePredicate;
774 
into_code(self) -> Self::Predicate775     fn into_code(self) -> Self::Predicate {
776         Self::Predicate::new(self.iter().cloned())
777     }
778 }
779 
780 /// Used by [`Assert::stdout`] and [`Assert::stderr`] to convert Self
781 /// into the needed [`predicates_core::Predicate<[u8]>`].
782 ///
783 /// # Examples
784 ///
785 /// ```rust,no_run
786 /// use assert_cmd::prelude::*;
787 ///
788 /// use std::process::Command;
789 /// use predicates::prelude::*;
790 ///
791 /// Command::cargo_bin("bin_fixture")
792 ///     .unwrap()
793 ///     .env("stdout", "hello")
794 ///     .env("stderr", "world")
795 ///     .assert()
796 ///     .stdout(predicate::str::diff("hello\n").from_utf8());
797 ///
798 /// // which can be shortened to:
799 /// Command::cargo_bin("bin_fixture")
800 ///     .unwrap()
801 ///     .env("stdout", "hello")
802 ///     .env("stderr", "world")
803 ///     .assert()
804 ///     .stdout("hello\n");
805 /// ```
806 pub trait IntoOutputPredicate<P>
807 where
808     P: predicates_core::Predicate<[u8]>,
809 {
810     /// The type of the predicate being returned.
811     type Predicate;
812 
813     /// Convert to a predicate for testing a path.
into_output(self) -> P814     fn into_output(self) -> P;
815 }
816 
817 impl<P> IntoOutputPredicate<P> for P
818 where
819     P: predicates_core::Predicate<[u8]>,
820 {
821     type Predicate = P;
822 
into_output(self) -> Self::Predicate823     fn into_output(self) -> Self::Predicate {
824         self
825     }
826 }
827 
828 /// Keep `predicates` concrete Predicates out of our public API.
829 /// [predicates_core::Predicate] used by [`IntoOutputPredicate`] for bytes.
830 ///
831 /// # Example
832 ///
833 /// ```rust,no_run
834 /// use assert_cmd::prelude::*;
835 ///
836 /// use std::process::Command;
837 ///
838 /// Command::cargo_bin("bin_fixture")
839 ///     .unwrap()
840 ///     .env("stdout", "hello")
841 ///     .env("stderr", "world")
842 ///     .assert()
843 ///     .stderr(b"world\n" as &[u8]);
844 /// ```
845 #[derive(Debug)]
846 pub struct BytesContentOutputPredicate(Cow<'static, [u8]>);
847 
848 impl BytesContentOutputPredicate {
new(value: &'static [u8]) -> Self849     pub(crate) fn new(value: &'static [u8]) -> Self {
850         BytesContentOutputPredicate(Cow::from(value))
851     }
852 
from_vec(value: Vec<u8>) -> Self853     pub(crate) fn from_vec(value: Vec<u8>) -> Self {
854         BytesContentOutputPredicate(Cow::from(value))
855     }
856 }
857 
858 impl predicates_core::reflection::PredicateReflection for BytesContentOutputPredicate {}
859 
860 impl predicates_core::Predicate<[u8]> for BytesContentOutputPredicate {
eval(&self, item: &[u8]) -> bool861     fn eval(&self, item: &[u8]) -> bool {
862         self.0.as_ref() == item
863     }
864 
find_case( &self, expected: bool, variable: &[u8], ) -> Option<predicates_core::reflection::Case>865     fn find_case(
866         &self,
867         expected: bool,
868         variable: &[u8],
869     ) -> Option<predicates_core::reflection::Case> {
870         let actual = self.eval(variable);
871         if expected == actual {
872             Some(predicates_core::reflection::Case::new(Some(self), actual))
873         } else {
874             None
875         }
876     }
877 }
878 
879 impl fmt::Display for BytesContentOutputPredicate {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result880     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
881         predicates::ord::eq(self.0.as_ref()).fmt(f)
882     }
883 }
884 
885 impl IntoOutputPredicate<BytesContentOutputPredicate> for Vec<u8> {
886     type Predicate = BytesContentOutputPredicate;
887 
into_output(self) -> Self::Predicate888     fn into_output(self) -> Self::Predicate {
889         Self::Predicate::from_vec(self)
890     }
891 }
892 
893 impl IntoOutputPredicate<BytesContentOutputPredicate> for &'static [u8] {
894     type Predicate = BytesContentOutputPredicate;
895 
into_output(self) -> Self::Predicate896     fn into_output(self) -> Self::Predicate {
897         Self::Predicate::new(self)
898     }
899 }
900 
901 /// Keep `predicates` concrete Predicates out of our public API.
902 /// [predicates_core::Predicate] used by [`IntoOutputPredicate`] for [`str`].
903 ///
904 /// # Example
905 ///
906 /// ```rust,no_run
907 /// use assert_cmd::prelude::*;
908 ///
909 /// use std::process::Command;
910 ///
911 /// Command::cargo_bin("bin_fixture")
912 ///     .unwrap()
913 ///     .env("stdout", "hello")
914 ///     .env("stderr", "world")
915 ///     .assert()
916 ///     .stderr("world\n");
917 /// ```
918 ///
919 /// [`str`]: https://doc.rust-lang.org/std/primitive.str.html
920 #[derive(Debug, Clone)]
921 pub struct StrContentOutputPredicate(
922     predicates::str::Utf8Predicate<predicates::str::DifferencePredicate>,
923 );
924 
925 impl StrContentOutputPredicate {
from_str(value: &'static str) -> Self926     pub(crate) fn from_str(value: &'static str) -> Self {
927         let pred = predicates::str::diff(value).from_utf8();
928         StrContentOutputPredicate(pred)
929     }
930 
from_string(value: String) -> Self931     pub(crate) fn from_string(value: String) -> Self {
932         let pred = predicates::str::diff(value).from_utf8();
933         StrContentOutputPredicate(pred)
934     }
935 }
936 
937 impl predicates_core::reflection::PredicateReflection for StrContentOutputPredicate {
parameters<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a>938     fn parameters<'a>(
939         &'a self,
940     ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a> {
941         self.0.parameters()
942     }
943 
944     /// Nested `Predicate`s of the current `Predicate`.
children<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a>945     fn children<'a>(
946         &'a self,
947     ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a> {
948         self.0.children()
949     }
950 }
951 
952 impl predicates_core::Predicate<[u8]> for StrContentOutputPredicate {
eval(&self, item: &[u8]) -> bool953     fn eval(&self, item: &[u8]) -> bool {
954         self.0.eval(item)
955     }
956 
find_case<'a>( &'a self, expected: bool, variable: &[u8], ) -> Option<predicates_core::reflection::Case<'a>>957     fn find_case<'a>(
958         &'a self,
959         expected: bool,
960         variable: &[u8],
961     ) -> Option<predicates_core::reflection::Case<'a>> {
962         self.0.find_case(expected, variable)
963     }
964 }
965 
966 impl fmt::Display for StrContentOutputPredicate {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result967     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
968         self.0.fmt(f)
969     }
970 }
971 
972 impl IntoOutputPredicate<StrContentOutputPredicate> for String {
973     type Predicate = StrContentOutputPredicate;
974 
into_output(self) -> Self::Predicate975     fn into_output(self) -> Self::Predicate {
976         Self::Predicate::from_string(self)
977     }
978 }
979 
980 impl IntoOutputPredicate<StrContentOutputPredicate> for &'static str {
981     type Predicate = StrContentOutputPredicate;
982 
into_output(self) -> Self::Predicate983     fn into_output(self) -> Self::Predicate {
984         Self::Predicate::from_str(self)
985     }
986 }
987 
988 // Keep `predicates` concrete Predicates out of our public API.
989 /// [predicates_core::Predicate] used by [`IntoOutputPredicate`] for
990 /// [`Predicate<str>`][predicates_core::Predicate].
991 ///
992 /// # Example
993 ///
994 /// ```rust,no_run
995 /// use assert_cmd::prelude::*;
996 ///
997 /// use std::process::Command;
998 /// use predicates::prelude::*;
999 ///
1000 /// Command::cargo_bin("bin_fixture")
1001 ///     .unwrap()
1002 ///     .env("stdout", "hello")
1003 ///     .env("stderr", "world")
1004 ///     .assert()
1005 ///     .stderr(predicate::str::diff("world\n"));
1006 /// ```
1007 #[derive(Debug, Clone)]
1008 pub struct StrOutputPredicate<P: predicates_core::Predicate<str>>(
1009     predicates::str::Utf8Predicate<P>,
1010 );
1011 
1012 impl<P> StrOutputPredicate<P>
1013 where
1014     P: predicates_core::Predicate<str>,
1015 {
new(pred: P) -> Self1016     pub(crate) fn new(pred: P) -> Self {
1017         let pred = pred.from_utf8();
1018         StrOutputPredicate(pred)
1019     }
1020 }
1021 
1022 impl<P> predicates_core::reflection::PredicateReflection for StrOutputPredicate<P>
1023 where
1024     P: predicates_core::Predicate<str>,
1025 {
parameters<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a>1026     fn parameters<'a>(
1027         &'a self,
1028     ) -> Box<dyn Iterator<Item = predicates_core::reflection::Parameter<'a>> + 'a> {
1029         self.0.parameters()
1030     }
1031 
1032     /// Nested `Predicate`s of the current `Predicate`.
children<'a>( &'a self, ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a>1033     fn children<'a>(
1034         &'a self,
1035     ) -> Box<dyn Iterator<Item = predicates_core::reflection::Child<'a>> + 'a> {
1036         self.0.children()
1037     }
1038 }
1039 
1040 impl<P> predicates_core::Predicate<[u8]> for StrOutputPredicate<P>
1041 where
1042     P: predicates_core::Predicate<str>,
1043 {
eval(&self, item: &[u8]) -> bool1044     fn eval(&self, item: &[u8]) -> bool {
1045         self.0.eval(item)
1046     }
1047 
find_case<'a>( &'a self, expected: bool, variable: &[u8], ) -> Option<predicates_core::reflection::Case<'a>>1048     fn find_case<'a>(
1049         &'a self,
1050         expected: bool,
1051         variable: &[u8],
1052     ) -> Option<predicates_core::reflection::Case<'a>> {
1053         self.0.find_case(expected, variable)
1054     }
1055 }
1056 
1057 impl<P> fmt::Display for StrOutputPredicate<P>
1058 where
1059     P: predicates_core::Predicate<str>,
1060 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1061     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1062         self.0.fmt(f)
1063     }
1064 }
1065 
1066 impl<P> IntoOutputPredicate<StrOutputPredicate<P>> for P
1067 where
1068     P: predicates_core::Predicate<str>,
1069 {
1070     type Predicate = StrOutputPredicate<P>;
1071 
into_output(self) -> Self::Predicate1072     fn into_output(self) -> Self::Predicate {
1073         Self::Predicate::new(self)
1074     }
1075 }
1076 
1077 #[cfg(test)]
1078 mod test {
1079     use super::*;
1080 
1081     use predicates::prelude::*;
1082 
1083     // Since IntoCodePredicate exists solely for conversion, test it under that scenario to ensure
1084     // it works as expected.
convert_code<I, P>(pred: I) -> P where I: IntoCodePredicate<P>, P: predicates_core::Predicate<i32>,1085     fn convert_code<I, P>(pred: I) -> P
1086     where
1087         I: IntoCodePredicate<P>,
1088         P: predicates_core::Predicate<i32>,
1089     {
1090         pred.into_code()
1091     }
1092 
1093     #[test]
into_code_from_pred()1094     fn into_code_from_pred() {
1095         let pred = convert_code(predicate::eq(10));
1096         assert!(pred.eval(&10));
1097     }
1098 
1099     #[test]
into_code_from_i32()1100     fn into_code_from_i32() {
1101         let pred = convert_code(10);
1102         assert!(pred.eval(&10));
1103     }
1104 
1105     #[test]
into_code_from_vec()1106     fn into_code_from_vec() {
1107         let pred = convert_code(vec![3, 10]);
1108         assert!(pred.eval(&10));
1109     }
1110 
1111     #[test]
into_code_from_array()1112     fn into_code_from_array() {
1113         let pred = convert_code(&[3, 10] as &[i32]);
1114         assert!(pred.eval(&10));
1115     }
1116 
1117     // Since IntoOutputPredicate exists solely for conversion, test it under that scenario to ensure
1118     // it works as expected.
convert_output<I, P>(pred: I) -> P where I: IntoOutputPredicate<P>, P: predicates_core::Predicate<[u8]>,1119     fn convert_output<I, P>(pred: I) -> P
1120     where
1121         I: IntoOutputPredicate<P>,
1122         P: predicates_core::Predicate<[u8]>,
1123     {
1124         pred.into_output()
1125     }
1126 
1127     #[test]
into_output_from_pred()1128     fn into_output_from_pred() {
1129         let pred = convert_output(predicate::eq(b"Hello" as &[u8]));
1130         assert!(pred.eval(b"Hello" as &[u8]));
1131     }
1132 
1133     #[test]
into_output_from_bytes()1134     fn into_output_from_bytes() {
1135         let pred = convert_output(b"Hello" as &[u8]);
1136         assert!(pred.eval(b"Hello" as &[u8]));
1137     }
1138 
1139     #[test]
into_output_from_vec()1140     fn into_output_from_vec() {
1141         let pred = convert_output(vec![b'H', b'e', b'l', b'l', b'o']);
1142         assert!(pred.eval(b"Hello" as &[u8]));
1143     }
1144 
1145     #[test]
into_output_from_str()1146     fn into_output_from_str() {
1147         let pred = convert_output("Hello");
1148         assert!(pred.eval(b"Hello" as &[u8]));
1149     }
1150 }
1151