Skip to main content

assertables/assert_command/
assert_command_stdout_eq.rs

1//! Assert a command stdout string is equal to another.
2//!
3//! Pseudocode:<br>
4//! (a_command ⇒ stdout) = (b_command ⇒ stdout)
5//!
6//! # Example
7//!
8//! ```rust
9//! use assertables::*;
10//! use std::process::Command;
11//!
12//! let mut a = Command::new("bin/printf-stdout");
13//! a.args(["%s", "alfa"]);
14//! let mut b = Command::new("bin/printf-stdout");
15//! b.args(["%s", "alfa"]);
16//! assert_command_stdout_eq!(a, b);
17//! ```
18//!
19//! # Module macros
20//!
21//! * [`assert_command_stdout_eq`](macro@crate::assert_command_stdout_eq)
22//! * [`assert_command_stdout_eq_as_result`](macro@crate::assert_command_stdout_eq_as_result)
23//! * [`debug_assert_command_stdout_eq`](macro@crate::debug_assert_command_stdout_eq)
24
25/// Assert a command stdout string is equal to another.
26///
27/// Pseudocode:<br>
28/// (a_command ⇒ stdout) = (b_command ⇒ stdout)
29///
30/// * If true, return Result `Ok(stdout)`.
31///
32/// * Otherwise, return Result `Err(message)`.
33///
34/// This macro is useful for runtime checks, such as checking parameters,
35/// or sanitizing inputs, or handling different results in different ways.
36///
37/// # Module macros
38///
39/// * [`assert_command_stdout_eq`](macro@crate::assert_command_stdout_eq)
40/// * [`assert_command_stdout_eq_as_result`](macro@crate::assert_command_stdout_eq_as_result)
41/// * [`debug_assert_command_stdout_eq`](macro@crate::debug_assert_command_stdout_eq)
42///
43#[macro_export]
44macro_rules! assert_command_stdout_eq_as_result {
45    ($a_command:expr, $b_command:expr $(,)?) => {
46        match ($a_command.output(), $b_command.output()) {
47            (Ok(a), Ok(b)) => {
48                let a = a.stdout;
49                let b = b.stdout;
50                if a.eq(&b) {
51                    Ok((a, b))
52                } else {
53                    Err(
54                        format!(
55                            concat!(
56                                "assertion failed: `assert_command_stdout_eq!(a_command, b_command)`\n",
57                                "https://docs.rs/assertables/9.8.6/assertables/macro.assert_command_stdout_eq.html\n",
58                                " a label: `{}`,\n",
59                                " a debug: `{:?}`,\n",
60                                " a value: `{:?}`,\n",
61                                " b label: `{}`,\n",
62                                " b debug: `{:?}`,\n",
63                                " b value: `{:?}`"
64                            ),
65                            stringify!($a_command),
66                            $a_command,
67                            a,
68                            stringify!($b_command),
69                            $b_command,
70                            b
71                        )
72                    )
73                }
74            },
75            (a, b) => {
76                Err(
77                    format!(
78                        concat!(
79                            "assertion failed: `assert_command_stdout_eq!(a_command, b_command)`\n",
80                            "https://docs.rs/assertables/8.18/assert_command_stdout_eq/assertables/macro.assert_command_stdout_eq.html\n",
81                            " a label: `{}`,\n",
82                            " a debug: `{:?}`,\n",
83                            " a value: `{:?}`,\n",
84                            " b label: `{}`,\n",
85                            " b debug: `{:?}`,\n",
86                            " b value: `{:?}`"
87                        ),
88                        stringify!($a_command),
89                        $a_command,
90                        a,
91                        stringify!($b_command),
92                        $b_command,
93                        b
94                    )
95                )
96            }
97        }
98    };
99}
100
101#[cfg(test)]
102mod test_assert_command_stdout_eq_as_result {
103    use std::process::Command;
104    use std::sync::Once;
105
106    #[test]
107    fn eq() {
108        let mut a = Command::new("bin/printf-stdout");
109        a.args(["%s", "alfa"]);
110        let mut b = Command::new("bin/printf-stdout");
111        b.args(["%s", "alfa"]);
112        for _ in 0..1 {
113            let actual = assert_command_stdout_eq_as_result!(a, b);
114            assert_eq!(
115                actual.unwrap(),
116                (vec![b'a', b'l', b'f', b'a'], vec![b'a', b'l', b'f', b'a'])
117            );
118        }
119    }
120
121    #[test]
122    fn eq_once() {
123        static A: Once = Once::new();
124        fn a() -> Command {
125            if A.is_completed() {
126                panic!("A.is_completed()")
127            } else {
128                A.call_once(|| {})
129            }
130            let mut a = Command::new("bin/printf-stdout");
131            a.args(["%s", "alfa"]);
132            a
133        }
134
135        static B: Once = Once::new();
136        fn b() -> Command {
137            if B.is_completed() {
138                panic!("B.is_completed()")
139            } else {
140                B.call_once(|| {})
141            }
142            let mut b = Command::new("bin/printf-stdout");
143            b.args(["%s", "alfa"]);
144            b
145        }
146
147        assert_eq!(A.is_completed(), false);
148        assert_eq!(B.is_completed(), false);
149        let result = assert_command_stdout_eq_as_result!(a(), b());
150        assert!(result.is_ok());
151        assert_eq!(A.is_completed(), true);
152        assert_eq!(B.is_completed(), true);
153    }
154
155    #[test]
156    fn lt() {
157        let mut a = Command::new("bin/printf-stdout");
158        a.args(["%s", "alfa"]);
159        let mut b = Command::new("bin/printf-stdout");
160        b.args(["%s", "zz"]);
161        let actual = assert_command_stdout_eq_as_result!(a, b);
162        let message = concat!(
163            "assertion failed: `assert_command_stdout_eq!(a_command, b_command)`\n",
164            "https://docs.rs/assertables/9.8.6/assertables/macro.assert_command_stdout_eq.html\n",
165            " a label: `a`,\n",
166            " a debug: `\"bin/printf-stdout\" \"%s\" \"alfa\"`,\n",
167            " a value: `[97, 108, 102, 97]`,\n",
168            " b label: `b`,\n",
169            " b debug: `\"bin/printf-stdout\" \"%s\" \"zz\"`,\n",
170            " b value: `[122, 122]`"
171        );
172        assert_eq!(actual.unwrap_err(), message);
173    }
174
175    #[test]
176    fn gt() {
177        let mut a = Command::new("bin/printf-stdout");
178        a.args(["%s", "alfa"]);
179        let mut b = Command::new("bin/printf-stdout");
180        b.args(["%s", "aa"]);
181        let actual = assert_command_stdout_eq_as_result!(a, b);
182        let message = concat!(
183            "assertion failed: `assert_command_stdout_eq!(a_command, b_command)`\n",
184            "https://docs.rs/assertables/9.8.6/assertables/macro.assert_command_stdout_eq.html\n",
185            " a label: `a`,\n",
186            " a debug: `\"bin/printf-stdout\" \"%s\" \"alfa\"`,\n",
187            " a value: `[97, 108, 102, 97]`,\n",
188            " b label: `b`,\n",
189            " b debug: `\"bin/printf-stdout\" \"%s\" \"aa\"`,\n",
190            " b value: `[97, 97]`"
191        );
192        assert_eq!(actual.unwrap_err(), message);
193    }
194}
195
196/// Assert a command stdout string is equal to another.
197///
198/// Pseudocode:<br>
199/// (a_command ⇒ stdout) = (b_command ⇒ stdout)
200///
201/// * If true, return `(a_stdout, b_stdout)`.
202///
203/// * Otherwise, call [`panic!`] with a message and the values of the
204///   expressions with their debug representations.
205///
206/// # Examples
207///
208/// ```rust
209/// use assertables::*;
210/// # use std::panic;
211/// use std::process::Command;
212///
213/// # fn main() {
214/// let mut a = Command::new("bin/printf-stdout");
215/// a.args(["%s", "alfa"]);
216/// let mut b = Command::new("bin/printf-stdout");
217/// b.args(["%s", "alfa"]);
218/// assert_command_stdout_eq!(a, b);
219///
220/// # let result = panic::catch_unwind(|| {
221/// // This will panic
222/// let mut a = Command::new("bin/printf-stdout");
223/// a.args(["%s", "alfa"]);
224/// let mut b = Command::new("bin/printf-stdout");
225/// b.args(["%s", "zz"]);
226/// assert_command_stdout_eq!(a, b);
227/// # });
228/// // assertion failed: `assert_command_stdout_eq!(a_command, b_command)`
229/// // https://docs.rs/assertables/…/assertables/macro.assert_command_stdout_eq.html
230/// //  a label: `a`,
231/// //  a debug: `\"bin/printf-stdout\" \"%s\" \"alfa\"`,
232/// //  a value: `[97, 108, 102, 97]`,
233/// //  b label: `b`,
234/// //  b debug: `\"bin/printf-stdout\" \"%s\" \"zz\"`,
235/// //  b value: `[122, 122]`
236/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
237/// # let message = concat!(
238/// #     "assertion failed: `assert_command_stdout_eq!(a_command, b_command)`\n",
239/// #     "https://docs.rs/assertables/9.8.6/assertables/macro.assert_command_stdout_eq.html\n",
240/// #     " a label: `a`,\n",
241/// #     " a debug: `\"bin/printf-stdout\" \"%s\" \"alfa\"`,\n",
242/// #     " a value: `[97, 108, 102, 97]`,\n",
243/// #     " b label: `b`,\n",
244/// #     " b debug: `\"bin/printf-stdout\" \"%s\" \"zz\"`,\n",
245/// #     " b value: `[122, 122]`"
246/// # );
247/// # assert_eq!(actual, message);
248/// # }
249/// ```
250///
251/// # Module macros
252///
253/// * [`assert_command_stdout_eq`](macro@crate::assert_command_stdout_eq)
254/// * [`assert_command_stdout_eq_as_result`](macro@crate::assert_command_stdout_eq_as_result)
255/// * [`debug_assert_command_stdout_eq`](macro@crate::debug_assert_command_stdout_eq)
256///
257#[macro_export]
258macro_rules! assert_command_stdout_eq {
259    ($a_command:expr, $b_command:expr $(,)?) => {
260        match $crate::assert_command_stdout_eq_as_result!($a_command, $b_command) {
261            Ok(x) => x,
262            Err(err) => panic!("{}", err),
263        }
264    };
265    ($a_command:expr, $b_command:expr, $($message:tt)+) => {
266        match $crate::assert_command_stdout_eq_as_result!($a_command, $b_command) {
267            Ok(x) => x,
268            Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
269        }
270    };
271}
272
273#[cfg(test)]
274mod test_assert_command_stdout_eq {
275    use std::panic;
276    use std::process::Command;
277
278    #[test]
279    fn eq() {
280        let mut a = Command::new("bin/printf-stdout");
281        a.args(["%s", "alfa"]);
282        let mut b = Command::new("bin/printf-stdout");
283        b.args(["%s", "alfa"]);
284        for _ in 0..1 {
285            let actual = assert_command_stdout_eq!(a, b);
286            let expect = (vec![b'a', b'l', b'f', b'a'], vec![b'a', b'l', b'f', b'a']);
287            assert_eq!(actual, expect);
288        }
289    }
290
291    #[test]
292    fn lt() {
293        let result = panic::catch_unwind(|| {
294            let mut a = Command::new("bin/printf-stdout");
295            a.args(["%s", "alfa"]);
296            let mut b = Command::new("bin/printf-stdout");
297            b.args(["%s", "zz"]);
298            let _actual = assert_command_stdout_eq!(a, b);
299        });
300        let message = concat!(
301            "assertion failed: `assert_command_stdout_eq!(a_command, b_command)`\n",
302            "https://docs.rs/assertables/9.8.6/assertables/macro.assert_command_stdout_eq.html\n",
303            " a label: `a`,\n",
304            " a debug: `\"bin/printf-stdout\" \"%s\" \"alfa\"`,\n",
305            " a value: `[97, 108, 102, 97]`,\n",
306            " b label: `b`,\n",
307            " b debug: `\"bin/printf-stdout\" \"%s\" \"zz\"`,\n",
308            " b value: `[122, 122]`"
309        );
310        assert_eq!(
311            result
312                .unwrap_err()
313                .downcast::<String>()
314                .unwrap()
315                .to_string(),
316            message
317        );
318    }
319
320    #[test]
321    fn gt() {
322        let result = panic::catch_unwind(|| {
323            let mut a = Command::new("bin/printf-stdout");
324            a.args(["%s", "alfa"]);
325            let mut b = Command::new("bin/printf-stdout");
326            b.args(["%s", "aa"]);
327            let _actual = assert_command_stdout_eq!(a, b);
328        });
329        let message = concat!(
330            "assertion failed: `assert_command_stdout_eq!(a_command, b_command)`\n",
331            "https://docs.rs/assertables/9.8.6/assertables/macro.assert_command_stdout_eq.html\n",
332            " a label: `a`,\n",
333            " a debug: `\"bin/printf-stdout\" \"%s\" \"alfa\"`,\n",
334            " a value: `[97, 108, 102, 97]`,\n",
335            " b label: `b`,\n",
336            " b debug: `\"bin/printf-stdout\" \"%s\" \"aa\"`,\n",
337            " b value: `[97, 97]`"
338        );
339        assert_eq!(
340            result
341                .unwrap_err()
342                .downcast::<String>()
343                .unwrap()
344                .to_string(),
345            message
346        );
347    }
348}
349
350/// Assert a command stdout string is equal to another.
351///
352/// This macro provides the same statements as [`assert_command_stdout_eq {`](macro.assert_command_stdout_eq {.html),
353/// except this macro's statements are only enabled in non-optimized
354/// builds by default. An optimized build will not execute this macro's
355/// statements unless `-C debug-assertions` is passed to the compiler.
356///
357/// This macro is useful for checks that are too expensive to be present
358/// in a release build but may be helpful during development.
359///
360/// The result of expanding this macro is always type checked.
361///
362/// An unchecked assertion allows a program in an inconsistent state to
363/// keep running, which might have unexpected consequences but does not
364/// introduce unsafety as long as this only happens in safe code. The
365/// performance cost of assertions, however, is not measurable in general.
366/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
367/// after thorough profiling, and more importantly, only in safe code!
368///
369/// This macro is intended to work in a similar way to
370/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
371///
372/// # Module macros
373///
374/// * [`assert_command_stdout_eq {`](macro@crate::assert_command_stdout_eq {)
375/// * [`assert_command_stdout_eq {`](macro@crate::assert_command_stdout_eq {)
376/// * [`debug_assert_command_stdout_eq {`](macro@crate::debug_assert_command_stdout_eq {)
377///
378#[macro_export]
379macro_rules! debug_assert_command_stdout_eq {
380    ($($arg:tt)*) => {
381        if cfg!(debug_assertions) {
382            $crate::assert_command_stdout_eq!($($arg)*);
383        }
384    };
385}
386
387#[cfg(test)]
388mod test_debug_assert_command_stdout_eq {
389    use std::panic;
390    use std::process::Command;
391
392    #[test]
393    fn eq() {
394        let mut a = Command::new("bin/printf-stdout");
395        a.args(["%s", "alfa"]);
396        let mut b = Command::new("bin/printf-stdout");
397        b.args(["%s", "alfa"]);
398        for _ in 0..1 {
399            let _actual = debug_assert_command_stdout_eq!(a, b);
400            // assert_eq!(
401            //     actual,
402            //     (vec![b'a', b'l', b'f', b'a'], vec![b'a', b'l', b'f', b'a'])
403            // );
404        }
405    }
406
407    #[test]
408    fn lt() {
409        let result = panic::catch_unwind(|| {
410            let mut a = Command::new("bin/printf-stdout");
411            a.args(["%s", "alfa"]);
412            let mut b = Command::new("bin/printf-stdout");
413            b.args(["%s", "zz"]);
414            let _actual = debug_assert_command_stdout_eq!(a, b);
415        });
416        let message = concat!(
417            "assertion failed: `assert_command_stdout_eq!(a_command, b_command)`\n",
418            "https://docs.rs/assertables/9.8.6/assertables/macro.assert_command_stdout_eq.html\n",
419            " a label: `a`,\n",
420            " a debug: `\"bin/printf-stdout\" \"%s\" \"alfa\"`,\n",
421            " a value: `[97, 108, 102, 97]`,\n",
422            " b label: `b`,\n",
423            " b debug: `\"bin/printf-stdout\" \"%s\" \"zz\"`,\n",
424            " b value: `[122, 122]`"
425        );
426        assert_eq!(
427            result
428                .unwrap_err()
429                .downcast::<String>()
430                .unwrap()
431                .to_string(),
432            message
433        );
434    }
435
436    #[test]
437    fn gt() {
438        let result = panic::catch_unwind(|| {
439            let mut a = Command::new("bin/printf-stdout");
440            a.args(["%s", "alfa"]);
441            let mut b = Command::new("bin/printf-stdout");
442            b.args(["%s", "aa"]);
443            let _actual = debug_assert_command_stdout_eq!(a, b);
444        });
445        let message = concat!(
446            "assertion failed: `assert_command_stdout_eq!(a_command, b_command)`\n",
447            "https://docs.rs/assertables/9.8.6/assertables/macro.assert_command_stdout_eq.html\n",
448            " a label: `a`,\n",
449            " a debug: `\"bin/printf-stdout\" \"%s\" \"alfa\"`,\n",
450            " a value: `[97, 108, 102, 97]`,\n",
451            " b label: `b`,\n",
452            " b debug: `\"bin/printf-stdout\" \"%s\" \"aa\"`,\n",
453            " b value: `[97, 97]`"
454        );
455        assert_eq!(
456            result
457                .unwrap_err()
458                .downcast::<String>()
459                .unwrap()
460                .to_string(),
461            message
462        );
463    }
464}