blob: c005a69057869b107e5dcde6b8467c9509a0caf6 [file] [log] [blame]
pph34r@gmail.com4f029ab2011-06-25 13:33:18 +09001// Copyright (c) 2011 The Chromium Authors. All rights reserved.
phajdan.jr@chromium.orga12746c2009-08-19 23:56:38 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/id_map.h"
6
7#include "testing/gtest/include/gtest/gtest.h"
8
9namespace {
10
phajdan.jr@chromium.orga12746c2009-08-19 23:56:38 +090011class TestObject {
12};
13
neb@chromium.orged1f8d72010-01-26 08:25:16 +090014class DestructorCounter {
15 public:
16 explicit DestructorCounter(int* counter) : counter_(counter) {}
17 ~DestructorCounter() { ++(*counter_); }
tfarina@chromium.org6ac12282012-12-04 02:04:28 +090018
neb@chromium.orged1f8d72010-01-26 08:25:16 +090019 private:
20 int* counter_;
21};
22
tfarina@chromium.org6ac12282012-12-04 02:04:28 +090023TEST(IDMapTest, Basic) {
phajdan.jr@chromium.orga12746c2009-08-19 23:56:38 +090024 IDMap<TestObject> map;
25 EXPECT_TRUE(map.IsEmpty());
26 EXPECT_EQ(0U, map.size());
27
28 TestObject obj1;
29 TestObject obj2;
30
31 int32 id1 = map.Add(&obj1);
32 EXPECT_FALSE(map.IsEmpty());
33 EXPECT_EQ(1U, map.size());
34 EXPECT_EQ(&obj1, map.Lookup(id1));
35
36 int32 id2 = map.Add(&obj2);
37 EXPECT_FALSE(map.IsEmpty());
38 EXPECT_EQ(2U, map.size());
39
40 EXPECT_EQ(&obj1, map.Lookup(id1));
41 EXPECT_EQ(&obj2, map.Lookup(id2));
42
43 map.Remove(id1);
44 EXPECT_FALSE(map.IsEmpty());
45 EXPECT_EQ(1U, map.size());
46
47 map.Remove(id2);
48 EXPECT_TRUE(map.IsEmpty());
49 EXPECT_EQ(0U, map.size());
50
51 map.AddWithID(&obj1, 1);
52 map.AddWithID(&obj2, 2);
53 EXPECT_EQ(&obj1, map.Lookup(1));
54 EXPECT_EQ(&obj2, map.Lookup(2));
phajdan.jr@chromium.org7c63ed82012-10-27 10:03:01 +090055
56 EXPECT_EQ(0, map.iteration_depth());
phajdan.jr@chromium.orga12746c2009-08-19 23:56:38 +090057}
58
tfarina@chromium.org6ac12282012-12-04 02:04:28 +090059TEST(IDMapTest, IteratorRemainsValidWhenRemovingCurrentElement) {
phajdan.jr@chromium.orga12746c2009-08-19 23:56:38 +090060 IDMap<TestObject> map;
61
62 TestObject obj1;
63 TestObject obj2;
64 TestObject obj3;
65
66 map.Add(&obj1);
67 map.Add(&obj2);
68 map.Add(&obj3);
69
phajdan.jr@chromium.org61544a02010-02-16 18:15:38 +090070 {
71 IDMap<TestObject>::const_iterator iter(&map);
phajdan.jr@chromium.org7c63ed82012-10-27 10:03:01 +090072
73 EXPECT_EQ(1, map.iteration_depth());
74
phajdan.jr@chromium.org61544a02010-02-16 18:15:38 +090075 while (!iter.IsAtEnd()) {
76 map.Remove(iter.GetCurrentKey());
77 iter.Advance();
78 }
79
80 // Test that while an iterator is still in scope, we get the map emptiness
81 // right (http://crbug.com/35571).
82 EXPECT_TRUE(map.IsEmpty());
83 EXPECT_EQ(0U, map.size());
phajdan.jr@chromium.orga12746c2009-08-19 23:56:38 +090084 }
phajdan.jr@chromium.org61544a02010-02-16 18:15:38 +090085
86 EXPECT_TRUE(map.IsEmpty());
87 EXPECT_EQ(0U, map.size());
phajdan.jr@chromium.org7c63ed82012-10-27 10:03:01 +090088
89 EXPECT_EQ(0, map.iteration_depth());
phajdan.jr@chromium.orga12746c2009-08-19 23:56:38 +090090}
91
tfarina@chromium.org6ac12282012-12-04 02:04:28 +090092TEST(IDMapTest, IteratorRemainsValidWhenRemovingOtherElements) {
phajdan.jr@chromium.orga12746c2009-08-19 23:56:38 +090093 IDMap<TestObject> map;
94
95 const int kCount = 5;
96 TestObject obj[kCount];
phajdan.jr@chromium.orga12746c2009-08-19 23:56:38 +090097
98 for (int i = 0; i < kCount; i++)
earthdok@chromium.org8be6e992014-01-24 03:17:15 +090099 map.Add(&obj[i]);
phajdan.jr@chromium.orga12746c2009-08-19 23:56:38 +0900100
earthdok@chromium.org8be6e992014-01-24 03:17:15 +0900101 // IDMap uses a hash_map, which has no predictable iteration order.
102 int32 ids_in_iteration_order[kCount];
103 const TestObject* objs_in_iteration_order[kCount];
phajdan.jr@chromium.orga12746c2009-08-19 23:56:38 +0900104 int counter = 0;
105 for (IDMap<TestObject>::const_iterator iter(&map);
106 !iter.IsAtEnd(); iter.Advance()) {
earthdok@chromium.org8be6e992014-01-24 03:17:15 +0900107 ids_in_iteration_order[counter] = iter.GetCurrentKey();
108 objs_in_iteration_order[counter] = iter.GetCurrentValue();
109 counter++;
110 }
111
112 counter = 0;
113 for (IDMap<TestObject>::const_iterator iter(&map);
114 !iter.IsAtEnd(); iter.Advance()) {
phajdan.jr@chromium.org7c63ed82012-10-27 10:03:01 +0900115 EXPECT_EQ(1, map.iteration_depth());
116
phajdan.jr@chromium.orga12746c2009-08-19 23:56:38 +0900117 switch (counter) {
118 case 0:
earthdok@chromium.org8be6e992014-01-24 03:17:15 +0900119 EXPECT_EQ(ids_in_iteration_order[0], iter.GetCurrentKey());
120 EXPECT_EQ(objs_in_iteration_order[0], iter.GetCurrentValue());
121 map.Remove(ids_in_iteration_order[1]);
phajdan.jr@chromium.orga12746c2009-08-19 23:56:38 +0900122 break;
123 case 1:
earthdok@chromium.org8be6e992014-01-24 03:17:15 +0900124 EXPECT_EQ(ids_in_iteration_order[2], iter.GetCurrentKey());
125 EXPECT_EQ(objs_in_iteration_order[2], iter.GetCurrentValue());
126 map.Remove(ids_in_iteration_order[3]);
phajdan.jr@chromium.orga12746c2009-08-19 23:56:38 +0900127 break;
128 case 2:
earthdok@chromium.org8be6e992014-01-24 03:17:15 +0900129 EXPECT_EQ(ids_in_iteration_order[4], iter.GetCurrentKey());
130 EXPECT_EQ(objs_in_iteration_order[4], iter.GetCurrentValue());
131 map.Remove(ids_in_iteration_order[0]);
phajdan.jr@chromium.orga12746c2009-08-19 23:56:38 +0900132 break;
133 default:
134 FAIL() << "should not have that many elements";
135 break;
136 }
137
138 counter++;
139 }
phajdan.jr@chromium.org7c63ed82012-10-27 10:03:01 +0900140
141 EXPECT_EQ(0, map.iteration_depth());
142}
143
tfarina@chromium.org6ac12282012-12-04 02:04:28 +0900144TEST(IDMapTest, CopyIterator) {
phajdan.jr@chromium.org7c63ed82012-10-27 10:03:01 +0900145 IDMap<TestObject> map;
146
147 TestObject obj1;
148 TestObject obj2;
149 TestObject obj3;
150
151 map.Add(&obj1);
152 map.Add(&obj2);
153 map.Add(&obj3);
154
155 EXPECT_EQ(0, map.iteration_depth());
156
157 {
158 IDMap<TestObject>::const_iterator iter1(&map);
159 EXPECT_EQ(1, map.iteration_depth());
160
161 // Make sure that copying the iterator correctly increments
162 // map's iteration depth.
163 IDMap<TestObject>::const_iterator iter2(iter1);
164 EXPECT_EQ(2, map.iteration_depth());
165 }
166
167 // Make sure after destroying all iterators the map's iteration depth
168 // returns to initial state.
169 EXPECT_EQ(0, map.iteration_depth());
170}
171
tfarina@chromium.org6ac12282012-12-04 02:04:28 +0900172TEST(IDMapTest, AssignIterator) {
phajdan.jr@chromium.org7c63ed82012-10-27 10:03:01 +0900173 IDMap<TestObject> map;
174
175 TestObject obj1;
176 TestObject obj2;
177 TestObject obj3;
178
179 map.Add(&obj1);
180 map.Add(&obj2);
181 map.Add(&obj3);
182
183 EXPECT_EQ(0, map.iteration_depth());
184
185 {
186 IDMap<TestObject>::const_iterator iter1(&map);
187 EXPECT_EQ(1, map.iteration_depth());
188
189 IDMap<TestObject>::const_iterator iter2(&map);
190 EXPECT_EQ(2, map.iteration_depth());
191
192 // Make sure that assigning the iterator correctly updates
193 // map's iteration depth (-1 for destruction, +1 for assignment).
194 EXPECT_EQ(2, map.iteration_depth());
195 }
196
197 // Make sure after destroying all iterators the map's iteration depth
198 // returns to initial state.
199 EXPECT_EQ(0, map.iteration_depth());
phajdan.jr@chromium.orga12746c2009-08-19 23:56:38 +0900200}
201
tfarina@chromium.org6ac12282012-12-04 02:04:28 +0900202TEST(IDMapTest, IteratorRemainsValidWhenClearing) {
jsbell@chromium.org8fe2a8f2012-10-30 06:36:22 +0900203 IDMap<TestObject> map;
204
205 const int kCount = 5;
206 TestObject obj[kCount];
jsbell@chromium.org8fe2a8f2012-10-30 06:36:22 +0900207
208 for (int i = 0; i < kCount; i++)
earthdok@chromium.org8be6e992014-01-24 03:17:15 +0900209 map.Add(&obj[i]);
jsbell@chromium.org8fe2a8f2012-10-30 06:36:22 +0900210
earthdok@chromium.org8be6e992014-01-24 03:17:15 +0900211 // IDMap uses a hash_map, which has no predictable iteration order.
212 int32 ids_in_iteration_order[kCount];
213 const TestObject* objs_in_iteration_order[kCount];
jsbell@chromium.org8fe2a8f2012-10-30 06:36:22 +0900214 int counter = 0;
215 for (IDMap<TestObject>::const_iterator iter(&map);
216 !iter.IsAtEnd(); iter.Advance()) {
earthdok@chromium.org8be6e992014-01-24 03:17:15 +0900217 ids_in_iteration_order[counter] = iter.GetCurrentKey();
218 objs_in_iteration_order[counter] = iter.GetCurrentValue();
219 counter++;
220 }
221
222 counter = 0;
223 for (IDMap<TestObject>::const_iterator iter(&map);
224 !iter.IsAtEnd(); iter.Advance()) {
jsbell@chromium.org8fe2a8f2012-10-30 06:36:22 +0900225 switch (counter) {
226 case 0:
earthdok@chromium.org8be6e992014-01-24 03:17:15 +0900227 EXPECT_EQ(ids_in_iteration_order[0], iter.GetCurrentKey());
228 EXPECT_EQ(objs_in_iteration_order[0], iter.GetCurrentValue());
jsbell@chromium.org8fe2a8f2012-10-30 06:36:22 +0900229 break;
230 case 1:
earthdok@chromium.org8be6e992014-01-24 03:17:15 +0900231 EXPECT_EQ(ids_in_iteration_order[1], iter.GetCurrentKey());
232 EXPECT_EQ(objs_in_iteration_order[1], iter.GetCurrentValue());
jsbell@chromium.org8fe2a8f2012-10-30 06:36:22 +0900233 map.Clear();
234 EXPECT_TRUE(map.IsEmpty());
235 EXPECT_EQ(0U, map.size());
236 break;
237 default:
238 FAIL() << "should not have that many elements";
239 break;
240 }
241 counter++;
242 }
243
244 EXPECT_TRUE(map.IsEmpty());
245 EXPECT_EQ(0U, map.size());
246}
247
tfarina@chromium.org6ac12282012-12-04 02:04:28 +0900248TEST(IDMapTest, OwningPointersDeletesThemOnRemove) {
neb@chromium.orged1f8d72010-01-26 08:25:16 +0900249 const int kCount = 3;
250
251 int external_del_count = 0;
252 DestructorCounter* external_obj[kCount];
253 int map_external_ids[kCount];
254
255 int owned_del_count = 0;
256 DestructorCounter* owned_obj[kCount];
257 int map_owned_ids[kCount];
258
259 IDMap<DestructorCounter> map_external;
260 IDMap<DestructorCounter, IDMapOwnPointer> map_owned;
261
262 for (int i = 0; i < kCount; ++i) {
263 external_obj[i] = new DestructorCounter(&external_del_count);
264 map_external_ids[i] = map_external.Add(external_obj[i]);
265
266 owned_obj[i] = new DestructorCounter(&owned_del_count);
267 map_owned_ids[i] = map_owned.Add(owned_obj[i]);
268 }
269
270 for (int i = 0; i < kCount; ++i) {
271 EXPECT_EQ(external_del_count, 0);
272 EXPECT_EQ(owned_del_count, i);
273
274 map_external.Remove(map_external_ids[i]);
275 map_owned.Remove(map_owned_ids[i]);
276 }
277
278 for (int i = 0; i < kCount; ++i) {
279 delete external_obj[i];
280 }
281
282 EXPECT_EQ(external_del_count, kCount);
283 EXPECT_EQ(owned_del_count, kCount);
284}
285
tfarina@chromium.org6ac12282012-12-04 02:04:28 +0900286TEST(IDMapTest, OwningPointersDeletesThemOnClear) {
jsbell@chromium.org8fe2a8f2012-10-30 06:36:22 +0900287 const int kCount = 3;
288
289 int external_del_count = 0;
290 DestructorCounter* external_obj[kCount];
291
292 int owned_del_count = 0;
293 DestructorCounter* owned_obj[kCount];
294
295 IDMap<DestructorCounter> map_external;
296 IDMap<DestructorCounter, IDMapOwnPointer> map_owned;
297
298 for (int i = 0; i < kCount; ++i) {
299 external_obj[i] = new DestructorCounter(&external_del_count);
300 map_external.Add(external_obj[i]);
301
302 owned_obj[i] = new DestructorCounter(&owned_del_count);
303 map_owned.Add(owned_obj[i]);
304 }
305
306 EXPECT_EQ(external_del_count, 0);
307 EXPECT_EQ(owned_del_count, 0);
308
309 map_external.Clear();
310 map_owned.Clear();
311
312 EXPECT_EQ(external_del_count, 0);
313 EXPECT_EQ(owned_del_count, kCount);
314
315 for (int i = 0; i < kCount; ++i) {
316 delete external_obj[i];
317 }
318
319 EXPECT_EQ(external_del_count, kCount);
320 EXPECT_EQ(owned_del_count, kCount);
321}
322
tfarina@chromium.org6ac12282012-12-04 02:04:28 +0900323TEST(IDMapTest, OwningPointersDeletesThemOnDestruct) {
neb@chromium.orged1f8d72010-01-26 08:25:16 +0900324 const int kCount = 3;
325
326 int external_del_count = 0;
327 DestructorCounter* external_obj[kCount];
neb@chromium.orged1f8d72010-01-26 08:25:16 +0900328
329 int owned_del_count = 0;
330 DestructorCounter* owned_obj[kCount];
neb@chromium.orged1f8d72010-01-26 08:25:16 +0900331
332 {
333 IDMap<DestructorCounter> map_external;
334 IDMap<DestructorCounter, IDMapOwnPointer> map_owned;
335
336 for (int i = 0; i < kCount; ++i) {
337 external_obj[i] = new DestructorCounter(&external_del_count);
pph34r@gmail.com4f029ab2011-06-25 13:33:18 +0900338 map_external.Add(external_obj[i]);
neb@chromium.orged1f8d72010-01-26 08:25:16 +0900339
340 owned_obj[i] = new DestructorCounter(&owned_del_count);
pph34r@gmail.com4f029ab2011-06-25 13:33:18 +0900341 map_owned.Add(owned_obj[i]);
neb@chromium.orged1f8d72010-01-26 08:25:16 +0900342 }
343 }
344
345 EXPECT_EQ(external_del_count, 0);
346
347 for (int i = 0; i < kCount; ++i) {
348 delete external_obj[i];
349 }
350
351 EXPECT_EQ(external_del_count, kCount);
352 EXPECT_EQ(owned_del_count, kCount);
353}
354
phajdan.jr@chromium.orga12746c2009-08-19 23:56:38 +0900355} // namespace