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