summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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_