assertables/assert_status/
assert_status_code_value_eq_x.rs

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