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