assertables/
assert_infix.rs

1//! Assert a infix operator, such as assert_infix!(a == b).
2//!
3//! Pseudocode:<br>
4//! a infix b
5//!
6//! Compare values via infix value operator:
7//!
8//! * `assert_infix!(a == b)` ≈ a == b
9//!
10//! * `assert_infix!(a != b)` ≈ a ≠ b
11//!
12//! * `assert_infix!(a < b)` ≈ a < b
13//!
14//! * `assert_infix!(a <= b)` ≈ a ≤ b
15//!
16//! * `assert_infix!(a > b)` ≈ a > b
17//!
18//! * `assert_infix!(a >= b)` ≈ a ≥ b
19//!
20//! Relate values via infix logical operator:
21//!
22//! * `assert_infix!(a & b)` ≈ a ∧ b ≈ a AND b
23//!
24//! * `assert_infix!(a | b)` ≈ a ∨ b ≈ a OR b
25//!
26//! * `assert_infix!(a ^ b)` ≈ a ⊻ b ≈ a XOR b
27//!
28//! * `assert_infix!(a && b)` ≈ a …∧ b ≈ a lazy AND b
29//!
30//! * `assert_infix!(a || b)` ≈ a …∨ b ≈ a lazy OR b
31//!
32//!
33//! # Example
34//!
35//! ```rust
36//! use assertables::*;
37//!
38//! let a = 1;
39//! let b = 1;
40//! assert_infix!(a == b);
41//! ```
42//!
43//! # Infix operators
44//!
45//! For values:
46//!
47//! * `==`  equal
48//! * `!=`  not equal
49//! * `<`	less than
50//! * `<=`	less than or equal to
51//! * `>`	greater than
52//! * `>=`	greater than or equal to
53//!
54//! For booleans:
55//!
56//! * `^`	logical XOR
57//! * `!`	logical NOT
58//! * `&`	logical AND
59//! * `|`	logical OR
60//! * `&&`	logical lazy AND
61//! * `||`	logical lazy OR
62//!
63//! # Module macros
64//!
65//! * [`assert_infix`](macro@crate::assert_infix)
66//! * [`assert_infix_as_result`](macro@crate::assert_infix_as_result)
67//! * [`debug_assert_infix`](macro@crate::debug_assert_infix)
68
69/// Assert a infix operator, such as assert_infix!(a == b).
70///
71/// Pseudocode:<br>
72/// a infix b
73///
74/// * If true, return Result `Ok(())`.
75///
76/// * Otherwise, return Result `Err(message)`.
77///
78/// This macro is useful for runtime checks, such as checking parameters,
79/// or sanitizing inputs, or handling different results in different ways.
80///
81/// # Module macros
82///
83/// * [`assert_infix`](macro@crate::assert_infix)
84/// * [`assert_infix_as_result`](macro@crate::assert_infix_as_result)
85/// * [`debug_assert_infix`](macro@crate::debug_assert_infix)
86///
87#[macro_export]
88macro_rules! assert_infix_as_result {
89    ($a:tt $infix:tt $b:tt) => {
90        if $a $infix $b {
91            Ok(())
92        } else {
93            Err(
94                format!(
95                    concat!(
96                        "assertion failed: `assert_infix!(a {} b)`\n",
97                        "https://docs.rs/assertables/", env!("CARGO_PKG_VERSION"), "/assertables/macro.assert_infix.html\n",
98                        " a label: `{}`,\n",
99                        " a debug: `{:?}`,\n",
100                        " b label: `{}`,\n",
101                        " b debug: `{:?}`",
102                    ),
103                    stringify!($infix),
104                    stringify!($a),
105                    $a,
106                    stringify!($b),
107                    $b,
108                )
109            )
110        }
111    };
112}
113
114#[cfg(test)]
115mod test_assert_infix_as_result {
116    // use std::sync::Once;
117
118    #[test]
119    fn success() {
120        let a: i8 = 1;
121        let b: i8 = 1;
122        for _ in 0..1 {
123            let actual = assert_infix_as_result!(a == b);
124            assert_eq!(actual.unwrap(), ());
125        }
126    }
127
128    #[test]
129    fn failure() {
130        let a: i8 = 1;
131        let b: i8 = 2;
132        let actual = assert_infix_as_result!(a == b);
133        let message = concat!(
134            "assertion failed: `assert_infix!(a == b)`\n",
135            "https://docs.rs/assertables/",
136            env!("CARGO_PKG_VERSION"),
137            "/assertables/macro.assert_infix.html\n",
138            " a label: `a`,\n",
139            " a debug: `1`,\n",
140            " b label: `b`,\n",
141            " b debug: `2`",
142        );
143        assert_eq!(actual.unwrap_err(), message);
144    }
145}
146
147/// Assert a infix operator, such as assert_infix!(a == b).
148///
149/// Pseudocode:<br>
150/// a infix b
151///
152/// * If true, return `()`.
153///
154/// * Otherwise, call [`panic!`] with a message and the values of the
155///   expressions with their debug representations.
156///
157/// # Examples
158///
159/// ```rust
160/// use assertables::*;
161/// # use std::panic;
162///
163/// # fn main() {
164/// let a = 1;
165/// let b = 1;
166/// assert_infix!(a == b);
167///
168/// # let result = panic::catch_unwind(|| {
169/// // This will panic
170/// let a = 1;
171/// let b = 2;
172/// assert_infix!(a == b);
173/// # });
174/// // assertion failed: `assert_infix!(a == b)`
175/// // https://docs.rs/assertables/9.7.0/assertables/macro.assert_infix.html
176/// //  a label: `a`,
177/// //  a debug: `1`,
178/// //  b label: `b`,
179/// //  b debug: `2`
180/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
181/// # let message = concat!(
182/// #     "assertion failed: `assert_infix!(a == b)`\n",
183/// #     "https://docs.rs/assertables/", env!("CARGO_PKG_VERSION"), "/assertables/macro.assert_infix.html\n",
184/// #     " a label: `a`,\n",
185/// #     " a debug: `1`,\n",
186/// #     " b label: `b`,\n",
187/// #     " b debug: `2`",
188/// # );
189/// # assert_eq!(actual, message);
190/// # }
191/// ```
192///
193/// # Infix operators
194///
195/// For values:
196///
197/// * `==`  equal
198/// * `!=`  not equal
199/// * `<`	less than
200/// * `<=`	less than or equal to
201/// * `>`	greater than
202/// * `>=`	greater than or equal to
203///
204/// For booleans:
205///
206/// * `^`	logical XOR
207/// * `!`	logical NOT
208/// * `&`	logical AND
209/// * `|`	logical OR
210/// * `&&`	logical lazy AND
211/// * `||`	logical lazy OR
212///
213/// # Module macros
214///
215/// * [`assert_infix`](macro@crate::assert_infix)
216/// * [`assert_infix_as_result`](macro@crate::assert_infix_as_result)
217/// * [`debug_assert_infix`](macro@crate::debug_assert_infix)
218///
219#[macro_export]
220macro_rules! assert_infix {
221    ($a:tt $infix:tt $b:tt) => {
222        match $crate::assert_infix_as_result!($a $infix $b) {
223            Ok(()) => (),
224            Err(err) => panic!("{}", err),
225        }
226    };
227    ($a:tt $infix:tt $b:tt, $($message:tt)+) => {
228        match $crate::assert_infix_as_result!($a $infix $b) {
229            Ok(()) => (),
230            Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
231        }
232    };
233}
234
235#[cfg(test)]
236mod test_assert_infix {
237    use std::panic;
238
239    #[test]
240    fn success() {
241        let a: i8 = 1;
242        let b: i8 = 1;
243        for _ in 0..1 {
244            let actual = assert_infix!(a == b);
245            assert_eq!(actual, ());
246        }
247    }
248
249    #[test]
250    fn failure() {
251        let a: i8 = 1;
252        let b: i8 = 2;
253        let result = panic::catch_unwind(|| {
254            let _actual = assert_infix!(a == b);
255        });
256        let message = concat!(
257            "assertion failed: `assert_infix!(a == b)`\n",
258            "https://docs.rs/assertables/",
259            env!("CARGO_PKG_VERSION"),
260            "/assertables/macro.assert_infix.html\n",
261            " a label: `a`,\n",
262            " a debug: `1`,\n",
263            " b label: `b`,\n",
264            " b debug: `2`",
265        );
266        assert_eq!(
267            result
268                .unwrap_err()
269                .downcast::<String>()
270                .unwrap()
271                .to_string(),
272            message
273        );
274    }
275}
276
277/// Assert a infix operator, such as assert_infix!(a == b).
278///
279/// Pseudocode:<br>
280/// a infix b
281///
282/// This macro provides the same statements as [`assert_infix`](macro.assert_infix.html),
283/// except this macro's statements are only enabled in non-optimized
284/// builds by default. An optimized build will not execute this macro's
285/// statements unless `-C debug-assertions` is passed to the compiler.
286///
287/// This macro is useful for checks that are too expensive to be present
288/// in a release build but may be helpful during development.
289///
290/// The result of expanding this macro is always type checked.
291///
292/// An unchecked assertion allows a program in an inconsistent state to
293/// keep running, which might have unexpected consequences but does not
294/// introduce unsafety as long as this only happens in safe code. The
295/// performance cost of assertions, however, is not measurable in general.
296/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
297/// after thorough profiling, and more importantly, only in safe code!
298///
299/// This macro is intended to work in a similar way to
300/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
301///
302/// # Module macros
303///
304/// * [`assert_infix`](macro@crate::assert_infix)
305/// * [`assert_infix`](macro@crate::assert_infix)
306/// * [`debug_assert_infix`](macro@crate::debug_assert_infix)
307///
308#[macro_export]
309macro_rules! debug_assert_infix {
310    ($($arg:tt)*) => {
311        if $crate::cfg!(debug_assertions) {
312            $crate::assert_infix!($($arg)*);
313        }
314    };
315}