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