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/9.5.3/assertables/macro.assert_lt.html\n",
53                            " a label: `{}`,\n",
54                            " a debug: `{:?}`,\n",
55                            " b label: `{}`,\n",
56                            " b debug: `{:?}`",
57                        ),
58                        stringify!($a),
59                        a,
60                        stringify!($b),
61                        b
62                    ))
63                }
64            }
65        }
66    }};
67}
68
69#[cfg(test)]
70mod test_assert_lt_as_result {
71
72    #[test]
73    fn lt() {
74        let a: i8 = 1;
75        let b: i8 = 2;
76        let actual = assert_lt_as_result!(a, b);
77        assert_eq!(actual.unwrap(), ());
78    }
79
80    #[test]
81    fn eq() {
82        let a: i8 = 1;
83        let b: i8 = 1;
84        let actual = assert_lt_as_result!(a, b);
85        let message = concat!(
86            "assertion failed: `assert_lt!(a, b)`\n",
87            "https://docs.rs/assertables/9.5.3/assertables/macro.assert_lt.html\n",
88            " a label: `a`,\n",
89            " a debug: `1`,\n",
90            " b label: `b`,\n",
91            " b debug: `1`",
92        );
93        assert_eq!(actual.unwrap_err(), message);
94    }
95
96    #[test]
97    fn gt() {
98        let a: i8 = 2;
99        let b: i8 = 1;
100        let actual = assert_lt_as_result!(a, b);
101        let message = concat!(
102            "assertion failed: `assert_lt!(a, b)`\n",
103            "https://docs.rs/assertables/9.5.3/assertables/macro.assert_lt.html\n",
104            " a label: `a`,\n",
105            " a debug: `2`,\n",
106            " b label: `b`,\n",
107            " b debug: `1`",
108        );
109        assert_eq!(actual.unwrap_err(), message);
110    }
111
112    use std::sync::Once;
113    #[test]
114    fn once() {
115
116        static A: Once = Once::new();
117        fn a() -> i8 {
118            if A.is_completed() { panic!("A.is_completed()") } else { A.call_once(|| {}) }
119            1
120        }
121
122        static B: Once = Once::new();
123        fn b() -> i8 {
124            if B.is_completed() { panic!("B.is_completed()") } else { B.call_once(|| {}) }
125            2
126        }
127
128        assert_eq!(A.is_completed(), false);
129        assert_eq!(B.is_completed(), false);
130        let result = assert_lt_as_result!(a(), b());
131        assert!(result.is_ok());
132        assert_eq!(A.is_completed(), true);
133        assert_eq!(B.is_completed(), true);
134    }
135
136}
137
138/// Assert an expression is less than another.
139///
140/// Pseudocode:<br>
141/// a < b
142///
143/// * If true, return `()`.
144///
145/// * Otherwise, call [`panic!`] with a message and the values of the
146///   expressions with their debug representations.
147///
148/// # Examples
149///
150/// ```rust
151/// use assertables::*;
152/// # use std::panic;
153///
154/// # fn main() {
155/// let a = 1;
156/// let b = 2;
157/// assert_lt!(a, b);
158///
159/// # let result = panic::catch_unwind(|| {
160/// // This will panic
161/// let a = 2;
162/// let b = 1;
163/// assert_lt!(a, b);
164/// # });
165/// // assertion failed: `assert_lt!(a, b)`
166/// // https://docs.rs/assertables/9.5.3/assertables/macro.assert_lt.html
167/// //  a label: `a`,
168/// //  a debug: `2`,
169/// //  b label: `b`,
170/// //  b debug: `1`
171/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
172/// # let message = concat!(
173/// #     "assertion failed: `assert_lt!(a, b)`\n",
174/// #     "https://docs.rs/assertables/9.5.3/assertables/macro.assert_lt.html\n",
175/// #     " a label: `a`,\n",
176/// #     " a debug: `2`,\n",
177/// #     " b label: `b`,\n",
178/// #     " b debug: `1`",
179/// # );
180/// # assert_eq!(actual, message);
181/// # }
182/// ```
183///
184/// # Module macros
185///
186/// * [`assert_lt`](macro@crate::assert_lt)
187/// * [`assert_lt_as_result`](macro@crate::assert_lt_as_result)
188/// * [`debug_assert_lt`](macro@crate::debug_assert_lt)
189///
190#[macro_export]
191macro_rules! assert_lt {
192    ($a:expr, $b:expr $(,)?) => {{
193        match $crate::assert_lt_as_result!($a, $b) {
194            Ok(()) => (),
195            Err(err) => panic!("{}", err),
196        }
197    }};
198    ($a:expr, $b:expr, $($message:tt)+) => {{
199        match $crate::assert_lt_as_result!($a, $b) {
200            Ok(()) => (),
201            Err(err) => panic!("{}\n{}", format_args!($($message)+), err)
202        }
203    }};
204}
205
206#[cfg(test)]
207mod test_assert_lt {
208    use std::panic;
209
210    #[test]
211    fn lt() {
212        let a: i8 = 1;
213        let b: i8 = 2;
214        let actual = assert_lt!(a, b);
215        assert_eq!(actual, ());
216    }
217
218    #[test]
219    fn eq() {
220        let a: i8 = 1;
221        let b: i8 = 1;
222        let result = panic::catch_unwind(|| {
223            let _actual = assert_lt!(a, b);
224        });
225        let message = concat!(
226            "assertion failed: `assert_lt!(a, b)`\n",
227            "https://docs.rs/assertables/9.5.3/assertables/macro.assert_lt.html\n",
228            " a label: `a`,\n",
229            " a debug: `1`,\n",
230            " b label: `b`,\n",
231            " b debug: `1`",
232        );
233        assert_eq!(
234            result
235                .unwrap_err()
236                .downcast::<String>()
237                .unwrap()
238                .to_string(),
239            message
240        );
241    }
242
243    #[test]
244    fn gt() {
245        let a: i8 = 2;
246        let b: i8 = 1;
247        let result = panic::catch_unwind(|| {
248            let _actual = assert_lt!(a, b);
249        });
250        let message = concat!(
251            "assertion failed: `assert_lt!(a, b)`\n",
252            "https://docs.rs/assertables/9.5.3/assertables/macro.assert_lt.html\n",
253            " a label: `a`,\n",
254            " a debug: `2`,\n",
255            " b label: `b`,\n",
256            " b debug: `1`",
257        );
258        assert_eq!(
259            result
260                .unwrap_err()
261                .downcast::<String>()
262                .unwrap()
263                .to_string(),
264            message
265        );
266    }
267}
268
269/// Assert an expression is less than another.
270///
271/// Pseudocode:<br>
272/// a < b
273///
274/// This macro provides the same statements as [`assert_lt`](macro.assert_lt.html),
275/// except this macro's statements are only enabled in non-optimized
276/// builds by default. An optimized build will not execute this macro's
277/// statements unless `-C debug-assertions` is passed to the compiler.
278///
279/// This macro is useful for checks that are too expensive to be present
280/// in a release build but may be helpful during development.
281///
282/// The result of expanding this macro is always type checked.
283///
284/// An unchecked assertion allows a program in an inconsistent state to
285/// keep running, which might have unexpected consequences but does not
286/// introduce unsafety as long as this only happens in safe code. The
287/// performance cost of assertions, however, is not measurable in general.
288/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
289/// after thorough profiling, and more importantly, only in safe code!
290///
291/// This macro is intended to work in a similar way to
292/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
293///
294/// # Module macros
295///
296/// * [`assert_lt`](macro@crate::assert_lt)
297/// * [`assert_lt`](macro@crate::assert_lt)
298/// * [`debug_assert_lt`](macro@crate::debug_assert_lt)
299///
300#[macro_export]
301macro_rules! debug_assert_lt {
302    ($($arg:tt)*) => {
303        if $crate::cfg!(debug_assertions) {
304            $crate::assert_lt!($($arg)*);
305        }
306    };
307}