googletest/matchers/
is_encoded_string_matcher.rs1use crate::{
16 description::Description,
17 matcher::{Matcher, MatcherBase, MatcherResult},
18};
19use std::fmt::Debug;
20
21pub fn is_utf8_string<InnerMatcherT>(inner: InnerMatcherT) -> IsEncodedStringMatcher<InnerMatcherT>
52where
53 InnerMatcherT: for<'a> Matcher<&'a str>,
54{
55 IsEncodedStringMatcher { inner }
56}
57
58#[derive(MatcherBase)]
59pub struct IsEncodedStringMatcher<InnerMatcherT> {
60 inner: InnerMatcherT,
61}
62
63impl<ActualT: AsRef<[u8]> + Debug + Copy, InnerMatcherT> Matcher<ActualT>
64 for IsEncodedStringMatcher<InnerMatcherT>
65where
66 InnerMatcherT: for<'a> Matcher<&'a str>,
67{
68 fn matches(&self, actual: ActualT) -> MatcherResult {
69 std::str::from_utf8(actual.as_ref())
70 .map(|s| self.inner.matches(s))
71 .unwrap_or(MatcherResult::NoMatch)
72 }
73
74 fn describe(&self, matcher_result: MatcherResult) -> Description {
75 match matcher_result {
76 MatcherResult::Match => format!(
77 "is a UTF-8 encoded string which {}",
78 self.inner.describe(MatcherResult::Match)
79 )
80 .into(),
81 MatcherResult::NoMatch => format!(
82 "is not a UTF-8 encoded string which {}",
83 self.inner.describe(MatcherResult::Match)
84 )
85 .into(),
86 }
87 }
88
89 fn explain_match(&self, actual: ActualT) -> Description {
90 match std::str::from_utf8(actual.as_ref()) {
91 Ok(s) => {
92 format!("which is a UTF-8 encoded string {}", self.inner.explain_match(s)).into()
93 }
94 Err(e) => format!("which is not a UTF-8 encoded string: {e}").into(),
95 }
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use crate::matcher::MatcherResult;
102 use crate::prelude::*;
103 use crate::Result;
104
105 #[test]
106 fn matches_string_as_byte_slice() -> Result<()> {
107 verify_that!("A string".as_bytes(), is_utf8_string(eq("A string")))
108 }
109
110 #[test]
111 fn matches_string_as_byte_vec() -> Result<()> {
112 verify_that!("A string".as_bytes().to_vec(), is_utf8_string(eq("A string")))
113 }
114
115 #[test]
116 fn matches_string_with_utf_8_encoded_sequences() -> Result<()> {
117 verify_that!("äöüÄÖÜ".as_bytes().to_vec(), is_utf8_string(eq("äöüÄÖÜ")))
118 }
119
120 #[test]
121 fn does_not_match_non_equal_string() -> Result<()> {
122 verify_that!("äöüÄÖÜ".as_bytes().to_vec(), not(is_utf8_string(eq("A string"))))
123 }
124
125 #[test]
126 fn does_not_match_non_utf_8_encoded_byte_sequence() -> Result<()> {
127 verify_that!(&[192, 64, 255, 32], not(is_utf8_string(eq("A string"))))
128 }
129
130 #[test]
131 fn has_correct_description_in_matched_case() -> Result<()> {
132 let matcher = is_utf8_string(eq("A string"));
133
134 verify_that!(
135 Matcher::<&[u8]>::describe(&matcher, MatcherResult::Match),
136 displays_as(eq("is a UTF-8 encoded string which is equal to \"A string\""))
137 )
138 }
139
140 #[test]
141 fn has_correct_description_in_not_matched_case() -> Result<()> {
142 let matcher = is_utf8_string(eq("A string"));
143
144 verify_that!(
145 Matcher::<&[u8]>::describe(&matcher, MatcherResult::NoMatch),
146 displays_as(eq("is not a UTF-8 encoded string which is equal to \"A string\""))
147 )
148 }
149
150 #[test]
151 fn has_correct_explanation_in_matched_case() -> Result<()> {
152 let explanation = is_utf8_string(eq("A string")).explain_match("A string".as_bytes());
153
154 verify_that!(
155 explanation,
156 displays_as(eq("which is a UTF-8 encoded string which is equal to \"A string\""))
157 )
158 }
159
160 #[test]
161 fn has_correct_explanation_when_byte_array_is_not_utf8_encoded() -> Result<()> {
162 let explanation = is_utf8_string(eq("A string")).explain_match([192, 128, 0, 64]);
163
164 verify_that!(explanation, displays_as(starts_with("which is not a UTF-8 encoded string: ")))
165 }
166
167 #[test]
168 fn has_correct_explanation_when_inner_matcher_does_not_match() -> Result<()> {
169 let explanation = is_utf8_string(eq("A string")).explain_match("Another string".as_bytes());
170
171 verify_that!(
172 explanation,
173 displays_as(eq("which is a UTF-8 encoded string which isn't equal to \"A string\""))
174 )
175 }
176}