assertables/assert_contains/
assert_contains.rs

1//! Assert a container is a match for an expression.
2//!
3//! Pseudocode:<br>
4//! a.contains(b)
5//!
6//! These macros work with many kinds of Rust types, such as String, Vec, Range, HashSet.
7//! The specifics depend on each type's implementation of a method `contains`, and some types
8//! require the second argument to be borrowable, so be sure to check the Rust documentation.
9//!
10//! # Example
11//!
12//! ```rust
13//! use assertables::*;
14//! use std::collections::HashSet;
15//!
16//! // String contains substring
17//! let a = "alfa";
18//! let b = "lf";
19//! assert_contains!(a, b);
20//!
21//! // Range contains value.
22//! // Notice the &b because the macro calls Range.contains(&self, &value).
23//! let a = 1..3;
24//! let b = 2;
25//! assert_contains!(a, &b);
26//!
27//! // Vector contains element.
28//! // Notice the &b because the macro calls Vec.contains(&self, &value).
29//! let a = vec![1, 2, 3];
30//! let b = 2;
31//! assert_contains!(a, &b);
32//!
33//! // HashSet contains element.
34//! // Notice the &b because the macro calls HashSet.contains(&self, &value).
35//! let a: HashSet<String> = [String::from("1")].into();
36//! let b: String = String::from("1");
37//! assert_contains!(a, &b);
38//!
39//! // HashSet contains element with automatic borrow optimization.
40//! // Notice the b because the value type &str is already a reference,
41//! // which HashSet.contains knows how to borrow to compare to String.
42//! let a: HashSet<String> = [String::from("1")].into();
43//! let b = "1";
44//! assert_contains!(a, b);
45//! ```
46//!
47//! # Module macros
48//!
49//! * [`assert_contains`](macro@crate::assert_contains)
50//! * [`assert_contains_as_result`](macro@crate::assert_contains_as_result)
51//! * [`debug_assert_contains`](macro@crate::debug_assert_contains)
52
53/// Assert an expression (such as a string) contains an expression (such as a substring).
54///
55/// Pseudocode:<br>
56/// a.contains(b)
57///
58/// * If true, return Result `Ok(())`.
59///
60/// * Otherwise, return Result `Err(message)`.
61///
62/// This macro is useful for runtime checks, such as checking parameters,
63/// or sanitizing inputs, or handling different results in different ways.
64///
65/// # Module macros
66///
67/// * [`assert_contains`](macro@crate::assert_contains)
68/// * [`assert_contains_as_result`](macro@crate::assert_contains_as_result)
69/// * [`debug_assert_contains`](macro@crate::debug_assert_contains)
70///
71#[macro_export]
72macro_rules! assert_contains_as_result {
73    ($container:expr, $containee:expr $(,)?) => {
74        match (&$container, &$containee) {
75            (container, containee) => {
76                if (container).contains(*containee) {
77                    Ok(())
78                } else {
79                    Err(format!(
80                        concat!(
81                            "assertion failed: `assert_contains!(container, containee)`\n",
82                            "https://docs.rs/assertables/9.8.2/assertables/macro.assert_contains.html\n",
83                            " container label: `{}`,\n",
84                            " container debug: `{:?}`,\n",
85                            " containee label: `{}`,\n",
86                            " containee debug: `{:?}`",
87                        ),
88                        stringify!($container),
89                        container,
90                        stringify!($containee),
91                        containee,
92                    ))
93                }
94            }
95        }
96    };
97}
98
99#[cfg(test)]
100mod test_assert_contains_as_result {
101    use std::panic;
102    use std::sync::Once;
103
104    mod str {
105        use super::*;
106
107        #[test]
108        fn success() {
109            let a: &'static str = "alfa";
110            let b: &'static str = "lf";
111            for _ in 0..1 {
112                let actual = assert_contains_as_result!(a, b);
113                assert_eq!(actual.unwrap(), ());
114            }
115        }
116
117        #[test]
118        fn success_once() {
119            static A: Once = Once::new();
120            fn a() -> &'static str {
121                if A.is_completed() {
122                    panic!("A.is_completed()")
123                } else {
124                    A.call_once(|| {})
125                }
126                "alfa"
127            }
128
129            static B: Once = Once::new();
130            fn b() -> &'static str {
131                if B.is_completed() {
132                    panic!("B.is_completed()")
133                } else {
134                    B.call_once(|| {})
135                }
136                "lf"
137            }
138
139            assert_eq!(A.is_completed(), false);
140            assert_eq!(B.is_completed(), false);
141            let result = assert_contains_as_result!(a(), b());
142            assert!(result.is_ok());
143            assert_eq!(A.is_completed(), true);
144            assert_eq!(B.is_completed(), true);
145        }
146
147        #[test]
148        fn failure() {
149            let a: &'static str = "alfa";
150            let b: &'static str = "xx";
151            let actual = assert_contains_as_result!(a, b);
152            let message = concat!(
153                "assertion failed: `assert_contains!(container, containee)`\n",
154                "https://docs.rs/assertables/9.8.2/assertables/macro.assert_contains.html\n",
155                " container label: `a`,\n",
156                " container debug: `\"alfa\"`,\n",
157                " containee label: `b`,\n",
158                " containee debug: `\"xx\"`"
159            );
160            assert_eq!(actual.unwrap_err(), message);
161        }
162    }
163
164    mod range_i32 {
165        use super::*;
166        use std::ops::Range;
167
168        #[test]
169        fn success() {
170            let a: Range<i32> = 1..3;
171            let b: i32 = 2;
172            for _ in 0..1 {
173                let actual = assert_contains_as_result!(a, &b);
174                assert_eq!(actual.unwrap(), ());
175            }
176        }
177
178        #[test]
179        fn success_once() {
180            static A: Once = Once::new();
181            fn a() -> Range<i32> {
182                if A.is_completed() {
183                    panic!("A.is_completed()")
184                } else {
185                    A.call_once(|| {})
186                }
187                1..3
188            }
189
190            static B: Once = Once::new();
191            fn b() -> i32 {
192                if B.is_completed() {
193                    panic!("B.is_completed()")
194                } else {
195                    B.call_once(|| {})
196                }
197                2
198            }
199
200            assert_eq!(A.is_completed(), false);
201            assert_eq!(B.is_completed(), false);
202            let result = assert_contains_as_result!(a(), &b());
203            assert!(result.is_ok());
204            assert_eq!(A.is_completed(), true);
205            assert_eq!(B.is_completed(), true);
206        }
207
208        #[test]
209        fn failure() {
210            let a: Range<i32> = 1..3;
211            let b: i32 = 4;
212            let actual = assert_contains_as_result!(a, &b);
213            let message = concat!(
214                "assertion failed: `assert_contains!(container, containee)`\n",
215                "https://docs.rs/assertables/9.8.2/assertables/macro.assert_contains.html\n",
216                " container label: `a`,\n",
217                " container debug: `1..3`,\n",
218                " containee label: `&b`,\n",
219                " containee debug: `4`"
220            );
221            assert_eq!(actual.unwrap_err(), message);
222        }
223    }
224
225    mod range_string {
226        use super::*;
227        use std::ops::Range;
228
229        #[test]
230        fn success() {
231            let a: Range<String> = String::from("1")..String::from("3");
232            let b: String = String::from("2");
233            for _ in 0..1 {
234                let actual = assert_contains_as_result!(a, &b);
235                assert_eq!(actual.unwrap(), ());
236            }
237        }
238
239        #[test]
240        fn success_once() {
241            static A: Once = Once::new();
242            fn a() -> Range<String> {
243                if A.is_completed() {
244                    panic!("A.is_completed()")
245                } else {
246                    A.call_once(|| {})
247                }
248                String::from("1")..String::from("3")
249            }
250
251            static B: Once = Once::new();
252            fn b() -> String {
253                if B.is_completed() {
254                    panic!("B.is_completed()")
255                } else {
256                    B.call_once(|| {})
257                }
258                String::from("2")
259            }
260
261            assert_eq!(A.is_completed(), false);
262            assert_eq!(B.is_completed(), false);
263            let result = assert_contains_as_result!(a(), &b());
264            assert!(result.is_ok());
265            assert_eq!(A.is_completed(), true);
266            assert_eq!(B.is_completed(), true);
267        }
268
269        #[test]
270        fn failure() {
271            let a: Range<String> = String::from("1")..String::from("3");
272            let b: String = String::from("4");
273            let actual = assert_contains_as_result!(a, &b);
274            let message = concat!(
275                "assertion failed: `assert_contains!(container, containee)`\n",
276                "https://docs.rs/assertables/9.8.2/assertables/macro.assert_contains.html\n",
277                " container label: `a`,\n",
278                " container debug: `\"1\"..\"3\"`,\n",
279                " containee label: `&b`,\n",
280                " containee debug: `\"4\"`"
281            );
282            assert_eq!(actual.unwrap_err(), message);
283        }
284    }
285
286    mod vec_i32 {
287        use super::*;
288
289        #[test]
290        fn success() {
291            let a: Vec<i32> = vec![1, 2, 3];
292            let b: i32 = 2;
293            for _ in 0..1 {
294                let actual = assert_contains_as_result!(a, &b);
295                assert_eq!(actual.unwrap(), ());
296            }
297        }
298
299        #[test]
300        fn success_once() {
301            static A: Once = Once::new();
302            fn a() -> Vec<i32> {
303                if A.is_completed() {
304                    panic!("A.is_completed()")
305                } else {
306                    A.call_once(|| {})
307                }
308                vec![1, 2, 3]
309            }
310
311            static B: Once = Once::new();
312            fn b() -> i32 {
313                if B.is_completed() {
314                    panic!("B.is_completed()")
315                } else {
316                    B.call_once(|| {})
317                }
318                2
319            }
320
321            assert_eq!(A.is_completed(), false);
322            assert_eq!(B.is_completed(), false);
323            let result = assert_contains_as_result!(a(), &b());
324            assert!(result.is_ok());
325            assert_eq!(A.is_completed(), true);
326            assert_eq!(B.is_completed(), true);
327        }
328
329        #[test]
330        fn failure() {
331            let a: Vec<i32> = vec![1, 2, 3];
332            let b: i32 = 4;
333            let actual = assert_contains_as_result!(a, &b);
334            let message = concat!(
335                "assertion failed: `assert_contains!(container, containee)`\n",
336                "https://docs.rs/assertables/9.8.2/assertables/macro.assert_contains.html\n",
337                " container label: `a`,\n",
338                " container debug: `[1, 2, 3]`,\n",
339                " containee label: `&b`,\n",
340                " containee debug: `4`"
341            );
342            assert_eq!(actual.unwrap_err(), message);
343        }
344    }
345
346    mod vec_string {
347        use super::*;
348
349        #[test]
350        fn success() {
351            let a: Vec<String> = vec![String::from("1"), String::from("2"), String::from("3")];
352            let b: String = String::from("2");
353
354            for _ in 0..1 {
355                let actual = assert_contains_as_result!(a, &b);
356                assert_eq!(actual.unwrap(), ());
357            }
358        }
359
360        #[test]
361        fn success_once() {
362            static A: Once = Once::new();
363            fn a() -> Vec<String> {
364                if A.is_completed() {
365                    panic!("A.is_completed()")
366                } else {
367                    A.call_once(|| {})
368                }
369                vec![String::from("1"), String::from("2"), String::from("3")]
370            }
371
372            static B: Once = Once::new();
373            fn b() -> String {
374                if B.is_completed() {
375                    panic!("B.is_completed()")
376                } else {
377                    B.call_once(|| {})
378                }
379                String::from("2")
380            }
381
382            assert_eq!(A.is_completed(), false);
383            assert_eq!(B.is_completed(), false);
384            let result = assert_contains_as_result!(a(), &b());
385            assert!(result.is_ok());
386            assert_eq!(A.is_completed(), true);
387            assert_eq!(B.is_completed(), true);
388        }
389
390        #[test]
391        fn failure() {
392            let a: Vec<String> = vec![String::from("1"), String::from("2"), String::from("3")];
393            let b: String = String::from("4");
394            let actual = assert_contains_as_result!(a, &b);
395            let message = concat!(
396                "assertion failed: `assert_contains!(container, containee)`\n",
397                "https://docs.rs/assertables/9.8.2/assertables/macro.assert_contains.html\n",
398                " container label: `a`,\n",
399                " container debug: `[\"1\", \"2\", \"3\"]`,\n",
400                " containee label: `&b`,\n",
401                " containee debug: `\"4\"`"
402            );
403            assert_eq!(actual.unwrap_err(), message);
404        }
405    }
406
407    mod hashset_string {
408        use super::*;
409        use std::collections::HashSet;
410
411        #[test]
412        fn success() {
413            let a: HashSet<String> = [String::from("1")].into();
414            let b: String = String::from("1");
415            for _ in 0..1 {
416                let actual = assert_contains_as_result!(a, &b);
417                assert_eq!(actual.unwrap(), ());
418            }
419        }
420
421        #[test]
422        fn success_once() {
423            static A: Once = Once::new();
424            fn a() -> HashSet<String> {
425                if A.is_completed() {
426                    panic!("A.is_completed()")
427                } else {
428                    A.call_once(|| {})
429                }
430                [String::from("1")].into()
431            }
432
433            static B: Once = Once::new();
434            fn b() -> String {
435                if B.is_completed() {
436                    panic!("B.is_completed()")
437                } else {
438                    B.call_once(|| {})
439                }
440                String::from("1")
441            }
442
443            assert_eq!(A.is_completed(), false);
444            assert_eq!(B.is_completed(), false);
445            let result = assert_contains_as_result!(a(), &b());
446            assert!(result.is_ok());
447            assert_eq!(A.is_completed(), true);
448            assert_eq!(B.is_completed(), true);
449        }
450
451        #[test]
452        fn failure() {
453            let a: HashSet<String> = [String::from("1")].into();
454            let b: String = String::from("2");
455            let actual = assert_contains_as_result!(a, &b);
456            let message = concat!(
457                "assertion failed: `assert_contains!(container, containee)`\n",
458                "https://docs.rs/assertables/9.8.2/assertables/macro.assert_contains.html\n",
459                " container label: `a`,\n",
460                " container debug: `{\"1\"}`,\n",
461                " containee label: `&b`,\n",
462                " containee debug: `\"2\"`"
463            );
464            assert_eq!(actual.unwrap_err(), message);
465        }
466    }
467
468    mod hashset_string_with_str_automatic_borrow_optimization {
469        use super::*;
470        use std::collections::HashSet;
471
472        #[test]
473        fn success() {
474            let a: HashSet<String> = [String::from("1")].into();
475            let b: &'static str = "1";
476            for _ in 0..1 {
477                let actual = assert_contains_as_result!(a, b);
478                assert_eq!(actual.unwrap(), ());
479            }
480        }
481
482        #[test]
483        fn success_once() {
484            static A: Once = Once::new();
485            fn a() -> HashSet<String> {
486                if A.is_completed() {
487                    panic!("A.is_completed()")
488                } else {
489                    A.call_once(|| {})
490                }
491                [String::from("1")].into()
492            }
493
494            static B: Once = Once::new();
495            fn b() -> &'static str {
496                if B.is_completed() {
497                    panic!("B.is_completed()")
498                } else {
499                    B.call_once(|| {})
500                }
501                "1"
502            }
503
504            assert_eq!(A.is_completed(), false);
505            assert_eq!(B.is_completed(), false);
506            let result = assert_contains_as_result!(a(), b());
507            assert!(result.is_ok());
508            assert_eq!(A.is_completed(), true);
509            assert_eq!(B.is_completed(), true);
510        }
511
512        #[test]
513        fn failure() {
514            let a: HashSet<String> = [String::from("1")].into();
515            let b: &'static str = "2";
516            let actual = assert_contains_as_result!(a, b);
517            let message = concat!(
518                "assertion failed: `assert_contains!(container, containee)`\n",
519                "https://docs.rs/assertables/9.8.2/assertables/macro.assert_contains.html\n",
520                " container label: `a`,\n",
521                " container debug: `{\"1\"}`,\n",
522                " containee label: `b`,\n",
523                " containee debug: `\"2\"`"
524            );
525            assert_eq!(actual.unwrap_err(), message);
526        }
527    }
528}
529
530/// Assert a container is a match for an expression.
531///
532/// Pseudocode:<br>
533/// a.contains(b)
534///
535/// * If true, return `()`.
536///
537/// * Otherwise, call [`panic!`] with a message and the values of the
538///   expressions with their debug representations.
539///
540/// # Examples
541///
542/// ```rust
543/// use assertables::*;
544/// use std::collections::HashSet;
545/// # use std::panic;
546///
547/// # fn main() {
548/// // String contains a substring
549/// let a = "alfa";
550/// let b = "lf";
551/// assert_contains!(a, b);
552///
553/// // Range contains a value
554/// let a = 1..3;
555/// let b = 2;
556/// assert_contains!(a, &b);
557///
558/// // Vector contains element
559/// let a = vec![1, 2, 3];
560/// let b = 2;
561/// assert_contains!(a, &b);
562///
563/// // HashSet contains element.
564/// // Notice the &b because the macro calls HashSet.contains(&self, &value).
565/// let a: HashSet<String> = [String::from("1")].into();
566/// let b: String = String::from("1");
567/// assert_contains!(a, &b);
568///
569/// // HashSet contains element with automatic borrow optimization.
570/// // Notice the b because the value type &str is already a reference,
571/// // which HashSet.contains knows how to borrow to compare to String.
572/// let a: HashSet<String> = [String::from("1")].into();
573/// let b = "1";
574/// assert_contains!(a, b);
575///
576/// # let result = panic::catch_unwind(|| {
577/// // This will panic
578/// let a = "alfa";
579/// let b = "xx";
580/// assert_contains!(a, b);
581/// # });
582/// // assertion failed: `assert_contains!(container, containee)`
583/// // https://docs.rs/assertables/…/assertables/macro.assert_contains.html
584/// //  container label: `a`,
585/// //  container debug: `\"alfa\"`,
586/// //  containee label: `b`,
587/// //  containee debug: `\"xx\"`
588/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
589/// # let message = concat!(
590/// #     "assertion failed: `assert_contains!(container, containee)`\n",
591/// #     "https://docs.rs/assertables/9.8.2/assertables/macro.assert_contains.html\n",
592/// #     " container label: `a`,\n",
593/// #     " container debug: `\"alfa\"`,\n",
594/// #     " containee label: `b`,\n",
595/// #     " containee debug: `\"xx\"`"
596/// # );
597/// # assert_eq!(actual, message);
598/// # }
599/// ```
600///
601/// * [`assert_contains`](macro@crate::assert_contains)
602/// * [`assert_contains_as_result`](macro@crate::assert_contains_as_result)
603/// * [`debug_assert_contains`](macro@crate::debug_assert_contains)
604///
605#[macro_export]
606macro_rules! assert_contains {
607    ($container:expr, $containee:expr $(,)?) => {
608        match $crate::assert_contains_as_result!($container, $containee) {
609            Ok(()) => (),
610            Err(err) => panic!("{}", err),
611        }
612    };
613    ($container:expr, $containee:expr, $($message:tt)+) => {
614        match $crate::assert_contains_as_result!($container, $containee) {
615            Ok(()) => (),
616            Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
617        }
618    };
619}
620
621#[cfg(test)]
622mod test_assert_contains {
623    use std::panic;
624
625    mod str {
626        use super::*;
627
628        #[test]
629        fn success() {
630            let a: &'static str = "alfa";
631            let b: &'static str = "lf";
632            for _ in 0..1 {
633                let actual = assert_contains!(a, b);
634                assert_eq!(actual, ());
635            }
636        }
637
638        #[test]
639        fn failure() {
640            let a: &'static str = "alfa";
641            let b: &'static str = "xx";
642            let result = panic::catch_unwind(|| {
643                let _actual = assert_contains!(a, b);
644            });
645            let message = concat!(
646                "assertion failed: `assert_contains!(container, containee)`\n",
647                "https://docs.rs/assertables/9.8.2/assertables/macro.assert_contains.html\n",
648                " container label: `a`,\n",
649                " container debug: `\"alfa\"`,\n",
650                " containee label: `b`,\n",
651                " containee debug: `\"xx\"`"
652            );
653            assert_eq!(
654                result
655                    .unwrap_err()
656                    .downcast::<String>()
657                    .unwrap()
658                    .to_string(),
659                message
660            );
661        }
662    }
663
664    mod range_i32 {
665        use super::*;
666        use std::ops::Range;
667
668        #[test]
669        fn success() {
670            let a: Range<i32> = 1..3;
671            let b: i32 = 2;
672            for _ in 0..1 {
673                let actual = assert_contains!(a, &b);
674                assert_eq!(actual, ());
675            }
676        }
677
678        #[test]
679        fn failure() {
680            let a: Range<i32> = 1..3;
681            let b: i32 = 4;
682            let result = panic::catch_unwind(|| {
683                let _actual = assert_contains!(a, &b);
684            });
685            let message = concat!(
686                "assertion failed: `assert_contains!(container, containee)`\n",
687                "https://docs.rs/assertables/9.8.2/assertables/macro.assert_contains.html\n",
688                " container label: `a`,\n",
689                " container debug: `1..3`,\n",
690                " containee label: `&b`,\n",
691                " containee debug: `4`"
692            );
693            assert_eq!(
694                result
695                    .unwrap_err()
696                    .downcast::<String>()
697                    .unwrap()
698                    .to_string(),
699                message
700            );
701        }
702    }
703
704    mod range_string {
705        use super::*;
706        use std::ops::Range;
707
708        #[test]
709        fn success() {
710            let a: Range<String> = String::from("1")..String::from("3");
711            let b: String = String::from("2");
712            for _ in 0..1 {
713                let actual = assert_contains!(a, &b);
714                assert_eq!(actual, ());
715            }
716        }
717
718        #[test]
719        fn failure() {
720            let a: Range<String> = String::from("1")..String::from("3");
721            let b: String = String::from("4");
722            let result = panic::catch_unwind(|| {
723                let _actual = assert_contains!(a, &b);
724            });
725            let message = concat!(
726                "assertion failed: `assert_contains!(container, containee)`\n",
727                "https://docs.rs/assertables/9.8.2/assertables/macro.assert_contains.html\n",
728                " container label: `a`,\n",
729                " container debug: `\"1\"..\"3\"`,\n",
730                " containee label: `&b`,\n",
731                " containee debug: `\"4\"`"
732            );
733            assert_eq!(
734                result
735                    .unwrap_err()
736                    .downcast::<String>()
737                    .unwrap()
738                    .to_string(),
739                message
740            );
741        }
742    }
743
744    mod vec_i32 {
745        use super::*;
746
747        #[test]
748        fn success() {
749            let a: Vec<i32> = vec![1, 2, 3];
750            let b: i32 = 2;
751            for _ in 0..1 {
752                let actual = assert_contains!(a, &b);
753                assert_eq!(actual, ());
754            }
755        }
756
757        #[test]
758        fn failure() {
759            let a: Vec<i32> = vec![1, 2, 3];
760            let b: i32 = 4;
761            let result = panic::catch_unwind(|| {
762                let _actual = assert_contains!(a, &b);
763            });
764            let message = concat!(
765                "assertion failed: `assert_contains!(container, containee)`\n",
766                "https://docs.rs/assertables/9.8.2/assertables/macro.assert_contains.html\n",
767                " container label: `a`,\n",
768                " container debug: `[1, 2, 3]`,\n",
769                " containee label: `&b`,\n",
770                " containee debug: `4`"
771            );
772            assert_eq!(
773                result
774                    .unwrap_err()
775                    .downcast::<String>()
776                    .unwrap()
777                    .to_string(),
778                message
779            );
780        }
781    }
782
783    mod vec_string {
784        use super::*;
785
786        #[test]
787        fn success() {
788            let a: Vec<String> = vec![String::from("1"), String::from("2"), String::from("3")];
789            let b: String = String::from("2");
790            for _ in 0..1 {
791                let actual = assert_contains!(a, &b);
792                assert_eq!(actual, ());
793            }
794        }
795
796        #[test]
797        fn failure() {
798            let a = vec![String::from("1"), String::from("2"), String::from("3")];
799            let b: String = String::from("4");
800            let result = panic::catch_unwind(|| {
801                let _actual = assert_contains!(a, &b);
802            });
803            let message = concat!(
804                "assertion failed: `assert_contains!(container, containee)`\n",
805                "https://docs.rs/assertables/9.8.2/assertables/macro.assert_contains.html\n",
806                " container label: `a`,\n",
807                " container debug: `[\"1\", \"2\", \"3\"]`,\n",
808                " containee label: `&b`,\n",
809                " containee debug: `\"4\"`"
810            );
811            assert_eq!(
812                result
813                    .unwrap_err()
814                    .downcast::<String>()
815                    .unwrap()
816                    .to_string(),
817                message
818            );
819        }
820    }
821
822    mod hashset_string {
823        use super::*;
824        use std::collections::HashSet;
825
826        #[test]
827        fn success() {
828            let a: HashSet<String> = [String::from("1")].into();
829            let b: String = String::from("1");
830            for _ in 0..1 {
831                let actual = assert_contains!(a, &b);
832                assert_eq!(actual, ());
833            }
834        }
835
836        #[test]
837        fn failure() {
838            let a: HashSet<String> = [String::from("1")].into();
839            let b: String = String::from("2");
840            let result = panic::catch_unwind(|| {
841                let _actual = assert_contains!(a, &b);
842            });
843            let message = concat!(
844                "assertion failed: `assert_contains!(container, containee)`\n",
845                "https://docs.rs/assertables/9.8.2/assertables/macro.assert_contains.html\n",
846                " container label: `a`,\n",
847                " container debug: `{\"1\"}`,\n",
848                " containee label: `&b`,\n",
849                " containee debug: `\"2\"`"
850            );
851            assert_eq!(
852                result
853                    .unwrap_err()
854                    .downcast::<String>()
855                    .unwrap()
856                    .to_string(),
857                message
858            );
859        }
860    }
861
862    mod hashset_string_with_str_automatic_borrow_optimization {
863        use super::*;
864        use std::collections::HashSet;
865
866        #[test]
867        fn success() {
868            let a: HashSet<String> = [String::from("1")].into();
869            let b: &'static str = "1";
870            for _ in 0..1 {
871                let actual = assert_contains!(a, b);
872                assert_eq!(actual, ());
873            }
874        }
875
876        #[test]
877        fn failure() {
878            let a: HashSet<String> = [String::from("1")].into();
879            let b: &'static str = "2";
880            let result = panic::catch_unwind(|| {
881                let _actual = assert_contains!(a, b);
882            });
883            let message = concat!(
884                "assertion failed: `assert_contains!(container, containee)`\n",
885                "https://docs.rs/assertables/9.8.2/assertables/macro.assert_contains.html\n",
886                " container label: `a`,\n",
887                " container debug: `{\"1\"}`,\n",
888                " containee label: `b`,\n",
889                " containee debug: `\"2\"`"
890            );
891            assert_eq!(
892                result
893                    .unwrap_err()
894                    .downcast::<String>()
895                    .unwrap()
896                    .to_string(),
897                message
898            );
899        }
900    }
901}
902
903/// Assert a container is a match for an expression.
904///
905/// Pseudocode:<br>
906/// a.contains(b)
907///
908/// This macro provides the same statements as [`assert_contains`](macro.assert_contains.html),
909/// except this macro's statements are only enabled in non-optimized
910/// builds by default. An optimized build will not execute this macro's
911/// statements unless `-C debug-assertions` is passed to the compiler.
912///
913/// This macro is useful for checks that are too expensive to be present
914/// in a release build but may be helpful during development.
915///
916/// The result of expanding this macro is always type checked.
917///
918/// An unchecked assertion allows a program in an inconsistent state to
919/// keep running, which might have unexpected consequences but does not
920/// introduce unsafety as long as this only happens in safe code. The
921/// performance cost of assertions, however, is not measurable in general.
922/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
923/// after thorough profiling, and more importantly, only in safe code!
924///
925/// This macro is intended to work in a similar way to
926/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
927///
928/// # Module macros
929///
930/// * [`assert_contains`](macro@crate::assert_contains)
931/// * [`assert_contains`](macro@crate::assert_contains)
932/// * [`debug_assert_contains`](macro@crate::debug_assert_contains)
933///
934#[macro_export]
935macro_rules! debug_assert_contains {
936    ($($arg:tt)*) => {
937        if $crate::cfg!(debug_assertions) {
938            $crate::assert_contains!($($arg)*);
939        }
940    };
941}