Skip to main content

assertables/assert_command/
assert_command_stdout_ne_x.rs

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