assertables/assert_bag/
assert_bag_ne.rs

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