assertables/assert_status/assert_status_code_value_lt.rs
1//! Assert a status code value is less than 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("1");
13//! let mut b = Command::new("bin/exit-with-arg"); b.arg("2");
14//! assert_status_code_value_lt!(a, b);
15//! ```
16//!
17//! # Module macros
18//!
19//! * [`assert_status_code_value_lt`](macro@crate::assert_status_code_value_lt)
20//! * [`assert_status_code_value_lt_as_result`](macro@crate::assert_status_code_value_lt_as_result)
21//! * [`debug_assert_status_code_value_lt`](macro@crate::debug_assert_status_code_value_lt)
22
23/// Assert a status code value is less than 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_lt`](macro@crate::assert_status_code_value_lt)
38/// * [`assert_status_code_value_lt_as_result`](macro@crate::assert_status_code_value_lt_as_result)
39/// * [`debug_assert_status_code_value_lt`](macro@crate::debug_assert_status_code_value_lt)
40///
41#[macro_export]
42macro_rules! assert_status_code_value_lt_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_lt!(a, b)`\n",
53 "https://docs.rs/assertables/9.8.3/assertables/macro.assert_status_code_value_lt.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_lt!(a, b)`\n",
73 "https://docs.rs/assertables/9.8.3/assertables/macro.assert_status_code_value_lt.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_lt!(a, b)`\n",
88 "https://docs.rs/assertables/9.8.3/assertables/macro.assert_status_code_value_lt.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_lt_as_result {
105 use std::process::Command;
106 use std::sync::Once;
107
108 #[test]
109 fn lt() {
110 let mut a = Command::new("bin/exit-with-arg");
111 a.arg("1");
112 let mut b = Command::new("bin/exit-with-arg");
113 b.arg("2");
114 for _ in 0..1 {
115 let actual = assert_status_code_value_lt_as_result!(a, b);
116 assert_eq!(actual.unwrap(), (1, 2));
117 }
118 }
119
120 #[test]
121 fn lt_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("1");
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("2");
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_lt_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 let actual = assert_status_code_value_lt_as_result!(a, b);
161 let message = concat!(
162 "assertion failed: `assert_status_code_value_lt!(a, b)`\n",
163 "https://docs.rs/assertables/9.8.3/assertables/macro.assert_status_code_value_lt.html\n",
164 " a label: `a`,\n",
165 " a debug: `\"bin/exit-with-arg\" \"1\"`,\n",
166 " a code: `1`,\n",
167 " b label: `b`,\n",
168 " b debug: `\"bin/exit-with-arg\" \"1\"`\n",
169 " b code: `1`"
170 );
171 assert_eq!(actual.unwrap_err(), message);
172 }
173
174 #[test]
175 fn gt() {
176 let mut a = Command::new("bin/exit-with-arg");
177 a.arg("2");
178 let mut b = Command::new("bin/exit-with-arg");
179 b.arg("1");
180 let actual = assert_status_code_value_lt_as_result!(a, b);
181 let message = concat!(
182 "assertion failed: `assert_status_code_value_lt!(a, b)`\n",
183 "https://docs.rs/assertables/9.8.3/assertables/macro.assert_status_code_value_lt.html\n",
184 " a label: `a`,\n",
185 " a debug: `\"bin/exit-with-arg\" \"2\"`,\n",
186 " a code: `2`,\n",
187 " b label: `b`,\n",
188 " b debug: `\"bin/exit-with-arg\" \"1\"`\n",
189 " b code: `1`"
190 );
191 assert_eq!(actual.unwrap_err(), message);
192 }
193}
194
195/// Assert a status code value is less than another.
196///
197/// Pseudocode:<br>
198/// a ⇒ status ⇒ code ⇒ value < b ⇒ status ⇒ code ⇒ value
199///
200/// * If true, return `(a value, b value)`.
201///
202/// * Otherwise, call [`panic!`] with a message and the values of the
203/// expressions with their debug representations.
204///
205/// # Examples
206///
207/// ```rust
208/// use assertables::*;
209/// use std::process::Command;
210/// # use std::panic;
211///
212/// # fn main() {
213/// let mut a = Command::new("bin/exit-with-arg"); a.arg("1");
214/// let mut b = Command::new("bin/exit-with-arg"); b.arg("2");
215/// assert_status_code_value_lt!(a, b);
216///
217/// # let result = panic::catch_unwind(|| {
218/// // This will panic
219/// let mut a = Command::new("bin/exit-with-arg"); a.arg("2");
220/// let mut b = Command::new("bin/exit-with-arg"); b.arg("1");
221/// assert_status_code_value_lt!(a, b);
222/// # });
223/// // assertion failed: `assert_status_code_value_lt!(a, b)`
224/// // https://docs.rs/assertables/…/assertables/macro.assert_status_code_value_lt.html
225/// // a label: `a`,
226/// // a debug: `\"bin/exit-with-arg\" \"1\"`,
227/// // a value: `2`",
228/// // b label: `b`,
229/// // b debug: `\"bin/exit-with-arg\" \"1\"`,
230/// // b value: `1`"
231/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
232/// # let message = concat!(
233/// # "assertion failed: `assert_status_code_value_lt!(a, b)`\n",
234/// # "https://docs.rs/assertables/9.8.3/assertables/macro.assert_status_code_value_lt.html\n",
235/// # " a label: `a`,\n",
236/// # " a debug: `\"bin/exit-with-arg\" \"2\"`,\n",
237/// # " a code: `2`,\n",
238/// # " b label: `b`,\n",
239/// # " b debug: `\"bin/exit-with-arg\" \"1\"`\n",
240/// # " b code: `1`",
241/// # );
242/// # assert_eq!(actual, message);
243/// # }
244/// ```
245///
246/// # Module macros
247///
248/// * [`assert_status_code_value_lt`](macro@crate::assert_status_code_value_lt)
249/// * [`assert_status_code_value_lt_as_result`](macro@crate::assert_status_code_value_lt_as_result)
250/// * [`debug_assert_status_code_value_lt`](macro@crate::debug_assert_status_code_value_lt)
251///
252#[macro_export]
253macro_rules! assert_status_code_value_lt {
254 ($a_process:expr, $b_process:expr $(,)?) => {
255 match $crate::assert_status_code_value_lt_as_result!($a_process, $b_process) {
256 Ok(x) => x,
257 Err(err) => panic!("{}", err),
258 }
259 };
260 ($a_process:expr, $b_process:expr, $($message:tt)+) => {
261 match $crate::assert_status_code_value_lt_as_result!($a_process, $b_process) {
262 Ok(x) => x,
263 Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
264 }
265 };
266}
267
268#[cfg(test)]
269mod test_assert_status_code_value_lt {
270 use std::panic;
271 use std::process::Command;
272
273 #[test]
274 fn lt() {
275 let mut a = Command::new("bin/exit-with-arg");
276 a.arg("1");
277 let mut b = Command::new("bin/exit-with-arg");
278 b.arg("2");
279 for _ in 0..1 {
280 let actual = assert_status_code_value_lt!(a, b);
281 assert_eq!(actual, (1, 2));
282 }
283 }
284
285 #[test]
286 fn eq() {
287 let result = panic::catch_unwind(|| {
288 let mut a = Command::new("bin/exit-with-arg");
289 a.arg("1");
290 let mut b = Command::new("bin/exit-with-arg");
291 b.arg("1");
292 let _actual = assert_status_code_value_lt!(a, b);
293 });
294 let message = concat!(
295 "assertion failed: `assert_status_code_value_lt!(a, b)`\n",
296 "https://docs.rs/assertables/9.8.3/assertables/macro.assert_status_code_value_lt.html\n",
297 " a label: `a`,\n",
298 " a debug: `\"bin/exit-with-arg\" \"1\"`,\n",
299 " a code: `1`,\n",
300 " b label: `b`,\n",
301 " b debug: `\"bin/exit-with-arg\" \"1\"`\n",
302 " b code: `1`"
303 );
304 assert_eq!(
305 result
306 .unwrap_err()
307 .downcast::<String>()
308 .unwrap()
309 .to_string(),
310 message
311 );
312 }
313
314 #[test]
315 fn gt() {
316 let result = panic::catch_unwind(|| {
317 let mut a = Command::new("bin/exit-with-arg");
318 a.arg("2");
319 let mut b = Command::new("bin/exit-with-arg");
320 b.arg("1");
321 let _actual = assert_status_code_value_lt!(a, b);
322 });
323 let message = concat!(
324 "assertion failed: `assert_status_code_value_lt!(a, b)`\n",
325 "https://docs.rs/assertables/9.8.3/assertables/macro.assert_status_code_value_lt.html\n",
326 " a label: `a`,\n",
327 " a debug: `\"bin/exit-with-arg\" \"2\"`,\n",
328 " a code: `2`,\n",
329 " b label: `b`,\n",
330 " b debug: `\"bin/exit-with-arg\" \"1\"`\n",
331 " b code: `1`"
332 );
333 assert_eq!(
334 result
335 .unwrap_err()
336 .downcast::<String>()
337 .unwrap()
338 .to_string(),
339 message
340 );
341 }
342}
343
344/// Assert a status code value is less than another.
345///
346/// Pseudocode:<br>
347/// a ⇒ status ⇒ code ⇒ value < b ⇒ status ⇒ code ⇒ value
348///
349/// This macro provides the same statements as [`assert_status_code_value_lt`](macro.assert_status_code_value_lt.html),
350/// except this macro's statements are only enabled in non-optimized
351/// builds by default. An optimized build will not execute this macro's
352/// statements unless `-C debug-assertions` is passed to the compiler.
353///
354/// This macro is useful for checks that are too expensive to be present
355/// in a release build but may be helpful during development.
356///
357/// The result of expanding this macro is always type checked.
358///
359/// An unchecked assertion allows a "bin/exit-with-arg" in an inconsistent state to
360/// keep running, which might have unexpected consequences but does not
361/// introduce unsafety as long as this only happens in safe code. The
362/// performance cost of assertions, however, is not measurable in general.
363/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
364/// after thorough profiling, and more importantly, only in safe code!
365///
366/// This macro is intended to work in a similar way to
367/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
368///
369/// # Module macros
370///
371/// * [`assert_status_code_value_lt`](macro@crate::assert_status_code_value_lt)
372/// * [`assert_status_code_value_lt`](macro@crate::assert_status_code_value_lt)
373/// * [`debug_assert_status_code_value_lt`](macro@crate::debug_assert_status_code_value_lt)
374///
375#[macro_export]
376macro_rules! debug_assert_status_code_value_lt {
377 ($($arg:tt)*) => {
378 if $crate::cfg!(debug_assertions) {
379 $crate::assert_status_code_value_lt!($($arg)*);
380 }
381 };
382}