1 // Copyright 2018 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #ifndef ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MODIFIERS_TEST_H_
16 #define ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MODIFIERS_TEST_H_
17
18 #include <memory>
19
20 #include "gmock/gmock.h"
21 #include "gtest/gtest.h"
22 #include "absl/container/internal/hash_generator_testing.h"
23 #include "absl/container/internal/hash_policy_testing.h"
24
25 namespace absl {
26 ABSL_NAMESPACE_BEGIN
27 namespace container_internal {
28
29 template <class UnordMap>
30 class ModifiersTest : public ::testing::Test {};
31
32 TYPED_TEST_SUITE_P(ModifiersTest);
33
TYPED_TEST_P(ModifiersTest,Clear)34 TYPED_TEST_P(ModifiersTest, Clear) {
35 using T = hash_internal::GeneratedType<TypeParam>;
36 std::vector<T> values;
37 std::generate_n(std::back_inserter(values), 10,
38 hash_internal::Generator<T>());
39 TypeParam m(values.begin(), values.end());
40 ASSERT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
41 m.clear();
42 EXPECT_THAT(items(m), ::testing::UnorderedElementsAre());
43 EXPECT_TRUE(m.empty());
44 }
45
TYPED_TEST_P(ModifiersTest,Insert)46 TYPED_TEST_P(ModifiersTest, Insert) {
47 using T = hash_internal::GeneratedType<TypeParam>;
48 using V = typename TypeParam::mapped_type;
49 T val = hash_internal::Generator<T>()();
50 TypeParam m;
51 auto p = m.insert(val);
52 EXPECT_TRUE(p.second);
53 EXPECT_EQ(val, *p.first);
54 T val2 = {val.first, hash_internal::Generator<V>()()};
55 p = m.insert(val2);
56 EXPECT_FALSE(p.second);
57 EXPECT_EQ(val, *p.first);
58 }
59
TYPED_TEST_P(ModifiersTest,InsertHint)60 TYPED_TEST_P(ModifiersTest, InsertHint) {
61 using T = hash_internal::GeneratedType<TypeParam>;
62 using V = typename TypeParam::mapped_type;
63 T val = hash_internal::Generator<T>()();
64 TypeParam m;
65 auto it = m.insert(m.end(), val);
66 EXPECT_TRUE(it != m.end());
67 EXPECT_EQ(val, *it);
68 T val2 = {val.first, hash_internal::Generator<V>()()};
69 it = m.insert(it, val2);
70 EXPECT_TRUE(it != m.end());
71 EXPECT_EQ(val, *it);
72 }
73
TYPED_TEST_P(ModifiersTest,InsertRange)74 TYPED_TEST_P(ModifiersTest, InsertRange) {
75 using T = hash_internal::GeneratedType<TypeParam>;
76 std::vector<T> values;
77 std::generate_n(std::back_inserter(values), 10,
78 hash_internal::Generator<T>());
79 TypeParam m;
80 m.insert(values.begin(), values.end());
81 ASSERT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
82 }
83
TYPED_TEST_P(ModifiersTest,InsertOrAssign)84 TYPED_TEST_P(ModifiersTest, InsertOrAssign) {
85 #ifdef UNORDERED_MAP_CXX17
86 using std::get;
87 using K = typename TypeParam::key_type;
88 using V = typename TypeParam::mapped_type;
89 K k = hash_internal::Generator<K>()();
90 V val = hash_internal::Generator<V>()();
91 TypeParam m;
92 auto p = m.insert_or_assign(k, val);
93 EXPECT_TRUE(p.second);
94 EXPECT_EQ(k, get<0>(*p.first));
95 EXPECT_EQ(val, get<1>(*p.first));
96 V val2 = hash_internal::Generator<V>()();
97 p = m.insert_or_assign(k, val2);
98 EXPECT_FALSE(p.second);
99 EXPECT_EQ(k, get<0>(*p.first));
100 EXPECT_EQ(val2, get<1>(*p.first));
101 #endif
102 }
103
TYPED_TEST_P(ModifiersTest,InsertOrAssignHint)104 TYPED_TEST_P(ModifiersTest, InsertOrAssignHint) {
105 #ifdef UNORDERED_MAP_CXX17
106 using std::get;
107 using K = typename TypeParam::key_type;
108 using V = typename TypeParam::mapped_type;
109 K k = hash_internal::Generator<K>()();
110 V val = hash_internal::Generator<V>()();
111 TypeParam m;
112 auto it = m.insert_or_assign(m.end(), k, val);
113 EXPECT_TRUE(it != m.end());
114 EXPECT_EQ(k, get<0>(*it));
115 EXPECT_EQ(val, get<1>(*it));
116 V val2 = hash_internal::Generator<V>()();
117 it = m.insert_or_assign(it, k, val2);
118 EXPECT_EQ(k, get<0>(*it));
119 EXPECT_EQ(val2, get<1>(*it));
120 #endif
121 }
122
TYPED_TEST_P(ModifiersTest,Emplace)123 TYPED_TEST_P(ModifiersTest, Emplace) {
124 using T = hash_internal::GeneratedType<TypeParam>;
125 using V = typename TypeParam::mapped_type;
126 T val = hash_internal::Generator<T>()();
127 TypeParam m;
128 // TODO(alkis): We need a way to run emplace in a more meaningful way. Perhaps
129 // with test traits/policy.
130 auto p = m.emplace(val);
131 EXPECT_TRUE(p.second);
132 EXPECT_EQ(val, *p.first);
133 T val2 = {val.first, hash_internal::Generator<V>()()};
134 p = m.emplace(val2);
135 EXPECT_FALSE(p.second);
136 EXPECT_EQ(val, *p.first);
137 }
138
TYPED_TEST_P(ModifiersTest,EmplaceHint)139 TYPED_TEST_P(ModifiersTest, EmplaceHint) {
140 using T = hash_internal::GeneratedType<TypeParam>;
141 using V = typename TypeParam::mapped_type;
142 T val = hash_internal::Generator<T>()();
143 TypeParam m;
144 // TODO(alkis): We need a way to run emplace in a more meaningful way. Perhaps
145 // with test traits/policy.
146 auto it = m.emplace_hint(m.end(), val);
147 EXPECT_EQ(val, *it);
148 T val2 = {val.first, hash_internal::Generator<V>()()};
149 it = m.emplace_hint(it, val2);
150 EXPECT_EQ(val, *it);
151 }
152
TYPED_TEST_P(ModifiersTest,TryEmplace)153 TYPED_TEST_P(ModifiersTest, TryEmplace) {
154 #ifdef UNORDERED_MAP_CXX17
155 using T = hash_internal::GeneratedType<TypeParam>;
156 using V = typename TypeParam::mapped_type;
157 T val = hash_internal::Generator<T>()();
158 TypeParam m;
159 // TODO(alkis): We need a way to run emplace in a more meaningful way. Perhaps
160 // with test traits/policy.
161 auto p = m.try_emplace(val.first, val.second);
162 EXPECT_TRUE(p.second);
163 EXPECT_EQ(val, *p.first);
164 T val2 = {val.first, hash_internal::Generator<V>()()};
165 p = m.try_emplace(val2.first, val2.second);
166 EXPECT_FALSE(p.second);
167 EXPECT_EQ(val, *p.first);
168 #endif
169 }
170
TYPED_TEST_P(ModifiersTest,TryEmplaceHint)171 TYPED_TEST_P(ModifiersTest, TryEmplaceHint) {
172 #ifdef UNORDERED_MAP_CXX17
173 using T = hash_internal::GeneratedType<TypeParam>;
174 using V = typename TypeParam::mapped_type;
175 T val = hash_internal::Generator<T>()();
176 TypeParam m;
177 // TODO(alkis): We need a way to run emplace in a more meaningful way. Perhaps
178 // with test traits/policy.
179 auto it = m.try_emplace(m.end(), val.first, val.second);
180 EXPECT_EQ(val, *it);
181 T val2 = {val.first, hash_internal::Generator<V>()()};
182 it = m.try_emplace(it, val2.first, val2.second);
183 EXPECT_EQ(val, *it);
184 #endif
185 }
186
187 template <class V>
188 using IfNotVoid = typename std::enable_if<!std::is_void<V>::value, V>::type;
189
190 // In openmap we chose not to return the iterator from erase because that's
191 // more expensive. As such we adapt erase to return an iterator here.
192 struct EraseFirst {
193 template <class Map>
194 auto operator()(Map* m, int) const
195 -> IfNotVoid<decltype(m->erase(m->begin()))> {
196 return m->erase(m->begin());
197 }
198 template <class Map>
operatorEraseFirst199 typename Map::iterator operator()(Map* m, ...) const {
200 auto it = m->begin();
201 m->erase(it++);
202 return it;
203 }
204 };
205
TYPED_TEST_P(ModifiersTest,Erase)206 TYPED_TEST_P(ModifiersTest, Erase) {
207 using T = hash_internal::GeneratedType<TypeParam>;
208 using std::get;
209 std::vector<T> values;
210 std::generate_n(std::back_inserter(values), 10,
211 hash_internal::Generator<T>());
212 TypeParam m(values.begin(), values.end());
213 ASSERT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
214 auto& first = *m.begin();
215 std::vector<T> values2;
216 for (const auto& val : values)
217 if (get<0>(val) != get<0>(first)) values2.push_back(val);
218 auto it = EraseFirst()(&m, 0);
219 ASSERT_TRUE(it != m.end());
220 EXPECT_EQ(1, std::count(values2.begin(), values2.end(), *it));
221 EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values2.begin(),
222 values2.end()));
223 }
224
TYPED_TEST_P(ModifiersTest,EraseRange)225 TYPED_TEST_P(ModifiersTest, EraseRange) {
226 using T = hash_internal::GeneratedType<TypeParam>;
227 std::vector<T> values;
228 std::generate_n(std::back_inserter(values), 10,
229 hash_internal::Generator<T>());
230 TypeParam m(values.begin(), values.end());
231 ASSERT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
232 auto it = m.erase(m.begin(), m.end());
233 EXPECT_THAT(items(m), ::testing::UnorderedElementsAre());
234 EXPECT_TRUE(it == m.end());
235 }
236
TYPED_TEST_P(ModifiersTest,EraseKey)237 TYPED_TEST_P(ModifiersTest, EraseKey) {
238 using T = hash_internal::GeneratedType<TypeParam>;
239 std::vector<T> values;
240 std::generate_n(std::back_inserter(values), 10,
241 hash_internal::Generator<T>());
242 TypeParam m(values.begin(), values.end());
243 ASSERT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
244 EXPECT_EQ(1, m.erase(values[0].first));
245 EXPECT_EQ(0, std::count(m.begin(), m.end(), values[0]));
246 EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values.begin() + 1,
247 values.end()));
248 }
249
TYPED_TEST_P(ModifiersTest,Swap)250 TYPED_TEST_P(ModifiersTest, Swap) {
251 using T = hash_internal::GeneratedType<TypeParam>;
252 std::vector<T> v1;
253 std::vector<T> v2;
254 std::generate_n(std::back_inserter(v1), 5, hash_internal::Generator<T>());
255 std::generate_n(std::back_inserter(v2), 5, hash_internal::Generator<T>());
256 TypeParam m1(v1.begin(), v1.end());
257 TypeParam m2(v2.begin(), v2.end());
258 EXPECT_THAT(items(m1), ::testing::UnorderedElementsAreArray(v1));
259 EXPECT_THAT(items(m2), ::testing::UnorderedElementsAreArray(v2));
260 m1.swap(m2);
261 EXPECT_THAT(items(m1), ::testing::UnorderedElementsAreArray(v2));
262 EXPECT_THAT(items(m2), ::testing::UnorderedElementsAreArray(v1));
263 }
264
265 // TODO(alkis): Write tests for extract.
266 // TODO(alkis): Write tests for merge.
267
268 REGISTER_TYPED_TEST_CASE_P(ModifiersTest, Clear, Insert, InsertHint,
269 InsertRange, InsertOrAssign, InsertOrAssignHint,
270 Emplace, EmplaceHint, TryEmplace, TryEmplaceHint,
271 Erase, EraseRange, EraseKey, Swap);
272
273 template <typename Type>
274 struct is_unique_ptr : std::false_type {};
275
276 template <typename Type>
277 struct is_unique_ptr<std::unique_ptr<Type>> : std::true_type {};
278
279 template <class UnordMap>
280 class UniquePtrModifiersTest : public ::testing::Test {
281 protected:
282 UniquePtrModifiersTest() {
283 static_assert(is_unique_ptr<typename UnordMap::mapped_type>::value,
284 "UniquePtrModifiersTyest may only be called with a "
285 "std::unique_ptr value type.");
286 }
287 };
288
289 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UniquePtrModifiersTest);
290
291 TYPED_TEST_SUITE_P(UniquePtrModifiersTest);
292
293 // Test that we do not move from rvalue arguments if an insertion does not
294 // happen.
295 TYPED_TEST_P(UniquePtrModifiersTest, TryEmplace) {
296 #ifdef UNORDERED_MAP_CXX17
297 using T = hash_internal::GeneratedType<TypeParam>;
298 using V = typename TypeParam::mapped_type;
299 T val = hash_internal::Generator<T>()();
300 TypeParam m;
301 auto p = m.try_emplace(val.first, std::move(val.second));
302 EXPECT_TRUE(p.second);
303 // A moved from std::unique_ptr is guaranteed to be nullptr.
304 EXPECT_EQ(val.second, nullptr);
305 T val2 = {val.first, hash_internal::Generator<V>()()};
306 p = m.try_emplace(val2.first, std::move(val2.second));
307 EXPECT_FALSE(p.second);
308 EXPECT_NE(val2.second, nullptr);
309 #endif
310 }
311
312 REGISTER_TYPED_TEST_SUITE_P(UniquePtrModifiersTest, TryEmplace);
313
314 } // namespace container_internal
315 ABSL_NAMESPACE_END
316 } // namespace absl
317
318 #endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MODIFIERS_TEST_H_
319