assert_cmp/
lib.rs

1//! Convenient assertion macros that print the failed expressions and their evaluated values.
2#![no_std]
3#![no_implicit_prelude]
4
5/// Create assertion macros for boolean binary operators.
6#[macro_export]
7macro_rules! operator_assertion_macros {
8    (
9        $(#![$shared_attr:meta])*
10        in $module:path;
11        use $assert:path;
12        $(#[$attr_simple:meta])* simple = $name_simple:ident;
13        $(#[$attr_expr:meta])* expr = $name_expr:ident;
14    ) => {
15        $(#[$shared_attr])*
16        $(#[$attr_expr])*
17        macro_rules! $name_expr {
18            ($left:expr, $op:tt, $right:expr) => {
19                match ($left, $right) {
20                    (left, right) => {
21                        $assert!(
22                            left $op right,
23                            "{left_expr} {op} {right_expr} ⇒ {left_value:?} {op} {right_value:?} ⇒ false",
24                            op = stringify!($op),
25                            left_expr = stringify!($left),
26                            right_expr = stringify!($right),
27                            left_value = left,
28                            right_value = right,
29                        )
30                    }
31                }
32            };
33        }
34
35        $(#[$shared_attr])*
36        $(#[$attr_simple])*
37        macro_rules! $name_simple {
38            ($left:ident $op:tt $right:ident) => {
39                $module::$name_expr!($left, $op, $right)
40            };
41            ($left:ident $op:tt $right:literal) => {
42                $module::$name_expr!($left, $op, $right)
43            };
44            ($left:literal $op:tt $right:ident) => {
45                $module::$name_expr!($left, $op, $right)
46            };
47            ($left:literal $op:tt $right:literal) => {
48                $module::$name_expr!($left, $op, $right)
49            };
50        }
51    };
52}
53
54/// Create an assertion macro for boolean function calls.
55#[macro_export]
56macro_rules! function_assertion_macro {
57    (
58        $(#![$shared_attr:meta])*
59        use $assert:path;
60        $(#[$attr:meta])* $name:ident;
61    ) => {
62        $(#[$shared_attr])*
63        $(#[$attr])*
64        macro_rules! $name {
65            ($function:ident($left:expr, $right:expr)) => {
66                match ($left, $right) {
67                    (left, right) => {
68                        $assert!(
69                            $function($left, $right),
70                            "{func}({left_expr}, {right_expr}) ⇒ {func}({left_value:?}, {right_value:?}) ⇒ false",
71                            func = stringify!($function),
72                            left_expr = stringify!($left),
73                            right_expr = stringify!($right),
74                            left_value = left,
75                            right_value = right,
76                        )
77                    }
78                }
79            };
80
81            (not $function:ident($left:expr, $right:expr)) => {
82                match ($left, $right) {
83                    (left, right) => {
84                        $assert!(
85                            !$function($left, $right),
86                            "{func}({left_expr}, {right_expr}) ⇒ {func}({left_value}, {right_value}) ⇒ true",
87                            func = stringify!($function),
88                            left_expr = stringify!($left),
89                            right_expr = stringify!($right),
90                            left_value = left,
91                            right_value = right,
92                        )
93                    }
94                }
95            };
96        }
97    };
98}
99
100operator_assertion_macros! {
101    #![macro_export]
102    in ::assert_cmp;
103    use ::core::assert;
104
105    /// Assert that a binary expression of 2 identifiers/literals returns `true`.
106    ///
107    /// **Syntax:**
108    ///
109    /// ```ignore
110    /// assert_op!($left $op $right)
111    /// ```
112    ///
113    /// * `$left` and `$right` are either identifiers or literals or both.
114    /// * `$op` is a binary operator (e.g. `>`, `<`, `>=`, `<=`, `==`, `!=`).
115    ///
116    /// **Example:** An assertion that passes
117    ///
118    /// ```
119    /// # use assert_cmp::assert_op;
120    /// assert_op!(123 < 456);
121    /// ```
122    ///
123    /// **Example:** An assertion that fails
124    ///
125    /// ```should_panic
126    /// # use assert_cmp::assert_op;
127    /// assert_op!(123 > 456); // panic: 123 > 456 ⇒ 123 > 456 ⇒ false
128    /// ```
129    simple = assert_op;
130
131    /// Assert that a binary expression of 2 expressions returns `true`.
132    ///
133    /// **Syntax:**
134    ///
135    /// ```ignore
136    /// assert_op_expr!($left, $op, $right)
137    /// ```
138    ///
139    /// * `$left` and `$right` are expressions.
140    /// * `$op` is a binary operator (e.g. `>`, `<`, `>=`, `<=`, `==`, `!=`).
141    ///
142    /// **Example:** An assertion that passes
143    ///
144    /// ```
145    /// # use assert_cmp::assert_op_expr;
146    /// assert_op_expr!(12 + 34, ==, 34 + 12);
147    /// ```
148    ///
149    /// **Example:** An assertion that fails
150    ///
151    /// ```should_panic
152    /// # use assert_cmp::assert_op_expr;
153    /// assert_op_expr!(12 + 34, ==, 43 + 21); // panic: 12 + 34 == 43 + 21 ⇒ 46 == 64 ⇒ false
154    /// ```
155    expr = assert_op_expr;
156}
157
158operator_assertion_macros! {
159    #![macro_export]
160    in ::assert_cmp;
161    use ::core::debug_assert;
162
163    /// Assert that a binary expression of 2 identifiers/literals returns `true`.
164    ///
165    /// This macro is the debug-only version of [`assert_op`].
166    /// It acts like `assert_op` in debug mode, but does nothing in release mode.
167    simple = debug_assert_op;
168
169    /// Assert that a binary expression of 2 expressions returns `true`.
170    ///
171    /// This macro is the debug-only version of [`assert_op`].
172    /// It acts like `assert_op_expr` in debug mode, but does nothing in release mode.
173    expr = debug_assert_op_expr;
174}
175
176function_assertion_macro! {
177    #![macro_export]
178    use ::core::assert;
179
180    /// Assert that a binary function call of 2 expressions returns `true`.
181    ///
182    /// **Syntax:**
183    ///
184    /// ```ignore
185    /// assert_fn!($function($left, $right))
186    /// ```
187    ///
188    /// ```ignore
189    /// assert_fn!(not $function($left, $right))
190    /// ```
191    ///
192    /// * `$function` is an identifier of a binary function.
193    /// * `$left` and `$right` are expressions.
194    /// * `not`'s appearance means expecting the function call to returns `false` instead of `true`.
195    ///
196    /// **Example:** An assertion that passes
197    ///
198    /// ```
199    /// # use assert_cmp::assert_fn;
200    /// fn func<A, B>(_: A, _: B) -> bool {
201    ///   true
202    /// }
203    /// assert_fn!(func(123, 456));
204    /// ```
205    ///
206    /// **Example:** An assertion that fails
207    ///
208    /// ```should_panic
209    /// # use assert_cmp::assert_fn;
210    /// fn func<A, B>(_: A, _: B) -> bool {
211    ///   false
212    /// }
213    /// assert_fn!(func(123, 456)); // panic: func(123, 456) ⇒ func(123, 456) ⇒ false
214    /// ```
215    ///
216    /// **Example:** A negative assertion that passes
217    ///
218    /// ```
219    /// # use assert_cmp::assert_fn;
220    /// fn func<A, B>(_: A, _: B) -> bool {
221    ///   false
222    /// }
223    /// assert_fn!(not func(123, 456));
224    /// ```
225    ///
226    /// **Example:** A negative assertion that fails
227    ///
228    /// ```should_panic
229    /// # use assert_cmp::assert_fn;
230    /// fn func<A, B>(_: A, _: B) -> bool {
231    ///   true
232    /// }
233    /// assert_fn!(not func(123, 456)); // panic: func(123, 456) ⇒ func(123, 456) ⇒ true
234    /// ```
235    assert_fn;
236}
237
238function_assertion_macro! {
239    #![macro_export]
240    use ::core::debug_assert;
241
242    /// Assert that a binary function call of 2 expressions returns `true`.
243    ///
244    /// This macro is the debug-only version of [`assert_fn`].
245    /// It acts like `assert_op_expr` in debug mode, but does nothing in release mode.
246    debug_assert_fn;
247}