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