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