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