Skip to main content

assert_cmd/
assert.rs

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