assertables/assert_status/
assert_status_code_value_ge_x.rs

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