assertables/assert_fn_ok/assert_fn_ok_le.rs
1//! Assert a function Ok(…) is less than or equal to another.
2//!
3//! Pseudocode:<br>
4//! (a_function(a_param) ⇒ Ok(a) ⇒ a) ≤ (b_function(b_param) ⇒ Ok(b) ⇒ b)
5//!
6//! # Example
7//!
8//! ```rust
9//! use assertables::*;
10//! fn f(i: i8) -> Result<String, String> {
11//! match i {
12//! 0..=9 => Ok(format!("{}", i)),
13//! _ => Err(format!("{:?} is out of range", i)),
14//! }
15//! }
16//!
17//! let a: i8 = 1;
18//! let b: i8 = 2;
19//! assert_fn_ok_le!(f, a, f, b);
20//! ```
21//!
22//! # Module macros
23//!
24//! * [`assert_fn_ok_le`](macro@crate::assert_fn_ok_le)
25//! * [`assert_fn_ok_le_as_result`](macro@crate::assert_fn_ok_le_as_result)
26//! * [`debug_assert_fn_ok_le`](macro@crate::debug_assert_fn_ok_le)
27
28/// Assert a function Ok(…) is less than or equal to another.
29///
30/// Pseudocode:<br>
31/// (a_function(a_param) ⇒ Ok(a) ⇒ a) ≤ (b_function(b_param) ⇒ Ok(b) ⇒ b)
32///
33/// * If true, return Result `Ok(a, b)`.
34///
35/// * Otherwise, return Result `Err(message)`.
36///
37/// This macro is useful for runtime checks, such as checking parameters,
38/// or sanitizing inputs, or handling different results in different ways.
39///
40/// # Module macros
41///
42/// * [`assert_fn_ok_le`](macro@crate::assert_fn_ok_le)
43/// * [`assert_fn_ok_le_as_result`](macro@crate::assert_fn_ok_le_as_result)
44/// * [`debug_assert_fn_ok_le`](macro@crate::debug_assert_fn_ok_le)
45///
46#[macro_export]
47macro_rules! assert_fn_ok_le_as_result {
48
49 //// Arity 1
50
51 ($a_function:path, $a_param:expr, $b_function:path, $b_param:expr $(,)?) => {{
52 match (&$a_function, &$a_param, &$b_function, &$b_param) {
53 (_a_function, a_param, _b_function, b_param) => {
54 match (
55 $a_function($a_param),
56 $b_function($b_param)
57 ) {
58 (Ok(a), Ok(b)) => {
59 if a <= b {
60 Ok((a, b))
61 } else {
62 Err(
63 format!(
64 concat!(
65 "assertion failed: `assert_fn_ok_le!(a_function, a_param, b_function, b_param)`\n",
66 "https://docs.rs/assertables/9.5.3/assertables/macro.assert_fn_ok_le.html\n",
67 " a_function label: `{}`,\n",
68 " a_param label: `{}`,\n",
69 " a_param debug: `{:?}`,\n",
70 " b_function label: `{}`,\n",
71 " b_param label: `{}`,\n",
72 " b_param debug: `{:?}`,\n",
73 " a: `{:?}`,\n",
74 " b: `{:?}`"
75 ),
76 stringify!($a_function),
77 stringify!($a_param),
78 a_param,
79 stringify!($b_function),
80 stringify!($b_param),
81 b_param,
82 a,
83 b
84 )
85 )
86 }
87 },
88 (a, b) => {
89 Err(
90 format!(
91 concat!(
92 "assertion failed: `assert_fn_err_le!(a_function, a_param, b_function, b_param)`\n",
93 "https://docs.rs/assertables/9.5.3/assertables/macro.assert_fn_err_le.html\n",
94 " a_function label: `{}`,\n",
95 " a_param label: `{}`,\n",
96 " a_param debug: `{:?}`,\n",
97 " b_function label: `{}`,\n",
98 " b_param label: `{}`,\n",
99 " b_param debug: `{:?}`,\n",
100 " a: `{:?}`,\n",
101 " b: `{:?}`"
102 ),
103 stringify!($a_function),
104 stringify!($a_param),
105 a_param,
106 stringify!($b_function),
107 stringify!($b_param),
108 b_param,
109 a,
110 b
111 )
112 )
113 }
114 }
115 }
116 }
117 }};
118
119 //// Arity 0
120
121 ($a_function:path, $b_function:path) => {{
122 match (
123 $a_function(),
124 $b_function()
125 ) {
126 (Ok(a), Ok(b)) => {
127 if a <= b {
128 Ok((a, b))
129 } else {
130 Err(
131 format!(
132 concat!(
133 "assertion failed: `assert_fn_ok_le!(a_function, b_function)`\n",
134 "https://docs.rs/assertables/9.5.3/assertables/macro.assert_fn_ok_le.html\n",
135 " a_function label: `{}`,\n",
136 " b_function label: `{}`,\n",
137 " a: `{:?}`,\n",
138 " b: `{:?}`"
139 ),
140 stringify!($a_function),
141 stringify!($b_function),
142 a,
143 b
144 )
145 )
146 }
147 },
148 (a, b) => {
149 Err(
150 format!(
151 concat!(
152 "assertion failed: `assert_fn_err_le!(a_function, b_function)`\n",
153 "https://docs.rs/assertables/9.5.3/assertables/macro.assert_fn_err_le.html\n",
154 " a_function label: `{}`,\n",
155 " b_function label: `{}`,\n",
156 " a: `{:?}`,\n",
157 " b: `{:?}`"
158 ),
159 stringify!($a_function),
160 stringify!($b_function),
161 a,
162 b
163 )
164 )
165 }
166 }
167 }};
168
169}
170
171#[cfg(test)]
172mod test_assert_fn_ok_le_as_result {
173
174 mod arity_1 {
175
176 fn f(i: i8) -> Result<i8, i8> {
177 return Ok(i);
178 }
179
180 fn g(i: i8) -> Result<i8, i8> {
181 return Ok(i);
182 }
183
184 #[test]
185 fn lt() {
186 let a: i8 = 1;
187 let b: i8 = 2;
188 let actual = assert_fn_ok_le_as_result!(f, a, g, b);
189 assert_eq!(actual.unwrap(), (1, 2));
190 }
191
192 #[test]
193 fn eq() {
194 let a: i8 = 1;
195 let b: i8 = 1;
196 let actual = assert_fn_ok_le_as_result!(f, a, g, b);
197 assert_eq!(actual.unwrap(), (1, 1));
198 }
199
200 #[test]
201 fn gt() {
202 let a: i8 = 2;
203 let b: i8 = 1;
204 let actual = assert_fn_ok_le_as_result!(f, a, g, b);
205 let message = concat!(
206 "assertion failed: `assert_fn_ok_le!(a_function, a_param, b_function, b_param)`\n",
207 "https://docs.rs/assertables/9.5.3/assertables/macro.assert_fn_ok_le.html\n",
208 " a_function label: `f`,\n",
209 " a_param label: `a`,\n",
210 " a_param debug: `2`,\n",
211 " b_function label: `g`,\n",
212 " b_param label: `b`,\n",
213 " b_param debug: `1`,\n",
214 " a: `2`,\n",
215 " b: `1`"
216 );
217 assert_eq!(actual.unwrap_err(), message);
218 }
219 }
220
221 mod arity_0 {
222
223 fn f() -> Result<i8, i8> {
224 return Ok(1);
225 }
226
227 fn g() -> Result<i8, i8> {
228 return Ok(2);
229 }
230
231 #[test]
232 fn lt() {
233 let actual = assert_fn_ok_le_as_result!(f, g);
234 assert_eq!(actual.unwrap(), (1, 2));
235 }
236
237 #[test]
238 fn eq() {
239 let actual = assert_fn_ok_le_as_result!(f, f);
240 assert_eq!(actual.unwrap(), (1, 1));
241 }
242
243 #[test]
244 fn gt() {
245 let actual = assert_fn_ok_le_as_result!(g, f);
246 let message = concat!(
247 "assertion failed: `assert_fn_ok_le!(a_function, b_function)`\n",
248 "https://docs.rs/assertables/9.5.3/assertables/macro.assert_fn_ok_le.html\n",
249 " a_function label: `g`,\n",
250 " b_function label: `f`,\n",
251 " a: `2`,\n",
252 " b: `1`"
253 );
254 assert_eq!(actual.unwrap_err(), message);
255 }
256 }
257}
258
259/// Assert a function Ok(…) is less than or equal to another.
260///
261/// Pseudocode:<br>
262/// (a_function(a_param) ⇒ Ok(a) ⇒ a) ≤ (b_function(b_param) ⇒ Ok(b) ⇒ b)
263///
264/// * If true, return `(a, b)`.
265///
266/// * Otherwise, call [`panic!`] with a message and the values of the
267/// expressions with their debug representations.
268///
269/// # Examples
270///
271/// ```rust
272/// use assertables::*;
273/// # use std::panic;
274/// fn f(i: i8) -> Result<String, String> {
275/// match i {
276/// 0..=9 => Ok(format!("{}", i)),
277/// _ => Err(format!("{:?} is out of range", i)),
278/// }
279/// }
280///
281/// # fn main() {
282/// let a: i8 = 1;
283/// let b: i8 = 2;
284/// assert_fn_ok_le!(f, a, f, b);
285///
286/// # let result = panic::catch_unwind(|| {
287/// // This will panic
288/// let a: i8 = 2;
289/// let b: i8 = 1;
290/// assert_fn_ok_le!(f, a, f, b);
291/// # });
292/// // assertion failed: `assert_fn_ok_le!(a_function, a_param, b_function, b_param)`
293/// // https://docs.rs/assertables/9.5.3/assertables/macro.assert_fn_ok_le.html
294/// // a_function label: `f`,
295/// // a_param label: `a`,
296/// // a_param debug: `2`,
297/// // b_function label: `f`,
298/// // b_param label: `b`,
299/// // b_param debug: `1`,
300/// // a: `\"2\"`,
301/// // b: `\"1\"`
302/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
303/// # let message = concat!(
304/// # "assertion failed: `assert_fn_ok_le!(a_function, a_param, b_function, b_param)`\n",
305/// # "https://docs.rs/assertables/9.5.3/assertables/macro.assert_fn_ok_le.html\n",
306/// # " a_function label: `f`,\n",
307/// # " a_param label: `a`,\n",
308/// # " a_param debug: `2`,\n",
309/// # " b_function label: `f`,\n",
310/// # " b_param label: `b`,\n",
311/// # " b_param debug: `1`,\n",
312/// # " a: `\"2\"`,\n",
313/// # " b: `\"1\"`"
314/// # );
315/// # assert_eq!(actual, message);
316/// # }
317/// ```
318///
319/// # Module macros
320///
321/// * [`assert_fn_ok_le`](macro@crate::assert_fn_ok_le)
322/// * [`assert_fn_ok_le_as_result`](macro@crate::assert_fn_ok_le_as_result)
323/// * [`debug_assert_fn_ok_le`](macro@crate::debug_assert_fn_ok_le)
324///
325#[macro_export]
326macro_rules! assert_fn_ok_le {
327
328 //// Arity 1
329
330 ($a_function:path, $a_param:expr, $b_function:path, $b_param:expr $(,)?) => {{
331 match $crate::assert_fn_ok_le_as_result!($a_function, $a_param, $b_function, $b_param) {
332 Ok(x) => x,
333 Err(err) => panic!("{}", err),
334 }
335 }};
336
337 ($a_function:path, $a_param:expr, $b_function:path, $b_param:expr, $($message:tt)+) => {{
338 match $crate::assert_fn_ok_le_as_result!($a_function, $a_param, $b_function, $b_param) {
339 Ok(x) => x,
340 Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
341 }
342 }};
343
344 //// Arity 0
345
346 ($a_function:path, $b_function:path) => {{
347 match $crate::assert_fn_ok_le_as_result!($a_function, $b_function) {
348 Ok(x) => x,
349 Err(err) => panic!("{}", err),
350 }
351 }};
352
353 ($a_function:path, $b_function:path, $($message:tt)+) => {{
354 match $crate::assert_fn_ok_le_as_result!($a_function, $b_function) {
355 Ok(x) => x,
356 Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
357 }
358 }};
359}
360
361#[cfg(test)]
362mod test_assert_fn_ok_le {
363 use std::panic;
364
365 mod arity_1 {
366 use super::*;
367
368 fn f(i: i8) -> Result<i8, i8> {
369 return Ok(i);
370 }
371
372 fn g(i: i8) -> Result<i8, i8> {
373 return Ok(i);
374 }
375
376 #[test]
377 fn lt() {
378 let a: i8 = 1;
379 let b: i8 = 2;
380 let actual = assert_fn_ok_le!(f, a, g, b);
381 assert_eq!(actual, (1, 2));
382 }
383
384 #[test]
385 fn eq() {
386 let a: i8 = 1;
387 let b: i8 = 1;
388 let actual = assert_fn_ok_le!(f, a, g, b);
389 assert_eq!(actual, (1, 1));
390 }
391
392 #[test]
393 fn gt() {
394 let result = panic::catch_unwind(|| {
395 let a: i8 = 2;
396 let b: i8 = 1;
397 let _actual = assert_fn_ok_le!(f, a, g, b);
398 });
399 let message = concat!(
400 "assertion failed: `assert_fn_ok_le!(a_function, a_param, b_function, b_param)`\n",
401 "https://docs.rs/assertables/9.5.3/assertables/macro.assert_fn_ok_le.html\n",
402 " a_function label: `f`,\n",
403 " a_param label: `a`,\n",
404 " a_param debug: `2`,\n",
405 " b_function label: `g`,\n",
406 " b_param label: `b`,\n",
407 " b_param debug: `1`,\n",
408 " a: `2`,\n",
409 " b: `1`"
410 );
411 assert_eq!(
412 result
413 .unwrap_err()
414 .downcast::<String>()
415 .unwrap()
416 .to_string(),
417 message
418 );
419 }
420 }
421
422 mod arity_0 {
423 use super::*;
424
425 fn f() -> Result<i8, i8> {
426 return Ok(1);
427 }
428
429 fn g() -> Result<i8, i8> {
430 return Ok(2);
431 }
432
433 #[test]
434 fn lt() {
435 let actual = assert_fn_ok_le!(f, g);
436 assert_eq!(actual, (1, 2));
437 }
438
439 #[test]
440 fn eq() {
441 let actual = assert_fn_ok_le!(f, f);
442 assert_eq!(actual, (1, 1));
443 }
444
445 #[test]
446 fn gt() {
447 let result = panic::catch_unwind(|| {
448 let _actual = assert_fn_ok_le!(g, f);
449 });
450 let message = concat!(
451 "assertion failed: `assert_fn_ok_le!(a_function, b_function)`\n",
452 "https://docs.rs/assertables/9.5.3/assertables/macro.assert_fn_ok_le.html\n",
453 " a_function label: `g`,\n",
454 " b_function label: `f`,\n",
455 " a: `2`,\n",
456 " b: `1`"
457 );
458 assert_eq!(
459 result
460 .unwrap_err()
461 .downcast::<String>()
462 .unwrap()
463 .to_string(),
464 message
465 );
466 }
467 }
468}
469
470/// Assert a function Ok(…) is less than or equal to another.
471///
472/// Pseudocode:<br>
473/// (a_function(a_param) ⇒ Ok(a) ⇒ a) ≤ (b_function(b_param) ⇒ Ok(b) ⇒ b)
474///
475/// This macro provides the same statements as [`assert_fn_ok_le`](macro.assert_fn_ok_le.html),
476/// except this macro's statements are only enabled in non-optimized
477/// builds by default. An optimized build will not execute this macro's
478/// statements unless `-C debug-assertions` is passed to the compiler.
479///
480/// This macro is useful for checks that are too expensive to be present
481/// in a release build but may be helpful during development.
482///
483/// The result of expanding this macro is always type checked.
484///
485/// An unchecked assertion allows a program in an inconsistent state to
486/// keep running, which might have unexpected consequences but does not
487/// introduce unsafety as long as this only happens in safe code. The
488/// performance cost of assertions, however, is not measurable in general.
489/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
490/// after thorough profiling, and more importantly, only in safe code!
491///
492/// This macro is intended to work in a similar way to
493/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
494///
495/// # Module macros
496///
497/// * [`assert_fn_ok_le`](macro@crate::assert_fn_ok_le)
498/// * [`assert_fn_ok_le`](macro@crate::assert_fn_ok_le)
499/// * [`debug_assert_fn_ok_le`](macro@crate::debug_assert_fn_ok_le)
500///
501#[macro_export]
502macro_rules! debug_assert_fn_ok_le {
503 ($($arg:tt)*) => {
504 if $crate::cfg!(debug_assertions) {
505 $crate::assert_fn_ok_le!($($arg)*);
506 }
507 };
508}