blob: be670e5ee6999216ac8f2a97bbd778cf6c523289 [file] [log] [blame]
#include "./fuzztest/internal/table_of_recent_compares.h"
#include <cstdint>
#include <string>
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/random/random.h"
#include "./fuzztest/internal/domain.h"
namespace fuzztest::internal {
namespace {
// TODO(JunyangShao) : Make these functions neater (https://abseil.io/tips/122).
TablesOfRecentCompares GetFilledIntegerTORC() {
TablesOfRecentCompares table = {};
// Fill container TORC and uint32 TORC,
// duplicate 8 to test dedup.
for (int i = 0; i < 8; ++i) {
table.GetMutable<4>().Insert(1234, 5678);
}
// Fill uint32_t TORC with casted values.
table.GetMutable<4>().Insert(-10, -5);
return table;
}
// TODO(JunyangShao) : Make these functions neater (https://abseil.io/tips/122).
TablesOfRecentCompares GetFilledContainerTORC() {
TablesOfRecentCompares table = {};
std::string lhs = "\x11\x11\x22\x22";
std::string rhs = "\x33\x33\x44\x44";
for (int i = 0; i < 8; ++i) {
table.GetMutable<0>().Insert(reinterpret_cast<const uint8_t*>(lhs.data()),
reinterpret_cast<const uint8_t*>(rhs.data()),
4);
}
// Fill uint64_t TORC with cast-from-string values. Which could be
// matched by a ContainerDictionary. To test cast-int-to-buffer matching.
lhs = "\xaa\xaa\xbb\xbb";
rhs = "\xcc\xcc\xdd\xdd";
uint32_t uint64_lhs = *(reinterpret_cast<const uint32_t*>(lhs.data()));
uint32_t uint64_rhs = *(reinterpret_cast<const uint32_t*>(rhs.data()));
table.GetMutable<8>().Insert(uint64_lhs, uint64_rhs);
return table;
}
// TODO(JunyangShao) : Use EXPECT_THAT instead of EXPECT_EQ.
TEST(TablesOfRecentComparesTest, IntegerTORCCorrect) {
auto table = GetFilledIntegerTORC();
// Integer TORC can match and can dedup.
auto v = table.Get<4>().GetMatchingIntegerDictionaryEntries(1234);
EXPECT_EQ(v.size(), 1);
EXPECT_EQ(v[0], 5678);
// Integer TORC range check works.
auto v_limited =
table.Get<4>().GetMatchingIntegerDictionaryEntries(1234, 0, 5677);
EXPECT_EQ(v_limited.size(), 0);
// Integer TORC works with type casts.
int magic_value = -10;
auto v_casted =
table.Get<4>().GetMatchingIntegerDictionaryEntries(magic_value);
EXPECT_EQ(v_casted.size(), 1);
EXPECT_EQ(v_casted[0], -5);
auto v_casted_limited =
table.Get<4>().GetMatchingIntegerDictionaryEntries(magic_value, -15, -11);
EXPECT_EQ(v_casted_limited.size(), 0);
}
// TODO(JunyangShao) : Use EXPECT_THAT instead of EXPECT_EQ.
TEST(TablesOfRecentComparesTest, ContainerTORCCorrect) {
auto table = GetFilledContainerTORC();
// Container TORC can match and can dedup.
std::string haystack = "\xff\xff\xff\xff\x11\x11\x22\x22\xff\xff";
std::string needle = "\x33\x33\x44\x44";
auto found = table.Get<0>().GetMatchingContainerDictionaryEntries(haystack);
EXPECT_EQ(found.size(), 1);
EXPECT_TRUE(found[0].position_hint.has_value());
EXPECT_EQ(*found[0].position_hint, 4);
EXPECT_EQ(found[0].value, needle);
// Container TORC can match casted-to container values.
std::vector<uint16_t> haystack_vec = {0xffff, 0x1111, 0x2222, 0xffff};
std::vector<uint16_t> needle_vec = {0x3333, 0x4444};
auto found_vec =
table.Get<0>().GetMatchingContainerDictionaryEntries(haystack_vec);
EXPECT_EQ(found_vec.size(), 1);
EXPECT_TRUE(found_vec[0].position_hint.has_value());
EXPECT_EQ(*found_vec[0].position_hint, 1);
EXPECT_EQ(found_vec[0].value, needle_vec);
}
// TODO(JunyangShao) : Use EXPECT_THAT instead of EXPECT_EQ.
TEST(TablesOfRecentComparesTest, IntegerDictionaryCorrect) {
auto table = GetFilledIntegerTORC();
IntegerDictionary<uint32_t> dict = {};
absl::BitGen bitgen;
// Match works.
dict.MatchEntriesFromTableOfRecentCompares(1234, table);
EXPECT_EQ(dict.Size(), 1);
EXPECT_EQ(dict.GetRandomSavedEntry(bitgen), 5678);
// Get random from TORC works.
int try_count = 10000;
while (try_count--) {
auto v = IntegerDictionary<uint32_t>::GetRandomTORCEntry(1234, bitgen,
table, 5000, 6000);
if (v == 5678) break;
}
EXPECT_GT(try_count, 0);
}
// TODO(JunyangShao) : Use EXPECT_THAT instead of EXPECT_EQ.
TEST(TablesOfRecentComparesTest, ContainerDictionaryCorrect) {
auto table = GetFilledContainerTORC();
ContainerDictionary<std::string> dict = {};
absl::BitGen bitgen;
std::string test_string = "\x11\x11\x22\x22\xff\xff\xaa\xaa\xbb\xbb\xff\xff";
// Match works.
dict.MatchEntriesFromTableOfRecentCompares(test_string, table);
bool get_3344 = false;
bool get_ccdd = false;
EXPECT_EQ(dict.Size(), 2);
int try_count = 10000;
while (try_count--) {
auto v = dict.GetRandomSavedEntry(bitgen);
EXPECT_TRUE(v.position_hint.has_value());
if (v.value == "\x33\x33\x44\x44") {
EXPECT_EQ(*v.position_hint, 0);
get_3344 = true;
}
if (v.value == "\xcc\xcc\xdd\xdd") {
EXPECT_EQ(*v.position_hint, 6);
get_ccdd = true;
}
if (get_3344 && get_ccdd) break;
}
EXPECT_GT(try_count, 0);
// Get random from TORC works.
try_count = 3000;
get_3344 = false;
// Since ccdd is in the integer TORC which is much larger, we don't
// check them here.
while (try_count--) {
auto v = dict.GetRandomTORCEntry(test_string, bitgen, table);
if (v.has_value()) {
if (v->position_hint.has_value()) {
if (v->value == "\x33\x33\x44\x44") {
EXPECT_EQ(*(v->position_hint), 0);
break;
}
}
}
}
EXPECT_GT(try_count, 0);
}
} // namespace
} // namespace fuzztest::internal