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