fluent_test/backend/matchers/
hashmap.rs1use crate::backend::Assertion;
2use crate::backend::assertions::sentence::AssertionSentence;
3use std::borrow::Borrow;
4use std::collections::HashMap;
5use std::fmt::Debug;
6use std::hash::Hash;
7
8pub trait HashMapMatchers<K, V> {
9 fn to_be_empty(self) -> Self;
10 fn to_have_length(self, expected: usize) -> Self;
11 fn to_contain_key<Q>(self, key: &Q) -> Self
12 where
13 K: Borrow<Q>,
14 Q: Hash + Eq + Debug + ?Sized;
15 fn to_contain_entry<Q, R>(self, key: &Q, value: &R) -> Self
16 where
17 K: Borrow<Q>,
18 V: Borrow<R>,
19 Q: Hash + Eq + Debug + ?Sized,
20 R: PartialEq + Debug + ?Sized;
21}
22
23trait AsHashMap<K, V> {
25 fn is_map_empty(&self) -> bool;
26 fn map_length(&self) -> usize;
27 fn map_contains_key<Q>(&self, key: &Q) -> bool
28 where
29 K: Borrow<Q>,
30 Q: Hash + Eq + ?Sized;
31 fn map_contains_entry<Q, R>(&self, key: &Q, value: &R) -> bool
32 where
33 K: Borrow<Q>,
34 V: Borrow<R>,
35 Q: Hash + Eq + ?Sized,
36 R: PartialEq + ?Sized;
37}
38
39impl<K, V> AsHashMap<K, V> for &HashMap<K, V>
41where
42 K: Hash + Eq,
43 V: Clone,
44{
45 fn is_map_empty(&self) -> bool {
46 self.is_empty()
47 }
48
49 fn map_length(&self) -> usize {
50 self.len()
51 }
52
53 fn map_contains_key<Q>(&self, key: &Q) -> bool
54 where
55 K: Borrow<Q>,
56 Q: Hash + Eq + ?Sized,
57 {
58 self.contains_key(key)
59 }
60
61 fn map_contains_entry<Q, R>(&self, key: &Q, value: &R) -> bool
62 where
63 K: Borrow<Q>,
64 V: Borrow<R>,
65 Q: Hash + Eq + ?Sized,
66 R: PartialEq + ?Sized,
67 {
68 self.get(key).is_some_and(|v| v.borrow() == value)
69 }
70}
71
72impl<K, V> AsHashMap<K, V> for HashMap<K, V>
74where
75 K: Hash + Eq,
76 V: Clone,
77{
78 fn is_map_empty(&self) -> bool {
79 self.is_empty()
80 }
81
82 fn map_length(&self) -> usize {
83 self.len()
84 }
85
86 fn map_contains_key<Q>(&self, key: &Q) -> bool
87 where
88 K: Borrow<Q>,
89 Q: Hash + Eq + ?Sized,
90 {
91 self.contains_key(key)
92 }
93
94 fn map_contains_entry<Q, R>(&self, key: &Q, value: &R) -> bool
95 where
96 K: Borrow<Q>,
97 V: Borrow<R>,
98 Q: Hash + Eq + ?Sized,
99 R: PartialEq + ?Sized,
100 {
101 self.get(key).is_some_and(|v| v.borrow() == value)
102 }
103}
104
105impl<M, K, V> HashMapMatchers<K, V> for Assertion<M>
107where
108 K: Hash + Eq + Debug + Clone,
109 V: Debug + Clone,
110 M: AsHashMap<K, V> + Debug + Clone,
111{
112 fn to_be_empty(self) -> Self {
113 let result = self.value.is_map_empty();
114 let sentence = AssertionSentence::new("be", "empty");
115
116 return self.add_step(sentence, result);
117 }
118
119 fn to_have_length(self, expected: usize) -> Self {
120 let actual_length = self.value.map_length();
121 let result = actual_length == expected;
122 let sentence = AssertionSentence::new("have", format!("length {}", expected));
123
124 return self.add_step(sentence, result);
125 }
126
127 fn to_contain_key<Q>(self, key: &Q) -> Self
128 where
129 K: Borrow<Q>,
130 Q: Hash + Eq + Debug + ?Sized,
131 {
132 let result = self.value.map_contains_key(key);
133 let sentence = AssertionSentence::new("contain", format!("key {:?}", key));
134
135 return self.add_step(sentence, result);
136 }
137
138 fn to_contain_entry<Q, R>(self, key: &Q, value: &R) -> Self
139 where
140 K: Borrow<Q>,
141 V: Borrow<R>,
142 Q: Hash + Eq + Debug + ?Sized,
143 R: PartialEq + Debug + ?Sized,
144 {
145 let result = self.value.map_contains_entry(key, value);
146 let sentence = AssertionSentence::new("contain", format!("entry ({:?}, {:?})", key, value));
147
148 return self.add_step(sentence, result);
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use crate::prelude::*;
155 use std::collections::HashMap;
156
157 #[test]
158 fn test_hashmap_to_be_empty() {
159 crate::Reporter::disable_deduplication();
161
162 let empty: HashMap<i32, i32> = HashMap::new();
163 let not_empty: HashMap<i32, i32> = [(1, 2)].iter().cloned().collect();
164
165 expect!(&empty).to_be_empty();
167 expect!(¬_empty).not().to_be_empty();
168 }
169
170 #[test]
171 #[should_panic(expected = "be empty")]
172 fn test_non_empty_to_be_empty_fails() {
173 let map: HashMap<i32, i32> = [(1, 2)].iter().cloned().collect();
174 let _assertion = expect!(&map).to_be_empty();
175 std::hint::black_box(_assertion);
176 }
177
178 #[test]
179 #[should_panic(expected = "not be empty")]
180 fn test_empty_not_to_be_empty_fails() {
181 let map: HashMap<i32, i32> = HashMap::new();
182 let _assertion = expect!(&map).not().to_be_empty();
183 std::hint::black_box(_assertion);
184 }
185
186 #[test]
187 fn test_hashmap_to_have_length() {
188 crate::Reporter::disable_deduplication();
190
191 let map: HashMap<i32, i32> = [(1, 2), (3, 4)].iter().cloned().collect();
192
193 expect!(&map).to_have_length(2);
195 expect!(&map).not().to_have_length(3);
196 }
197
198 #[test]
199 #[should_panic(expected = "have length")]
200 fn test_wrong_length_fails() {
201 let map: HashMap<i32, i32> = [(1, 2)].iter().cloned().collect();
202 let _assertion = expect!(&map).to_have_length(2);
203 std::hint::black_box(_assertion);
204 }
205
206 #[test]
207 #[should_panic(expected = "not have length")]
208 fn test_right_length_not_fails() {
209 let map: HashMap<i32, i32> = [(1, 2)].iter().cloned().collect();
210 let _assertion = expect!(&map).not().to_have_length(1);
211 std::hint::black_box(_assertion);
212 }
213
214 #[test]
215 fn test_hashmap_to_contain_key() {
216 crate::Reporter::disable_deduplication();
218
219 let map: HashMap<i32, i32> = [(1, 2), (3, 4)].iter().cloned().collect();
220
221 expect!(&map).to_contain_key(&1);
223 expect!(&map).not().to_contain_key(&2);
224 }
225
226 #[test]
227 #[should_panic(expected = "not contain key")]
228 fn test_present_key_not_fails() {
229 let map: HashMap<i32, i32> = [(1, 2)].iter().cloned().collect();
230 let _assertion = expect!(&map).not().to_contain_key(&1);
231 std::hint::black_box(_assertion);
232 }
233
234 #[test]
235 #[should_panic(expected = "contain key")]
236 fn test_missing_key_fails() {
237 let map: HashMap<i32, i32> = [(1, 2)].iter().cloned().collect();
238 let _assertion = expect!(&map).to_contain_key(&2);
239 std::hint::black_box(_assertion);
240 }
241
242 #[test]
243 fn test_hashmap_to_contain_entry() {
244 crate::Reporter::disable_deduplication();
246
247 let map: HashMap<i32, i32> = [(1, 2), (3, 4)].iter().cloned().collect();
248
249 expect!(&map).to_contain_entry(&1, &2);
251 expect!(&map).not().to_contain_entry(&1, &3);
252 expect!(&map).not().to_contain_entry(&2, &3);
253 }
254
255 #[test]
256 #[should_panic(expected = "not contain entry")]
257 fn test_right_entry_not_fails() {
258 let map: HashMap<i32, i32> = [(1, 2)].iter().cloned().collect();
259 let _assertion = expect!(&map).not().to_contain_entry(&1, &2);
260 std::hint::black_box(_assertion);
261 }
262
263 #[test]
264 #[should_panic(expected = "contain entry")]
265 fn test_missing_key_entry_fails() {
266 let map: HashMap<i32, i32> = [(1, 2)].iter().cloned().collect();
267 let _assertion = expect!(&map).to_contain_entry(&2, &3);
268 std::hint::black_box(_assertion);
269 }
270
271 #[test]
272 #[should_panic(expected = "contain entry")]
273 fn test_wrong_value_fails() {
274 let map: HashMap<i32, i32> = [(1, 2)].iter().cloned().collect();
275 let _assertion = expect!(&map).to_contain_entry(&1, &3);
276 std::hint::black_box(_assertion);
277 }
278}