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_SET_CONSTRUCTOR_TEST_H_
16 #define ABSL_CONTAINER_INTERNAL_UNORDERED_SET_CONSTRUCTOR_TEST_H_
19 #include <unordered_set>
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "absl/container/internal/hash_generator_testing.h"
25 #include "absl/container/internal/hash_policy_testing.h"
26 #include "absl/meta/type_traits.h"
29 namespace container_internal {
31 template <class UnordMap>
32 class ConstructorTest : public ::testing::Test {};
34 TYPED_TEST_SUITE_P(ConstructorTest);
36 TYPED_TEST_P(ConstructorTest, NoArgs) {
38 EXPECT_TRUE(m.empty());
39 EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
42 TYPED_TEST_P(ConstructorTest, BucketCount) {
44 EXPECT_TRUE(m.empty());
45 EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
46 EXPECT_GE(m.bucket_count(), 123);
49 TYPED_TEST_P(ConstructorTest, BucketCountHash) {
50 using H = typename TypeParam::hasher;
52 TypeParam m(123, hasher);
53 EXPECT_EQ(m.hash_function(), hasher);
54 EXPECT_TRUE(m.empty());
55 EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
56 EXPECT_GE(m.bucket_count(), 123);
59 TYPED_TEST_P(ConstructorTest, BucketCountHashEqual) {
60 using H = typename TypeParam::hasher;
61 using E = typename TypeParam::key_equal;
64 TypeParam m(123, hasher, equal);
65 EXPECT_EQ(m.hash_function(), hasher);
66 EXPECT_EQ(m.key_eq(), equal);
67 EXPECT_TRUE(m.empty());
68 EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
69 EXPECT_GE(m.bucket_count(), 123);
72 TYPED_TEST_P(ConstructorTest, BucketCountHashEqualAlloc) {
73 using H = typename TypeParam::hasher;
74 using E = typename TypeParam::key_equal;
75 using A = typename TypeParam::allocator_type;
79 TypeParam m(123, hasher, equal, alloc);
80 EXPECT_EQ(m.hash_function(), hasher);
81 EXPECT_EQ(m.key_eq(), equal);
82 EXPECT_EQ(m.get_allocator(), alloc);
83 EXPECT_TRUE(m.empty());
84 EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
85 EXPECT_GE(m.bucket_count(), 123);
88 EXPECT_EQ(cm.hash_function(), hasher);
89 EXPECT_EQ(cm.key_eq(), equal);
90 EXPECT_EQ(cm.get_allocator(), alloc);
91 EXPECT_TRUE(cm.empty());
92 EXPECT_THAT(keys(cm), ::testing::UnorderedElementsAre());
93 EXPECT_GE(cm.bucket_count(), 123);
97 struct is_std_unordered_set : std::false_type {};
99 template <typename... T>
100 struct is_std_unordered_set<std::unordered_set<T...>> : std::true_type {};
102 #if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17)
103 using has_cxx14_std_apis = std::true_type;
105 using has_cxx14_std_apis = std::false_type;
108 template <typename T>
109 using expect_cxx14_apis =
110 absl::disjunction<absl::negation<is_std_unordered_set<T>>,
113 template <typename TypeParam>
114 void BucketCountAllocTest(std::false_type) {}
116 template <typename TypeParam>
117 void BucketCountAllocTest(std::true_type) {
118 using A = typename TypeParam::allocator_type;
120 TypeParam m(123, alloc);
121 EXPECT_EQ(m.get_allocator(), alloc);
122 EXPECT_TRUE(m.empty());
123 EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
124 EXPECT_GE(m.bucket_count(), 123);
127 TYPED_TEST_P(ConstructorTest, BucketCountAlloc) {
128 BucketCountAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
131 template <typename TypeParam>
132 void BucketCountHashAllocTest(std::false_type) {}
134 template <typename TypeParam>
135 void BucketCountHashAllocTest(std::true_type) {
136 using H = typename TypeParam::hasher;
137 using A = typename TypeParam::allocator_type;
140 TypeParam m(123, hasher, alloc);
141 EXPECT_EQ(m.hash_function(), hasher);
142 EXPECT_EQ(m.get_allocator(), alloc);
143 EXPECT_TRUE(m.empty());
144 EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
145 EXPECT_GE(m.bucket_count(), 123);
148 TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc) {
149 BucketCountHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
152 #if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS
153 using has_alloc_std_constructors = std::true_type;
155 using has_alloc_std_constructors = std::false_type;
158 template <typename T>
159 using expect_alloc_constructors =
160 absl::disjunction<absl::negation<is_std_unordered_set<T>>,
161 has_alloc_std_constructors>;
163 template <typename TypeParam>
164 void AllocTest(std::false_type) {}
166 template <typename TypeParam>
167 void AllocTest(std::true_type) {
168 using A = typename TypeParam::allocator_type;
171 EXPECT_EQ(m.get_allocator(), alloc);
172 EXPECT_TRUE(m.empty());
173 EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
176 TYPED_TEST_P(ConstructorTest, Alloc) {
177 AllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
180 TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashEqualAlloc) {
181 using T = hash_internal::GeneratedType<TypeParam>;
182 using H = typename TypeParam::hasher;
183 using E = typename TypeParam::key_equal;
184 using A = typename TypeParam::allocator_type;
188 std::vector<T> values;
189 for (size_t i = 0; i != 10; ++i)
190 values.push_back(hash_internal::Generator<T>()());
191 TypeParam m(values.begin(), values.end(), 123, hasher, equal, alloc);
192 EXPECT_EQ(m.hash_function(), hasher);
193 EXPECT_EQ(m.key_eq(), equal);
194 EXPECT_EQ(m.get_allocator(), alloc);
195 EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
196 EXPECT_GE(m.bucket_count(), 123);
199 template <typename TypeParam>
200 void InputIteratorBucketAllocTest(std::false_type) {}
202 template <typename TypeParam>
203 void InputIteratorBucketAllocTest(std::true_type) {
204 using T = hash_internal::GeneratedType<TypeParam>;
205 using A = typename TypeParam::allocator_type;
207 std::vector<T> values;
208 for (size_t i = 0; i != 10; ++i)
209 values.push_back(hash_internal::Generator<T>()());
210 TypeParam m(values.begin(), values.end(), 123, alloc);
211 EXPECT_EQ(m.get_allocator(), alloc);
212 EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
213 EXPECT_GE(m.bucket_count(), 123);
216 TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc) {
217 InputIteratorBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
220 template <typename TypeParam>
221 void InputIteratorBucketHashAllocTest(std::false_type) {}
223 template <typename TypeParam>
224 void InputIteratorBucketHashAllocTest(std::true_type) {
225 using T = hash_internal::GeneratedType<TypeParam>;
226 using H = typename TypeParam::hasher;
227 using A = typename TypeParam::allocator_type;
230 std::vector<T> values;
231 for (size_t i = 0; i != 10; ++i)
232 values.push_back(hash_internal::Generator<T>()());
233 TypeParam m(values.begin(), values.end(), 123, hasher, alloc);
234 EXPECT_EQ(m.hash_function(), hasher);
235 EXPECT_EQ(m.get_allocator(), alloc);
236 EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
237 EXPECT_GE(m.bucket_count(), 123);
240 TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc) {
241 InputIteratorBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
244 TYPED_TEST_P(ConstructorTest, CopyConstructor) {
245 using T = hash_internal::GeneratedType<TypeParam>;
246 using H = typename TypeParam::hasher;
247 using E = typename TypeParam::key_equal;
248 using A = typename TypeParam::allocator_type;
252 TypeParam m(123, hasher, equal, alloc);
253 for (size_t i = 0; i != 10; ++i) m.insert(hash_internal::Generator<T>()());
255 EXPECT_EQ(m.hash_function(), n.hash_function());
256 EXPECT_EQ(m.key_eq(), n.key_eq());
257 EXPECT_EQ(m.get_allocator(), n.get_allocator());
259 EXPECT_NE(TypeParam(0, hasher, equal, alloc), n);
262 template <typename TypeParam>
263 void CopyConstructorAllocTest(std::false_type) {}
265 template <typename TypeParam>
266 void CopyConstructorAllocTest(std::true_type) {
267 using T = hash_internal::GeneratedType<TypeParam>;
268 using H = typename TypeParam::hasher;
269 using E = typename TypeParam::key_equal;
270 using A = typename TypeParam::allocator_type;
274 TypeParam m(123, hasher, equal, alloc);
275 for (size_t i = 0; i != 10; ++i) m.insert(hash_internal::Generator<T>()());
276 TypeParam n(m, A(11));
277 EXPECT_EQ(m.hash_function(), n.hash_function());
278 EXPECT_EQ(m.key_eq(), n.key_eq());
279 EXPECT_NE(m.get_allocator(), n.get_allocator());
283 TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc) {
284 CopyConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
287 // TODO(alkis): Test non-propagating allocators on copy constructors.
289 TYPED_TEST_P(ConstructorTest, MoveConstructor) {
290 using T = hash_internal::GeneratedType<TypeParam>;
291 using H = typename TypeParam::hasher;
292 using E = typename TypeParam::key_equal;
293 using A = typename TypeParam::allocator_type;
297 TypeParam m(123, hasher, equal, alloc);
298 for (size_t i = 0; i != 10; ++i) m.insert(hash_internal::Generator<T>()());
300 TypeParam n(std::move(t));
301 EXPECT_EQ(m.hash_function(), n.hash_function());
302 EXPECT_EQ(m.key_eq(), n.key_eq());
303 EXPECT_EQ(m.get_allocator(), n.get_allocator());
307 template <typename TypeParam>
308 void MoveConstructorAllocTest(std::false_type) {}
310 template <typename TypeParam>
311 void MoveConstructorAllocTest(std::true_type) {
312 using T = hash_internal::GeneratedType<TypeParam>;
313 using H = typename TypeParam::hasher;
314 using E = typename TypeParam::key_equal;
315 using A = typename TypeParam::allocator_type;
319 TypeParam m(123, hasher, equal, alloc);
320 for (size_t i = 0; i != 10; ++i) m.insert(hash_internal::Generator<T>()());
322 TypeParam n(std::move(t), A(1));
323 EXPECT_EQ(m.hash_function(), n.hash_function());
324 EXPECT_EQ(m.key_eq(), n.key_eq());
325 EXPECT_NE(m.get_allocator(), n.get_allocator());
329 TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc) {
330 MoveConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
333 // TODO(alkis): Test non-propagating allocators on move constructors.
335 TYPED_TEST_P(ConstructorTest, InitializerListBucketHashEqualAlloc) {
336 using T = hash_internal::GeneratedType<TypeParam>;
337 hash_internal::Generator<T> gen;
338 std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
339 using H = typename TypeParam::hasher;
340 using E = typename TypeParam::key_equal;
341 using A = typename TypeParam::allocator_type;
345 TypeParam m(values, 123, hasher, equal, alloc);
346 EXPECT_EQ(m.hash_function(), hasher);
347 EXPECT_EQ(m.key_eq(), equal);
348 EXPECT_EQ(m.get_allocator(), alloc);
349 EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
350 EXPECT_GE(m.bucket_count(), 123);
353 template <typename TypeParam>
354 void InitializerListBucketAllocTest(std::false_type) {}
356 template <typename TypeParam>
357 void InitializerListBucketAllocTest(std::true_type) {
358 using T = hash_internal::GeneratedType<TypeParam>;
359 using A = typename TypeParam::allocator_type;
360 hash_internal::Generator<T> gen;
361 std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
363 TypeParam m(values, 123, alloc);
364 EXPECT_EQ(m.get_allocator(), alloc);
365 EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
366 EXPECT_GE(m.bucket_count(), 123);
369 TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc) {
370 InitializerListBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
373 template <typename TypeParam>
374 void InitializerListBucketHashAllocTest(std::false_type) {}
376 template <typename TypeParam>
377 void InitializerListBucketHashAllocTest(std::true_type) {
378 using T = hash_internal::GeneratedType<TypeParam>;
379 using H = typename TypeParam::hasher;
380 using A = typename TypeParam::allocator_type;
383 hash_internal::Generator<T> gen;
384 std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
385 TypeParam m(values, 123, hasher, alloc);
386 EXPECT_EQ(m.hash_function(), hasher);
387 EXPECT_EQ(m.get_allocator(), alloc);
388 EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
389 EXPECT_GE(m.bucket_count(), 123);
392 TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc) {
393 InitializerListBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
396 TYPED_TEST_P(ConstructorTest, CopyAssignment) {
397 using T = hash_internal::GeneratedType<TypeParam>;
398 using H = typename TypeParam::hasher;
399 using E = typename TypeParam::key_equal;
400 using A = typename TypeParam::allocator_type;
404 hash_internal::Generator<T> gen;
405 TypeParam m({gen(), gen(), gen()}, 123, hasher, equal, alloc);
408 EXPECT_EQ(m.hash_function(), n.hash_function());
409 EXPECT_EQ(m.key_eq(), n.key_eq());
413 // TODO(alkis): Test [non-]propagating allocators on move/copy assignments
414 // (it depends on traits).
416 TYPED_TEST_P(ConstructorTest, MoveAssignment) {
417 using T = hash_internal::GeneratedType<TypeParam>;
418 using H = typename TypeParam::hasher;
419 using E = typename TypeParam::key_equal;
420 using A = typename TypeParam::allocator_type;
424 hash_internal::Generator<T> gen;
425 TypeParam m({gen(), gen(), gen()}, 123, hasher, equal, alloc);
429 EXPECT_EQ(m.hash_function(), n.hash_function());
430 EXPECT_EQ(m.key_eq(), n.key_eq());
434 TYPED_TEST_P(ConstructorTest, AssignmentFromInitializerList) {
435 using T = hash_internal::GeneratedType<TypeParam>;
436 hash_internal::Generator<T> gen;
437 std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
440 EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
443 TYPED_TEST_P(ConstructorTest, AssignmentOverwritesExisting) {
444 using T = hash_internal::GeneratedType<TypeParam>;
445 hash_internal::Generator<T> gen;
446 TypeParam m({gen(), gen(), gen()});
447 TypeParam n({gen()});
452 TYPED_TEST_P(ConstructorTest, MoveAssignmentOverwritesExisting) {
453 using T = hash_internal::GeneratedType<TypeParam>;
454 hash_internal::Generator<T> gen;
455 TypeParam m({gen(), gen(), gen()});
457 TypeParam n({gen()});
462 TYPED_TEST_P(ConstructorTest, AssignmentFromInitializerListOverwritesExisting) {
463 using T = hash_internal::GeneratedType<TypeParam>;
464 hash_internal::Generator<T> gen;
465 std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
468 EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
471 TYPED_TEST_P(ConstructorTest, AssignmentOnSelf) {
472 using T = hash_internal::GeneratedType<TypeParam>;
473 hash_internal::Generator<T> gen;
474 std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
476 m = *&m; // Avoid -Wself-assign.
477 EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
480 REGISTER_TYPED_TEST_CASE_P(
481 ConstructorTest, NoArgs, BucketCount, BucketCountHash, BucketCountHashEqual,
482 BucketCountHashEqualAlloc, BucketCountAlloc, BucketCountHashAlloc, Alloc,
483 InputIteratorBucketHashEqualAlloc, InputIteratorBucketAlloc,
484 InputIteratorBucketHashAlloc, CopyConstructor, CopyConstructorAlloc,
485 MoveConstructor, MoveConstructorAlloc, InitializerListBucketHashEqualAlloc,
486 InitializerListBucketAlloc, InitializerListBucketHashAlloc, CopyAssignment,
487 MoveAssignment, AssignmentFromInitializerList, AssignmentOverwritesExisting,
488 MoveAssignmentOverwritesExisting,
489 AssignmentFromInitializerListOverwritesExisting, AssignmentOnSelf);
491 } // namespace container_internal
494 #endif // ABSL_CONTAINER_INTERNAL_UNORDERED_SET_CONSTRUCTOR_TEST_H_