3 * Copyright 2017 gRPC authors.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 #include "src/core/lib/gprpp/map.h"
21 #include <gtest/gtest.h>
23 #include "include/grpc/support/string_util.h"
24 #include "src/core/lib/gprpp/inlined_vector.h"
25 #include "src/core/lib/gprpp/memory.h"
26 #include "src/core/lib/gprpp/orphanable.h"
27 #include "src/core/lib/gprpp/ref_counted_ptr.h"
28 #include "test/core/util/test_config.h"
34 Payload() : data_(-1) {}
35 explicit Payload(int data) : data_(data) {}
36 Payload(const Payload& other) : data_(other.data_) {}
37 Payload& operator=(const Payload& other) {
43 int data() { return data_; }
49 inline UniquePtr<char> CopyString(const char* string) {
50 return UniquePtr<char>(gpr_strdup(string));
53 static constexpr char kKeys[][4] = {"abc", "efg", "hij", "klm", "xyz"};
55 class MapTest : public ::testing::Test {
57 template <class Key, class T, class Compare>
58 typename ::grpc_core::Map<Key, T, Compare>::Entry* Root(
59 typename ::grpc_core::Map<Key, T, Compare>* map) {
64 // Test insertion of Payload
65 TEST_F(MapTest, EmplaceAndFind) {
66 Map<const char*, Payload, StringLess> test_map;
67 for (int i = 0; i < 5; i++) {
68 test_map.emplace(kKeys[i], Payload(i));
70 for (int i = 0; i < 5; i++) {
71 EXPECT_EQ(i, test_map.find(kKeys[i])->second.data());
75 // Test insertion of Payload Unique Ptrs
76 TEST_F(MapTest, EmplaceAndFindWithUniquePtrValue) {
77 Map<const char*, UniquePtr<Payload>, StringLess> test_map;
78 for (int i = 0; i < 5; i++) {
79 test_map.emplace(kKeys[i], MakeUnique<Payload>(i));
81 for (int i = 0; i < 5; i++) {
82 EXPECT_EQ(i, test_map.find(kKeys[i])->second->data());
86 // Test insertion of Unique Ptr kKeys and Payload
87 TEST_F(MapTest, EmplaceAndFindWithUniquePtrKey) {
88 Map<UniquePtr<char>, Payload, StringLess> test_map;
89 for (int i = 0; i < 5; i++) {
90 test_map.emplace(CopyString(kKeys[i]), Payload(i));
92 for (int i = 0; i < 5; i++) {
93 EXPECT_EQ(i, test_map.find(CopyString(kKeys[i]))->second.data());
97 // Test insertion of Payload
98 TEST_F(MapTest, InsertAndFind) {
99 Map<const char*, Payload, StringLess> test_map;
100 for (int i = 0; i < 5; i++) {
101 test_map.insert(MakePair(kKeys[i], Payload(i)));
103 for (int i = 0; i < 5; i++) {
104 EXPECT_EQ(i, test_map.find(kKeys[i])->second.data());
108 // Test insertion of Payload Unique Ptrs
109 TEST_F(MapTest, InsertAndFindWithUniquePtrValue) {
110 Map<const char*, UniquePtr<Payload>, StringLess> test_map;
111 for (int i = 0; i < 5; i++) {
112 test_map.insert(MakePair(kKeys[i], MakeUnique<Payload>(i)));
114 for (int i = 0; i < 5; i++) {
115 EXPECT_EQ(i, test_map.find(kKeys[i])->second->data());
119 // Test insertion of Unique Ptr kKeys and Payload
120 TEST_F(MapTest, InsertAndFindWithUniquePtrKey) {
121 Map<UniquePtr<char>, Payload, StringLess> test_map;
122 for (int i = 0; i < 5; i++) {
123 test_map.insert(MakePair(CopyString(kKeys[i]), Payload(i)));
125 for (int i = 0; i < 5; i++) {
126 EXPECT_EQ(i, test_map.find(CopyString(kKeys[i]))->second.data());
130 // Test bracket operators
131 TEST_F(MapTest, BracketOperator) {
132 Map<const char*, Payload, StringLess> test_map;
133 for (int i = 0; i < 5; i++) {
134 test_map[kKeys[i]] = Payload(i);
136 for (int i = 0; i < 5; i++) {
137 EXPECT_EQ(i, test_map[kKeys[i]].data());
141 // Test bracket operators with unique pointer to payload
142 TEST_F(MapTest, BracketOperatorWithUniquePtrValue) {
143 Map<const char*, UniquePtr<Payload>, StringLess> test_map;
144 for (int i = 0; i < 5; i++) {
145 test_map[kKeys[i]] = MakeUnique<Payload>(i);
147 for (int i = 0; i < 5; i++) {
148 EXPECT_EQ(i, test_map[kKeys[i]]->data());
152 // Test bracket operators with unique pointer to payload
153 TEST_F(MapTest, BracketOperatorWithUniquePtrKey) {
154 Map<UniquePtr<char>, Payload, StringLess> test_map;
155 for (int i = 0; i < 5; i++) {
156 test_map[CopyString(kKeys[i])] = Payload(i);
158 for (int i = 0; i < 5; i++) {
159 EXPECT_EQ(i, test_map[CopyString(kKeys[i])].data());
163 // Test removal of a single value
164 TEST_F(MapTest, Erase) {
165 Map<const char*, Payload, StringLess> test_map;
166 for (int i = 0; i < 5; i++) {
167 test_map.emplace(kKeys[i], Payload(i));
169 EXPECT_EQ(test_map.size(), 5UL);
170 EXPECT_EQ(test_map.erase(kKeys[3]), 1UL); // Remove "hij"
171 for (int i = 0; i < 5; i++) {
172 if (i == 3) { // "hij" should not be present
173 EXPECT_TRUE(test_map.find(kKeys[i]) == test_map.end());
175 EXPECT_EQ(i, test_map.find(kKeys[i])->second.data());
178 EXPECT_EQ(test_map.size(), 4UL);
181 // Test removal of a single value with unique ptr to payload
182 TEST_F(MapTest, EraseWithUniquePtrValue) {
183 Map<const char*, UniquePtr<Payload>, StringLess> test_map;
184 for (int i = 0; i < 5; i++) {
185 test_map.emplace(kKeys[i], MakeUnique<Payload>(i));
187 EXPECT_EQ(test_map.size(), 5UL);
188 test_map.erase(kKeys[3]); // Remove "hij"
189 for (int i = 0; i < 5; i++) {
190 if (i == 3) { // "hij" should not be present
191 EXPECT_TRUE(test_map.find(kKeys[i]) == test_map.end());
193 EXPECT_EQ(i, test_map.find(kKeys[i])->second->data());
196 EXPECT_EQ(test_map.size(), 4UL);
199 // Test removal of a single value
200 TEST_F(MapTest, EraseWithUniquePtrKey) {
201 Map<UniquePtr<char>, Payload, StringLess> test_map;
202 for (int i = 0; i < 5; i++) {
203 test_map.emplace(CopyString(kKeys[i]), Payload(i));
205 EXPECT_EQ(test_map.size(), 5UL);
206 test_map.erase(CopyString(kKeys[3])); // Remove "hij"
207 for (int i = 0; i < 5; i++) {
208 if (i == 3) { // "hij" should not be present
209 EXPECT_TRUE(test_map.find(CopyString(kKeys[i])) == test_map.end());
211 EXPECT_EQ(i, test_map.find(CopyString(kKeys[i]))->second.data());
214 EXPECT_EQ(test_map.size(), 4UL);
218 TEST_F(MapTest, SizeAndClear) {
219 Map<const char*, Payload, StringLess> test_map;
220 for (int i = 0; i < 5; i++) {
221 test_map.emplace(kKeys[i], Payload(i));
223 EXPECT_EQ(test_map.size(), 5UL);
224 EXPECT_FALSE(test_map.empty());
226 EXPECT_EQ(test_map.size(), 0UL);
227 EXPECT_TRUE(test_map.empty());
230 // Test clear with unique ptr payload
231 TEST_F(MapTest, SizeAndClearWithUniquePtrValue) {
232 Map<const char*, UniquePtr<Payload>, StringLess> test_map;
233 for (int i = 0; i < 5; i++) {
234 test_map.emplace(kKeys[i], MakeUnique<Payload>(i));
236 EXPECT_EQ(test_map.size(), 5UL);
237 EXPECT_FALSE(test_map.empty());
239 EXPECT_EQ(test_map.size(), 0UL);
240 EXPECT_TRUE(test_map.empty());
243 // Test clear with unique ptr char key
244 TEST_F(MapTest, SizeAndClearWithUniquePtrKey) {
245 Map<UniquePtr<char>, Payload, StringLess> test_map;
246 for (int i = 0; i < 5; i++) {
247 test_map.emplace(CopyString(kKeys[i]), Payload(i));
249 EXPECT_EQ(test_map.size(), 5UL);
250 EXPECT_FALSE(test_map.empty());
252 EXPECT_EQ(test_map.size(), 0UL);
253 EXPECT_TRUE(test_map.empty());
256 // Test correction of Left-Left Tree imbalance
257 TEST_F(MapTest, MapLL) {
258 Map<const char*, Payload, StringLess> test_map;
259 for (int i = 2; i >= 0; i--) {
260 test_map.emplace(kKeys[i], Payload(i));
262 EXPECT_EQ(strcmp(Root(&test_map)->pair.first, kKeys[1]), 0);
263 EXPECT_EQ(strcmp(Root(&test_map)->left->pair.first, kKeys[0]), 0);
264 EXPECT_EQ(strcmp(Root(&test_map)->right->pair.first, kKeys[2]), 0);
267 // Test correction of Left-Right tree imbalance
268 TEST_F(MapTest, MapLR) {
269 Map<const char*, Payload, StringLess> test_map;
270 int insertion_key_index[] = {2, 0, 1};
271 for (int i = 0; i < 3; i++) {
272 int key_index = insertion_key_index[i];
273 test_map.emplace(kKeys[key_index], Payload(key_index));
275 EXPECT_EQ(strcmp(Root(&test_map)->pair.first, kKeys[1]), 0);
276 EXPECT_EQ(strcmp(Root(&test_map)->left->pair.first, kKeys[0]), 0);
277 EXPECT_EQ(strcmp(Root(&test_map)->right->pair.first, kKeys[2]), 0);
280 // Test correction of Right-Left tree imbalance
281 TEST_F(MapTest, MapRL) {
282 Map<const char*, Payload, StringLess> test_map;
283 int insertion_key_index[] = {0, 2, 1};
284 for (int i = 0; i < 3; i++) {
285 int key_index = insertion_key_index[i];
286 test_map.emplace(kKeys[key_index], Payload(key_index));
288 EXPECT_EQ(strcmp(Root(&test_map)->pair.first, kKeys[1]), 0);
289 EXPECT_EQ(strcmp(Root(&test_map)->left->pair.first, kKeys[0]), 0);
290 EXPECT_EQ(strcmp(Root(&test_map)->right->pair.first, kKeys[2]), 0);
293 // Test correction of Right-Right tree imbalance
294 TEST_F(MapTest, MapRR) {
295 Map<const char*, Payload, StringLess> test_map;
296 for (int i = 0; i < 5; i++) {
297 test_map.emplace(kKeys[i], Payload(i));
299 EXPECT_EQ(strcmp(Root(&test_map)->pair.first, kKeys[1]), 0);
300 EXPECT_EQ(strcmp(Root(&test_map)->left->pair.first, kKeys[0]), 0);
301 EXPECT_EQ(strcmp(Root(&test_map)->right->pair.first, kKeys[3]), 0);
302 EXPECT_EQ(strcmp(Root(&test_map)->right->left->pair.first, kKeys[2]), 0);
303 EXPECT_EQ(strcmp(Root(&test_map)->right->right->pair.first, kKeys[4]), 0);
306 // Test correction after random insertion
307 TEST_F(MapTest, MapRandomInsertions) {
308 Map<const char*, Payload, StringLess> test_map;
309 int insertion_key_index[] = {1, 4, 3, 0, 2};
310 for (int i = 0; i < 5; i++) {
311 int key_index = insertion_key_index[i];
312 test_map.emplace(kKeys[key_index], Payload(key_index));
314 EXPECT_EQ(strcmp(Root(&test_map)->pair.first, kKeys[3]), 0);
315 EXPECT_EQ(strcmp(Root(&test_map)->left->pair.first, kKeys[1]), 0);
316 EXPECT_EQ(strcmp(Root(&test_map)->right->pair.first, kKeys[4]), 0);
317 EXPECT_EQ(strcmp(Root(&test_map)->left->right->pair.first, kKeys[2]), 0);
318 EXPECT_EQ(strcmp(Root(&test_map)->left->left->pair.first, kKeys[0]), 0);
322 TEST_F(MapTest, Iteration) {
323 Map<const char*, Payload, StringLess> test_map;
324 for (int i = 4; i >= 0; --i) {
325 test_map.emplace(kKeys[i], Payload(i));
327 auto it = test_map.begin();
328 for (int i = 0; i < 5; ++i) {
329 ASSERT_NE(it, test_map.end());
330 EXPECT_STREQ(kKeys[i], it->first);
331 EXPECT_EQ(i, it->second.data());
334 EXPECT_EQ(it, test_map.end());
337 // Test Map iterator with unique ptr payload
338 TEST_F(MapTest, IterationWithUniquePtrValue) {
339 Map<const char*, UniquePtr<Payload>, StringLess> test_map;
340 for (int i = 4; i >= 0; --i) {
341 test_map.emplace(kKeys[i], MakeUnique<Payload>(i));
343 auto it = test_map.begin();
344 for (int i = 0; i < 5; ++i) {
345 ASSERT_NE(it, test_map.end());
346 EXPECT_STREQ(kKeys[i], it->first);
347 EXPECT_EQ(i, it->second->data());
350 EXPECT_EQ(it, test_map.end());
353 // Test Map iterator with unique ptr to char key
354 TEST_F(MapTest, IterationWithUniquePtrKey) {
355 Map<UniquePtr<char>, Payload, StringLess> test_map;
356 for (int i = 4; i >= 0; --i) {
357 test_map.emplace(CopyString(kKeys[i]), Payload(i));
359 auto it = test_map.begin();
360 for (int i = 0; i < 5; ++i) {
361 ASSERT_NE(it, test_map.end());
362 EXPECT_STREQ(kKeys[i], it->first.get());
363 EXPECT_EQ(i, it->second.data());
366 EXPECT_EQ(it, test_map.end());
369 // Test removing entries while iterating the map
370 TEST_F(MapTest, EraseUsingIterator) {
371 Map<const char*, Payload, StringLess> test_map;
372 for (int i = 0; i < 5; i++) {
373 test_map.emplace(kKeys[i], Payload(i));
376 for (auto iter = test_map.begin(); iter != test_map.end();) {
377 EXPECT_EQ(iter->second.data(), count);
378 if (count % 2 == 1) {
379 iter = test_map.erase(iter);
386 auto it = test_map.begin();
387 for (int i = 0; i < 5; ++i) {
389 EXPECT_STREQ(kKeys[i], it->first);
390 EXPECT_EQ(i, it->second.data());
394 EXPECT_EQ(it, test_map.end());
397 // Random ops on a Map with Integer key of Payload value,
398 // tests default comparator
399 TEST_F(MapTest, RandomOpsWithIntKey) {
400 Map<int, Payload> test_map;
401 for (int i = 0; i < 5; i++) {
402 test_map.emplace(i, Payload(i));
404 for (int i = 0; i < 5; i++) {
405 EXPECT_EQ(i, test_map.find(i)->second.data());
407 for (int i = 0; i < 5; i++) {
408 test_map[i] = Payload(i + 10);
410 for (int i = 0; i < 5; i++) {
411 EXPECT_EQ(i + 10, test_map[i].data());
413 EXPECT_EQ(test_map.erase(3), 1UL);
414 EXPECT_TRUE(test_map.find(3) == test_map.end());
415 EXPECT_FALSE(test_map.empty());
416 EXPECT_EQ(test_map.size(), 4UL);
418 EXPECT_EQ(test_map.size(), 0UL);
419 EXPECT_TRUE(test_map.empty());
422 // Tests lower_bound().
423 TEST_F(MapTest, LowerBound) {
424 Map<int, Payload> test_map;
425 for (int i = 0; i < 10; i += 2) {
426 test_map.emplace(i, Payload(i));
428 auto it = test_map.lower_bound(-1);
429 EXPECT_EQ(it, test_map.begin());
430 it = test_map.lower_bound(0);
431 EXPECT_EQ(it, test_map.begin());
432 it = test_map.lower_bound(2);
433 EXPECT_EQ(it->first, 2);
434 it = test_map.lower_bound(3);
435 EXPECT_EQ(it->first, 4);
436 it = test_map.lower_bound(9);
437 EXPECT_EQ(it, test_map.end());
440 } // namespace testing
441 } // namespace grpc_core
443 int main(int argc, char** argv) {
444 grpc::testing::TestEnvironment env(argc, argv);
445 ::testing::InitGoogleTest(&argc, argv);
446 return RUN_ALL_TESTS();