Add TestDriver class
This commit is contained in:
@@ -17,8 +17,6 @@
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
|
||||
#define DEBUG_VERBOSE 0
|
||||
|
||||
// ==================== BEGIN IMPLEMENTATION ====================
|
||||
|
||||
struct Entry {
|
||||
@@ -45,11 +43,6 @@ struct Node {
|
||||
|
||||
Type type = Type::Invalid;
|
||||
};
|
||||
Node *getChild(Node *self, uint8_t index);
|
||||
int getChildGeq(Node *self, int child);
|
||||
Node *&getOrCreateChild(Node *&self, uint8_t index);
|
||||
Node *newNode();
|
||||
void eraseChild(Node *self, uint8_t index);
|
||||
|
||||
struct Node4 : Node {
|
||||
// Sorted
|
||||
@@ -1015,95 +1008,15 @@ int main(void) {
|
||||
|
||||
#ifdef ENABLE_FUZZ
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
// TODO call setOldestVersion, and check range writes/reads
|
||||
Arbitrary arbitrary{{data, size}};
|
||||
TestDriver<ConflictSet::Impl> driver{data, size};
|
||||
|
||||
int64_t writeVersion = 0;
|
||||
ConflictSet::Impl cs{writeVersion};
|
||||
ReferenceImpl refImpl{writeVersion};
|
||||
|
||||
while (arbitrary.hasEntropy()) {
|
||||
Arena arena;
|
||||
{
|
||||
int numWrites = arbitrary.bounded(10);
|
||||
int64_t v = ++writeVersion;
|
||||
auto *writes = new (arena) ConflictSet::WriteRange[numWrites];
|
||||
auto keys = set<std::string_view>(arena);
|
||||
while (int(keys.size()) < numWrites) {
|
||||
if (!arbitrary.hasEntropy()) {
|
||||
// Tell the fuzzer it's not interesting
|
||||
return -1;
|
||||
}
|
||||
int keyLen = arbitrary.bounded(8);
|
||||
auto *begin = new (arena) uint8_t[keyLen];
|
||||
arbitrary.randomBytes(begin, keyLen);
|
||||
keys.insert(std::string_view((const char *)begin, keyLen));
|
||||
}
|
||||
auto iter = keys.begin();
|
||||
for (int i = 0; i < numWrites; ++i) {
|
||||
writes[i].begin.p = (const uint8_t *)iter->data();
|
||||
writes[i].begin.len = iter->size();
|
||||
++iter;
|
||||
writes[i].end.len = 0;
|
||||
writes[i].writeVersion = v;
|
||||
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
||||
printf("Write: {%s} -> %d\n", printable(writes[i].begin).c_str(),
|
||||
int(writes[i].writeVersion));
|
||||
#endif
|
||||
}
|
||||
assert(iter == keys.end());
|
||||
cs.addWrites(writes, numWrites);
|
||||
refImpl.addWrites(writes, numWrites);
|
||||
}
|
||||
bool success = checkCorrectness(cs.root, refImpl);
|
||||
do {
|
||||
bool success = checkCorrectness(driver.cs.root, driver.refImpl);
|
||||
if (!success) {
|
||||
abort();
|
||||
}
|
||||
{
|
||||
int numReads = arbitrary.bounded(10);
|
||||
int64_t v = writeVersion - arbitrary.bounded(10);
|
||||
auto *reads = new (arena) ConflictSet::ReadRange[numReads];
|
||||
auto keys = set<std::string_view>(arena);
|
||||
while (int(keys.size()) < numReads) {
|
||||
if (!arbitrary.hasEntropy()) {
|
||||
// Tell the fuzzer it's not interesting
|
||||
return -1;
|
||||
}
|
||||
int keyLen = arbitrary.bounded(8);
|
||||
auto *begin = new (arena) uint8_t[keyLen];
|
||||
arbitrary.randomBytes(begin, keyLen);
|
||||
keys.insert(std::string_view((const char *)begin, keyLen));
|
||||
}
|
||||
auto iter = keys.begin();
|
||||
for (int i = 0; i < numReads; ++i) {
|
||||
reads[i].begin.p = (const uint8_t *)iter->data();
|
||||
reads[i].begin.len = iter->size();
|
||||
++iter;
|
||||
reads[i].end.len = 0;
|
||||
reads[i].readVersion = v;
|
||||
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
||||
printf("Read: {%s} at %d\n", printable(reads[i].begin).c_str(),
|
||||
int(reads[i].readVersion));
|
||||
#endif
|
||||
}
|
||||
assert(iter == keys.end());
|
||||
auto *results1 = new (arena) ConflictSet::Result[numReads];
|
||||
auto *results2 = new (arena) ConflictSet::Result[numReads];
|
||||
cs.check(reads, results1, numReads);
|
||||
refImpl.check(reads, results2, numReads);
|
||||
for (int i = 0; i < numReads; ++i) {
|
||||
if (results1[i] != results2[i]) {
|
||||
fprintf(stderr, "Expected %d, got %d for read of %s at version %d\n",
|
||||
results2[i], results1[i], printable(reads[i].begin).c_str(),
|
||||
int(reads[i].readVersion));
|
||||
std::string referenceLogicalMap;
|
||||
refImpl.printLogical(referenceLogicalMap);
|
||||
fprintf(stderr, "Logical map:\n\n%s\n", referenceLogicalMap.c_str());
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!driver.next());
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
97
Internal.h
97
Internal.h
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "ConflictSet.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
@@ -12,6 +13,11 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#define DEBUG_VERBOSE 0
|
||||
|
||||
// This header contains code that we want to reuse outside of ConflictSet.cpp or
|
||||
// want to exclude from coverage since it's only testing related.
|
||||
|
||||
// GCOVR_EXCL_START
|
||||
|
||||
__attribute__((always_inline)) inline void *safe_malloc(size_t s) {
|
||||
@@ -442,4 +448,95 @@ inline std::string printable(const Key &key) {
|
||||
return printable(std::string_view((const char *)key.p, key.len));
|
||||
}
|
||||
|
||||
template <class ConflictSetImpl> struct TestDriver {
|
||||
// TODO call setOldestVersion, and check range writes/reads
|
||||
Arbitrary arbitrary;
|
||||
explicit TestDriver(const uint8_t *data, size_t size)
|
||||
: arbitrary({data, size}) {}
|
||||
|
||||
int64_t writeVersion = 0;
|
||||
ConflictSetImpl cs{writeVersion};
|
||||
ReferenceImpl refImpl{writeVersion};
|
||||
|
||||
// Call until it returns true, for "done". Check internal invariants etc
|
||||
// between calls to next.
|
||||
bool next() {
|
||||
if (!arbitrary.hasEntropy()) {
|
||||
return true;
|
||||
}
|
||||
Arena arena;
|
||||
{
|
||||
int numWrites = arbitrary.bounded(10);
|
||||
int64_t v = ++writeVersion;
|
||||
auto *writes = new (arena) ConflictSet::WriteRange[numWrites];
|
||||
auto keys = set<std::string_view>(arena);
|
||||
while (int(keys.size()) < numWrites) {
|
||||
if (!arbitrary.hasEntropy()) {
|
||||
return true;
|
||||
}
|
||||
int keyLen = arbitrary.bounded(8);
|
||||
auto *begin = new (arena) uint8_t[keyLen];
|
||||
arbitrary.randomBytes(begin, keyLen);
|
||||
keys.insert(std::string_view((const char *)begin, keyLen));
|
||||
}
|
||||
auto iter = keys.begin();
|
||||
for (int i = 0; i < numWrites; ++i) {
|
||||
writes[i].begin.p = (const uint8_t *)iter->data();
|
||||
writes[i].begin.len = iter->size();
|
||||
++iter;
|
||||
writes[i].end.len = 0;
|
||||
writes[i].writeVersion = v;
|
||||
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
||||
printf("Write: {%s} -> %d\n", printable(writes[i].begin).c_str(),
|
||||
int(writes[i].writeVersion));
|
||||
#endif
|
||||
}
|
||||
assert(iter == keys.end());
|
||||
cs.addWrites(writes, numWrites);
|
||||
refImpl.addWrites(writes, numWrites);
|
||||
}
|
||||
{
|
||||
int numReads = arbitrary.bounded(10);
|
||||
int64_t v = writeVersion - arbitrary.bounded(10);
|
||||
auto *reads = new (arena) ConflictSet::ReadRange[numReads];
|
||||
auto keys = set<std::string_view>(arena);
|
||||
while (int(keys.size()) < numReads) {
|
||||
if (!arbitrary.hasEntropy()) {
|
||||
return true;
|
||||
}
|
||||
int keyLen = arbitrary.bounded(8);
|
||||
auto *begin = new (arena) uint8_t[keyLen];
|
||||
arbitrary.randomBytes(begin, keyLen);
|
||||
keys.insert(std::string_view((const char *)begin, keyLen));
|
||||
}
|
||||
auto iter = keys.begin();
|
||||
for (int i = 0; i < numReads; ++i) {
|
||||
reads[i].begin.p = (const uint8_t *)iter->data();
|
||||
reads[i].begin.len = iter->size();
|
||||
++iter;
|
||||
reads[i].end.len = 0;
|
||||
reads[i].readVersion = v;
|
||||
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
||||
printf("Read: {%s} at %d\n", printable(reads[i].begin).c_str(),
|
||||
int(reads[i].readVersion));
|
||||
#endif
|
||||
}
|
||||
assert(iter == keys.end());
|
||||
auto *results1 = new (arena) ConflictSet::Result[numReads];
|
||||
auto *results2 = new (arena) ConflictSet::Result[numReads];
|
||||
cs.check(reads, results1, numReads);
|
||||
refImpl.check(reads, results2, numReads);
|
||||
for (int i = 0; i < numReads; ++i) {
|
||||
if (results1[i] != results2[i]) {
|
||||
fprintf(stderr, "Expected %d, got %d for read of %s at version %d\n",
|
||||
results2[i], results1[i], printable(reads[i].begin).c_str(),
|
||||
int(reads[i].readVersion));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// GCOVR_EXCL_STOP
|
Reference in New Issue
Block a user