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