assertables/assert_status/assert_status_success.rs
1//! Assert a status is a success.
2//!
3//! Pseudocode:<br>
4//! a ⇒ status ⇒ success = true
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("0");
13//! assert_status_success!(a);
14//! ```
15//!
16//! # Module macros
17//!
18//! * [`assert_status_success`](macro@crate::assert_status_success)
19//! * [`assert_status_success_as_result`](macro@crate::assert_status_success_as_result)
20//! * [`debug_assert_status_success`](macro@crate::debug_assert_status_success)
21
22/// Assert a status is a success.
23///
24/// Pseudocode:<br>
25/// a ⇒ status ⇒ success = true
26///
27/// * If true, return Result `Ok(a ⇒ status ⇒ code ⇒ value)`.
28///
29/// * Otherwise, return Result `Err(message)`.
30///
31/// This macro is useful for runtime checks, such as checking parameters,
32/// or sanitizing inputs, or handling different results in different ways.
33///
34/// # Module macros
35///
36/// * [`assert_status_success`](macro@crate::assert_status_success)
37/// * [`assert_status_success_as_result`](macro@crate::assert_status_success_as_result)
38/// * [`debug_assert_status_success`](macro@crate::debug_assert_status_success)
39///
40#[macro_export]
41macro_rules! assert_status_success_as_result {
42 ($a:expr $(,)?) => {
43 match ($a.status()) {
44 Ok(a1) => {
45 if a1.success() {
46 Ok(true)
47 } else {
48 Err(format!(
49 concat!(
50 "assertion failed: `assert_status_success!(a)`\n",
51 "https://docs.rs/assertables/9.8.3/assertables/macro.assert_status_success.html\n",
52 " a label: `{}`,\n",
53 " a debug: `{:?}`",
54 ),
55 stringify!($a),
56 $a,
57 ))
58 }
59 }
60 a_status => Err(format!(
61 concat!(
62 "assertion failed: `assert_status_success!(a)`\n",
63 "https://docs.rs/assertables/9.8.3/assertables/macro.assert_status_success.html\n",
64 " a label: `{}`,\n",
65 " a debug: `{:?}`,\n",
66 " a status: `{:?}`",
67 ),
68 stringify!($a),
69 $a,
70 a_status
71 )),
72 }
73 };
74}
75
76#[cfg(test)]
77mod test_assert_status_success_as_result {
78 use std::process::Command;
79 use std::sync::Once;
80
81 #[test]
82 fn success() {
83 let mut a = Command::new("bin/exit-with-arg");
84 a.arg("0");
85 for _ in 0..1 {
86 let actual = assert_status_success_as_result!(a);
87 assert_eq!(actual.unwrap(), true);
88 }
89 }
90
91 #[test]
92 fn success_once() {
93 static A: Once = Once::new();
94 fn a() -> Command {
95 if A.is_completed() {
96 panic!("A.is_completed()")
97 } else {
98 A.call_once(|| {})
99 }
100 let mut a = Command::new("bin/exit-with-arg");
101 a.arg("0");
102 a
103 }
104
105 assert_eq!(A.is_completed(), false);
106 let result = assert_status_success_as_result!(a());
107 assert!(result.is_ok());
108 assert_eq!(A.is_completed(), true);
109 }
110
111 #[test]
112 fn failure() {
113 let mut a = Command::new("bin/exit-with-arg");
114 a.arg("1");
115 let actual = assert_status_success_as_result!(a);
116 let message = concat!(
117 "assertion failed: `assert_status_success!(a)`\n",
118 "https://docs.rs/assertables/9.8.3/assertables/macro.assert_status_success.html\n",
119 " a label: `a`,\n",
120 " a debug: `\"bin/exit-with-arg\" \"1\"`",
121 );
122 assert_eq!(actual.unwrap_err(), message);
123 }
124}
125
126/// Assert a status is a success.
127///
128/// Pseudocode:<br>
129/// a ⇒ status ⇒ success = true
130///
131/// * If true, return `a ⇒ status ⇒ code ⇒ value``.
132///
133/// * Otherwise, call [`panic!`] with a message and the values of the
134/// expressions with their debug representations.
135///
136/// # Examples
137///
138/// ```rust
139/// use assertables::*;
140/// use std::process::Command;
141/// # use std::panic;
142///
143/// # fn main() {
144/// let mut a = Command::new("bin/exit-with-arg"); a.arg("0");
145/// assert_status_success!(a);
146///
147/// # let result = panic::catch_unwind(|| {
148/// // This will panic
149/// let mut a = Command::new("bin/exit-with-arg"); a.arg("1");
150/// assert_status_success!(a);
151/// # });
152/// // assertion failed: `assert_status_success!(a)`
153/// // https://docs.rs/assertables/…/assertables/macro.assert_status_success.html
154/// // a label: `a`,
155/// // a debug: `\"bin/exit-with-arg\" \"1\"`
156/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
157/// # let message = concat!(
158/// # "assertion failed: `assert_status_success!(a)`\n",
159/// # "https://docs.rs/assertables/9.8.3/assertables/macro.assert_status_success.html\n",
160/// # " a label: `a`,\n",
161/// # " a debug: `\"bin/exit-with-arg\" \"1\"`"
162/// # );
163/// # assert_eq!(actual, message);
164/// # }
165/// ```
166///
167/// # Module macros
168///
169/// * [`assert_status_success`](macro@crate::assert_status_success)
170/// * [`assert_status_success_as_result`](macro@crate::assert_status_success_as_result)
171/// * [`debug_assert_status_success`](macro@crate::debug_assert_status_success)
172///
173#[macro_export]
174macro_rules! assert_status_success {
175 ($a:expr $(,)?) => {
176 match $crate::assert_status_success_as_result!($a) {
177 Ok(x) => x,
178 Err(err) => panic!("{}", err),
179 }
180 };
181 ($a:expr, $($message:tt)+) => {
182 match $crate::assert_status_success_as_result!($a) {
183 Ok(x) => x,
184 Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
185 }
186 };
187}
188
189#[cfg(test)]
190mod test_assert_status_success {
191 use std::panic;
192 use std::process::Command;
193
194 #[test]
195 fn success() {
196 let mut a = Command::new("bin/exit-with-arg");
197 a.arg("0");
198 for _ in 0..1 {
199 let actual = assert_status_success!(a);
200 assert_eq!(actual, true);
201 }
202 }
203
204 #[test]
205 fn failure() {
206 let result = panic::catch_unwind(|| {
207 let mut a = Command::new("bin/exit-with-arg");
208 a.arg("1");
209 let _actual = assert_status_success!(a);
210 });
211 let message = concat!(
212 "assertion failed: `assert_status_success!(a)`\n",
213 "https://docs.rs/assertables/9.8.3/assertables/macro.assert_status_success.html\n",
214 " a label: `a`,\n",
215 " a debug: `\"bin/exit-with-arg\" \"1\"`",
216 );
217 assert_eq!(
218 result
219 .unwrap_err()
220 .downcast::<String>()
221 .unwrap()
222 .to_string(),
223 message
224 );
225 }
226}
227
228/// Assert a status is a success.
229///
230/// Pseudocode:<br>
231/// a ⇒ status ⇒ success = true
232///
233/// This macro provides the same statements as [`assert_status_success`](macro.assert_status_success.html),
234/// except this macro's statements are only enabled in non-optimized
235/// builds by default. An optimized build will not execute this macro's
236/// statements unless `-C debug-assertions` is passed to the compiler.
237///
238/// This macro is useful for checks that are too expensive to be present
239/// in a release build but may be helpful during development.
240///
241/// The result of expanding this macro is always type checked.
242///
243/// An unchecked assertion allows a "bin/exit-with-arg" in an inconsistent state to
244/// keep running, which might have unexpected consequences but does not
245/// introduce unsafety as long as this only happens in safe code. The
246/// performance cost of assertions, however, is not measurable in general.
247/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
248/// after thorough profiling, and more importantly, only in safe code!
249///
250/// This macro is intended to work in a similar way to
251/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
252///
253/// # Module macros
254///
255/// * [`assert_status_success`](macro@crate::assert_status_success)
256/// * [`assert_status_success`](macro@crate::assert_status_success)
257/// * [`debug_assert_status_success`](macro@crate::debug_assert_status_success)
258///
259#[macro_export]
260macro_rules! debug_assert_status_success {
261 ($($arg:tt)*) => {
262 if $crate::cfg!(debug_assertions) {
263 $crate::assert_status_success!($($arg)*);
264 }
265 };
266}