1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // 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
9 namespace {
10
11 class IDMapTest : public testing::Test {
12 };
13
14 class TestObject {
15 };
16
17 class DestructorCounter {
18 public:
DestructorCounter(int * counter)19 explicit DestructorCounter(int* counter) : counter_(counter) {}
~DestructorCounter()20 ~DestructorCounter() { ++(*counter_); }
21 private:
22 int* counter_;
23 };
24
TEST_F(IDMapTest,Basic)25 TEST_F(IDMapTest, Basic) {
26 IDMap<TestObject> map;
27 EXPECT_TRUE(map.IsEmpty());
28 EXPECT_EQ(0U, map.size());
29
30 TestObject obj1;
31 TestObject obj2;
32
33 int32 id1 = map.Add(&obj1);
34 EXPECT_FALSE(map.IsEmpty());
35 EXPECT_EQ(1U, map.size());
36 EXPECT_EQ(&obj1, map.Lookup(id1));
37
38 int32 id2 = map.Add(&obj2);
39 EXPECT_FALSE(map.IsEmpty());
40 EXPECT_EQ(2U, map.size());
41
42 EXPECT_EQ(&obj1, map.Lookup(id1));
43 EXPECT_EQ(&obj2, map.Lookup(id2));
44
45 map.Remove(id1);
46 EXPECT_FALSE(map.IsEmpty());
47 EXPECT_EQ(1U, map.size());
48
49 map.Remove(id2);
50 EXPECT_TRUE(map.IsEmpty());
51 EXPECT_EQ(0U, map.size());
52
53 map.AddWithID(&obj1, 1);
54 map.AddWithID(&obj2, 2);
55 EXPECT_EQ(&obj1, map.Lookup(1));
56 EXPECT_EQ(&obj2, map.Lookup(2));
57 }
58
TEST_F(IDMapTest,IteratorRemainsValidWhenRemovingCurrentElement)59 TEST_F(IDMapTest, IteratorRemainsValidWhenRemovingCurrentElement) {
60 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
70 {
71 IDMap<TestObject>::const_iterator iter(&map);
72 while (!iter.IsAtEnd()) {
73 map.Remove(iter.GetCurrentKey());
74 iter.Advance();
75 }
76
77 // Test that while an iterator is still in scope, we get the map emptiness
78 // right (http://crbug.com/35571).
79 EXPECT_TRUE(map.IsEmpty());
80 EXPECT_EQ(0U, map.size());
81 }
82
83 EXPECT_TRUE(map.IsEmpty());
84 EXPECT_EQ(0U, map.size());
85 }
86
TEST_F(IDMapTest,IteratorRemainsValidWhenRemovingOtherElements)87 TEST_F(IDMapTest, IteratorRemainsValidWhenRemovingOtherElements) {
88 IDMap<TestObject> map;
89
90 const int kCount = 5;
91 TestObject obj[kCount];
92 int32 ids[kCount];
93
94 for (int i = 0; i < kCount; i++)
95 ids[i] = map.Add(&obj[i]);
96
97 int counter = 0;
98 for (IDMap<TestObject>::const_iterator iter(&map);
99 !iter.IsAtEnd(); iter.Advance()) {
100 switch (counter) {
101 case 0:
102 EXPECT_EQ(ids[0], iter.GetCurrentKey());
103 EXPECT_EQ(&obj[0], iter.GetCurrentValue());
104 map.Remove(ids[1]);
105 break;
106 case 1:
107 EXPECT_EQ(ids[2], iter.GetCurrentKey());
108 EXPECT_EQ(&obj[2], iter.GetCurrentValue());
109 map.Remove(ids[3]);
110 break;
111 case 2:
112 EXPECT_EQ(ids[4], iter.GetCurrentKey());
113 EXPECT_EQ(&obj[4], iter.GetCurrentValue());
114 map.Remove(ids[0]);
115 break;
116 default:
117 FAIL() << "should not have that many elements";
118 break;
119 }
120
121 counter++;
122 }
123 }
124
TEST_F(IDMapTest,OwningPointersDeletesThemOnRemove)125 TEST_F(IDMapTest, OwningPointersDeletesThemOnRemove) {
126 const int kCount = 3;
127
128 int external_del_count = 0;
129 DestructorCounter* external_obj[kCount];
130 int map_external_ids[kCount];
131
132 int owned_del_count = 0;
133 DestructorCounter* owned_obj[kCount];
134 int map_owned_ids[kCount];
135
136 IDMap<DestructorCounter> map_external;
137 IDMap<DestructorCounter, IDMapOwnPointer> map_owned;
138
139 for (int i = 0; i < kCount; ++i) {
140 external_obj[i] = new DestructorCounter(&external_del_count);
141 map_external_ids[i] = map_external.Add(external_obj[i]);
142
143 owned_obj[i] = new DestructorCounter(&owned_del_count);
144 map_owned_ids[i] = map_owned.Add(owned_obj[i]);
145 }
146
147 for (int i = 0; i < kCount; ++i) {
148 EXPECT_EQ(external_del_count, 0);
149 EXPECT_EQ(owned_del_count, i);
150
151 map_external.Remove(map_external_ids[i]);
152 map_owned.Remove(map_owned_ids[i]);
153 }
154
155 for (int i = 0; i < kCount; ++i) {
156 delete external_obj[i];
157 }
158
159 EXPECT_EQ(external_del_count, kCount);
160 EXPECT_EQ(owned_del_count, kCount);
161 }
162
TEST_F(IDMapTest,OwningPointersDeletesThemOnDestruct)163 TEST_F(IDMapTest, OwningPointersDeletesThemOnDestruct) {
164 const int kCount = 3;
165
166 int external_del_count = 0;
167 DestructorCounter* external_obj[kCount];
168 int map_external_ids[kCount];
169
170 int owned_del_count = 0;
171 DestructorCounter* owned_obj[kCount];
172 int map_owned_ids[kCount];
173
174 {
175 IDMap<DestructorCounter> map_external;
176 IDMap<DestructorCounter, IDMapOwnPointer> map_owned;
177
178 for (int i = 0; i < kCount; ++i) {
179 external_obj[i] = new DestructorCounter(&external_del_count);
180 map_external_ids[i] = map_external.Add(external_obj[i]);
181
182 owned_obj[i] = new DestructorCounter(&owned_del_count);
183 map_owned_ids[i] = map_owned.Add(owned_obj[i]);
184 }
185 }
186
187 EXPECT_EQ(external_del_count, 0);
188
189 for (int i = 0; i < kCount; ++i) {
190 delete external_obj[i];
191 }
192
193 EXPECT_EQ(external_del_count, kCount);
194 EXPECT_EQ(owned_del_count, kCount);
195 }
196
197 } // namespace
198