1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2023 Google LLC. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 use enums_rust_proto::{test_map_with_nested_enum, TestMapWithNestedEnum};
9 use googletest::prelude::*;
10 use map_unittest_rust_proto::{MapEnum, TestMap, TestMapWithMessages};
11 use paste::paste;
12 use protobuf::ProtoString;
13 use std::collections::HashMap;
14 use unittest_rust_proto::TestAllTypes;
15
16 macro_rules! generate_map_primitives_tests {
17 (
18 $(($k_type:ty, $v_type:ty, $k_field:ident, $v_field:ident,
19 $k_nonzero:expr, $v_nonzero:expr $(,)?)),*
20 $(,)?
21 ) => {
22 paste! { $(
23 #[gtest]
24 fn [< test_map_ $k_field _ $v_field >]() {
25 let mut msg = TestMap::new();
26 assert_that!(msg.[< map_ $k_field _ $v_field >]().len(), eq(0));
27 assert_that!(
28 msg.[< map_ $k_field _ $v_field >](),
29 elements_are![]
30 );
31 assert_that!(
32 msg.[< map_ $k_field _ $v_field >]().keys().collect::<Vec<_>>(),
33 elements_are![]
34 );
35 assert_that!(
36 msg.[< map_ $k_field _ $v_field >]().values().collect::<Vec<_>>(),
37 elements_are![]
38 );
39 let k = <$k_type>::default();
40 let v = <$v_type>::default();
41 assert_that!(msg.[< map_ $k_field _ $v_field _mut>]().insert(k, v), eq(true));
42 assert_that!(msg.[< map_ $k_field _ $v_field _mut>]().insert(k, v), eq(false));
43 assert_that!(msg.[< map_ $k_field _ $v_field >]().len(), eq(1));
44 assert_that!(
45 msg.[< map_ $k_field _ $v_field >](),
46 elements_are![eq((k, v))]
47 );
48 assert_that!(
49 msg.[< map_ $k_field _ $v_field >]().keys().collect::<Vec<_>>(),
50 elements_are![eq(&k)]
51 );
52 assert_that!(
53 msg.[< map_ $k_field _ $v_field >]().values().collect::<Vec<_>>(),
54 elements_are![eq(&v)]
55 );
56
57 let k2: $k_type = $k_nonzero;
58 let v2: $v_type = $v_nonzero;
59 assert_that!(msg.[< map_ $k_field _ $v_field _mut>]().insert(k2, v2), eq(true));
60 assert_that!(msg.[< map_ $k_field _ $v_field >](), len(eq(2)));
61 assert_that!(
62 msg.[< map_ $k_field _ $v_field >](),
63 unordered_elements_are![
64 eq((k, v)),
65 eq((k2, v2)),
66 ]
67 );
68 assert_that!(
69 msg.[< map_ $k_field _ $v_field >]().keys().collect::<Vec<_>>(),
70 unordered_elements_are![eq(&k), eq(&k2)]
71 );
72 assert_that!(
73 msg.[< map_ $k_field _ $v_field >]().values().collect::<Vec<_>>(),
74 unordered_elements_are![eq(&v), eq(&v2)]
75 );
76 }
77 )* }
78 };
79 }
80
81 generate_map_primitives_tests!(
82 (i32, i32, int32, int32, 1, 1),
83 (i64, i64, int64, int64, 1, 1),
84 (u32, u32, uint32, uint32, 1, 1),
85 (u64, u64, uint64, uint64, 1, 1),
86 (i32, i32, sint32, sint32, 1, 1),
87 (i64, i64, sint64, sint64, 1, 1),
88 (u32, u32, fixed32, fixed32, 1, 1),
89 (u64, u64, fixed64, fixed64, 1, 1),
90 (i32, i32, sfixed32, sfixed32, 1, 1),
91 (i64, i64, sfixed64, sfixed64, 1, 1),
92 (i32, f32, int32, float, 1, 1.),
93 (i32, f64, int32, double, 1, 1.),
94 (bool, bool, bool, bool, true, true),
95 (i32, &[u8], int32, bytes, 1, b"foo"),
96 (i32, MapEnum, int32, enum, 1, MapEnum::Baz),
97 );
98
99 #[gtest]
collect_as_hashmap()100 fn collect_as_hashmap() {
101 // Highlights conversion from protobuf map to hashmap.
102 let mut msg = TestMap::new();
103 msg.map_string_string_mut().insert("hello", "world");
104 msg.map_string_string_mut().insert("fizz", "buzz");
105 msg.map_string_string_mut().insert("boo", "blah");
106 let hashmap: HashMap<String, String> =
107 msg.map_string_string().iter().map(|(k, v)| (k.to_string(), v.to_string())).collect();
108 assert_that!(
109 hashmap,
110 unordered_elements_are![
111 (eq("hello"), eq("world")),
112 (eq("fizz"), eq("buzz")),
113 (eq("boo"), eq("blah")),
114 ]
115 );
116 }
117
118 #[gtest]
test_string_maps()119 fn test_string_maps() {
120 let mut msg = TestMap::new();
121 msg.map_string_string_mut().insert("hello", "world");
122 msg.map_string_string_mut().insert("fizz", "buzz");
123 assert_that!(msg.map_string_string().len(), eq(2));
124 assert_that!(msg.map_string_string().get("fizz").unwrap(), eq("buzz"));
125 assert_that!(msg.map_string_string().get("not found"), eq(None));
126 msg.map_string_string_mut().clear();
127 assert_that!(msg.map_string_string().len(), eq(0));
128 }
129
130 #[gtest]
test_nested_enum_maps()131 fn test_nested_enum_maps() {
132 // Verify that C++ thunks are generated and are with the right name for strings
133 TestMapWithNestedEnum::new()
134 .string_map_mut()
135 .insert("foo", test_map_with_nested_enum::inner_nested::NestedEnum::Foo);
136 }
137
138 #[gtest]
test_bytes_and_string_copied()139 fn test_bytes_and_string_copied() {
140 let mut msg = TestMap::new();
141
142 {
143 // Ensure val is dropped after inserting into the map.
144 let mut key = String::from("hello");
145 let mut val = String::from("world");
146 msg.map_string_string_mut().insert(key.as_str(), &val);
147 msg.map_int32_bytes_mut().insert(1, val.as_bytes());
148 // Validate that map keys are copied by mutating the originals.
149 key.replace_range(.., "ayo");
150 val.replace_range(.., "wOrld");
151 }
152
153 assert_that!(msg.map_string_string_mut().get("hello").unwrap(), eq("world"));
154 assert_that!(msg.map_string_string(), unordered_elements_are![(eq("hello"), eq("world"))]);
155 assert_that!(msg.map_int32_bytes_mut().get(1).unwrap(), eq(b"world"));
156 }
157
158 #[gtest]
test_map_setter()159 fn test_map_setter() {
160 // Set Map
161 {
162 let mut msg = TestMap::new();
163 let mut map = protobuf::Map::<ProtoString, ProtoString>::new();
164 map.as_mut().copy_from([("hello", "world"), ("fizz", "buzz")]);
165 msg.set_map_string_string(map);
166 assert_that!(
167 msg.map_string_string(),
168 unordered_elements_are![
169 eq(("hello".into(), "world".into())),
170 eq(("fizz".into(), "buzz".into()))
171 ]
172 );
173 }
174
175 // Set MapView
176 {
177 let mut msg = TestMap::new();
178 let mut map = protobuf::Map::<ProtoString, ProtoString>::new();
179 map.as_mut().copy_from([("hello", "world"), ("fizz", "buzz")]);
180 msg.set_map_string_string(map.as_view());
181 assert_that!(
182 msg.map_string_string(),
183 unordered_elements_are![
184 eq(("hello".into(), "world".into())),
185 eq(("fizz".into(), "buzz".into()))
186 ]
187 );
188 }
189
190 // Set MapMut
191 {
192 let mut msg = TestMap::new();
193 let mut map = protobuf::Map::<ProtoString, ProtoString>::new();
194 map.as_mut().copy_from([("hello", "world"), ("fizz", "buzz")]);
195 msg.set_map_string_string(map.as_mut());
196 assert_that!(
197 msg.map_string_string(),
198 unordered_elements_are![
199 eq(("hello".into(), "world".into())),
200 eq(("fizz".into(), "buzz".into()))
201 ]
202 );
203
204 // The original map should remain unchanged.
205 assert_that!(
206 map.as_view(),
207 unordered_elements_are![
208 eq(("hello".into(), "world".into())),
209 eq(("fizz".into(), "buzz".into()))
210 ]
211 );
212 }
213 }
214
215 #[test]
test_map_creation_with_message_values()216 fn test_map_creation_with_message_values() {
217 // Maps are usually created and owned by a parent message, but let's verify that
218 // we can successfully create and destroy them independently.
219 macro_rules! test_for_each_key {
220 ($($key_t:ty, $key:expr;)*) => {
221 $(
222 let msg = TestAllTypes::new();
223 let mut map = protobuf::Map::<$key_t, TestAllTypes>::new();
224 map.as_mut().insert($key, msg);
225 assert_that!(map.as_view().len(), eq(1));
226 )*
227 }
228 }
229
230 test_for_each_key!(
231 i32, -5;
232 u32, 13u32;
233 i64, 7;
234 u64, 11u64;
235 bool, false;
236 ProtoString, "looooooooooooooooooooooooong string";
237 );
238 }
239
240 #[test]
test_map_clearing_with_message_values()241 fn test_map_clearing_with_message_values() {
242 macro_rules! test_for_each_key {
243 ($($key_t:ty, $key:expr;)*) => {
244 $(
245 let msg = TestAllTypes::new();
246 let mut map = protobuf::Map::<$key_t, TestAllTypes>::new();
247 map.as_mut().insert($key, msg);
248 assert_that!(map.as_view().len(), eq(1));
249 map.as_mut().clear();
250 assert_that!(map.as_view().len(), eq(0));
251 )*
252 }
253 }
254
255 test_for_each_key!(
256 i32, -5;
257 u32, 13u32;
258 i64, 7;
259 u64, 11u64;
260 bool, false;
261 ProtoString, "looooooooooooooooooooooooong string";
262 );
263 }
264
265 macro_rules! generate_map_with_msg_values_tests {
266 (
267 $(($k_field:ident, $k_nonzero:expr, $k_other:expr $(,)?)),*
268 $(,)?
269 ) => {
270 paste! { $(
271 #[gtest]
272 fn [< test_map_ $k_field _all_types >]() {
273 // We need to cover the following upb/c++ thunks:
274 // TODO - b/323883851: Add test once Map::new is public.
275 // * new
276 // * free (covered implicitly by drop)
277 // * clear, size, insert, get, remove, iter, iter_next (all covered below)
278 let mut msg = TestMapWithMessages::new();
279 assert_that!(msg.[< map_ $k_field _all_types >]().len(), eq(0));
280 assert_that!(msg.[< map_ $k_field _all_types >]().get($k_nonzero), none());
281 // this block makes sure `insert` copies/moves, not borrows.
282 {
283 let mut msg_val = TestAllTypes::new();
284 msg_val.set_optional_int32(1001);
285 assert_that!(
286 msg
287 .[< map_ $k_field _all_types_mut >]()
288 .insert($k_nonzero, msg_val.as_view()),
289 eq(true),
290 "`insert` should return true when key was inserted."
291 );
292 assert_that!(
293 msg
294 .[< map_ $k_field _all_types_mut >]()
295 .insert($k_nonzero, msg_val.as_view()),
296 eq(false),
297 "`insert` should return false when key was already present."
298
299 );
300 }
301
302 assert_that!(
303 msg.[< map_ $k_field _all_types >]().len(),
304 eq(1),
305 "`size` thunk should return correct len.");
306
307 assert_that!(
308 msg.[< map_ $k_field _all_types >]().get($k_nonzero),
309 some(anything()),
310 "`get` should return Some when key present.");
311 assert_that!(
312 msg.[< map_ $k_field _all_types >]().get($k_nonzero).unwrap().optional_int32(),
313 eq(1001));
314 assert_that!(
315 msg.[< map_ $k_field _all_types >]().get($k_other),
316 none(),
317 "`get` should return None when key missing.");
318
319 msg.[< map_ $k_field _all_types_mut >]().clear();
320 assert_that!(
321 msg.[< map_ $k_field _all_types >]().len(),
322 eq(0),
323 "`clear` should drop all elements.");
324
325
326 assert_that!(
327 msg.[< map_ $k_field _all_types_mut >]().insert($k_nonzero, TestAllTypes::new()),
328 eq(true));
329 assert_that!(
330 msg.[< map_ $k_field _all_types_mut >]().remove($k_nonzero),
331 eq(true),
332 "`remove` should return true when key was present.");
333 assert_that!(msg.[< map_ $k_field _all_types >](), empty());
334 assert_that!(
335 msg.[< map_ $k_field _all_types_mut >]().remove($k_nonzero),
336 eq(false),
337 "`remove` should return false when key was missing.");
338
339 // empty iter
340 // assert_that!(
341 // msg.[< map_ $k_field _all_types_mut >]().iter().collect::<Vec<_>>(),
342 // elements_are![],
343 // "`iter` should work when empty."
344 // );
345 assert_that!(
346 msg.[< map_ $k_field _all_types_mut >]().keys().count(),
347 eq(0),
348 "`iter` should work when empty."
349 );
350 assert_that!(
351 msg.[< map_ $k_field _all_types_mut >]().values().count(),
352 eq(0),
353 "`iter` should work when empty."
354 );
355
356 // single element iter
357 assert_that!(
358 msg.[< map_ $k_field _all_types_mut >]().insert($k_nonzero, TestAllTypes::new()),
359 eq(true));
360 // assert_that!(
361 // msg.[< map_ $k_field _all_types >]().iter().collect::<Vec<_>>(),
362 // unordered_elements_are![
363 // eq(($k_nonzero, anything())),
364 // ]
365 // );
366 assert_that!(
367 msg.[< map_ $k_field _all_types >]().keys().collect::<Vec<_>>(),
368 unordered_elements_are![eq(&$k_nonzero)]
369 );
370 assert_that!(
371 msg.[< map_ $k_field _all_types >]().values().count(),
372 eq(1));
373
374
375 // 2 element iter
376 assert_that!(
377 msg
378 .[< map_ $k_field _all_types_mut >]()
379 .insert($k_other, TestAllTypes::new()),
380 eq(true));
381
382 assert_that!(
383 msg.[< map_ $k_field _all_types >](),
384 len(eq(2))
385 );
386 assert_that!(
387 msg.[< map_ $k_field _all_types >]().keys().collect::<Vec<_>>(),
388 unordered_elements_are![eq(&$k_nonzero), eq(&$k_other)]
389 );
390 assert_that!(
391 msg.[< map_ $k_field _all_types >]().values().count(),
392 eq(2)
393 );
394 }
395 )* }
396 }
397 }
398
399 generate_map_with_msg_values_tests!(
400 (int32, 1i32, 2i32),
401 (int64, 1i64, 2i64),
402 (uint32, 1u32, 2u32),
403 (uint64, 1u64, 2u64),
404 (sint32, 1, 2),
405 (sint64, 1, 2),
406 (fixed32, 1u32, 2u32),
407 (fixed64, 1u64, 2u64),
408 (sfixed32, 1, 2),
409 (sfixed64, 1, 2),
410 (bool, true, false),
411 (string, "foo", "bar"),
412 );
413