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(format!(
53                        concat!(
54                            "assertion failed: `assert_bag_ne!(a_collection, b_collection)`\n",
55                            "https://docs.rs/assertables/",
56                            env!("CARGO_PKG_VERSION"),
57                            "/assertables/macro.assert_bag_ne.html\n",
58                            " a label: `{}`,\n",
59                            " a debug: `{:?}`,\n",
60                            " b label: `{}`,\n",
61                            " b debug: `{:?}`,\n",
62                            "   a bag: `{:?}`,\n",
63                            "   b bag: `{:?}`"
64                        ),
65                        stringify!($a_collection),
66                        a_collection,
67                        stringify!($b_collection),
68                        b_collection,
69                        a,
70                        b
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/",
179            env!("CARGO_PKG_VERSION"),
180            "/assertables/macro.assert_bag_ne.html\n",
181            " a label: `a`,\n",
182            " a debug: `[1, 1]`,\n",
183            " b label: `b`,\n",
184            " b debug: `[1, 1]`,\n",
185            "   a bag: `{1: 2}`,\n",
186            "   b bag: `{1: 2}`"
187        );
188        assert_eq!(actual.unwrap_err(), message);
189    }
190}
191
192/// Assert a bag is not equal to another.
193///
194/// Pseudocode:<br>
195/// (a_collection ⇒ a_bag) ≠ (b_collection ⇒ b_bag)
196///
197/// * If true, return `(a, b)`.
198///
199/// * Otherwise, call [`panic!`] with a message and the values of the
200///   expressions with their debug representations.
201///
202/// # Examples
203///
204/// ```rust
205/// use assertables::*;
206/// # use std::panic;
207///
208/// # fn main() {
209/// let a = [1, 1];
210/// let b = [1, 1, 1];
211/// assert_bag_ne!(a, b);
212///
213/// # let result = panic::catch_unwind(|| {
214/// // This will panic
215/// let a = [1, 1];
216/// let b = [1, 1];
217/// assert_bag_ne!(a, b);
218/// # });
219/// // assertion failed: `assert_bag_ne!(a_collection, b_collection)`
220/// // https://docs.rs/assertables/9.7.0/assertables/macro.assert_bag_ne.html
221/// //  a label: `a`,
222/// //  a debug: `[1, 1]`,
223/// //  b label: `b`,
224/// //  b debug: `[1, 1]`,
225/// //    a bag: `{1: 2}`,
226/// //    b bag: `{1: 2}`
227/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
228/// # let message = concat!(
229/// #     "assertion failed: `assert_bag_ne!(a_collection, b_collection)`\n",
230/// #     "https://docs.rs/assertables/", env!("CARGO_PKG_VERSION"), "/assertables/macro.assert_bag_ne.html\n",
231/// #     " a label: `a`,\n",
232/// #     " a debug: `[1, 1]`,\n",
233/// #     " b label: `b`,\n",
234/// #     " b debug: `[1, 1]`,\n",
235/// #     "   a bag: `{1: 2}`,\n",
236/// #     "   b bag: `{1: 2}`"
237/// # );
238/// # assert_eq!(actual, message);
239/// # }
240/// ```
241///
242/// This implementation uses [`::std::collections::BTreeMap`](https://doc.rust-lang.org/std/collections/struct.BTreeMap.html) to count items and sort them.
243///
244/// # Module macros
245///
246/// * [`assert_bag_ne`](macro@crate::assert_bag_ne)
247/// * [`assert_bag_ne_as_result`](macro@crate::assert_bag_ne_as_result)
248/// * [`debug_assert_bag_ne`](macro@crate::debug_assert_bag_ne)
249///
250#[macro_export]
251macro_rules! assert_bag_ne {
252    ($a_collection:expr, $b_collection:expr $(,)?) => {
253        match $crate::assert_bag_ne_as_result!($a_collection, $b_collection) {
254            Ok(x) => x,
255            Err(err) => panic!("{}", err),
256        }
257    };
258    ($a_collection:expr, $b_collection:expr, $($message:tt)+) => {
259        match $crate::assert_bag_ne_as_result!($a_collection, $b_collection) {
260            Ok(x) => x,
261            Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
262        }
263    };
264}
265
266#[cfg(test)]
267mod test_assert_bag_ne {
268    use std::collections::BTreeMap;
269    use std::panic;
270
271    #[test]
272    fn success() {
273        let a = [1, 1];
274        let b = [1, 1, 1];
275        for _ in 0..1 {
276            let actual = assert_bag_ne!(a, b);
277            assert_eq!(
278                actual,
279                (BTreeMap::from([(&1, 2)]), BTreeMap::from([(&1, 3)]))
280            );
281        }
282    }
283
284    #[test]
285    fn failure() {
286        let result = panic::catch_unwind(|| {
287            let a = [1, 1];
288            let b = [1, 1];
289            let _actual = assert_bag_ne!(a, b);
290        });
291        let message = concat!(
292            "assertion failed: `assert_bag_ne!(a_collection, b_collection)`\n",
293            "https://docs.rs/assertables/",
294            env!("CARGO_PKG_VERSION"),
295            "/assertables/macro.assert_bag_ne.html\n",
296            " a label: `a`,\n",
297            " a debug: `[1, 1]`,\n",
298            " b label: `b`,\n",
299            " b debug: `[1, 1]`,\n",
300            "   a bag: `{1: 2}`,\n",
301            "   b bag: `{1: 2}`"
302        );
303        assert_eq!(
304            result
305                .unwrap_err()
306                .downcast::<String>()
307                .unwrap()
308                .to_string(),
309            message
310        );
311    }
312}
313
314/// Assert a bag is not equal to another.
315///
316/// Pseudocode:<br>
317/// (a_collection ⇒ a_bag) ≠ (b_collection ⇒ b_bag)
318///
319/// This macro provides the same statements as [`assert_bag_ne`](macro.assert_bag_ne.html),
320/// except this macro's statements are only enabled in non-optimized
321/// builds by default. An optimized build will not execute this macro's
322/// statements unless `-C debug-assertions` is passed to the compiler.
323///
324/// This macro is useful for checks that are too expensive to be present
325/// in a release build but may be helpful during development.
326///
327/// The result of expanding this macro is always type checked.
328///
329/// An unchecked assertion allows a program in an inconsistent state to
330/// keep running, which might have unexpected consequences but does not
331/// introduce unsafety as long as this only happens in safe code. The
332/// performance cost of assertions, however, is not measurable in general.
333/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
334/// after thorough profiling, and more importantly, only in safe code!
335///
336/// This macro is intended to work in a similar way to
337/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
338///
339/// # Module macros
340///
341/// * [`assert_bag_ne`](macro@crate::assert_bag_ne)
342/// * [`assert_bag_ne_as_result`](macro@crate::assert_bag_ne_as_result)
343/// * [`debug_assert_bag_ne`](macro@crate::debug_assert_bag_ne)
344///
345#[macro_export]
346macro_rules! debug_assert_bag_ne {
347    ($($arg:tt)*) => {
348        if $crate::cfg!(debug_assertions) {
349            $crate::assert_bag_ne!($($arg)*);
350        }
351    };
352}