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