1 // Copyright 2018 The Abseil Authors.
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
7 // https://www.apache.org/licenses/LICENSE-2.0
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.
15 #ifndef ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_CONSTRUCTOR_TEST_H_
16 #define ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_CONSTRUCTOR_TEST_H_
21 #include "gmock/gmock.h"
22 #include "gtest/gtest.h"
23 #include "absl/container/internal/hash_generator_testing.h"
24 #include "absl/container/internal/hash_policy_testing.h"
27 namespace container_internal {
29 template <class UnordMap>
30 class ConstructorTest : public ::testing::Test {};
32 TYPED_TEST_SUITE_P(ConstructorTest);
34 TYPED_TEST_P(ConstructorTest, NoArgs) {
36 EXPECT_TRUE(m.empty());
37 EXPECT_THAT(m, ::testing::UnorderedElementsAre());
40 TYPED_TEST_P(ConstructorTest, BucketCount) {
42 EXPECT_TRUE(m.empty());
43 EXPECT_THAT(m, ::testing::UnorderedElementsAre());
44 EXPECT_GE(m.bucket_count(), 123);
47 TYPED_TEST_P(ConstructorTest, BucketCountHash) {
48 using H = typename TypeParam::hasher;
50 TypeParam m(123, hasher);
51 EXPECT_EQ(m.hash_function(), hasher);
52 EXPECT_TRUE(m.empty());
53 EXPECT_THAT(m, ::testing::UnorderedElementsAre());
54 EXPECT_GE(m.bucket_count(), 123);
57 TYPED_TEST_P(ConstructorTest, BucketCountHashEqual) {
58 using H = typename TypeParam::hasher;
59 using E = typename TypeParam::key_equal;
62 TypeParam m(123, hasher, equal);
63 EXPECT_EQ(m.hash_function(), hasher);
64 EXPECT_EQ(m.key_eq(), equal);
65 EXPECT_TRUE(m.empty());
66 EXPECT_THAT(m, ::testing::UnorderedElementsAre());
67 EXPECT_GE(m.bucket_count(), 123);
70 TYPED_TEST_P(ConstructorTest, BucketCountHashEqualAlloc) {
71 using H = typename TypeParam::hasher;
72 using E = typename TypeParam::key_equal;
73 using A = typename TypeParam::allocator_type;
77 TypeParam m(123, hasher, equal, alloc);
78 EXPECT_EQ(m.hash_function(), hasher);
79 EXPECT_EQ(m.key_eq(), equal);
80 EXPECT_EQ(m.get_allocator(), alloc);
81 EXPECT_TRUE(m.empty());
82 EXPECT_THAT(m, ::testing::UnorderedElementsAre());
83 EXPECT_GE(m.bucket_count(), 123);
87 struct is_std_unordered_map : std::false_type {};
89 template <typename... T>
90 struct is_std_unordered_map<std::unordered_map<T...>> : std::true_type {};
92 #if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17)
93 using has_cxx14_std_apis = std::true_type;
95 using has_cxx14_std_apis = std::false_type;
99 using expect_cxx14_apis =
100 absl::disjunction<absl::negation<is_std_unordered_map<T>>,
103 template <typename TypeParam>
104 void BucketCountAllocTest(std::false_type) {}
106 template <typename TypeParam>
107 void BucketCountAllocTest(std::true_type) {
108 using A = typename TypeParam::allocator_type;
110 TypeParam m(123, alloc);
111 EXPECT_EQ(m.get_allocator(), alloc);
112 EXPECT_TRUE(m.empty());
113 EXPECT_THAT(m, ::testing::UnorderedElementsAre());
114 EXPECT_GE(m.bucket_count(), 123);
117 TYPED_TEST_P(ConstructorTest, BucketCountAlloc) {
118 BucketCountAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
121 template <typename TypeParam>
122 void BucketCountHashAllocTest(std::false_type) {}
124 template <typename TypeParam>
125 void BucketCountHashAllocTest(std::true_type) {
126 using H = typename TypeParam::hasher;
127 using A = typename TypeParam::allocator_type;
130 TypeParam m(123, hasher, alloc);
131 EXPECT_EQ(m.hash_function(), hasher);
132 EXPECT_EQ(m.get_allocator(), alloc);
133 EXPECT_TRUE(m.empty());
134 EXPECT_THAT(m, ::testing::UnorderedElementsAre());
135 EXPECT_GE(m.bucket_count(), 123);
138 TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc) {
139 BucketCountHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
142 #if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS
143 using has_alloc_std_constructors = std::true_type;
145 using has_alloc_std_constructors = std::false_type;
148 template <typename T>
149 using expect_alloc_constructors =
150 absl::disjunction<absl::negation<is_std_unordered_map<T>>,
151 has_alloc_std_constructors>;
153 template <typename TypeParam>
154 void AllocTest(std::false_type) {}
156 template <typename TypeParam>
157 void AllocTest(std::true_type) {
158 using A = typename TypeParam::allocator_type;
161 EXPECT_EQ(m.get_allocator(), alloc);
162 EXPECT_TRUE(m.empty());
163 EXPECT_THAT(m, ::testing::UnorderedElementsAre());
166 TYPED_TEST_P(ConstructorTest, Alloc) {
167 AllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
170 TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashEqualAlloc) {
171 using T = hash_internal::GeneratedType<TypeParam>;
172 using H = typename TypeParam::hasher;
173 using E = typename TypeParam::key_equal;
174 using A = typename TypeParam::allocator_type;
178 std::vector<T> values;
179 std::generate_n(std::back_inserter(values), 10,
180 hash_internal::Generator<T>());
181 TypeParam m(values.begin(), values.end(), 123, hasher, equal, alloc);
182 EXPECT_EQ(m.hash_function(), hasher);
183 EXPECT_EQ(m.key_eq(), equal);
184 EXPECT_EQ(m.get_allocator(), alloc);
185 EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
186 EXPECT_GE(m.bucket_count(), 123);
189 template <typename TypeParam>
190 void InputIteratorBucketAllocTest(std::false_type) {}
192 template <typename TypeParam>
193 void InputIteratorBucketAllocTest(std::true_type) {
194 using T = hash_internal::GeneratedType<TypeParam>;
195 using A = typename TypeParam::allocator_type;
197 std::vector<T> values;
198 std::generate_n(std::back_inserter(values), 10,
199 hash_internal::Generator<T>());
200 TypeParam m(values.begin(), values.end(), 123, alloc);
201 EXPECT_EQ(m.get_allocator(), alloc);
202 EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
203 EXPECT_GE(m.bucket_count(), 123);
206 TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc) {
207 InputIteratorBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
210 template <typename TypeParam>
211 void InputIteratorBucketHashAllocTest(std::false_type) {}
213 template <typename TypeParam>
214 void InputIteratorBucketHashAllocTest(std::true_type) {
215 using T = hash_internal::GeneratedType<TypeParam>;
216 using H = typename TypeParam::hasher;
217 using A = typename TypeParam::allocator_type;
220 std::vector<T> values;
221 std::generate_n(std::back_inserter(values), 10,
222 hash_internal::Generator<T>());
223 TypeParam m(values.begin(), values.end(), 123, hasher, alloc);
224 EXPECT_EQ(m.hash_function(), hasher);
225 EXPECT_EQ(m.get_allocator(), alloc);
226 EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
227 EXPECT_GE(m.bucket_count(), 123);
230 TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc) {
231 InputIteratorBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
234 TYPED_TEST_P(ConstructorTest, CopyConstructor) {
235 using T = hash_internal::GeneratedType<TypeParam>;
236 using H = typename TypeParam::hasher;
237 using E = typename TypeParam::key_equal;
238 using A = typename TypeParam::allocator_type;
242 TypeParam m(123, hasher, equal, alloc);
243 for (size_t i = 0; i != 10; ++i) m.insert(hash_internal::Generator<T>()());
245 EXPECT_EQ(m.hash_function(), n.hash_function());
246 EXPECT_EQ(m.key_eq(), n.key_eq());
247 EXPECT_EQ(m.get_allocator(), n.get_allocator());
251 template <typename TypeParam>
252 void CopyConstructorAllocTest(std::false_type) {}
254 template <typename TypeParam>
255 void CopyConstructorAllocTest(std::true_type) {
256 using T = hash_internal::GeneratedType<TypeParam>;
257 using H = typename TypeParam::hasher;
258 using E = typename TypeParam::key_equal;
259 using A = typename TypeParam::allocator_type;
263 TypeParam m(123, hasher, equal, alloc);
264 for (size_t i = 0; i != 10; ++i) m.insert(hash_internal::Generator<T>()());
265 TypeParam n(m, A(11));
266 EXPECT_EQ(m.hash_function(), n.hash_function());
267 EXPECT_EQ(m.key_eq(), n.key_eq());
268 EXPECT_NE(m.get_allocator(), n.get_allocator());
272 TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc) {
273 CopyConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
276 // TODO(alkis): Test non-propagating allocators on copy constructors.
278 TYPED_TEST_P(ConstructorTest, MoveConstructor) {
279 using T = hash_internal::GeneratedType<TypeParam>;
280 using H = typename TypeParam::hasher;
281 using E = typename TypeParam::key_equal;
282 using A = typename TypeParam::allocator_type;
286 TypeParam m(123, hasher, equal, alloc);
287 for (size_t i = 0; i != 10; ++i) m.insert(hash_internal::Generator<T>()());
289 TypeParam n(std::move(t));
290 EXPECT_EQ(m.hash_function(), n.hash_function());
291 EXPECT_EQ(m.key_eq(), n.key_eq());
292 EXPECT_EQ(m.get_allocator(), n.get_allocator());
296 template <typename TypeParam>
297 void MoveConstructorAllocTest(std::false_type) {}
299 template <typename TypeParam>
300 void MoveConstructorAllocTest(std::true_type) {
301 using T = hash_internal::GeneratedType<TypeParam>;
302 using H = typename TypeParam::hasher;
303 using E = typename TypeParam::key_equal;
304 using A = typename TypeParam::allocator_type;
308 TypeParam m(123, hasher, equal, alloc);
309 for (size_t i = 0; i != 10; ++i) m.insert(hash_internal::Generator<T>()());
311 TypeParam n(std::move(t), A(1));
312 EXPECT_EQ(m.hash_function(), n.hash_function());
313 EXPECT_EQ(m.key_eq(), n.key_eq());
314 EXPECT_NE(m.get_allocator(), n.get_allocator());
318 TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc) {
319 MoveConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
322 // TODO(alkis): Test non-propagating allocators on move constructors.
324 TYPED_TEST_P(ConstructorTest, InitializerListBucketHashEqualAlloc) {
325 using T = hash_internal::GeneratedType<TypeParam>;
326 hash_internal::Generator<T> gen;
327 std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
328 using H = typename TypeParam::hasher;
329 using E = typename TypeParam::key_equal;
330 using A = typename TypeParam::allocator_type;
334 TypeParam m(values, 123, hasher, equal, alloc);
335 EXPECT_EQ(m.hash_function(), hasher);
336 EXPECT_EQ(m.key_eq(), equal);
337 EXPECT_EQ(m.get_allocator(), alloc);
338 EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
339 EXPECT_GE(m.bucket_count(), 123);
342 template <typename TypeParam>
343 void InitializerListBucketAllocTest(std::false_type) {}
345 template <typename TypeParam>
346 void InitializerListBucketAllocTest(std::true_type) {
347 using T = hash_internal::GeneratedType<TypeParam>;
348 using A = typename TypeParam::allocator_type;
349 hash_internal::Generator<T> gen;
350 std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
352 TypeParam m(values, 123, alloc);
353 EXPECT_EQ(m.get_allocator(), alloc);
354 EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
355 EXPECT_GE(m.bucket_count(), 123);
358 TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc) {
359 InitializerListBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
362 template <typename TypeParam>
363 void InitializerListBucketHashAllocTest(std::false_type) {}
365 template <typename TypeParam>
366 void InitializerListBucketHashAllocTest(std::true_type) {
367 using T = hash_internal::GeneratedType<TypeParam>;
368 using H = typename TypeParam::hasher;
369 using A = typename TypeParam::allocator_type;
372 hash_internal::Generator<T> gen;
373 std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
374 TypeParam m(values, 123, hasher, alloc);
375 EXPECT_EQ(m.hash_function(), hasher);
376 EXPECT_EQ(m.get_allocator(), alloc);
377 EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
378 EXPECT_GE(m.bucket_count(), 123);
381 TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc) {
382 InitializerListBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
385 TYPED_TEST_P(ConstructorTest, Assignment) {
386 using T = hash_internal::GeneratedType<TypeParam>;
387 using H = typename TypeParam::hasher;
388 using E = typename TypeParam::key_equal;
389 using A = typename TypeParam::allocator_type;
393 hash_internal::Generator<T> gen;
394 TypeParam m({gen(), gen(), gen()}, 123, hasher, equal, alloc);
397 EXPECT_EQ(m.hash_function(), n.hash_function());
398 EXPECT_EQ(m.key_eq(), n.key_eq());
402 // TODO(alkis): Test [non-]propagating allocators on move/copy assignments
403 // (it depends on traits).
405 TYPED_TEST_P(ConstructorTest, MoveAssignment) {
406 using T = hash_internal::GeneratedType<TypeParam>;
407 using H = typename TypeParam::hasher;
408 using E = typename TypeParam::key_equal;
409 using A = typename TypeParam::allocator_type;
413 hash_internal::Generator<T> gen;
414 TypeParam m({gen(), gen(), gen()}, 123, hasher, equal, alloc);
418 EXPECT_EQ(m.hash_function(), n.hash_function());
419 EXPECT_EQ(m.key_eq(), n.key_eq());
423 TYPED_TEST_P(ConstructorTest, AssignmentFromInitializerList) {
424 using T = hash_internal::GeneratedType<TypeParam>;
425 hash_internal::Generator<T> gen;
426 std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
429 EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
432 TYPED_TEST_P(ConstructorTest, AssignmentOverwritesExisting) {
433 using T = hash_internal::GeneratedType<TypeParam>;
434 hash_internal::Generator<T> gen;
435 TypeParam m({gen(), gen(), gen()});
436 TypeParam n({gen()});
441 TYPED_TEST_P(ConstructorTest, MoveAssignmentOverwritesExisting) {
442 using T = hash_internal::GeneratedType<TypeParam>;
443 hash_internal::Generator<T> gen;
444 TypeParam m({gen(), gen(), gen()});
446 TypeParam n({gen()});
451 TYPED_TEST_P(ConstructorTest, AssignmentFromInitializerListOverwritesExisting) {
452 using T = hash_internal::GeneratedType<TypeParam>;
453 hash_internal::Generator<T> gen;
454 std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
457 EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
460 TYPED_TEST_P(ConstructorTest, AssignmentOnSelf) {
461 using T = hash_internal::GeneratedType<TypeParam>;
462 hash_internal::Generator<T> gen;
463 std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
465 m = *&m; // Avoid -Wself-assign
466 EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
469 // We cannot test self move as standard states that it leaves standard
470 // containers in unspecified state (and in practice in causes memory-leak
471 // according to heap-checker!).
473 REGISTER_TYPED_TEST_CASE_P(
474 ConstructorTest, NoArgs, BucketCount, BucketCountHash, BucketCountHashEqual,
475 BucketCountHashEqualAlloc, BucketCountAlloc, BucketCountHashAlloc, Alloc,
476 InputIteratorBucketHashEqualAlloc, InputIteratorBucketAlloc,
477 InputIteratorBucketHashAlloc, CopyConstructor, CopyConstructorAlloc,
478 MoveConstructor, MoveConstructorAlloc, InitializerListBucketHashEqualAlloc,
479 InitializerListBucketAlloc, InitializerListBucketHashAlloc, Assignment,
480 MoveAssignment, AssignmentFromInitializerList, AssignmentOverwritesExisting,
481 MoveAssignmentOverwritesExisting,
482 AssignmentFromInitializerListOverwritesExisting, AssignmentOnSelf);
484 } // namespace container_internal
487 #endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_CONSTRUCTOR_TEST_H_