googletest/matchers/
char_count_matcher.rs1use crate::{
16 description::Description,
17 matcher::{Matcher, MatcherBase, MatcherResult},
18};
19use std::fmt::Debug;
20
21pub fn char_count<E: Matcher<usize>>(expected: E) -> CharLenMatcher<E> {
60 CharLenMatcher { expected }
61}
62
63#[derive(MatcherBase)]
64pub struct CharLenMatcher<E> {
65 expected: E,
66}
67
68impl<T: Debug + Copy + AsRef<str>, E: Matcher<usize>> Matcher<T> for CharLenMatcher<E> {
69 fn matches(&self, actual: T) -> MatcherResult {
70 self.expected.matches(actual.as_ref().chars().count())
71 }
72
73 fn describe(&self, matcher_result: MatcherResult) -> Description {
74 match matcher_result {
75 MatcherResult::Match => format!(
76 "has character count, which {}",
77 self.expected.describe(MatcherResult::Match)
78 )
79 .into(),
80 MatcherResult::NoMatch => format!(
81 "has character count, which {}",
82 self.expected.describe(MatcherResult::NoMatch)
83 )
84 .into(),
85 }
86 }
87
88 fn explain_match(&self, actual: T) -> Description {
89 let actual_size = actual.as_ref().chars().count();
90 format!(
91 "which has character count {}, {}",
92 actual_size,
93 self.expected.explain_match(actual_size)
94 )
95 .into()
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use crate::description::Description;
102 use crate::matcher::MatcherResult;
103 use crate::prelude::*;
104 use crate::Result;
105 use indoc::indoc;
106 use std::fmt::Debug;
107
108 #[test]
109 fn char_count_matches_string_slice() -> Result<()> {
110 let value = "abcd";
111 verify_that!(value, char_count(eq(4)))
112 }
113
114 #[test]
115 fn char_count_matches_owned_string() -> Result<()> {
116 let value = String::from("abcd");
117 verify_that!(value, char_count(eq(4)))
118 }
119
120 #[test]
121 fn char_count_counts_non_ascii_characters_correctly() -> Result<()> {
122 let value = "äöüß";
123 verify_that!(value, char_count(eq(4)))
124 }
125
126 #[test]
127 fn char_count_explains_match() -> Result<()> {
128 #[derive(MatcherBase)]
129 struct TestMatcher;
130
131 impl<T: Debug + Copy> Matcher<T> for TestMatcher {
132 fn matches(&self, _: T) -> MatcherResult {
133 false.into()
134 }
135
136 fn describe(&self, _: MatcherResult) -> Description {
137 "called described".into()
138 }
139
140 fn explain_match(&self, _: T) -> Description {
141 "called explain_match".into()
142 }
143 }
144 verify_that!(
145 char_count(TestMatcher).explain_match("A string"),
146 displays_as(eq("which has character count 8, called explain_match"))
147 )
148 }
149
150 #[test]
151 fn char_count_has_correct_failure_message() -> Result<()> {
152 let result = verify_that!("äöüß", char_count(eq(3)));
153 verify_that!(
154 result,
155 err(displays_as(contains_substring(indoc!(
156 r#"
157 Value of: "äöüß"
158 Expected: has character count, which is equal to 3
159 Actual: "äöüß",
160 which has character count 4, which isn't equal to 3"#
161 ))))
162 )
163 }
164}