// Copyright 2014 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/base/functional.h" #include #include #include "test/unittests/test-utils.h" namespace v8 { namespace base { TEST(FunctionalTest, HashBool) { hash h, h1, h2; EXPECT_EQ(h1(true), h2(true)); EXPECT_EQ(h1(false), h2(false)); EXPECT_NE(h(true), h(false)); } TEST(FunctionalTest, HashFloatZero) { hash h; EXPECT_EQ(h(0.0f), h(-0.0f)); } TEST(FunctionalTest, HashDoubleZero) { hash h; EXPECT_EQ(h(0.0), h(-0.0)); } namespace { inline int64_t GetRandomSeedFromFlag(int random_seed) { return random_seed ? random_seed : TimeTicks::Now().ToInternalValue(); } } // namespace template class FunctionalTest : public ::testing::Test { public: FunctionalTest() : rng_(GetRandomSeedFromFlag(::v8::internal::v8_flags.random_seed)) {} ~FunctionalTest() override = default; FunctionalTest(const FunctionalTest&) = delete; FunctionalTest& operator=(const FunctionalTest&) = delete; RandomNumberGenerator* rng() { return &rng_; } private: RandomNumberGenerator rng_; }; using FunctionalTypes = ::testing::Types; TYPED_TEST_SUITE(FunctionalTest, FunctionalTypes); TYPED_TEST(FunctionalTest, EqualToImpliesSameHashCode) { hash h; std::equal_to e; TypeParam values[32]; this->rng()->NextBytes(values, sizeof(values)); TRACED_FOREACH(TypeParam, v1, values) { TRACED_FOREACH(TypeParam, v2, values) { if (e(v1, v2)) { EXPECT_EQ(h(v1), h(v2)); } } } } TYPED_TEST(FunctionalTest, HashEqualsHashValue) { for (int i = 0; i < 128; ++i) { TypeParam v; this->rng()->NextBytes(&v, sizeof(v)); hash h; EXPECT_EQ(h(v), hash_value(v)); } } TYPED_TEST(FunctionalTest, HashIsStateless) { hash h1, h2; for (int i = 0; i < 128; ++i) { TypeParam v; this->rng()->NextBytes(&v, sizeof(v)); EXPECT_EQ(h1(v), h2(v)); } } TYPED_TEST(FunctionalTest, HashIsOkish) { std::set vs; for (size_t i = 0; i < 128; ++i) { TypeParam v; this->rng()->NextBytes(&v, sizeof(v)); vs.insert(v); } std::set hs; for (const auto& v : vs) { hash h; hs.insert(h(v)); } EXPECT_LE(vs.size() / 4u, hs.size()); } TYPED_TEST(FunctionalTest, HashValueArrayUsesHashRange) { TypeParam values[128]; this->rng()->NextBytes(&values, sizeof(values)); EXPECT_EQ(hash_range(values, values + arraysize(values)), hash_value(values)); } TYPED_TEST(FunctionalTest, BitEqualTo) { bit_equal_to pred; for (size_t i = 0; i < 128; ++i) { TypeParam v1, v2; this->rng()->NextBytes(&v1, sizeof(v1)); this->rng()->NextBytes(&v2, sizeof(v2)); EXPECT_PRED2(pred, v1, v1); EXPECT_PRED2(pred, v2, v2); EXPECT_EQ(memcmp(&v1, &v2, sizeof(TypeParam)) == 0, pred(v1, v2)); } } TYPED_TEST(FunctionalTest, BitEqualToImpliesSameBitHash) { bit_hash h; bit_equal_to e; TypeParam values[32]; this->rng()->NextBytes(&values, sizeof(values)); TRACED_FOREACH(TypeParam, v1, values) { TRACED_FOREACH(TypeParam, v2, values) { if (e(v1, v2)) { EXPECT_EQ(h(v1), h(v2)); } } } } namespace { struct Foo { int x; double y; }; size_t hash_value(Foo const& v) { return hash_combine(v.x, v.y); } } // namespace TEST(FunctionalTest, HashUsesArgumentDependentLookup) { const int kIntValues[] = {std::numeric_limits::min(), -1, 0, 1, 42, std::numeric_limits::max()}; const double kDoubleValues[] = { std::numeric_limits::min(), -1, -0, 0, 1, std::numeric_limits::max()}; TRACED_FOREACH(int, x, kIntValues) { TRACED_FOREACH(double, y, kDoubleValues) { hash h; Foo foo = {x, y}; EXPECT_EQ(hash_combine(x, y), h(foo)); } } } TEST(FunctionalTest, BitEqualToFloat) { bit_equal_to pred; EXPECT_FALSE(pred(0.0f, -0.0f)); EXPECT_FALSE(pred(-0.0f, 0.0f)); float const qNaN = std::numeric_limits::quiet_NaN(); float const sNaN = std::numeric_limits::signaling_NaN(); EXPECT_PRED2(pred, qNaN, qNaN); EXPECT_PRED2(pred, sNaN, sNaN); } TEST(FunctionalTest, BitHashFloatDifferentForZeroAndMinusZero) { bit_hash h; EXPECT_NE(h(0.0f), h(-0.0f)); } TEST(FunctionalTest, BitEqualToDouble) { bit_equal_to pred; EXPECT_FALSE(pred(0.0, -0.0)); EXPECT_FALSE(pred(-0.0, 0.0)); double const qNaN = std::numeric_limits::quiet_NaN(); double const sNaN = std::numeric_limits::signaling_NaN(); EXPECT_PRED2(pred, qNaN, qNaN); EXPECT_PRED2(pred, sNaN, sNaN); } TEST(FunctionalTest, BitHashDoubleDifferentForZeroAndMinusZero) { bit_hash h; EXPECT_NE(h(0.0), h(-0.0)); } } // namespace base } // namespace v8