assertables/assert_fn/
assert_fn_ne.rs

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