blob: aa041b282b0d0fe25a0f5fd4e03609c2ec864eec [file] [log] [blame]
// Copyright 2018 The Chromium 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 "components/optimization_guide/bloom_filter.h"
#include <stdint.h>
#include <string>
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace optimization_guide {
namespace {
int CountBits(const ByteVector& vector) {
int bit_count = 0;
for (size_t i = 0; i < vector.size(); ++i) {
uint8_t byte = vector[i];
for (int j = 0; j < 8; ++j) {
if (byte & (1 << j))
bit_count++;
}
}
return bit_count;
}
} // namespace
TEST(BloomFilterTest, SingleHash) {
BloomFilter filter(1 /* num_hash_functions */, 16 /* num_bits */);
EXPECT_EQ(2u, filter.bytes().size());
EXPECT_EQ(0, CountBits(filter.bytes()));
EXPECT_FALSE(filter.Contains("Alfa"));
EXPECT_FALSE(filter.Contains("Bravo"));
EXPECT_FALSE(filter.Contains("Charlie"));
filter.Add("Alfa");
EXPECT_EQ(1, CountBits(filter.bytes()));
EXPECT_TRUE(filter.Contains("Alfa"));
EXPECT_FALSE(filter.Contains("Bravo"));
EXPECT_FALSE(filter.Contains("Charlie"));
filter.Add("Bravo");
filter.Add("Chuck");
EXPECT_EQ(3, CountBits(filter.bytes()));
EXPECT_TRUE(filter.Contains("Alfa"));
EXPECT_TRUE(filter.Contains("Bravo"));
EXPECT_FALSE(filter.Contains("Charlie"));
}
TEST(BloomFilterTest, FalsePositivesWithSingleBitFilterCollisions) {
BloomFilter filter(1 /* num_hash_functions */, 1 /* num_bits */);
EXPECT_EQ(1u, filter.bytes().size());
EXPECT_FALSE(filter.Contains("Alfa"));
EXPECT_FALSE(filter.Contains("Bravo"));
EXPECT_FALSE(filter.Contains("Charlie"));
filter.Add("Alfa");
EXPECT_TRUE(filter.Contains("Alfa"));
EXPECT_TRUE(filter.Contains("Bravo"));
EXPECT_TRUE(filter.Contains("Charlie"));
}
TEST(BloomFilterTest, MultiHash) {
// Provide zero-ed filter data.
std::string data(10, 0);
BloomFilter filter(3 /* num_hash_functions */, 75 /* num_bits */, data);
EXPECT_EQ(10u, filter.bytes().size());
EXPECT_EQ(0, CountBits(filter.bytes()));
EXPECT_FALSE(filter.Contains("Alfa"));
EXPECT_FALSE(filter.Contains("Bravo"));
EXPECT_FALSE(filter.Contains("Charlie"));
filter.Add("Alfa");
EXPECT_EQ(3, CountBits(filter.bytes()));
EXPECT_TRUE(filter.Contains("Alfa"));
EXPECT_FALSE(filter.Contains("Bravo"));
EXPECT_FALSE(filter.Contains("Charlie"));
filter.Add("Bravo");
filter.Add("Chuck");
EXPECT_EQ(9, CountBits(filter.bytes()));
EXPECT_TRUE(filter.Contains("Alfa"));
EXPECT_TRUE(filter.Contains("Bravo"));
EXPECT_FALSE(filter.Contains("Charlie"));
}
TEST(BloomFilterTest, EverythingMatches) {
// Provide filter data with all bits set ON.
std::string data(1024, 0xff);
BloomFilter filter(7 /* num_hash_functions */, 8191 /* num_bits */, data);
EXPECT_TRUE(filter.Contains("Alfa"));
EXPECT_TRUE(filter.Contains("Bravo"));
EXPECT_TRUE(filter.Contains("Charlie"));
EXPECT_TRUE(filter.Contains("Delta"));
EXPECT_TRUE(filter.Contains("Echo"));
}
// Disable this test in configurations that don't print CHECK failures.
#if !defined(OS_IOS) && !(defined(OFFICIAL_BUILD) && defined(NDEBUG))
TEST(BloomFilterTest, ByteVectorTooSmall) {
std::string data(1023, 0xff);
EXPECT_DEATH(
{
BloomFilter filter(7 /* num_hash_functions */, 8191 /* num_bits */,
data);
},
"Check failed");
}
#endif
} // namespace optimization_guide