assertables/
assert_lt.rs

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