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}