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