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