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