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