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) => 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_ge_x!(a, b)`\n",
53 "https://docs.rs/assertables/",
54 env!("CARGO_PKG_VERSION"),
55 "/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 None => Err(format!(
71 concat!(
72 "assertion failed: `assert_status_code_value_ge_x!(a, b)`\n",
73 "https://docs.rs/assertables/",
74 env!("CARGO_PKG_VERSION"),
75 "/assertables/macro.assert_status_code_value_ge_x.html\n",
76 " a label: `{}`,\n",
77 " a debug: `{:?}`,\n",
78 " b label: `{}`,\n",
79 " b debug: `{:?}`",
80 ),
81 stringify!($a_process),
82 $a_process,
83 stringify!($b),
84 b,
85 )),
86 },
87 _ => Err(format!(
88 concat!(
89 "assertion failed: `assert_status_code_value_ge_x!(a, b)`\n",
90 "https://docs.rs/assertables/",
91 env!("CARGO_PKG_VERSION"),
92 "/assertables/macro.assert_status_code_value_ge_x.html\n",
93 " a label: `{}`,\n",
94 " a debug: `{:?}`,\n",
95 " b label: `{}`,\n",
96 " b debug: `{:?}`",
97 ),
98 stringify!($a_process),
99 $a_process,
100 stringify!($b),
101 $b
102 )),
103 }
104 };
105}
106
107#[cfg(test)]
108mod test_assert_status_code_value_ge_x_as_result {
109 use std::process::Command;
110 use std::sync::Once;
111
112 #[test]
113 fn gt() {
114 let mut a = Command::new("bin/exit-with-arg");
115 a.arg("2");
116 let b = 1;
117 for _ in 0..1 {
118 let actual = assert_status_code_value_ge_x_as_result!(a, b);
119 assert_eq!(actual.unwrap(), 2);
120 }
121 }
122
123 #[test]
124 fn gt_once() {
125 static A: Once = Once::new();
126 fn a() -> Command {
127 if A.is_completed() {
128 panic!("A.is_completed()")
129 } else {
130 A.call_once(|| {})
131 }
132 let mut a = Command::new("bin/exit-with-arg");
133 a.arg("2");
134 a
135 }
136
137 static B: Once = Once::new();
138 fn b() -> i32 {
139 if B.is_completed() {
140 panic!("B.is_completed()")
141 } else {
142 B.call_once(|| {})
143 }
144 1
145 }
146
147 assert_eq!(A.is_completed(), false);
148 assert_eq!(B.is_completed(), false);
149 let result = assert_status_code_value_ge_x_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 eq() {
157 let mut a = Command::new("bin/exit-with-arg");
158 a.arg("1");
159 let b = 1;
160 for _ in 0..1 {
161 let actual = assert_status_code_value_ge_x_as_result!(a, b);
162 assert_eq!(actual.unwrap(), 1);
163 }
164 }
165
166 #[test]
167 fn eq_once() {
168 static A: Once = Once::new();
169 fn a() -> Command {
170 if A.is_completed() {
171 panic!("A.is_completed()")
172 } else {
173 A.call_once(|| {})
174 }
175 let mut a = Command::new("bin/exit-with-arg");
176 a.arg("1");
177 a
178 }
179
180 static B: Once = Once::new();
181 fn b() -> i32 {
182 if B.is_completed() {
183 panic!("B.is_completed()")
184 } else {
185 B.call_once(|| {})
186 }
187 1
188 }
189
190 assert_eq!(A.is_completed(), false);
191 assert_eq!(B.is_completed(), false);
192 let result = assert_status_code_value_ge_x_as_result!(a(), b());
193 assert!(result.is_ok());
194 assert_eq!(A.is_completed(), true);
195 assert_eq!(B.is_completed(), true);
196 }
197
198 #[test]
199 fn lt() {
200 let mut a = Command::new("bin/exit-with-arg");
201 a.arg("1");
202 let b = 2;
203 let actual = assert_status_code_value_ge_x_as_result!(a, b);
204 let message = concat!(
205 "assertion failed: `assert_status_code_value_ge_x!(a, b)`\n",
206 "https://docs.rs/assertables/",
207 env!("CARGO_PKG_VERSION"),
208 "/assertables/macro.assert_status_code_value_ge_x.html\n",
209 " a label: `a`,\n",
210 " a debug: `\"bin/exit-with-arg\" \"1\"`,\n",
211 " a code: `1`,\n",
212 " b label: `b`,\n",
213 " b debug: `2`"
214 );
215 assert_eq!(actual.unwrap_err(), message);
216 }
217}
218
219/// Assert a status code value is greater than or equal to an expression.
220///
221/// Pseudocode:<br>
222/// a.len() ≥ b
223///
224/// * If true, return `a ⇒ status ⇒ code ⇒ value``.
225///
226/// * Otherwise, call [`panic!`] with a message and the values of the
227/// expressions with their debug representations.
228///
229/// # Examples
230///
231/// ```rust
232/// use assertables::*;
233/// use std::process::Command;
234/// # use std::panic;
235///
236/// # fn main() {
237/// let mut a = Command::new("bin/exit-with-arg"); a.arg("2");
238/// let b = 1;
239/// assert_status_code_value_ge_x!(a, b);
240///
241/// # let result = panic::catch_unwind(|| {
242/// // This will panic
243/// let mut a = Command::new("bin/exit-with-arg"); a.arg("1");
244/// let b = 2;
245/// assert_status_code_value_ge_x!(a, b);
246/// # });
247/// // assertion failed: `assert_status_code_value_ge_x!(a, b)`
248/// // https://docs.rs/assertables/9.7.0/assertables/macro.assert_status_code_value_ge_x.html
249/// // a label: `a`,
250/// // a debug: `\"bin/exit-with-arg\" \"1\"`,
251/// // a value: `1`",
252/// // b label: `b`,
253/// // b debug: `2`
254/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
255/// # let message = concat!(
256/// # "assertion failed: `assert_status_code_value_ge_x!(a, b)`\n",
257/// # "https://docs.rs/assertables/", env!("CARGO_PKG_VERSION"), "/assertables/macro.assert_status_code_value_ge_x.html\n",
258/// # " a label: `a`,\n",
259/// # " a debug: `\"bin/exit-with-arg\" \"1\"`,\n",
260/// # " a code: `1`,\n",
261/// # " b label: `b`,\n",
262/// # " b debug: `2`"
263/// # );
264/// # assert_eq!(actual, message);
265/// # }
266/// ```
267///
268/// # Module macros
269///
270/// * [`assert_status_code_value_ge_x`](macro@crate::assert_status_code_value_ge_x)
271/// * [`assert_status_code_value_ge_x_as_result`](macro@crate::assert_status_code_value_ge_x_as_result)
272/// * [`debug_assert_status_code_value_ge_x`](macro@crate::debug_assert_status_code_value_ge_x)
273///
274#[macro_export]
275macro_rules! assert_status_code_value_ge_x {
276 ($a_process:expr, $b:expr $(,)?) => {
277 match $crate::assert_status_code_value_ge_x_as_result!($a_process, $b) {
278 Ok(x) => x,
279 Err(err) => panic!("{}", err),
280 }
281 };
282 ($a_process:expr, $b:expr, $($message:tt)+) => {
283 match $crate::assert_status_code_value_ge_x_as_result!($a_process, $b) {
284 Ok(x) => x,
285 Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
286 }
287 };
288}
289
290#[cfg(test)]
291mod test_assert_status_code_value_ge_x {
292 use std::panic;
293 use std::process::Command;
294
295 #[test]
296 fn gt() {
297 let mut a = Command::new("bin/exit-with-arg");
298 a.arg("2");
299 let b = 1;
300 for _ in 0..1 {
301 let actual = assert_status_code_value_ge_x!(a, b);
302 assert_eq!(actual, 2);
303 }
304 }
305
306 #[test]
307 fn eq() {
308 let mut a = Command::new("bin/exit-with-arg");
309 a.arg("1");
310 let b = 1;
311 for _ in 0..1 {
312 let actual = assert_status_code_value_ge_x!(a, b);
313 assert_eq!(actual, 1);
314 }
315 }
316
317 #[test]
318 fn lt() {
319 let result = panic::catch_unwind(|| {
320 let mut a = Command::new("bin/exit-with-arg");
321 a.arg("1");
322 let b = 2;
323 let _actual = assert_status_code_value_ge_x!(a, b);
324 });
325 let message = concat!(
326 "assertion failed: `assert_status_code_value_ge_x!(a, b)`\n",
327 "https://docs.rs/assertables/",
328 env!("CARGO_PKG_VERSION"),
329 "/assertables/macro.assert_status_code_value_ge_x.html\n",
330 " a label: `a`,\n",
331 " a debug: `\"bin/exit-with-arg\" \"1\"`,\n",
332 " a code: `1`,\n",
333 " b label: `b`,\n",
334 " b debug: `2`"
335 );
336 assert_eq!(
337 result
338 .unwrap_err()
339 .downcast::<String>()
340 .unwrap()
341 .to_string(),
342 message
343 );
344 }
345}
346
347/// Assert a status code value is greater than or equal to an expression.
348///
349/// Pseudocode:<br>
350/// a.len() ≥ b
351///
352/// This macro provides the same statements as [`assert_status_code_value_ge_x`](macro.assert_status_code_value_ge_x.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 "bin/exit-with-arg" 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_status_code_value_ge_x`](macro@crate::assert_status_code_value_ge_x)
375/// * [`assert_status_code_value_ge_x`](macro@crate::assert_status_code_value_ge_x)
376/// * [`debug_assert_status_code_value_ge_x`](macro@crate::debug_assert_status_code_value_ge_x)
377///
378#[macro_export]
379macro_rules! debug_assert_status_code_value_ge_x {
380 ($($arg:tt)*) => {
381 if $crate::cfg!(debug_assertions) {
382 $crate::assert_status_code_value_ge_x!($($arg)*);
383 }
384 };
385}