Split absl/hash/hash_test.cc into two files

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).

PiperOrigin-RevId: 535305679
Change-Id: Ic204da0a47c749c3f7db5f902ade8d74ed3043bb
diff --git a/absl/hash/BUILD.bazel b/absl/hash/BUILD.bazel
index a0db919..7f964ae 100644
--- 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",
@@ -88,6 +92,27 @@
     ],
 )
 
+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",
     testonly = 1,
diff --git a/absl/hash/CMakeLists.txt b/absl/hash/CMakeLists.txt
index f99f35b..1adce61 100644
--- 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
diff --git a/absl/hash/hash_instantiated_test.cc b/absl/hash/hash_instantiated_test.cc
new file mode 100644
index 0000000..e65de9c
--- /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
diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc
index 6727daf..a0e2e4a 100644
--- a/absl/hash/hash_test.cc
+++ b/absl/hash/hash_test.cc
@@ -48,6 +48,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"
@@ -59,52 +60,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>>;
@@ -122,11 +80,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));
 
@@ -566,121 +519,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
@@ -839,64 +677,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);
 
diff --git a/absl/hash/internal/hash_test.h b/absl/hash/internal/hash_test.h
new file mode 100644
index 0000000..9963dc0
--- /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_