00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #ifndef ABSL_HASH_HASH_TESTING_H_
00016 #define ABSL_HASH_HASH_TESTING_H_
00017
00018 #include <initializer_list>
00019 #include <tuple>
00020 #include <type_traits>
00021 #include <vector>
00022
00023 #include "gmock/gmock.h"
00024 #include "gtest/gtest.h"
00025 #include "absl/hash/internal/spy_hash_state.h"
00026 #include "absl/meta/type_traits.h"
00027 #include "absl/strings/str_cat.h"
00028 #include "absl/types/variant.h"
00029
00030 namespace absl {
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 template <int&... ExplicitBarrier, typename Container>
00143 ABSL_MUST_USE_RESULT testing::AssertionResult
00144 VerifyTypeImplementsAbslHashCorrectly(const Container& values);
00145
00146 template <int&... ExplicitBarrier, typename Container, typename Eq>
00147 ABSL_MUST_USE_RESULT testing::AssertionResult
00148 VerifyTypeImplementsAbslHashCorrectly(const Container& values, Eq equals);
00149
00150 template <int&..., typename T>
00151 ABSL_MUST_USE_RESULT testing::AssertionResult
00152 VerifyTypeImplementsAbslHashCorrectly(std::initializer_list<T> values);
00153
00154 template <int&..., typename T, typename Eq>
00155 ABSL_MUST_USE_RESULT testing::AssertionResult
00156 VerifyTypeImplementsAbslHashCorrectly(std::initializer_list<T> values,
00157 Eq equals);
00158
00159 namespace hash_internal {
00160
00161 struct PrintVisitor {
00162 size_t index;
00163 template <typename T>
00164 std::string operator()(const T* value) const {
00165 return absl::StrCat("#", index, "(", testing::PrintToString(*value), ")");
00166 }
00167 };
00168
00169 template <typename Eq>
00170 struct EqVisitor {
00171 Eq eq;
00172 template <typename T, typename U>
00173 bool operator()(const T* t, const U* u) const {
00174 return eq(*t, *u);
00175 }
00176 };
00177
00178 struct ExpandVisitor {
00179 template <typename T>
00180 SpyHashState operator()(const T* value) const {
00181 return SpyHashState::combine(SpyHashState(), *value);
00182 }
00183 };
00184
00185 template <typename Container, typename Eq>
00186 ABSL_MUST_USE_RESULT testing::AssertionResult
00187 VerifyTypeImplementsAbslHashCorrectly(const Container& values, Eq equals) {
00188 using V = typename Container::value_type;
00189
00190 struct Info {
00191 const V& value;
00192 size_t index;
00193 std::string ToString() const {
00194 return absl::visit(PrintVisitor{index}, value);
00195 }
00196 SpyHashState expand() const { return absl::visit(ExpandVisitor{}, value); }
00197 };
00198
00199 using EqClass = std::vector<Info>;
00200 std::vector<EqClass> classes;
00201
00202
00203 size_t i = 0;
00204 for (const auto& value : values) {
00205 EqClass* c = nullptr;
00206 for (auto& eqclass : classes) {
00207 if (absl::visit(EqVisitor<Eq>{equals}, value, eqclass[0].value)) {
00208 c = &eqclass;
00209 break;
00210 }
00211 }
00212 if (c == nullptr) {
00213 classes.emplace_back();
00214 c = &classes.back();
00215 }
00216 c->push_back({value, i});
00217 ++i;
00218
00219
00220 if (auto error = c->back().expand().error()) {
00221 return testing::AssertionFailure() << *error;
00222 }
00223 }
00224
00225 if (classes.size() < 2) {
00226 return testing::AssertionFailure()
00227 << "At least two equivalence classes are expected.";
00228 }
00229
00230
00231
00232
00233 for (const auto& c : classes) {
00234
00235
00236 const SpyHashState expected = c[0].expand();
00237 for (const Info& v : c) {
00238 if (v.expand() != v.expand()) {
00239 return testing::AssertionFailure()
00240 << "Hash expansion for " << v.ToString()
00241 << " is non-deterministic.";
00242 }
00243 if (v.expand() != expected) {
00244 return testing::AssertionFailure()
00245 << "Values " << c[0].ToString() << " and " << v.ToString()
00246 << " evaluate as equal but have an unequal hash expansion.";
00247 }
00248 }
00249
00250
00251 for (const auto& c2 : classes) {
00252 if (&c == &c2) continue;
00253 const SpyHashState c2_hash = c2[0].expand();
00254 switch (SpyHashState::Compare(expected, c2_hash)) {
00255 case SpyHashState::CompareResult::kEqual:
00256 return testing::AssertionFailure()
00257 << "Values " << c[0].ToString() << " and " << c2[0].ToString()
00258 << " evaluate as unequal but have an equal hash expansion.";
00259 case SpyHashState::CompareResult::kBSuffixA:
00260 return testing::AssertionFailure()
00261 << "Hash expansion of " << c2[0].ToString()
00262 << " is a suffix of the hash expansion of " << c[0].ToString()
00263 << ".";
00264 case SpyHashState::CompareResult::kASuffixB:
00265 return testing::AssertionFailure()
00266 << "Hash expansion of " << c[0].ToString()
00267 << " is a suffix of the hash expansion of " << c2[0].ToString()
00268 << ".";
00269 case SpyHashState::CompareResult::kUnequal:
00270 break;
00271 }
00272 }
00273 }
00274 return testing::AssertionSuccess();
00275 }
00276
00277 template <typename... T>
00278 struct TypeSet {
00279 template <typename U, bool = disjunction<std::is_same<T, U>...>::value>
00280 struct Insert {
00281 using type = TypeSet<U, T...>;
00282 };
00283 template <typename U>
00284 struct Insert<U, true> {
00285 using type = TypeSet;
00286 };
00287
00288 template <template <typename...> class C>
00289 using apply = C<T...>;
00290 };
00291
00292 template <typename... T>
00293 struct MakeTypeSet : TypeSet<> {};
00294 template <typename T, typename... Ts>
00295 struct MakeTypeSet<T, Ts...> : MakeTypeSet<Ts...>::template Insert<T>::type {};
00296
00297 template <typename... T>
00298 using VariantForTypes = typename MakeTypeSet<
00299 const typename std::decay<T>::type*...>::template apply<absl::variant>;
00300
00301 template <typename Container>
00302 struct ContainerAsVector {
00303 using V = absl::variant<const typename Container::value_type*>;
00304 using Out = std::vector<V>;
00305
00306 static Out Do(const Container& values) {
00307 Out out;
00308 for (const auto& v : values) out.push_back(&v);
00309 return out;
00310 }
00311 };
00312
00313 template <typename... T>
00314 struct ContainerAsVector<std::tuple<T...>> {
00315 using V = VariantForTypes<T...>;
00316 using Out = std::vector<V>;
00317
00318 template <size_t... I>
00319 static Out DoImpl(const std::tuple<T...>& tuple, absl::index_sequence<I...>) {
00320 return Out{&std::get<I>(tuple)...};
00321 }
00322
00323 static Out Do(const std::tuple<T...>& values) {
00324 return DoImpl(values, absl::index_sequence_for<T...>());
00325 }
00326 };
00327
00328 template <>
00329 struct ContainerAsVector<std::tuple<>> {
00330 static std::vector<VariantForTypes<int>> Do(std::tuple<>) { return {}; }
00331 };
00332
00333 struct DefaultEquals {
00334 template <typename T, typename U>
00335 bool operator()(const T& t, const U& u) const {
00336 return t == u;
00337 }
00338 };
00339
00340 }
00341
00342 template <int&..., typename Container>
00343 ABSL_MUST_USE_RESULT testing::AssertionResult
00344 VerifyTypeImplementsAbslHashCorrectly(const Container& values) {
00345 return hash_internal::VerifyTypeImplementsAbslHashCorrectly(
00346 hash_internal::ContainerAsVector<Container>::Do(values),
00347 hash_internal::DefaultEquals{});
00348 }
00349
00350 template <int&..., typename Container, typename Eq>
00351 ABSL_MUST_USE_RESULT testing::AssertionResult
00352 VerifyTypeImplementsAbslHashCorrectly(const Container& values, Eq equals) {
00353 return hash_internal::VerifyTypeImplementsAbslHashCorrectly(
00354 hash_internal::ContainerAsVector<Container>::Do(values), equals);
00355 }
00356
00357 template <int&..., typename T>
00358 ABSL_MUST_USE_RESULT testing::AssertionResult
00359 VerifyTypeImplementsAbslHashCorrectly(std::initializer_list<T> values) {
00360 return hash_internal::VerifyTypeImplementsAbslHashCorrectly(
00361 hash_internal::ContainerAsVector<std::initializer_list<T>>::Do(values),
00362 hash_internal::DefaultEquals{});
00363 }
00364
00365 template <int&..., typename T, typename Eq>
00366 ABSL_MUST_USE_RESULT testing::AssertionResult
00367 VerifyTypeImplementsAbslHashCorrectly(std::initializer_list<T> values,
00368 Eq equals) {
00369 return hash_internal::VerifyTypeImplementsAbslHashCorrectly(
00370 hash_internal::ContainerAsVector<std::initializer_list<T>>::Do(values),
00371 equals);
00372 }
00373
00374 }
00375
00376 #endif // ABSL_HASH_HASH_TESTING_H_