summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Benjamin Barenblat <bbaren@google.com>2023-06-26 13:09:57 -0400
committerGravatar Benjamin Barenblat <bbaren@google.com>2023-08-02 12:52:59 -0400
commit17046ae7503e82dd8484584619413eab688fa717 (patch)
tree3baf6b63a80153e58d9c0645df640f66ce8f0157
parenteb6db73f663df4eef48517a4dae62240c90783ff (diff)
Split hash tests to make life easier for mipsel
Some of the Abseil tests use so much RAM in template expansion that they exhaust memory on the mipsel buildds. Backport a patch from upstream to split the problematic tests into smaller files.
-rw-r--r--debian/changelog1
-rw-r--r--debian/patches/series1
-rw-r--r--debian/patches/split-hash-tests.diff677
3 files changed, 679 insertions, 0 deletions
diff --git a/debian/changelog b/debian/changelog
index 70a57c02..6abc1938 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -2,6 +2,7 @@ abseil (20230125.3-2) UNRELEASED; urgency=medium
* Reenable unit tests, which were accidentally disabled in the previous
version.
+ * Backport an upstream patch to allow building tests on mipsel.
-- Benjamin Barenblat <bbaren@debian.org> Tue, 27 Jun 2023 17:00:12 -0400
diff --git a/debian/patches/series b/debian/patches/series
index 29630f3c..66bf33ce 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -4,3 +4,4 @@ latomic.diff
empty-flags-library.diff
cordz-info-statistics-test.diff
pkg-config-directives.diff
+split-hash-tests.diff
diff --git a/debian/patches/split-hash-tests.diff b/debian/patches/split-hash-tests.diff
new file mode 100644
index 00000000..ae0d066f
--- /dev/null
+++ b/debian/patches/split-hash-tests.diff
@@ -0,0 +1,677 @@
+From: Benjamin Barenblat <bbaren@google.com>
+Subject: Split absl/hash/hash_test.cc into two files
+Origin: backport, https://github.com/abseil/abseil-cpp/commit/c154d20abce2f1ae6bd35bd774313e351493219b
+
+hash_test.cc leans heavily on INSTANTIATE_TYPED_TEST_SUITE_P, which is quite
+memory- and CPU-hungry. Split a few heavyweight tests into a new
+hash_instantiated_test.cc, reducing peak RAM consumption (or, on multicore
+systems, compilation time).
+
+--- a/absl/hash/BUILD.bazel
++++ b/absl/hash/BUILD.bazel
+@@ -68,13 +68,17 @@
+
+ cc_test(
+ name = "hash_test",
+- srcs = ["hash_test.cc"],
++ srcs = [
++ "hash_test.cc",
++ "internal/hash_test.h",
++ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":hash",
+ ":hash_testing",
+ ":spy_hash_state",
++ "//absl/base:config",
+ "//absl/base:core_headers",
+ "//absl/container:btree",
+ "//absl/container:flat_hash_map",
+@@ -87,6 +91,27 @@
+ "@com_google_googletest//:gtest_main",
+ ],
+ )
++
++cc_test(
++ name = "hash_instantiated_test",
++ srcs = [
++ "hash_instantiated_test.cc",
++ "internal/hash_test.h",
++ ],
++ copts = ABSL_TEST_COPTS,
++ linkopts = ABSL_DEFAULT_LINKOPTS,
++ deps = [
++ ":hash",
++ ":hash_testing",
++ "//absl/base:config",
++ "//absl/container:btree",
++ "//absl/container:flat_hash_map",
++ "//absl/container:flat_hash_set",
++ "//absl/container:node_hash_map",
++ "//absl/container:node_hash_set",
++ "@com_google_googletest//:gtest_main",
++ ],
++)
+
+ cc_binary(
+ name = "hash_benchmark",
+--- a/absl/hash/CMakeLists.txt
++++ b/absl/hash/CMakeLists.txt
+@@ -64,6 +64,7 @@
+ hash_test
+ SRCS
+ "hash_test.cc"
++ "internal/hash_test.h"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+@@ -82,6 +83,26 @@
+ GTest::gmock_main
+ )
+
++absl_cc_test(
++ NAME
++ hash_instantiated_test
++ SRCS
++ "hash_test.cc"
++ "internal/hash_test.h"
++ COPTS
++ ${ABSL_TEST_COPTS}
++ DEPS
++ absl::hash
++ absl::hash_testing
++ absl::config
++ absl::btree
++ absl::flat_hash_map
++ absl::flat_hash_set
++ absl::node_hash_map
++ absl::node_hash_set
++ GTest::gtest_main
++)
++
+ # Internal-only target, do not depend on directly.
+ #
+ # Note: Even though external code should not depend on this target
+--- /dev/null
++++ b/absl/hash/hash_instantiated_test.cc
+@@ -0,0 +1,224 @@
++// 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 <stddef.h>
++
++#include <algorithm>
++#include <deque>
++#include <forward_list>
++#include <initializer_list>
++#include <list>
++#include <map>
++#include <set>
++#include <string>
++#include <type_traits>
++#include <unordered_map>
++#include <unordered_set>
++#include <utility>
++#include <vector>
++
++#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 <typename T>
++class UnorderedSequence {
++ public:
++ UnorderedSequence() = default;
++ template <typename TT>
++ UnorderedSequence(std::initializer_list<TT> l)
++ : values_(l.begin(), l.end()) {}
++ template <typename ForwardIterator,
++ typename std::enable_if<!std::is_integral<ForwardIterator>::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<T>::const_iterator begin() const {
++ return values_.begin();
++ }
++ typename std::vector<T>::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 <typename H>
++ 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<T> values_;
++};
++
++template <typename T>
++class HashValueSequenceTest : public testing::Test {};
++TYPED_TEST_SUITE_P(HashValueSequenceTest);
++
++TYPED_TEST_P(HashValueSequenceTest, BasicUsage) {
++ EXPECT_TRUE((is_hashable<TypeParam>::value));
++
++ using IntType = typename TypeParam::value_type;
++ auto a = static_cast<IntType>(0);
++ auto b = static_cast<IntType>(23);
++ auto c = static_cast<IntType>(42);
++
++ std::vector<TypeParam> 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<int>, std::forward_list<int>, std::list<int>, std::vector<int>,
++ std::vector<bool>, TypeErasedContainer<std::vector<int>>, std::set<int>,
++ std::multiset<int>, UnorderedSequence<int>,
++ TypeErasedContainer<UnorderedSequence<int>>, std::unordered_set<int>,
++ std::unordered_multiset<int>, absl::flat_hash_set<int>,
++ absl::node_hash_set<int>, absl::btree_set<int>>;
++INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueSequenceTest, IntSequenceTypes);
++
++template <typename T>
++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<T> 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 <typename T>
++using TypeErasedSet = TypeErasedContainer<UnorderedSequence<T>>;
++
++using NestedIntSequenceTypes = testing::Types<
++ std::vector<std::vector<int>>, std::vector<UnorderedSequence<int>>,
++ std::vector<TypeErasedSet<int>>, UnorderedSequence<std::vector<int>>,
++ UnorderedSequence<UnorderedSequence<int>>,
++ UnorderedSequence<TypeErasedSet<int>>, TypeErasedSet<std::vector<int>>,
++ TypeErasedSet<UnorderedSequence<int>>, TypeErasedSet<TypeErasedSet<int>>>;
++INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueNestedSequenceTest,
++ NestedIntSequenceTypes);
++
++template <typename T>
++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<M> 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<int, std::string>, std::unordered_map<int, std::string>,
++ absl::flat_hash_map<int, std::string>,
++ absl::node_hash_map<int, std::string>, absl::btree_map<int, std::string>,
++ UnorderedSequence<std::pair<const int, std::string>>>;
++INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueAssociativeMapTest,
++ AssociativeMapTypes);
++
++template <typename T>
++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<MM> 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::multimap<int, std::string>,
++ std::unordered_multimap<int, std::string>>;
++INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueAssociativeMultimapTest,
++ AssociativeMultimapTypes);
++
++} // namespace
+--- a/absl/hash/hash_test.cc
++++ b/absl/hash/hash_test.cc
+@@ -47,6 +47,7 @@
+ #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"
+ #include "absl/hash/internal/spy_hash_state.h"
+ #include "absl/meta/type_traits.h"
+ #include "absl/numeric/int128.h"
+@@ -54,52 +55,9 @@
+
+ namespace {
+
+-// Utility wrapper of T for the purposes of testing the `AbslHash` type erasure
+-// mechanism. `TypeErasedValue<T>` can be constructed with a `T`, and can
+-// be compared and hashed. However, all hashing goes through the hashing
+-// type-erasure framework.
+-template <typename T>
+-class TypeErasedValue {
+- public:
+- TypeErasedValue() = default;
+- TypeErasedValue(const TypeErasedValue&) = default;
+- TypeErasedValue(TypeErasedValue&&) = default;
+- explicit TypeErasedValue(const T& n) : n_(n) {}
+-
+- template <typename H>
+- friend H AbslHashValue(H hash_state, const TypeErasedValue& v) {
+- v.HashValue(absl::HashState::Create(&hash_state));
+- return hash_state;
+- }
+-
+- void HashValue(absl::HashState state) const {
+- absl::HashState::combine(std::move(state), n_);
+- }
+-
+- bool operator==(const TypeErasedValue& rhs) const { return n_ == rhs.n_; }
+- bool operator!=(const TypeErasedValue& rhs) const { return !(*this == rhs); }
+-
+- private:
+- T n_;
+-};
+-
+-// A TypeErasedValue refinement, for containers. It exposes the wrapped
+-// `value_type` and is constructible from an initializer list.
+-template <typename T>
+-class TypeErasedContainer : public TypeErasedValue<T> {
+- public:
+- using value_type = typename T::value_type;
+- TypeErasedContainer() = default;
+- TypeErasedContainer(const TypeErasedContainer&) = default;
+- TypeErasedContainer(TypeErasedContainer&&) = default;
+- explicit TypeErasedContainer(const T& n) : TypeErasedValue<T>(n) {}
+- TypeErasedContainer(std::initializer_list<value_type> init_list)
+- : TypeErasedContainer(T(init_list.begin(), init_list.end())) {}
+- // one-argument constructor of value type T, to appease older toolchains that
+- // get confused by one-element initializer lists in some contexts
+- explicit TypeErasedContainer(const value_type& v)
+- : TypeErasedContainer(T(&v, &v + 1)) {}
+-};
++using ::absl::hash_test_internal::is_hashable;
++using ::absl::hash_test_internal::TypeErasedContainer;
++using ::absl::hash_test_internal::TypeErasedValue;
+
+ template <typename T>
+ using TypeErasedVector = TypeErasedContainer<std::vector<T>>;
+@@ -117,11 +75,6 @@
+ return SpyHashState::combine(SpyHashState(), value);
+ }
+
+-// Helper trait to verify if T is hashable. We use absl::Hash's poison status to
+-// detect it.
+-template <typename T>
+-using is_hashable = std::is_default_constructible<absl::Hash<T>>;
+-
+ TYPED_TEST_P(HashValueIntTest, BasicUsage) {
+ EXPECT_TRUE((is_hashable<TypeParam>::value));
+
+@@ -520,121 +473,6 @@
+ std::bitset<kNumBits>(bit_strings[5].c_str())}));
+ } // namespace
+
+-// 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 <typename T>
+-class UnorderedSequence {
+- public:
+- UnorderedSequence() = default;
+- template <typename TT>
+- UnorderedSequence(std::initializer_list<TT> l)
+- : values_(l.begin(), l.end()) {}
+- template <typename ForwardIterator,
+- typename std::enable_if<!std::is_integral<ForwardIterator>::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<T>::const_iterator begin() const {
+- return values_.begin();
+- }
+- typename std::vector<T>::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 <typename H>
+- 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<T> values_;
+-};
+-
+-template <typename T>
+-class HashValueSequenceTest : public testing::Test {
+-};
+-TYPED_TEST_SUITE_P(HashValueSequenceTest);
+-
+-TYPED_TEST_P(HashValueSequenceTest, BasicUsage) {
+- EXPECT_TRUE((is_hashable<TypeParam>::value));
+-
+- using IntType = typename TypeParam::value_type;
+- auto a = static_cast<IntType>(0);
+- auto b = static_cast<IntType>(23);
+- auto c = static_cast<IntType>(42);
+-
+- std::vector<TypeParam> 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<int>, std::forward_list<int>, std::list<int>, std::vector<int>,
+- std::vector<bool>, TypeErasedContainer<std::vector<int>>, std::set<int>,
+- std::multiset<int>, UnorderedSequence<int>,
+- TypeErasedContainer<UnorderedSequence<int>>, std::unordered_set<int>,
+- std::unordered_multiset<int>, absl::flat_hash_set<int>,
+- absl::node_hash_set<int>, absl::btree_set<int>>;
+-INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueSequenceTest, IntSequenceTypes);
+-
+-template <typename T>
+-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<T> 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 <typename T>
+-using TypeErasedSet = TypeErasedContainer<UnorderedSequence<T>>;
+-
+-using NestedIntSequenceTypes = testing::Types<
+- std::vector<std::vector<int>>, std::vector<UnorderedSequence<int>>,
+- std::vector<TypeErasedSet<int>>, UnorderedSequence<std::vector<int>>,
+- UnorderedSequence<UnorderedSequence<int>>,
+- UnorderedSequence<TypeErasedSet<int>>, TypeErasedSet<std::vector<int>>,
+- TypeErasedSet<UnorderedSequence<int>>, TypeErasedSet<TypeErasedSet<int>>>;
+-INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueNestedSequenceTest,
+- NestedIntSequenceTypes);
+-
+ // Private type that only supports AbslHashValue to make sure our chosen hash
+ // implementation is recursive within absl::Hash.
+ // It uses std::abs() on the value to provide different bitwise representations
+@@ -793,64 +631,6 @@
+ #endif
+ }
+
+-template <typename T>
+-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<M> 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<int, std::string>, std::unordered_map<int, std::string>,
+- absl::flat_hash_map<int, std::string>,
+- absl::node_hash_map<int, std::string>, absl::btree_map<int, std::string>,
+- UnorderedSequence<std::pair<const int, std::string>>>;
+-INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueAssociativeMapTest,
+- AssociativeMapTypes);
+-
+-template <typename T>
+-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<MM> 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::multimap<int, std::string>,
+- std::unordered_multimap<int, std::string>>;
+-INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueAssociativeMultimapTest,
+- AssociativeMultimapTypes);
+-
+ TEST(HashValueTest, ReferenceWrapper) {
+ EXPECT_TRUE(is_hashable<std::reference_wrapper<Private>>::value);
+
+--- /dev/null
++++ b/absl/hash/internal/hash_test.h
+@@ -0,0 +1,87 @@
++// Copyright 2023 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.
++
++// Common code shared between absl/hash/hash_test.cc and
++// absl/hash/hash_instantiated_test.cc.
++
++#ifndef ABSL_HASH_INTERNAL_HASH_TEST_H_
++#define ABSL_HASH_INTERNAL_HASH_TEST_H_
++
++#include <type_traits>
++#include <utility>
++
++#include "absl/base/config.h"
++#include "absl/hash/hash.h"
++
++namespace absl {
++ABSL_NAMESPACE_BEGIN
++namespace hash_test_internal {
++
++// Utility wrapper of T for the purposes of testing the `AbslHash` type erasure
++// mechanism. `TypeErasedValue<T>` can be constructed with a `T`, and can
++// be compared and hashed. However, all hashing goes through the hashing
++// type-erasure framework.
++template <typename T>
++class TypeErasedValue {
++ public:
++ TypeErasedValue() = default;
++ TypeErasedValue(const TypeErasedValue&) = default;
++ TypeErasedValue(TypeErasedValue&&) = default;
++ explicit TypeErasedValue(const T& n) : n_(n) {}
++
++ template <typename H>
++ friend H AbslHashValue(H hash_state, const TypeErasedValue& v) {
++ v.HashValue(absl::HashState::Create(&hash_state));
++ return hash_state;
++ }
++
++ void HashValue(absl::HashState state) const {
++ absl::HashState::combine(std::move(state), n_);
++ }
++
++ bool operator==(const TypeErasedValue& rhs) const { return n_ == rhs.n_; }
++ bool operator!=(const TypeErasedValue& rhs) const { return !(*this == rhs); }
++
++ private:
++ T n_;
++};
++
++// A TypeErasedValue refinement, for containers. It exposes the wrapped
++// `value_type` and is constructible from an initializer list.
++template <typename T>
++class TypeErasedContainer : public TypeErasedValue<T> {
++ public:
++ using value_type = typename T::value_type;
++ TypeErasedContainer() = default;
++ TypeErasedContainer(const TypeErasedContainer&) = default;
++ TypeErasedContainer(TypeErasedContainer&&) = default;
++ explicit TypeErasedContainer(const T& n) : TypeErasedValue<T>(n) {}
++ TypeErasedContainer(std::initializer_list<value_type> init_list)
++ : TypeErasedContainer(T(init_list.begin(), init_list.end())) {}
++ // one-argument constructor of value type T, to appease older toolchains that
++ // get confused by one-element initializer lists in some contexts
++ explicit TypeErasedContainer(const value_type& v)
++ : TypeErasedContainer(T(&v, &v + 1)) {}
++};
++
++// Helper trait to verify if T is hashable. We use absl::Hash's poison status to
++// detect it.
++template <typename T>
++using is_hashable = std::is_default_constructible<absl::Hash<T>>;
++
++} // namespace hash_test_internal
++ABSL_NAMESPACE_END
++} // namespace absl
++
++#endif // ABSL_HASH_INTERNAL_HASH_TEST_H_