Skip to main content

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.6/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.6/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.6/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.6/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.6/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.6/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.6/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.6/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.6/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                let expect = ();
635                assert_eq!(actual, expect);
636            }
637        }
638
639        #[test]
640        fn failure() {
641            let a: &'static str = "alfa";
642            let b: &'static str = "xx";
643            let result = panic::catch_unwind(|| {
644                let _actual = assert_contains!(a, b);
645            });
646            let message = concat!(
647                "assertion failed: `assert_contains!(container, containee)`\n",
648                "https://docs.rs/assertables/9.8.6/assertables/macro.assert_contains.html\n",
649                " container label: `a`,\n",
650                " container debug: `\"alfa\"`,\n",
651                " containee label: `b`,\n",
652                " containee debug: `\"xx\"`"
653            );
654            assert_eq!(
655                result
656                    .unwrap_err()
657                    .downcast::<String>()
658                    .unwrap()
659                    .to_string(),
660                message
661            );
662        }
663    }
664
665    mod range_i32 {
666        use super::*;
667        use std::ops::Range;
668
669        #[test]
670        fn success() {
671            let a: Range<i32> = 1..3;
672            let b: i32 = 2;
673            for _ in 0..1 {
674                let actual = assert_contains!(a, &b);
675                let expect = ();
676                assert_eq!(actual, expect);
677            }
678        }
679
680        #[test]
681        fn failure() {
682            let a: Range<i32> = 1..3;
683            let b: i32 = 4;
684            let result = panic::catch_unwind(|| {
685                let _actual = assert_contains!(a, &b);
686            });
687            let message = concat!(
688                "assertion failed: `assert_contains!(container, containee)`\n",
689                "https://docs.rs/assertables/9.8.6/assertables/macro.assert_contains.html\n",
690                " container label: `a`,\n",
691                " container debug: `1..3`,\n",
692                " containee label: `&b`,\n",
693                " containee debug: `4`"
694            );
695            assert_eq!(
696                result
697                    .unwrap_err()
698                    .downcast::<String>()
699                    .unwrap()
700                    .to_string(),
701                message
702            );
703        }
704    }
705
706    mod range_string {
707        use super::*;
708        use std::ops::Range;
709
710        #[test]
711        fn success() {
712            let a: Range<String> = String::from("1")..String::from("3");
713            let b: String = String::from("2");
714            for _ in 0..1 {
715                let actual = assert_contains!(a, &b);
716                let expect = ();
717                assert_eq!(actual, expect);
718            }
719        }
720
721        #[test]
722        fn failure() {
723            let a: Range<String> = String::from("1")..String::from("3");
724            let b: String = String::from("4");
725            let result = panic::catch_unwind(|| {
726                let _actual = assert_contains!(a, &b);
727            });
728            let message = concat!(
729                "assertion failed: `assert_contains!(container, containee)`\n",
730                "https://docs.rs/assertables/9.8.6/assertables/macro.assert_contains.html\n",
731                " container label: `a`,\n",
732                " container debug: `\"1\"..\"3\"`,\n",
733                " containee label: `&b`,\n",
734                " containee debug: `\"4\"`"
735            );
736            assert_eq!(
737                result
738                    .unwrap_err()
739                    .downcast::<String>()
740                    .unwrap()
741                    .to_string(),
742                message
743            );
744        }
745    }
746
747    mod vec_i32 {
748        use super::*;
749
750        #[test]
751        fn success() {
752            let a: Vec<i32> = vec![1, 2, 3];
753            let b: i32 = 2;
754            for _ in 0..1 {
755                let actual = assert_contains!(a, &b);
756                let expect = ();
757                assert_eq!(actual, expect);
758            }
759        }
760
761        #[test]
762        fn failure() {
763            let a: Vec<i32> = vec![1, 2, 3];
764            let b: i32 = 4;
765            let result = panic::catch_unwind(|| {
766                let _actual = assert_contains!(a, &b);
767            });
768            let message = concat!(
769                "assertion failed: `assert_contains!(container, containee)`\n",
770                "https://docs.rs/assertables/9.8.6/assertables/macro.assert_contains.html\n",
771                " container label: `a`,\n",
772                " container debug: `[1, 2, 3]`,\n",
773                " containee label: `&b`,\n",
774                " containee debug: `4`"
775            );
776            assert_eq!(
777                result
778                    .unwrap_err()
779                    .downcast::<String>()
780                    .unwrap()
781                    .to_string(),
782                message
783            );
784        }
785    }
786
787    mod vec_string {
788        use super::*;
789
790        #[test]
791        fn success() {
792            let a: Vec<String> = vec![String::from("1"), String::from("2"), String::from("3")];
793            let b: String = String::from("2");
794            for _ in 0..1 {
795                let actual = assert_contains!(a, &b);
796                let expect = ();
797                assert_eq!(actual, expect);
798            }
799        }
800
801        #[test]
802        fn failure() {
803            let a = vec![String::from("1"), String::from("2"), String::from("3")];
804            let b: String = String::from("4");
805            let result = panic::catch_unwind(|| {
806                let _actual = assert_contains!(a, &b);
807            });
808            let message = concat!(
809                "assertion failed: `assert_contains!(container, containee)`\n",
810                "https://docs.rs/assertables/9.8.6/assertables/macro.assert_contains.html\n",
811                " container label: `a`,\n",
812                " container debug: `[\"1\", \"2\", \"3\"]`,\n",
813                " containee label: `&b`,\n",
814                " containee debug: `\"4\"`"
815            );
816            assert_eq!(
817                result
818                    .unwrap_err()
819                    .downcast::<String>()
820                    .unwrap()
821                    .to_string(),
822                message
823            );
824        }
825    }
826
827    mod hashset_string {
828        use super::*;
829        use std::collections::HashSet;
830
831        #[test]
832        fn success() {
833            let a: HashSet<String> = [String::from("1")].into();
834            let b: String = String::from("1");
835            for _ in 0..1 {
836                let actual = assert_contains!(a, &b);
837                let expect = ();
838                assert_eq!(actual, expect);
839            }
840        }
841
842        #[test]
843        fn failure() {
844            let a: HashSet<String> = [String::from("1")].into();
845            let b: String = String::from("2");
846            let result = panic::catch_unwind(|| {
847                let _actual = assert_contains!(a, &b);
848            });
849            let message = concat!(
850                "assertion failed: `assert_contains!(container, containee)`\n",
851                "https://docs.rs/assertables/9.8.6/assertables/macro.assert_contains.html\n",
852                " container label: `a`,\n",
853                " container debug: `{\"1\"}`,\n",
854                " containee label: `&b`,\n",
855                " containee debug: `\"2\"`"
856            );
857            assert_eq!(
858                result
859                    .unwrap_err()
860                    .downcast::<String>()
861                    .unwrap()
862                    .to_string(),
863                message
864            );
865        }
866    }
867
868    mod hashset_string_with_str_automatic_borrow_optimization {
869        use super::*;
870        use std::collections::HashSet;
871
872        #[test]
873        fn success() {
874            let a: HashSet<String> = [String::from("1")].into();
875            let b: &'static str = "1";
876            for _ in 0..1 {
877                let actual = assert_contains!(a, b);
878                let expect = ();
879                assert_eq!(actual, expect);
880            }
881        }
882
883        #[test]
884        fn failure() {
885            let a: HashSet<String> = [String::from("1")].into();
886            let b: &'static str = "2";
887            let result = panic::catch_unwind(|| {
888                let _actual = assert_contains!(a, b);
889            });
890            let message = concat!(
891                "assertion failed: `assert_contains!(container, containee)`\n",
892                "https://docs.rs/assertables/9.8.6/assertables/macro.assert_contains.html\n",
893                " container label: `a`,\n",
894                " container debug: `{\"1\"}`,\n",
895                " containee label: `b`,\n",
896                " containee debug: `\"2\"`"
897            );
898            assert_eq!(
899                result
900                    .unwrap_err()
901                    .downcast::<String>()
902                    .unwrap()
903                    .to_string(),
904                message
905            );
906        }
907    }
908}
909
910/// Assert a container is a match for an expression.
911///
912/// Pseudocode:<br>
913/// a.contains(b)
914///
915/// This macro provides the same statements as [`assert_contains`](macro.assert_contains.html),
916/// except this macro's statements are only enabled in non-optimized
917/// builds by default. An optimized build will not execute this macro's
918/// statements unless `-C debug-assertions` is passed to the compiler.
919///
920/// This macro is useful for checks that are too expensive to be present
921/// in a release build but may be helpful during development.
922///
923/// The result of expanding this macro is always type checked.
924///
925/// An unchecked assertion allows a program in an inconsistent state to
926/// keep running, which might have unexpected consequences but does not
927/// introduce unsafety as long as this only happens in safe code. The
928/// performance cost of assertions, however, is not measurable in general.
929/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
930/// after thorough profiling, and more importantly, only in safe code!
931///
932/// This macro is intended to work in a similar way to
933/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
934///
935/// # Module macros
936///
937/// * [`assert_contains`](macro@crate::assert_contains)
938/// * [`assert_contains`](macro@crate::assert_contains)
939/// * [`debug_assert_contains`](macro@crate::debug_assert_contains)
940///
941#[macro_export]
942macro_rules! debug_assert_contains {
943    ($($arg:tt)*) => {
944        if cfg!(debug_assertions) {
945            $crate::assert_contains!($($arg)*);
946        }
947    };
948}
949
950#[cfg(test)]
951mod test_debug_assert_contains {
952    use std::panic;
953
954    mod str {
955        use super::*;
956
957        #[test]
958        fn success() {
959            let a: &'static str = "alfa";
960            let b: &'static str = "lf";
961            for _ in 0..1 {
962                let _actual = debug_assert_contains!(a, b);
963                let _expect = ();
964                // assert_eq!(actual, expect);
965            }
966        }
967
968        #[test]
969        fn failure() {
970            let a: &'static str = "alfa";
971            let b: &'static str = "xx";
972            let result = panic::catch_unwind(|| {
973                let _actual = debug_assert_contains!(a, b);
974            });
975            let message = concat!(
976                "assertion failed: `assert_contains!(container, containee)`\n",
977                "https://docs.rs/assertables/9.8.6/assertables/macro.assert_contains.html\n",
978                " container label: `a`,\n",
979                " container debug: `\"alfa\"`,\n",
980                " containee label: `b`,\n",
981                " containee debug: `\"xx\"`"
982            );
983            assert_eq!(
984                result
985                    .unwrap_err()
986                    .downcast::<String>()
987                    .unwrap()
988                    .to_string(),
989                message
990            );
991        }
992    }
993
994    mod range_i32 {
995        use super::*;
996        use std::ops::Range;
997
998        #[test]
999        fn success() {
1000            let a: Range<i32> = 1..3;
1001            let b: i32 = 2;
1002            for _ in 0..1 {
1003                let _actual = debug_assert_contains!(a, &b);
1004                let _expect = ();
1005                // assert_eq!(actual, expect);
1006            }
1007        }
1008
1009        #[test]
1010        fn failure() {
1011            let a: Range<i32> = 1..3;
1012            let b: i32 = 4;
1013            let result = panic::catch_unwind(|| {
1014                let _actual = debug_assert_contains!(a, &b);
1015            });
1016            let message = concat!(
1017                "assertion failed: `assert_contains!(container, containee)`\n",
1018                "https://docs.rs/assertables/9.8.6/assertables/macro.assert_contains.html\n",
1019                " container label: `a`,\n",
1020                " container debug: `1..3`,\n",
1021                " containee label: `&b`,\n",
1022                " containee debug: `4`"
1023            );
1024            assert_eq!(
1025                result
1026                    .unwrap_err()
1027                    .downcast::<String>()
1028                    .unwrap()
1029                    .to_string(),
1030                message
1031            );
1032        }
1033    }
1034
1035    mod range_string {
1036        use super::*;
1037        use std::ops::Range;
1038
1039        #[test]
1040        fn success() {
1041            let a: Range<String> = String::from("1")..String::from("3");
1042            let b: String = String::from("2");
1043            for _ in 0..1 {
1044                let _actual = debug_assert_contains!(a, &b);
1045                let _expect = ();
1046                // assert_eq!(actual, expect);
1047            }
1048        }
1049
1050        #[test]
1051        fn failure() {
1052            let a: Range<String> = String::from("1")..String::from("3");
1053            let b: String = String::from("4");
1054            let result = panic::catch_unwind(|| {
1055                let _actual = debug_assert_contains!(a, &b);
1056            });
1057            let message = concat!(
1058                "assertion failed: `assert_contains!(container, containee)`\n",
1059                "https://docs.rs/assertables/9.8.6/assertables/macro.assert_contains.html\n",
1060                " container label: `a`,\n",
1061                " container debug: `\"1\"..\"3\"`,\n",
1062                " containee label: `&b`,\n",
1063                " containee debug: `\"4\"`"
1064            );
1065            assert_eq!(
1066                result
1067                    .unwrap_err()
1068                    .downcast::<String>()
1069                    .unwrap()
1070                    .to_string(),
1071                message
1072            );
1073        }
1074    }
1075
1076    mod vec_i32 {
1077        use super::*;
1078
1079        #[test]
1080        fn success() {
1081            let a: Vec<i32> = vec![1, 2, 3];
1082            let b: i32 = 2;
1083            for _ in 0..1 {
1084                let _actual = debug_assert_contains!(a, &b);
1085                let _expect = ();
1086                // assert_eq!(actual, expect);
1087            }
1088        }
1089
1090        #[test]
1091        fn failure() {
1092            let a: Vec<i32> = vec![1, 2, 3];
1093            let b: i32 = 4;
1094            let result = panic::catch_unwind(|| {
1095                let _actual = debug_assert_contains!(a, &b);
1096            });
1097            let message = concat!(
1098                "assertion failed: `assert_contains!(container, containee)`\n",
1099                "https://docs.rs/assertables/9.8.6/assertables/macro.assert_contains.html\n",
1100                " container label: `a`,\n",
1101                " container debug: `[1, 2, 3]`,\n",
1102                " containee label: `&b`,\n",
1103                " containee debug: `4`"
1104            );
1105            assert_eq!(
1106                result
1107                    .unwrap_err()
1108                    .downcast::<String>()
1109                    .unwrap()
1110                    .to_string(),
1111                message
1112            );
1113        }
1114    }
1115
1116    mod vec_string {
1117        use super::*;
1118
1119        #[test]
1120        fn success() {
1121            let a: Vec<String> = vec![String::from("1"), String::from("2"), String::from("3")];
1122            let b: String = String::from("2");
1123            for _ in 0..1 {
1124                let _actual = debug_assert_contains!(a, &b);
1125                let _expect = ();
1126                // assert_eq!(actual, expect);
1127            }
1128        }
1129
1130        #[test]
1131        fn failure() {
1132            let a = vec![String::from("1"), String::from("2"), String::from("3")];
1133            let b: String = String::from("4");
1134            let result = panic::catch_unwind(|| {
1135                let _actual = debug_assert_contains!(a, &b);
1136            });
1137            let message = concat!(
1138                "assertion failed: `assert_contains!(container, containee)`\n",
1139                "https://docs.rs/assertables/9.8.6/assertables/macro.assert_contains.html\n",
1140                " container label: `a`,\n",
1141                " container debug: `[\"1\", \"2\", \"3\"]`,\n",
1142                " containee label: `&b`,\n",
1143                " containee debug: `\"4\"`"
1144            );
1145            assert_eq!(
1146                result
1147                    .unwrap_err()
1148                    .downcast::<String>()
1149                    .unwrap()
1150                    .to_string(),
1151                message
1152            );
1153        }
1154    }
1155
1156    mod hashset_string {
1157        use super::*;
1158        use std::collections::HashSet;
1159
1160        #[test]
1161        fn success() {
1162            let a: HashSet<String> = [String::from("1")].into();
1163            let b: String = String::from("1");
1164            for _ in 0..1 {
1165                let _actual = debug_assert_contains!(a, &b);
1166                let _expect = ();
1167                // assert_eq!(actual, expect);
1168            }
1169        }
1170
1171        #[test]
1172        fn failure() {
1173            let a: HashSet<String> = [String::from("1")].into();
1174            let b: String = String::from("2");
1175            let result = panic::catch_unwind(|| {
1176                let _actual = debug_assert_contains!(a, &b);
1177            });
1178            let message = concat!(
1179                "assertion failed: `assert_contains!(container, containee)`\n",
1180                "https://docs.rs/assertables/9.8.6/assertables/macro.assert_contains.html\n",
1181                " container label: `a`,\n",
1182                " container debug: `{\"1\"}`,\n",
1183                " containee label: `&b`,\n",
1184                " containee debug: `\"2\"`"
1185            );
1186            assert_eq!(
1187                result
1188                    .unwrap_err()
1189                    .downcast::<String>()
1190                    .unwrap()
1191                    .to_string(),
1192                message
1193            );
1194        }
1195    }
1196
1197    mod hashset_string_with_str_automatic_borrow_optimization {
1198        use super::*;
1199        use std::collections::HashSet;
1200
1201        #[test]
1202        fn success() {
1203            let a: HashSet<String> = [String::from("1")].into();
1204            let b: &'static str = "1";
1205            for _ in 0..1 {
1206                let _actual = debug_assert_contains!(a, b);
1207                let _expect = ();
1208                // assert_eq!(actual, expect);
1209            }
1210        }
1211
1212        #[test]
1213        fn failure() {
1214            let a: HashSet<String> = [String::from("1")].into();
1215            let b: &'static str = "2";
1216            let result = panic::catch_unwind(|| {
1217                let _actual = debug_assert_contains!(a, b);
1218            });
1219            let message = concat!(
1220                "assertion failed: `assert_contains!(container, containee)`\n",
1221                "https://docs.rs/assertables/9.8.6/assertables/macro.assert_contains.html\n",
1222                " container label: `a`,\n",
1223                " container debug: `{\"1\"}`,\n",
1224                " containee label: `b`,\n",
1225                " containee debug: `\"2\"`"
1226            );
1227            assert_eq!(
1228                result
1229                    .unwrap_err()
1230                    .downcast::<String>()
1231                    .unwrap()
1232                    .to_string(),
1233                message
1234            );
1235        }
1236    }
1237}