File indexing completed on 2025-10-31 08:31:49
0001 
0002 
0003 
0004 
0005 
0006 
0007 
0008 
0009 
0010 
0011 
0012 
0013 
0014 
0015 #ifndef ABSL_HASH_HASH_TESTING_H_
0016 #define ABSL_HASH_HASH_TESTING_H_
0017 
0018 #include <initializer_list>
0019 #include <tuple>
0020 #include <type_traits>
0021 #include <vector>
0022 
0023 #include "gmock/gmock.h"
0024 #include "gtest/gtest.h"
0025 #include "absl/hash/internal/spy_hash_state.h"
0026 #include "absl/meta/type_traits.h"
0027 #include "absl/strings/str_cat.h"
0028 #include "absl/types/variant.h"
0029 
0030 namespace absl {
0031 ABSL_NAMESPACE_BEGIN
0032 
0033 
0034 
0035 
0036 
0037 
0038 
0039 
0040 
0041 
0042 
0043 
0044 
0045 
0046 
0047 
0048 
0049 
0050 
0051 
0052 
0053 
0054 
0055 
0056 
0057 
0058 
0059 
0060 
0061 
0062 
0063 
0064 
0065 
0066 
0067 
0068 
0069 
0070 
0071 
0072 
0073 
0074 
0075 
0076 
0077 
0078 
0079 
0080 
0081 
0082 
0083 
0084 
0085 
0086 
0087 
0088 
0089 
0090 
0091 
0092 
0093 
0094 
0095 
0096 
0097 
0098 
0099 
0100 
0101 
0102 
0103 
0104 
0105 
0106 
0107 
0108 
0109 
0110 
0111 
0112 
0113 
0114 
0115 
0116 
0117 
0118 
0119 
0120 
0121 
0122 
0123 
0124 
0125 
0126 
0127 
0128 
0129 
0130 
0131 
0132 
0133 
0134 
0135 
0136 
0137 
0138 
0139 
0140 
0141 
0142 
0143 template <int&... ExplicitBarrier, typename Container>
0144 ABSL_MUST_USE_RESULT testing::AssertionResult
0145 VerifyTypeImplementsAbslHashCorrectly(const Container& values);
0146 
0147 template <int&... ExplicitBarrier, typename Container, typename Eq>
0148 ABSL_MUST_USE_RESULT testing::AssertionResult
0149 VerifyTypeImplementsAbslHashCorrectly(const Container& values, Eq equals);
0150 
0151 template <int&..., typename T>
0152 ABSL_MUST_USE_RESULT testing::AssertionResult
0153 VerifyTypeImplementsAbslHashCorrectly(std::initializer_list<T> values);
0154 
0155 template <int&..., typename T, typename Eq>
0156 ABSL_MUST_USE_RESULT testing::AssertionResult
0157 VerifyTypeImplementsAbslHashCorrectly(std::initializer_list<T> values,
0158                                       Eq equals);
0159 
0160 namespace hash_internal {
0161 
0162 struct PrintVisitor {
0163   size_t index;
0164   template <typename T>
0165   std::string operator()(const T* value) const {
0166     return absl::StrCat("#", index, "(", testing::PrintToString(*value), ")");
0167   }
0168 };
0169 
0170 template <typename Eq>
0171 struct EqVisitor {
0172   Eq eq;
0173   template <typename T, typename U>
0174   bool operator()(const T* t, const U* u) const {
0175     return eq(*t, *u);
0176   }
0177 };
0178 
0179 struct ExpandVisitor {
0180   template <typename T>
0181   SpyHashState operator()(const T* value) const {
0182     return SpyHashState::combine(SpyHashState(), *value);
0183   }
0184 };
0185 
0186 template <typename Container, typename Eq>
0187 ABSL_MUST_USE_RESULT testing::AssertionResult
0188 VerifyTypeImplementsAbslHashCorrectly(const Container& values, Eq equals) {
0189   using V = typename Container::value_type;
0190 
0191   struct Info {
0192     const V& value;
0193     size_t index;
0194     std::string ToString() const {
0195       return absl::visit(PrintVisitor{index}, value);
0196     }
0197     SpyHashState expand() const { return absl::visit(ExpandVisitor{}, value); }
0198   };
0199 
0200   using EqClass = std::vector<Info>;
0201   std::vector<EqClass> classes;
0202 
0203   
0204   size_t i = 0;
0205   for (const auto& value : values) {
0206     EqClass* c = nullptr;
0207     for (auto& eqclass : classes) {
0208       if (absl::visit(EqVisitor<Eq>{equals}, value, eqclass[0].value)) {
0209         c = &eqclass;
0210         break;
0211       }
0212     }
0213     if (c == nullptr) {
0214       classes.emplace_back();
0215       c = &classes.back();
0216     }
0217     c->push_back({value, i});
0218     ++i;
0219 
0220     
0221     if (auto error = c->back().expand().error()) {
0222       return testing::AssertionFailure() << *error;
0223     }
0224   }
0225 
0226   if (classes.size() < 2) {
0227     return testing::AssertionFailure()
0228            << "At least two equivalence classes are expected.";
0229   }
0230 
0231   
0232   
0233 
0234   for (const auto& c : classes) {
0235     
0236     
0237     const SpyHashState expected = c[0].expand();
0238     for (const Info& v : c) {
0239       if (v.expand() != v.expand()) {
0240         return testing::AssertionFailure()
0241                << "Hash expansion for " << v.ToString()
0242                << " is non-deterministic.";
0243       }
0244       if (v.expand() != expected) {
0245         return testing::AssertionFailure()
0246                << "Values " << c[0].ToString() << " and " << v.ToString()
0247                << " evaluate as equal but have an unequal hash expansion.";
0248       }
0249     }
0250 
0251     
0252     for (const auto& c2 : classes) {
0253       if (&c == &c2) continue;
0254       const SpyHashState c2_hash = c2[0].expand();
0255       switch (SpyHashState::Compare(expected, c2_hash)) {
0256         case SpyHashState::CompareResult::kEqual:
0257           return testing::AssertionFailure()
0258                  << "Values " << c[0].ToString() << " and " << c2[0].ToString()
0259                  << " evaluate as unequal but have an equal hash expansion.";
0260         case SpyHashState::CompareResult::kBSuffixA:
0261           return testing::AssertionFailure()
0262                  << "Hash expansion of " << c2[0].ToString()
0263                  << " is a suffix of the hash expansion of " << c[0].ToString()
0264                  << ".";
0265         case SpyHashState::CompareResult::kASuffixB:
0266           return testing::AssertionFailure()
0267                  << "Hash expansion of " << c[0].ToString()
0268                  << " is a suffix of the hash expansion of " << c2[0].ToString()
0269                  << ".";
0270         case SpyHashState::CompareResult::kUnequal:
0271           break;
0272       }
0273     }
0274   }
0275   return testing::AssertionSuccess();
0276 }
0277 
0278 template <typename... T>
0279 struct TypeSet {
0280   template <typename U, bool = disjunction<std::is_same<T, U>...>::value>
0281   struct Insert {
0282     using type = TypeSet<U, T...>;
0283   };
0284   template <typename U>
0285   struct Insert<U, true> {
0286     using type = TypeSet;
0287   };
0288 
0289   template <template <typename...> class C>
0290   using apply = C<T...>;
0291 };
0292 
0293 template <typename... T>
0294 struct MakeTypeSet : TypeSet<> {};
0295 template <typename T, typename... Ts>
0296 struct MakeTypeSet<T, Ts...> : MakeTypeSet<Ts...>::template Insert<T>::type {};
0297 
0298 template <typename... T>
0299 using VariantForTypes = typename MakeTypeSet<
0300     const typename std::decay<T>::type*...>::template apply<absl::variant>;
0301 
0302 template <typename Container>
0303 struct ContainerAsVector {
0304   using V = absl::variant<const typename Container::value_type*>;
0305   using Out = std::vector<V>;
0306 
0307   static Out Do(const Container& values) {
0308     Out out;
0309     for (const auto& v : values) out.push_back(&v);
0310     return out;
0311   }
0312 };
0313 
0314 template <typename... T>
0315 struct ContainerAsVector<std::tuple<T...>> {
0316   using V = VariantForTypes<T...>;
0317   using Out = std::vector<V>;
0318 
0319   template <size_t... I>
0320   static Out DoImpl(const std::tuple<T...>& tuple, absl::index_sequence<I...>) {
0321     return Out{&std::get<I>(tuple)...};
0322   }
0323 
0324   static Out Do(const std::tuple<T...>& values) {
0325     return DoImpl(values, absl::index_sequence_for<T...>());
0326   }
0327 };
0328 
0329 template <>
0330 struct ContainerAsVector<std::tuple<>> {
0331   static std::vector<VariantForTypes<int>> Do(std::tuple<>) { return {}; }
0332 };
0333 
0334 struct DefaultEquals {
0335   template <typename T, typename U>
0336   bool operator()(const T& t, const U& u) const {
0337     return t == u;
0338   }
0339 };
0340 
0341 }  
0342 
0343 template <int&..., typename Container>
0344 ABSL_MUST_USE_RESULT testing::AssertionResult
0345 VerifyTypeImplementsAbslHashCorrectly(const Container& values) {
0346   return hash_internal::VerifyTypeImplementsAbslHashCorrectly(
0347       hash_internal::ContainerAsVector<Container>::Do(values),
0348       hash_internal::DefaultEquals{});
0349 }
0350 
0351 template <int&..., typename Container, typename Eq>
0352 ABSL_MUST_USE_RESULT testing::AssertionResult
0353 VerifyTypeImplementsAbslHashCorrectly(const Container& values, Eq equals) {
0354   return hash_internal::VerifyTypeImplementsAbslHashCorrectly(
0355       hash_internal::ContainerAsVector<Container>::Do(values), equals);
0356 }
0357 
0358 template <int&..., typename T>
0359 ABSL_MUST_USE_RESULT testing::AssertionResult
0360 VerifyTypeImplementsAbslHashCorrectly(std::initializer_list<T> values) {
0361   return hash_internal::VerifyTypeImplementsAbslHashCorrectly(
0362       hash_internal::ContainerAsVector<std::initializer_list<T>>::Do(values),
0363       hash_internal::DefaultEquals{});
0364 }
0365 
0366 template <int&..., typename T, typename Eq>
0367 ABSL_MUST_USE_RESULT testing::AssertionResult
0368 VerifyTypeImplementsAbslHashCorrectly(std::initializer_list<T> values,
0369                                       Eq equals) {
0370   return hash_internal::VerifyTypeImplementsAbslHashCorrectly(
0371       hash_internal::ContainerAsVector<std::initializer_list<T>>::Do(values),
0372       equals);
0373 }
0374 
0375 ABSL_NAMESPACE_END
0376 }  
0377 
0378 #endif