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