Skip to main content

fluent_assertions/assertions/
option_assertion.rs

1use super::Assertion;
2use std::fmt::Debug;
3
4impl<T: Debug + PartialEq> Assertion<Option<T>> {
5    /// Asserts that the Option is Some and unwraps it into an `Assertion<T>`
6    ///
7    /// # Examples
8    ///
9    /// ```
10    /// use fluent_assertions::*;
11    /// Some(5).should().be_some().be(5);
12    /// ```
13    #[track_caller]
14    pub fn be_some(self) -> Assertion<T> {
15        match self.value {
16            Some(value) => Assertion { value },
17            None => panic!("Expected Some, but got None"),
18        }
19    }
20
21    /// Asserts that the Option is None
22    ///
23    /// # Examples
24    ///
25    /// ```
26    /// use fluent_assertions::*;
27    /// None::<i32>.should().be_none();
28    /// ```
29    #[track_caller]
30    pub fn be_none(self) -> Self {
31        assert!(
32            self.value.is_none(),
33            "Expected None, but got {:?}",
34            self.value
35        );
36        self
37    }
38}
39
40/// Containment assertion for `Option`.
41///
42/// This lives on a trait rather than being an inherent method for the same
43/// coherence reason as [`CollectionAssertion`]: an inherent `contain` on
44/// `Assertion<Option<T>>` would clash with the inherent `contain` from the
45/// `impl<T: AsRef<str>> Assertion<T>` string assertions, because coherence
46/// cannot rule out a future `AsRef<str>` impl for `Option<_>`.
47pub trait OptionAssertion<T> {
48    /// Asserts that the Option is Some and contains the expected value
49    ///
50    /// # Examples
51    ///
52    /// ```
53    /// use fluent_assertions::*;
54    /// Some(5).should().contain(&5);
55    /// ```
56    fn contain(self, expected: &T) -> Self;
57}
58
59impl<T: Debug + PartialEq> OptionAssertion<T> for Assertion<Option<T>> {
60    #[track_caller]
61    fn contain(self, expected: &T) -> Self {
62        assert_eq!(
63            self.value.as_ref(),
64            Some(expected),
65            "Expected Some({:?}), but was {:?}",
66            expected,
67            self.value
68        );
69        self
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use crate::assertions::*;
76    use rstest::*;
77
78    #[rstest]
79    #[case(None)]
80    fn should_be_none(#[case] input: Option<String>) {
81        input.should().be_none();
82    }
83
84    #[rstest]
85    #[case(42f64)]
86    #[case(0.0)]
87    fn should_be_some(#[case] expected: f64) {
88        let input = Some(expected);
89        input.should().be_some().be(expected);
90    }
91
92    #[rstest]
93    #[case("hello")]
94    fn should_contain(#[case] expected: &str) {
95        let input = Some(expected);
96        input.should().contain(&expected);
97    }
98
99    #[rstest]
100    #[case(Some(String::from("hello")))]
101    fn should_contain_string(#[case] input: Option<String>) {
102        input.should().contain(&String::from("hello"));
103    }
104
105    #[test]
106    #[should_panic(expected = "Expected None, but got Some(42)")]
107    fn be_none_panics_with_actual_value() {
108        Some(42).should().be_none();
109    }
110}