// Copyright 2018 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // This file contains a few select absl::Hash tests that, due to their reliance // on INSTANTIATE_TYPED_TEST_SUITE_P, require a large amount of memory to // compile. Put new tests in hash_test.cc, not this file. #include "absl/hash/hash.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gtest/gtest.h" #include "absl/container/btree_map.h" #include "absl/container/btree_set.h" #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "absl/container/node_hash_map.h" #include "absl/container/node_hash_set.h" #include "absl/hash/hash_testing.h" #include "absl/hash/internal/hash_test.h" namespace { using ::absl::hash_test_internal::is_hashable; using ::absl::hash_test_internal::TypeErasedContainer; // Dummy type with unordered equality and hashing semantics. This preserves // input order internally, and is used below to ensure we get test coverage // for equal sequences with different iteraton orders. template class UnorderedSequence { public: UnorderedSequence() = default; template UnorderedSequence(std::initializer_list l) : values_(l.begin(), l.end()) {} template ::value, bool>::type = true> UnorderedSequence(ForwardIterator begin, ForwardIterator end) : values_(begin, end) {} // one-argument constructor of value type T, to appease older toolchains that // get confused by one-element initializer lists in some contexts explicit UnorderedSequence(const T& v) : values_(&v, &v + 1) {} using value_type = T; size_t size() const { return values_.size(); } typename std::vector::const_iterator begin() const { return values_.begin(); } typename std::vector::const_iterator end() const { return values_.end(); } friend bool operator==(const UnorderedSequence& lhs, const UnorderedSequence& rhs) { return lhs.size() == rhs.size() && std::is_permutation(lhs.begin(), lhs.end(), rhs.begin()); } friend bool operator!=(const UnorderedSequence& lhs, const UnorderedSequence& rhs) { return !(lhs == rhs); } template friend H AbslHashValue(H h, const UnorderedSequence& u) { return H::combine(H::combine_unordered(std::move(h), u.begin(), u.end()), u.size()); } private: std::vector values_; }; template class HashValueSequenceTest : public testing::Test {}; TYPED_TEST_SUITE_P(HashValueSequenceTest); TYPED_TEST_P(HashValueSequenceTest, BasicUsage) { EXPECT_TRUE((is_hashable::value)); using IntType = typename TypeParam::value_type; auto a = static_cast(0); auto b = static_cast(23); auto c = static_cast(42); std::vector exemplars = { TypeParam(), TypeParam(), TypeParam{a, b, c}, TypeParam{a, c, b}, TypeParam{c, a, b}, TypeParam{a}, TypeParam{a, a}, TypeParam{a, a, a}, TypeParam{a, a, b}, TypeParam{a, b, a}, TypeParam{b, a, a}, TypeParam{a, b}, TypeParam{b, c}}; EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars)); } REGISTER_TYPED_TEST_SUITE_P(HashValueSequenceTest, BasicUsage); using IntSequenceTypes = testing::Types< std::deque, std::forward_list, std::list, std::vector, std::vector, TypeErasedContainer>, std::set, std::multiset, UnorderedSequence, TypeErasedContainer>, std::unordered_set, std::unordered_multiset, absl::flat_hash_set, absl::node_hash_set, absl::btree_set>; INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueSequenceTest, IntSequenceTypes); template class HashValueNestedSequenceTest : public testing::Test {}; TYPED_TEST_SUITE_P(HashValueNestedSequenceTest); TYPED_TEST_P(HashValueNestedSequenceTest, BasicUsage) { using T = TypeParam; using V = typename T::value_type; std::vector exemplars = { // empty case T{}, // sets of empty sets T{V{}}, T{V{}, V{}}, T{V{}, V{}, V{}}, // multisets of different values T{V{1}}, T{V{1, 1}, V{1, 1}}, T{V{1, 1, 1}, V{1, 1, 1}, V{1, 1, 1}}, // various orderings of same nested sets T{V{}, V{1, 2}}, T{V{}, V{2, 1}}, T{V{1, 2}, V{}}, T{V{2, 1}, V{}}, // various orderings of various nested sets, case 2 T{V{1, 2}, V{3, 4}}, T{V{1, 2}, V{4, 3}}, T{V{1, 3}, V{2, 4}}, T{V{1, 3}, V{4, 2}}, T{V{1, 4}, V{2, 3}}, T{V{1, 4}, V{3, 2}}, T{V{2, 3}, V{1, 4}}, T{V{2, 3}, V{4, 1}}, T{V{2, 4}, V{1, 3}}, T{V{2, 4}, V{3, 1}}, T{V{3, 4}, V{1, 2}}, T{V{3, 4}, V{2, 1}}}; EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars)); } REGISTER_TYPED_TEST_SUITE_P(HashValueNestedSequenceTest, BasicUsage); template using TypeErasedSet = TypeErasedContainer>; using NestedIntSequenceTypes = testing::Types< std::vector>, std::vector>, std::vector>, UnorderedSequence>, UnorderedSequence>, UnorderedSequence>, TypeErasedSet>, TypeErasedSet>, TypeErasedSet>>; INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueNestedSequenceTest, NestedIntSequenceTypes); template class HashValueAssociativeMapTest : public testing::Test {}; TYPED_TEST_SUITE_P(HashValueAssociativeMapTest); TYPED_TEST_P(HashValueAssociativeMapTest, BasicUsage) { using M = TypeParam; using V = typename M::value_type; std::vector exemplars{M{}, M{V{0, "foo"}}, M{V{1, "foo"}}, M{V{0, "bar"}}, M{V{1, "bar"}}, M{V{0, "foo"}, V{42, "bar"}}, M{V{42, "bar"}, V{0, "foo"}}, M{V{1, "foo"}, V{42, "bar"}}, M{V{1, "foo"}, V{43, "bar"}}, M{V{1, "foo"}, V{43, "baz"}}}; EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars)); } REGISTER_TYPED_TEST_SUITE_P(HashValueAssociativeMapTest, BasicUsage); using AssociativeMapTypes = testing::Types< std::map, std::unordered_map, absl::flat_hash_map, absl::node_hash_map, absl::btree_map, UnorderedSequence>>; INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueAssociativeMapTest, AssociativeMapTypes); template class HashValueAssociativeMultimapTest : public testing::Test {}; TYPED_TEST_SUITE_P(HashValueAssociativeMultimapTest); TYPED_TEST_P(HashValueAssociativeMultimapTest, BasicUsage) { using MM = TypeParam; using V = typename MM::value_type; std::vector exemplars{MM{}, MM{V{0, "foo"}}, MM{V{1, "foo"}}, MM{V{0, "bar"}}, MM{V{1, "bar"}}, MM{V{0, "foo"}, V{0, "bar"}}, MM{V{0, "bar"}, V{0, "foo"}}, MM{V{0, "foo"}, V{42, "bar"}}, MM{V{1, "foo"}, V{42, "bar"}}, MM{V{1, "foo"}, V{1, "foo"}, V{43, "bar"}}, MM{V{1, "foo"}, V{43, "bar"}, V{1, "foo"}}, MM{V{1, "foo"}, V{43, "baz"}}}; EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars)); } REGISTER_TYPED_TEST_SUITE_P(HashValueAssociativeMultimapTest, BasicUsage); using AssociativeMultimapTypes = testing::Types, std::unordered_multimap>; INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueAssociativeMultimapTest, AssociativeMultimapTypes); } // namespace