Skip to main content

fluent_assertions/assertions/
string_assertion.rs

1use crate::Assertion;
2
3/// Specific assertions for strings
4impl<T: AsRef<str>> Assertion<T> {
5    /// Asserts that the string is empty
6    ///
7    /// # Examples
8    ///
9    /// ```
10    /// use fluent_assertions::*;
11    /// "".should().be_empty();
12    /// ```
13    #[track_caller]
14    pub fn be_empty(self) -> Self {
15        assert!(
16            self.value.as_ref().is_empty(),
17            "Expected string to be empty, but got '{}'",
18            self.value.as_ref()
19        );
20        self
21    }
22    /// Asserts that the string is not empty
23    ///
24    /// # Examples
25    ///
26    /// ```
27    /// use fluent_assertions::*;
28    /// "hello".should().not_be_empty();
29    /// ```
30    #[track_caller]
31    pub fn not_be_empty(self) -> Self {
32        assert!(
33            !self.value.as_ref().is_empty(),
34            "Expected string to not be empty, but got empty string"
35        );
36        self
37    }
38    /// Asserts that the string starts with a given prefix
39    ///
40    /// # Examples
41    ///
42    /// ```
43    /// use fluent_assertions::*;
44    /// "hello world".should().start_with("hello");
45    /// ```
46    #[track_caller]
47    pub fn start_with(self, prefix: &str) -> Self {
48        assert!(
49            self.value.as_ref().starts_with(prefix),
50            "Expected string to start with '{}', but got '{}'",
51            prefix,
52            self.value.as_ref()
53        );
54        self
55    }
56    /// Asserts that the string ends with a given suffix
57    ///
58    /// # Examples
59    ///
60    /// ```
61    /// use fluent_assertions::*;
62    /// "hello world".should().end_with("world");
63    /// ```
64    #[track_caller]
65    pub fn end_with(self, suffix: &str) -> Self {
66        assert!(
67            self.value.as_ref().ends_with(suffix),
68            "Expected string to end with '{}', but got '{}'",
69            suffix,
70            self.value.as_ref()
71        );
72        self
73    }
74
75    /// Asserts that the string contains a given substring
76    ///
77    /// # Examples
78    ///
79    /// ```
80    /// use fluent_assertions::*;
81    /// "hello world".should().contain("lo wo");
82    /// ```
83    #[track_caller]
84    pub fn contain(self, substring: &str) -> Self {
85        assert!(
86            self.value.as_ref().contains(substring),
87            "Expected string to contain '{}', but it didn't",
88            substring
89        );
90        self
91    }
92
93    /// Asserts that the string has a given length
94    ///
95    /// The length is measured with [`str::len`], i.e. the number of bytes,
96    /// not the number of characters. For strings containing multi-byte
97    /// UTF-8 characters these two counts differ.
98    ///
99    /// # Examples
100    ///
101    /// ```
102    /// use fluent_assertions::*;
103    /// "hello".should().have_length(5);
104    /// // Bytes, not chars: 'é' is a two-byte UTF-8 sequence.
105    /// "é".should().have_length(2);
106    /// ```
107    #[track_caller]
108    pub fn have_length(self, length: usize) -> Self {
109        assert!(
110            self.value.as_ref().len() == length,
111            "Expected string to have length {}, but it had length {}",
112            length,
113            self.value.as_ref().len()
114        );
115        self
116    }
117}
118
119#[cfg(test)]
120mod tests {
121    use crate::assertions::*;
122    use rstest::*;
123
124    #[test]
125    fn test_str_assertions() {
126        let actual = "ABCDEFGHI";
127        actual
128            .should()
129            .start_with("AB")
130            .end_with("HI")
131            .contain("EF")
132            .have_length(9);
133    }
134
135    #[test]
136    fn test_string_assertions() {
137        let actual_string = "ABCDEFGHI".to_string();
138        actual_string
139            .should()
140            .start_with("AB")
141            .end_with("HI")
142            .contain("EF")
143            .have_length(9);
144    }
145
146    #[rstest]
147    #[case(String::default())]
148    #[case(String::from(""))]
149    #[case("".to_string())]
150    fn should_be_empty(#[case] input: String) {
151        input.should().be_empty();
152    }
153
154    #[rstest]
155    #[case(String::from("hello"))]
156    #[case("42".to_string())]
157    fn should_not_be_empty(#[case] input: String) {
158        input.should().not_be_empty();
159    }
160
161    #[rstest]
162    #[case("hello")]
163    #[case("42")]
164    fn should_be(#[case] input: &str) {
165        input.should().be(input);
166    }
167
168    #[test]
169    #[should_panic(expected = "Expected string to start with 'hello'")]
170    fn start_with_panics_when_actual_shorter_than_prefix() {
171        "hi".should().start_with("hello");
172    }
173
174    #[test]
175    #[should_panic(expected = "Expected string to end with 'world'")]
176    fn end_with_panics_when_actual_shorter_than_suffix() {
177        "hi".should().end_with("world");
178    }
179
180    #[test]
181    #[should_panic(expected = "Expected string to start with")]
182    fn start_with_panics_on_multibyte_actual() {
183        "é".should().start_with("prefix");
184    }
185}