chore: Gtest migration followups first pass (#7884)

This commit is contained in:
Alex Kremer
2026-07-31 00:04:38 +01:00
committed by GitHub
parent 85e73cbd32
commit ecdd457f35
16 changed files with 315 additions and 254 deletions

View File

@@ -20,21 +20,22 @@
namespace xrpl::node_store {
namespace {
constexpr std::size_t kPoolSizes[] = {1000, 10000, 100000};
constexpr int kThreadCounts[] = {1, 4, 8};
constexpr auto kPoolSizes = std::to_array<std::size_t>({1000, 10000, 100000});
constexpr auto kThreadCounts = std::to_array<std::size_t>({1, 4, 8});
constexpr std::size_t kBatchSize = 256;
constexpr std::size_t kMissRatio = 5;
constexpr std::string_view kNamePrefix = "BM_Backend_";
constexpr std::string_view kNameSeparator = "/";
struct RunState
{
std::unique_ptr<BackendHarness> harness;
Batch present; // prefix-1 objects, eligible to be stored
Batch recent; // prefix-1 objects in the "future" key space
std::vector<uint256> missing; // prefix-2 keys that are never stored
std::vector<std::size_t> shuffle; // [0, poolSize) permutation for random-like access
std::size_t avgPayload = 0; // mean getData().size() over `present`
std::unique_ptr<BackendHarness> harness; ///< backend under test, rebuilt per run
Batch present; ///< prefix-1 objects, eligible to be stored
Batch recent; ///< prefix-1 objects in the "future" key space
std::vector<uint256> missing; ///< prefix-2 keys that are never stored
std::vector<std::size_t> shuffle; ///< [0, poolSize) permutation for random-like access
std::size_t avgPayload = 0; ///< mean getData().size() over `present`
void
release()
@@ -85,7 +86,7 @@ Workload const kInsert{
},
.iterate =
[](IterateContext const& ctx) {
auto& [rs, backend, index, poolSize] = ctx;
auto const& [rs, backend, index, poolSize] = ctx;
backend.store(rs.present[index % poolSize]);
},
.reportBytes = true,
@@ -104,7 +105,7 @@ Workload const kFetch{
},
.iterate =
[](IterateContext const& ctx) {
auto& [rs, backend, index, poolSize] = ctx;
auto const& [rs, backend, index, poolSize] = ctx;
std::shared_ptr<NodeObject> result;
backend.fetch(rs.present[index % poolSize]->getHash(), &result);
benchmark::DoNotOptimize(result);
@@ -118,7 +119,7 @@ Workload const kMissing{
.setup = [](SetupContext const& ctx) { ctx.rs.missing = makeMissingKeys(ctx.poolSize); },
.iterate =
[](IterateContext const& ctx) {
auto& [rs, backend, index, poolSize] = ctx;
auto const& [rs, backend, index, poolSize] = ctx;
std::shared_ptr<NodeObject> result;
backend.fetch(rs.missing[index % poolSize], &result);
benchmark::DoNotOptimize(result);
@@ -139,10 +140,10 @@ Workload const kMixed{
},
.iterate =
[](IterateContext const& ctx) {
auto& [rs, backend, index, poolSize] = ctx;
auto const& [rs, backend, index, poolSize] = ctx;
std::shared_ptr<NodeObject> result;
auto const pick = rs.shuffle[index % poolSize];
if (index % 5 == 0)
if (index % kMissRatio == 0)
{
backend.fetch(rs.missing[pick], &result);
}
@@ -170,7 +171,7 @@ Workload const kWork{
},
.iterate =
[](IterateContext const& ctx) {
auto& [rs, backend, index, poolSize] = ctx;
auto const& [rs, backend, index, poolSize] = ctx;
auto const slot = index % poolSize;
auto const pick = rs.shuffle[slot];
@@ -239,7 +240,7 @@ registerWorkload(BackendConfig const& bc, Workload const& w)
{
auto rs = std::make_shared<RunState>();
auto* b = benchmark::RegisterBenchmark(name, makeRunner(w, cfg, rs));
b->RangeMultiplier(10)->Range(kPoolSizes[0], kPoolSizes[std::size(kPoolSizes) - 1]);
b->RangeMultiplier(10)->Range(kPoolSizes.front(), kPoolSizes.back());
b->Threads(1)->Threads(4)->Threads(8)->UseRealTime();
return;
@@ -249,14 +250,14 @@ registerWorkload(BackendConfig const& bc, Workload const& w)
{
for (auto const threads : kThreadCounts)
{
if (poolSize % static_cast<std::size_t>(threads) != 0)
if (poolSize % threads != 0)
continue;
auto rs = std::make_shared<RunState>();
benchmark::RegisterBenchmark(name, makeRunner(w, cfg, rs))
->Arg(poolSize)
->Iterations(poolSize / static_cast<std::size_t>(threads))
->Threads(threads)
->Iterations(poolSize / threads)
->Threads(static_cast<int>(threads))
->UseRealTime();
}
}
@@ -289,7 +290,7 @@ registerStoreBatch(BackendConfig const& bc)
rs->harness = std::make_unique<BackendHarness>(cfg);
rs->present = makePool(1, poolSize);
rs->avgPayload = averagePayload(rs->present);
std::vector<Batch> const batches = sliceBatches(rs->present, kBatchSize);
std::vector<Batch> const batches = sliceFixedBatches(rs->present, kBatchSize);
if (batches.empty())
{
state.SkipWithError("pool smaller than one batch");

View File

@@ -26,6 +26,7 @@
#include <memory>
#include <numeric>
#include <random>
#include <ranges>
#include <string>
#include <utility>
#include <vector>
@@ -40,18 +41,13 @@ inline void
rngcpy(void* buffer, std::size_t bytes, Generator& g)
{
using result_type = typename Generator::result_type;
while (bytes >= sizeof(result_type))
while (bytes > 0)
{
auto const v = g();
std::memcpy(buffer, &v, sizeof(v));
buffer = reinterpret_cast<std::uint8_t*>(buffer) + sizeof(v);
bytes -= sizeof(v);
}
if (bytes > 0)
{
auto const v = g();
std::memcpy(buffer, &v, bytes);
auto const chunk = std::min(bytes, sizeof(result_type));
std::memcpy(buffer, &v, chunk);
buffer = reinterpret_cast<std::uint8_t*>(buffer) + chunk;
bytes -= chunk;
}
}
@@ -145,7 +141,7 @@ makePool(std::uint8_t prefix, std::size_t count, std::size_t start = 0)
Sequence seq(prefix);
Batch pool;
pool.reserve(count);
for (std::size_t i = 0; i < count; ++i)
for (auto i = 0uz; i < count; ++i)
pool.push_back(seq.obj(start + i));
return pool;
}
@@ -158,7 +154,7 @@ makeMissingKeys(std::size_t count)
Sequence seq(2);
std::vector<uint256> keys;
keys.reserve(count);
for (std::size_t i = 0; i < count; ++i)
for (auto i = 0uz; i < count; ++i)
keys.push_back(seq.key(i));
return keys;
}
@@ -206,16 +202,16 @@ inline std::vector<std::size_t>
makeShuffle(std::size_t size, std::uint64_t seed)
{
std::vector<std::size_t> v(size);
std::iota(v.begin(), v.end(), std::size_t{0});
std::ranges::iota(v, 0uz);
beast::xor_shift_engine gen(seed);
std::shuffle(v.begin(), v.end(), gen);
std::ranges::shuffle(v, gen);
return v;
}
// Partition a pool into fixed-size batches. Any trailing remainder shorter than
// `batchSize` is dropped, so every returned batch has exactly `batchSize`.
inline std::vector<Batch>
sliceBatches(Batch const& pool, std::size_t batchSize)
sliceFixedBatches(Batch const& pool, std::size_t batchSize)
{
std::vector<Batch> batches;
if (batchSize == 0)
@@ -228,13 +224,10 @@ sliceBatches(Batch const& pool, std::size_t batchSize)
/**
* @brief RAII owner of a NodeStore Backend opened on a private temporary directory.
*
* Member declaration order matters: `tempDir` is declared first so it is
* destroyed last, after the backend has closed and released its files.
*/
struct BackendHarness
{
beast::TempDir tempDir;
beast::TempDir tempDir; ///< Declared first so it is destroyed last
DummyScheduler scheduler;
beast::Journal journal{beast::Journal::getNullSink()};
std::unique_ptr<Backend> backend;

View File

@@ -50,11 +50,11 @@ struct Barrier
{
std::mutex mtx;
std::condition_variable cv;
int count;
int const initial;
std::size_t count;
std::size_t const initial;
std::size_t generation{0};
explicit Barrier(int n) : count(n), initial(n)
explicit Barrier(std::size_t n) : count(n), initial(n)
{
}
@@ -217,7 +217,7 @@ TEST(IntrusiveSharedTest, basics)
auto id = b->id;
EXPECT_EQ(TIBase::getState(id), Alive);
EXPECT_EQ(b->useCount(), 1);
for (int i = 0; i < 10; ++i)
for (auto i = 0uz; i < 10; ++i)
{
strong.push_back(b);
}
@@ -232,7 +232,7 @@ TEST(IntrusiveSharedTest, basics)
id = b->id;
EXPECT_EQ(TIBase::getState(id), Alive);
EXPECT_EQ(b->useCount(), 1);
for (int i = 0; i < 10; ++i)
for (auto i = 0uz; i < 10; ++i)
{
weak.emplace_back(b);
EXPECT_EQ(b->useCount(), 1);
@@ -280,17 +280,17 @@ TEST(IntrusiveSharedTest, basics)
TIBase::ResetStatesGuard const rsg{true};
using enum TrackedState;
using swu = SharedWeakUnion<TIBase>;
swu b = makeSharedIntrusive<TIBase>();
using SharedWeak = SharedWeakUnion<TIBase>;
SharedWeak b = makeSharedIntrusive<TIBase>();
EXPECT_TRUE(b.isStrong() && b.useCount() == 1);
auto id = b.get()->id;
EXPECT_EQ(TIBase::getState(id), Alive);
swu w = b;
SharedWeak w = b;
EXPECT_TRUE(TIBase::getState(id) == Alive);
EXPECT_TRUE(w.isStrong() && b.useCount() == 2);
w.convertToWeak();
EXPECT_TRUE(w.isWeak() && b.useCount() == 1);
swu s = w;
SharedWeak s = w;
EXPECT_TRUE(s.isWeak() && b.useCount() == 1);
s.convertToStrong();
EXPECT_TRUE(s.isStrong() && b.useCount() == 2);
@@ -380,43 +380,57 @@ TEST(IntrusiveSharedTest, partial_delete)
std::atomic<bool> destructorRan{false};
std::atomic<bool> partialDeleteRan{false};
std::latch partialDeleteStartedSyncPoint{2};
strong->tracingCallback = [&](TrackedState cur, std::optional<TrackedState> next) {
using enum TrackedState;
if (next == DeletedStarted)
if (!next)
return;
switch (*next)
{
// strong goes out of scope while weak is still in scope
// This checks that partialDelete has run to completion
// before the destructor is called. A sleep is inserted
// inside the partial delete to make sure the destructor is
// given an opportunity to run during partial delete.
EXPECT_EQ(cur, PartiallyDeleted);
}
if (next == PartiallyDeletedStarted)
{
partialDeleteStartedSyncPoint.arrive_and_wait();
using namespace std::chrono_literals;
// Sleep and let the weak pointer go out of scope,
// potentially triggering a destructor while partial delete
// is running. The test is to make sure that doesn't happen.
std::this_thread::sleep_for(800ms);
}
if (next == PartiallyDeleted)
{
EXPECT_FALSE(partialDeleteRan.exchange(true) || destructorRan.load());
}
if (next == Deleted)
{
EXPECT_FALSE(destructorRan.exchange(true));
case DeletedStarted:
// strong goes out of scope while weak is still in scope
// This checks that partialDelete has run to completion
// before the destructor is called. A sleep is inserted
// inside the partial delete to make sure the destructor is
// given an opportunity to run during partial delete.
EXPECT_EQ(cur, PartiallyDeleted);
break;
case PartiallyDeletedStarted: {
partialDeleteStartedSyncPoint.arrive_and_wait();
using namespace std::chrono_literals;
// Sleep and let the weak pointer go out of scope,
// potentially triggering a destructor while partial delete
// is running. The test is to make sure that doesn't happen.
std::this_thread::sleep_for(800ms);
break;
}
case PartiallyDeleted:
EXPECT_FALSE(partialDeleteRan.exchange(true) || destructorRan.load());
break;
case Deleted:
EXPECT_FALSE(destructorRan.exchange(true));
break;
case Uninitialized:
case Alive:
break;
}
};
std::thread t1{[&] {
partialDeleteStartedSyncPoint.arrive_and_wait();
weak.reset(); // Trigger a full delete as soon as the partial
// delete starts
}};
std::thread t2{[&] {
strong.reset(); // Trigger a partial delete
}};
t1.join();
t2.join();
@@ -444,13 +458,24 @@ TEST(IntrusiveSharedTest, destructor)
std::latch weakResetSyncPoint{2};
strong->tracingCallback = [&](TrackedState cur, std::optional<TrackedState> next) {
using enum TrackedState;
if (next == PartiallyDeleted)
if (!next)
return;
switch (*next)
{
EXPECT_FALSE(partialDeleteRan.exchange(true) || destructorRan.load());
}
if (next == Deleted)
{
EXPECT_FALSE(destructorRan.exchange(true));
case PartiallyDeleted:
EXPECT_FALSE(partialDeleteRan.exchange(true) || destructorRan.load());
break;
case Deleted:
EXPECT_FALSE(destructorRan.exchange(true));
break;
case Uninitialized:
case Alive:
case PartiallyDeletedStarted:
case DeletedStarted:
break;
}
};
std::thread t1{[&] {
@@ -492,25 +517,36 @@ TEST(IntrusiveSharedTest, multithreaded_clear_mixed_variant)
auto tracingCallback = [&](TrackedState cur, std::optional<TrackedState> next) {
using enum TrackedState;
auto [destructorRan, partialDeleteRan] = getDestructorState();
if (next == PartiallyDeleted)
if (!next)
return;
switch (*next)
{
EXPECT_FALSE(partialDeleteRan || destructorRan);
setPartialDeleteRan();
}
if (next == Deleted)
{
EXPECT_FALSE(destructorRan);
setDestructorRan();
case PartiallyDeleted:
EXPECT_FALSE(partialDeleteRan || destructorRan);
setPartialDeleteRan();
break;
case Deleted:
EXPECT_FALSE(destructorRan);
setDestructorRan();
break;
case Uninitialized:
case Alive:
case PartiallyDeletedStarted:
case DeletedStarted:
break;
}
};
auto createVecOfPointers = [&](auto const& toClone, std::default_random_engine& eng)
-> std::vector<std::variant<SharedIntrusive<TIBase>, WeakIntrusive<TIBase>>> {
std::vector<std::variant<SharedIntrusive<TIBase>, WeakIntrusive<TIBase>>> result;
std::uniform_int_distribution<> toCreateDist(4, 64);
std::uniform_int_distribution<std::size_t> toCreateDist(4, 64);
std::uniform_int_distribution<> isStrongDist(0, 1);
auto numToCreate = toCreateDist(eng);
result.reserve(numToCreate);
for (int i = 0; i < numToCreate; ++i)
for (auto i = 0uz; i < numToCreate; ++i)
{
if (isStrongDist(eng))
{
@@ -523,8 +559,8 @@ TEST(IntrusiveSharedTest, multithreaded_clear_mixed_variant)
}
return result;
};
constexpr int kLoopIters = 2 * 1024;
constexpr int kNumThreads = 16;
constexpr auto kLoopIters = 2uz * 1024;
constexpr auto kNumThreads = 16uz;
std::vector<SharedIntrusive<TIBase>> toClone;
Barrier loopStartSyncPoint{kNumThreads};
Barrier postCreateToCloneSyncPoint{kNumThreads};
@@ -533,7 +569,7 @@ TEST(IntrusiveSharedTest, multithreaded_clear_mixed_variant)
std::random_device rd;
std::vector<std::default_random_engine> result;
result.reserve(kNumThreads);
for (int i = 0; i < kNumThreads; ++i)
for (auto i = 0uz; i < kNumThreads; ++i)
result.emplace_back(rd());
return result;
}();
@@ -541,8 +577,8 @@ TEST(IntrusiveSharedTest, multithreaded_clear_mixed_variant)
// cloneAndDestroy clones the strong pointer into a vector of mixed
// strong and weak pointers and destroys them all at once.
// threadId==0 is special.
auto cloneAndDestroy = [&](int threadId) {
for (int i = 0; i < kLoopIters; ++i)
auto cloneAndDestroy = [&](std::size_t threadId) {
for (auto i = 0uz; i < kLoopIters; ++i)
{
// ------ Sync Point ------
loopStartSyncPoint.arriveAndWait();
@@ -582,11 +618,11 @@ TEST(IntrusiveSharedTest, multithreaded_clear_mixed_variant)
};
std::vector<std::thread> threads;
threads.reserve(kNumThreads);
for (int i = 0; i < kNumThreads; ++i)
for (auto i = 0uz; i < kNumThreads; ++i)
{
threads.emplace_back(cloneAndDestroy, i);
}
for (int i = 0; i < kNumThreads; ++i)
for (auto i = 0uz; i < kNumThreads; ++i)
{
threads[i].join();
}
@@ -623,31 +659,42 @@ TEST(IntrusiveSharedTest, multithreaded_clear_mixed_union)
auto tracingCallback = [&](TrackedState cur, std::optional<TrackedState> next) {
using enum TrackedState;
auto [destructorRan, partialDeleteRan] = getDestructorState();
if (next == PartiallyDeleted)
if (!next)
return;
switch (*next)
{
EXPECT_FALSE(partialDeleteRan || destructorRan);
setPartialDeleteRan();
}
if (next == Deleted)
{
EXPECT_FALSE(destructorRan);
setDestructorRan();
case PartiallyDeleted:
EXPECT_FALSE(partialDeleteRan || destructorRan);
setPartialDeleteRan();
break;
case Deleted:
EXPECT_FALSE(destructorRan);
setDestructorRan();
break;
case Uninitialized:
case Alive:
case PartiallyDeletedStarted:
case DeletedStarted:
break;
}
};
auto createVecOfPointers =
[&](auto const& toClone,
std::default_random_engine& eng) -> std::vector<SharedWeakUnion<TIBase>> {
std::vector<SharedWeakUnion<TIBase>> result;
std::uniform_int_distribution<> toCreateDist(4, 64);
std::uniform_int_distribution<std::size_t> toCreateDist(4, 64);
auto numToCreate = toCreateDist(eng);
result.reserve(numToCreate);
for (int i = 0; i < numToCreate; ++i)
for (auto i = 0uz; i < numToCreate; ++i)
result.emplace_back(SharedIntrusive<TIBase>(toClone));
return result;
};
constexpr int kLoopIters = 2 * 1024;
constexpr int kFlipPointersLoopIters = 256;
constexpr int kNumThreads = 16;
constexpr auto kLoopIters = 2uz * 1024;
constexpr auto kFlipPointersLoopIters = 256uz;
constexpr auto kNumThreads = 16uz;
std::vector<SharedIntrusive<TIBase>> toClone;
Barrier loopStartSyncPoint{kNumThreads};
Barrier postCreateToCloneSyncPoint{kNumThreads};
@@ -657,7 +704,7 @@ TEST(IntrusiveSharedTest, multithreaded_clear_mixed_union)
std::random_device rd;
std::vector<std::default_random_engine> result;
result.reserve(kNumThreads);
for (int i = 0; i < kNumThreads; ++i)
for (auto i = 0uz; i < kNumThreads; ++i)
result.emplace_back(rd());
return result;
}();
@@ -666,8 +713,8 @@ TEST(IntrusiveSharedTest, multithreaded_clear_mixed_union)
// mixed strong and weak pointers, runs a loop that randomly
// changes strong pointers to weak pointers, and destroys them
// all at once.
auto cloneAndDestroy = [&](int threadId) {
for (int i = 0; i < kLoopIters; ++i)
auto cloneAndDestroy = [&](std::size_t threadId) {
for (auto i = 0uz; i < kLoopIters; ++i)
{
// ------ Sync Point ------
loopStartSyncPoint.arriveAndWait();
@@ -702,7 +749,7 @@ TEST(IntrusiveSharedTest, multithreaded_clear_mixed_union)
postCreateVecOfPointersSyncPoint.arriveAndWait();
std::uniform_int_distribution<> isStrongDist(0, 1);
for (int f = 0; f < kFlipPointersLoopIters; ++f)
for (auto f = 0uz; f < kFlipPointersLoopIters; ++f)
{
for (auto& p : v)
{
@@ -725,11 +772,11 @@ TEST(IntrusiveSharedTest, multithreaded_clear_mixed_union)
};
std::vector<std::thread> threads;
threads.reserve(kNumThreads);
for (int i = 0; i < kNumThreads; ++i)
for (auto i = 0uz; i < kNumThreads; ++i)
{
threads.emplace_back(cloneAndDestroy, i);
}
for (int i = 0; i < kNumThreads; ++i)
for (auto i = 0uz; i < kNumThreads; ++i)
{
threads[i].join();
}
@@ -761,21 +808,32 @@ TEST(IntrusiveSharedTest, multithreaded_locking_weak)
auto tracingCallback = [&](TrackedState cur, std::optional<TrackedState> next) {
using enum TrackedState;
auto [destructorRan, partialDeleteRan] = getDestructorState();
if (next == PartiallyDeleted)
if (!next)
return;
switch (*next)
{
EXPECT_FALSE(partialDeleteRan || destructorRan);
setPartialDeleteRan();
}
if (next == Deleted)
{
EXPECT_FALSE(destructorRan);
setDestructorRan();
case PartiallyDeleted:
EXPECT_FALSE(partialDeleteRan || destructorRan);
setPartialDeleteRan();
break;
case Deleted:
EXPECT_FALSE(destructorRan);
setDestructorRan();
break;
case Uninitialized:
case Alive:
case PartiallyDeletedStarted:
case DeletedStarted:
break;
}
};
constexpr int kLoopIters = 2 * 1024;
constexpr int kLockWeakLoopIters = 256;
constexpr int kNumThreads = 16;
constexpr auto kLoopIters = 2uz * 1024;
constexpr auto kLockWeakLoopIters = 256uz;
constexpr auto kNumThreads = 16uz;
std::vector<SharedIntrusive<TIBase>> toLock;
Barrier loopStartSyncPoint{kNumThreads};
Barrier postCreateToLockSyncPoint{kNumThreads};
@@ -784,8 +842,8 @@ TEST(IntrusiveSharedTest, multithreaded_locking_weak)
// lockAndDestroy creates weak pointers from the strong pointer
// and runs a loop that locks the weak pointer. At the end of the loop
// all the pointers are destroyed all at once.
auto lockAndDestroy = [&](int threadId) {
for (int i = 0; i < kLoopIters; ++i)
auto lockAndDestroy = [&](std::size_t threadId) {
for (auto i = 0uz; i < kLoopIters; ++i)
{
// ------ Sync Point ------
loopStartSyncPoint.arriveAndWait();
@@ -816,7 +874,7 @@ TEST(IntrusiveSharedTest, multithreaded_locking_weak)
// Multiple threads all create a weak pointer from the same
// strong pointer
WeakIntrusive const weak{toLock[threadId]};
for (int wi = 0; wi < kLockWeakLoopIters; ++wi)
for (auto wi = 0uz; wi < kLockWeakLoopIters; ++wi)
{
EXPECT_FALSE(weak.expired());
auto strong = weak.lock();
@@ -831,11 +889,11 @@ TEST(IntrusiveSharedTest, multithreaded_locking_weak)
};
std::vector<std::thread> threads;
threads.reserve(kNumThreads);
for (int i = 0; i < kNumThreads; ++i)
for (auto i = 0uz; i < kNumThreads; ++i)
{
threads.emplace_back(lockAndDestroy, i);
}
for (int i = 0; i < kNumThreads; ++i)
for (auto i = 0uz; i < kNumThreads; ++i)
{
threads[i].join();
}

View File

@@ -199,7 +199,7 @@ TEST(mallocTrim, repeated_calls)
beast::Journal const journal{beast::Journal::getNullSink()};
// Call malloc_trim multiple times to ensure it's safe
for (int i = 0; i < 5; ++i)
for (auto i = 0uz; i < 5; ++i)
{
MallocTrimReport const report = mallocTrim("iteration_" + std::to_string(i), journal);

View File

@@ -323,11 +323,11 @@ TEST(NumberTest, add)
__LINE__,
},
{
// Does not round. Mantissas are going to be > maxRep, so if
// Does not round. Mantissas are going to be > kMaxRep, so if
// added together as uint64_t's, the result will overflow.
// With addition using uint128_t, there's no problem. After
// normalizing, the resulting mantissa ends up less than
// maxRep.
// kMaxRep.
Number{false, 9'999'999'999'999'999'990ULL, 0, Number::Normalized{}},
Number{false, 9'999'999'999'999'999'990ULL, 0, Number::Normalized{}},
Number{false, 1'999'999'999'999'999'998ULL, 1, Number::Normalized{}},
@@ -1078,14 +1078,6 @@ TEST(NumberTest, root)
EXPECT_EQ(result, z) << ss.str();
}
};
/*
auto tests = [&](auto const& cSmall, auto const& cLarge) {
test(cSmall);
if (scale != MantissaRange::mantissa_scale::small)
test(cLarge);
};
*/
auto const cSmall = std::to_array<Case>(
{{Number{2}, 2, Number{1414213562373095049, -18}},
{Number{2'000'000}, 2, Number{1414213562373095049, -15}},
@@ -1511,7 +1503,7 @@ TEST(NumberTest, to_string)
NumberRoundModeGuard const mg(Number::RoundingMode::TowardsZero);
auto const maxMantissa = Number::maxMantissa();
EXPECT_EQ(maxMantissa, (9'999'999'999'999'999));
EXPECT_EQ(maxMantissa, 9'999'999'999'999'999);
test(
Number{false, (maxMantissa * 1000) + 999, -3, Number::Normalized()},
"9999999999999999",
@@ -1550,7 +1542,7 @@ TEST(NumberTest, to_string)
NumberRoundModeGuard const mg(Number::RoundingMode::TowardsZero);
auto const maxMantissa = Number::maxMantissa();
EXPECT_EQ((maxMantissa), (9'999'999'999'999'999'999ULL));
EXPECT_EQ(maxMantissa, 9'999'999'999'999'999'999ULL);
test(
Number{false, maxMantissa, 0, Number::Normalized{}},
"9999999999999999990",

View File

@@ -151,7 +151,7 @@ randomBigInt(std::uint8_t minSize = 1, std::uint8_t maxSize = 5)
auto const numCoeff = numCoeffDist(eng);
std::vector<std::uint64_t> coeffs;
coeffs.reserve(numCoeff);
for (int i = 0; i < numCoeff; ++i)
for (auto i = 0uz; i < numCoeff; ++i)
{
coeffs.push_back(dist(eng));
}
@@ -167,7 +167,7 @@ TEST(Base58Test, multiprecision)
auto eng = randEngine();
std::uniform_int_distribution<std::uint64_t> dist;
std::uniform_int_distribution<std::uint64_t> dist1(1);
for (int i = 0; i < kIters; ++i)
for (auto i = 0uz; i < kIters; ++i)
{
std::uint64_t const d = dist(eng);
if (d == 0u)
@@ -185,7 +185,7 @@ TEST(Base58Test, multiprecision)
EXPECT_EQ(refMod.convert_to<std::uint64_t>(), mod);
EXPECT_EQ(foundDiv, refDiv);
}
for (int i = 0; i < kIters; ++i)
for (auto i = 0uz; i < kIters; ++i)
{
std::uint64_t const d = dist(eng);
auto bigInt = multiprecision_utils::randomBigInt(/*minSize*/ 2);
@@ -204,7 +204,7 @@ TEST(Base58Test, multiprecision)
auto const foundAdd = multiprecision_utils::toBoostMP(bigInt);
EXPECT_EQ(refAdd, foundAdd);
}
for (int i = 0; i < kIters; ++i)
for (auto i = 0uz; i < kIters; ++i)
{
std::uint64_t const d = dist1(eng);
// Force overflow
@@ -221,7 +221,7 @@ TEST(Base58Test, multiprecision)
auto const foundAdd = multiprecision_utils::toBoostMP(bigInt);
EXPECT_NE(refAdd, foundAdd);
}
for (int i = 0; i < kIters; ++i)
for (auto i = 0uz; i < kIters; ++i)
{
std::uint64_t const d = dist(eng);
auto bigInt = multiprecision_utils::randomBigInt(/* minSize */ 2);
@@ -239,7 +239,7 @@ TEST(Base58Test, multiprecision)
auto const foundMul = multiprecision_utils::toBoostMP(bigInt);
EXPECT_EQ(refMul, foundMul);
}
for (int i = 0; i < kIters; ++i)
for (auto i = 0uz; i < kIters; ++i)
{
std::uint64_t const d = dist1(eng);
// Force overflow
@@ -265,7 +265,7 @@ TEST(Base58Test, fast_matches_ref)
std::array<std::uint8_t, 64> b256ResultBuf[2];
std::array<std::span<std::uint8_t>, 2> b256Result;
for (int i = 0; i < 2; ++i)
for (auto i = 0uz; i < 2; ++i)
{
std::span const outBuf{b58ResultBuf[i]};
if (i == 0)
@@ -297,7 +297,7 @@ TEST(Base58Test, fast_matches_ref)
}
}
for (int i = 0; i < 2; ++i)
for (auto i = 0uz; i < 2; ++i)
{
std::span const outBuf{b256ResultBuf[i].data(), b256ResultBuf[i].size()};
if (i == 0)
@@ -339,7 +339,7 @@ TEST(Base58Test, fast_matches_ref)
std::array<std::uint8_t, 64> b256ResultBuf[2];
std::array<std::span<std::uint8_t>, 2> b256Result;
for (int i = 0; i < 2; ++i)
for (auto i = 0uz; i < 2; ++i)
{
std::span const outBuf{b58ResultBuf[i].data(), b58ResultBuf[i].size()};
if (i == 0)
@@ -370,7 +370,7 @@ TEST(Base58Test, fast_matches_ref)
}
}
for (int i = 0; i < 2; ++i)
for (auto i = 0uz; i < 2; ++i)
{
std::span const outBuf{b256ResultBuf[i].data(), b256ResultBuf[i].size()};
if (i == 0)
@@ -425,7 +425,7 @@ TEST(Base58Test, fast_matches_ref)
// test with random data
constexpr std::size_t kIters = 100000;
for (int i = 0; i < kIters; ++i)
for (auto i = 0uz; i < kIters; ++i)
{
std::array<std::uint8_t, 128> b256DataBuf{};
auto const [tokType, b256Data] = randomB256TestData(b256DataBuf);

View File

@@ -59,65 +59,67 @@ struct BaseUintTest : public ::testing::Test
static void
testComparisons()
{
{
static constexpr std::array<std::pair<std::string_view, std::string_view>, 6> kTestArgs{
{{"0000000000000000", "0000000000000001"},
{"0000000000000000", "ffffffffffffffff"},
{"1234567812345678", "2345678923456789"},
{"8000000000000000", "8000000000000001"},
{"aaaaaaaaaaaaaaa9", "aaaaaaaaaaaaaaaa"},
{"fffffffffffffffe", "ffffffffffffffff"}}};
using HexPair = std::pair<std::string_view, std::string_view>;
for (auto const& arg : kTestArgs)
{
static constexpr auto kTestArgs = std::to_array<HexPair>({
{"0000000000000000", "0000000000000001"},
{"0000000000000000", "ffffffffffffffff"},
{"1234567812345678", "2345678923456789"},
{"8000000000000000", "8000000000000001"},
{"aaaaaaaaaaaaaaa9", "aaaaaaaaaaaaaaaa"},
{"fffffffffffffffe", "ffffffffffffffff"},
});
for (auto const& [smallerText, largerText] : kTestArgs)
{
xrpl::BaseUInt<64> const u{arg.first}, v{arg.second};
xrpl::BaseUInt<64> const smaller{smallerText}, larger{largerText};
// For code readability, we want to use general boolean
// expectations instead of specific EXPECT_LT etc.
EXPECT_TRUE(u < v);
EXPECT_TRUE(u <= v);
EXPECT_TRUE(u != v);
EXPECT_FALSE(u == v);
EXPECT_FALSE(u > v);
EXPECT_FALSE(u >= v);
EXPECT_FALSE(v < u);
EXPECT_FALSE(v <= u);
EXPECT_TRUE(v != u);
EXPECT_FALSE(v == u);
EXPECT_TRUE(v > u);
EXPECT_TRUE(v >= u);
EXPECT_TRUE(u == u);
EXPECT_TRUE(v == v);
EXPECT_TRUE(smaller < larger);
EXPECT_TRUE(smaller <= larger);
EXPECT_TRUE(smaller != larger);
EXPECT_FALSE(smaller == larger);
EXPECT_FALSE(smaller > larger);
EXPECT_FALSE(smaller >= larger);
EXPECT_FALSE(larger < smaller);
EXPECT_FALSE(larger <= smaller);
EXPECT_TRUE(larger != smaller);
EXPECT_FALSE(larger == smaller);
EXPECT_TRUE(larger > smaller);
EXPECT_TRUE(larger >= smaller);
EXPECT_TRUE(smaller == smaller);
EXPECT_TRUE(larger == larger);
}
}
{
static constexpr std::array<std::pair<std::string_view, std::string_view>, 6> kTestArgs{
{
{"000000000000000000000000", "000000000000000000000001"},
{"000000000000000000000000", "ffffffffffffffffffffffff"},
{"0123456789ab0123456789ab", "123456789abc123456789abc"},
{"555555555555555555555555", "55555555555a555555555555"},
{"aaaaaaaaaaaaaaa9aaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaa"},
{"fffffffffffffffffffffffe", "ffffffffffffffffffffffff"},
}};
static constexpr auto kTestArgs = std::to_array<HexPair>({
{"000000000000000000000000", "000000000000000000000001"},
{"000000000000000000000000", "ffffffffffffffffffffffff"},
{"0123456789ab0123456789ab", "123456789abc123456789abc"},
{"555555555555555555555555", "55555555555a555555555555"},
{"aaaaaaaaaaaaaaa9aaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaa"},
{"fffffffffffffffffffffffe", "ffffffffffffffffffffffff"},
});
for (auto const& arg : kTestArgs)
for (auto const& [smallerText, largerText] : kTestArgs)
{
xrpl::BaseUInt<96> const u{arg.first}, v{arg.second};
EXPECT_TRUE(u < v);
EXPECT_TRUE(u <= v);
EXPECT_TRUE(u != v);
EXPECT_FALSE(u == v);
EXPECT_FALSE(u > v);
EXPECT_FALSE(u >= v);
EXPECT_FALSE(v < u);
EXPECT_FALSE(v <= u);
EXPECT_TRUE(v != u);
EXPECT_FALSE(v == u);
EXPECT_TRUE(v > u);
EXPECT_TRUE(v >= u);
EXPECT_TRUE(u == u);
EXPECT_TRUE(v == v);
xrpl::BaseUInt<96> const smaller{smallerText}, larger{largerText};
EXPECT_TRUE(smaller < larger);
EXPECT_TRUE(smaller <= larger);
EXPECT_TRUE(smaller != larger);
EXPECT_FALSE(smaller == larger);
EXPECT_FALSE(smaller > larger);
EXPECT_FALSE(smaller >= larger);
EXPECT_FALSE(larger < smaller);
EXPECT_FALSE(larger <= smaller);
EXPECT_TRUE(larger != smaller);
EXPECT_FALSE(larger == smaller);
EXPECT_TRUE(larger > smaller);
EXPECT_TRUE(larger >= smaller);
EXPECT_TRUE(smaller == smaller);
EXPECT_TRUE(larger == larger);
}
}
}
@@ -401,14 +403,14 @@ TEST_F(BaseUintTest, base_uint)
{
}
};
constexpr StrBaseUInt kTestCases[] = {
constexpr auto kTestCases = std::to_array<StrBaseUInt>({
"000000000000000000000000",
"000000000000000000000001",
"fedcba9876543210ABCDEF91",
"19FEDCBA0123456789abcdef",
"800000000000000000000000",
"fFfFfFfFfFfFfFfFfFfFfFfF",
};
});
for (StrBaseUInt const& t : kTestCases)
{

View File

@@ -19,11 +19,11 @@ struct JoinTest : public ::testing::Test
TEST_F(JoinTest, join)
{
auto test = [](auto collectionanddelimiter, std::string expected) {
auto test = [](auto collectionAndDelimiter, std::string expected) {
std::stringstream ss;
// Put something else in the buffer before and after to ensure that
// the << operator returns the stream correctly.
ss << "(" << collectionanddelimiter << ")";
ss << "(" << collectionAndDelimiter << ")";
auto const str = ss.str();
EXPECT_EQ(str.substr(1, str.length() - 2), expected);
EXPECT_EQ(str.front(), '(');

View File

@@ -69,7 +69,7 @@ TEST(CensorshipDetectorTest, censorship_detector)
runRound(cdet, ++round, {23, 24, 25, 26}, {25, 27}, {23, 26}, {24});
runRound(cdet, ++round, {23, 26, 28}, {26, 28}, {23}, {});
for (int i = 0; i != 10; ++i)
for (auto i = 0uz; i != 10; ++i)
runRound(cdet, ++round, {23}, {}, {23}, {});
runRound(cdet, ++round, {23, 29}, {29}, {23}, {});

View File

@@ -118,9 +118,9 @@ public:
std::vector<ForkInfo> res;
// Loop over all pairs of uniqueUNLs
for (int i = 0; i < uniqueUNLs.size(); ++i)
for (auto i = 0uz; i < uniqueUNLs.size(); ++i)
{
for (int j = (i + 1); j < uniqueUNLs.size(); ++j)
for (auto j = i + 1; j < uniqueUNLs.size(); ++j)
{
auto const& unlA = uniqueUNLs[i];
auto const& unlB = uniqueUNLs[j];

View File

@@ -24,11 +24,12 @@ randomWeightedShuffle(std::vector<T> v, std::vector<double> w, G& g)
{
using std::swap;
for (int i = 0; i < v.size() - 1; ++i)
for (auto i = 0uz; i + 1 < v.size(); ++i)
{
// pick a random item weighted by w
std::discrete_distribution<> dd(w.begin() + i, w.end()); // NOLINT(misc-const-correctness)
auto idx = dd(g);
// Pick a random item from the unplaced tail, weighted by w.
// NOLINTNEXTLINE(misc-const-correctness)
std::discrete_distribution<std::size_t> dd(w.begin() + i, w.end());
auto const idx = i + dd(g);
std::swap(v[i], v[idx]);
std::swap(w[i], w[idx]);
}

View File

@@ -27,11 +27,11 @@ namespace {
std::vector<std::string>
allBackends()
{
std::vector<std::string> types{"memory", "nudb"};
#if XRPL_ROCKSDB_AVAILABLE
types.emplace_back("rocksdb");
return {"memory", "nudb", "rocksdb"};
#else
return {"memory", "nudb"};
#endif
return types;
}
std::vector<std::string>

View File

@@ -17,9 +17,12 @@
#include <gtest/gtest.h>
#include <helpers/TestSink.h>
#include <algorithm>
#include <chrono>
#include <cstdint>
#include <ranges>
#include <string>
#include <utility>
namespace xrpl::Resource {
@@ -54,9 +57,10 @@ protected:
//--------------------------------------------------------------------------
static void
populateGossip(Gossip& gossip)
static Gossip
makeGossip()
{
Gossip gossip;
std::uint8_t const v(10 + randInt(9));
std::uint8_t const n(10 + randInt(9));
gossip.items.reserve(n);
@@ -71,8 +75,9 @@ protected:
static_cast<std::uint8_t>(v + i),
}};
item.address = beast::IP::Endpoint{beast::IP::AddressV4{d}};
gossip.items.push_back(item);
gossip.items.push_back(std::move(item));
}
return gossip;
}
};
@@ -87,8 +92,8 @@ TEST_F(ResourceManagerTest, limited_warn_drop)
Consumer c{logic.newInboundEndpoint(addr)};
// Create load until we get a warning
int n = 10000;
bool warned = false;
auto n = 10000;
auto warned = false;
while (--n >= 0)
{
@@ -97,7 +102,7 @@ TEST_F(ResourceManagerTest, limited_warn_drop)
warned = true;
break;
}
++logic.clock();
logic.advance();
}
ASSERT_TRUE(warned) << "Loop count exceeded without warning";
@@ -113,7 +118,7 @@ TEST_F(ResourceManagerTest, limited_warn_drop)
EXPECT_TRUE(c.disconnect(j_));
break;
}
++logic.clock();
logic.advance();
}
ASSERT_TRUE(dropped) << "Loop count exceeded without dropping";
@@ -135,7 +140,7 @@ TEST_F(ResourceManagerTest, limited_warn_drop)
auto n = kSecondsUntilExpiration + 1s;
while (--n > 0s)
{
++logic.clock();
logic.advance();
logic.periodicActivity();
Consumer const c{logic.newInboundEndpoint(addr)};
if (c.disposition() != Disposition::Drop)
@@ -167,7 +172,7 @@ TEST_F(ResourceManagerTest, unlimited_warn_drop)
warned = true;
break;
}
++logic.clock();
logic.advance();
}
EXPECT_FALSE(warned) << "Should loop forever with no warning";
@@ -175,6 +180,8 @@ TEST_F(ResourceManagerTest, unlimited_warn_drop)
TEST_F(ResourceManagerTest, charges)
{
static constexpr auto kDecayTicks = 128uz;
TestLogic logic{j_};
{
@@ -183,7 +190,7 @@ TEST_F(ResourceManagerTest, charges)
Charge const fee{1000};
JLOG(j_.info()) << "Charging " << c.toString() << " " << fee << " per second";
c.charge(fee);
for (int i = 0; i < 128; ++i)
for (auto tick = 0uz; tick < kDecayTicks; ++tick)
{
JLOG(j_.info()) << "Time= " << logic.clock().now().time_since_epoch().count()
<< ", Balance = " << c.balance();
@@ -196,7 +203,7 @@ TEST_F(ResourceManagerTest, charges)
Consumer c{logic.newInboundEndpoint(address)};
Charge const fee{1000};
JLOG(j_.info()) << "Charging " << c.toString() << " " << fee << " per second";
for (int i = 0; i < 128; ++i)
for (auto tick = 0uz; tick < kDecayTicks; ++tick)
{
c.charge(fee);
JLOG(j_.info()) << "Time= " << logic.clock().now().time_since_epoch().count()
@@ -210,13 +217,10 @@ TEST_F(ResourceManagerTest, imports)
{
TestLogic logic{j_};
Gossip g[5];
for (auto& i : g)
populateGossip(i);
for (int i = 0; i < 5; ++i)
logic.importConsumers(std::to_string(i), g[i]);
static constexpr auto kGossipSources = 5uz;
std::ranges::for_each(std::views::iota(0uz, kGossipSources), [&](auto const i) {
logic.importConsumers(std::to_string(i), makeGossip());
});
}
TEST_F(ResourceManagerTest, import)
@@ -233,7 +237,7 @@ TEST_F(ResourceManagerTest, import)
1,
}};
item.address = beast::IP::Endpoint{beast::IP::AddressV4{d}};
g.items.push_back(item);
g.items.push_back(std::move(item));
logic.importConsumers("g", g);
}

View File

@@ -257,12 +257,9 @@ TEST_P(SHAMapTest, add_traverse_snapshot_build_tear_and_iterate)
map.invariants();
}
int h = 7;
auto keyIndex = kKeys.size();
for (auto const& k : map)
{
EXPECT_EQ(k.key(), kKeys[h]);
--h;
}
EXPECT_EQ(k.key(), kKeys[--keyIndex]);
}
}
@@ -288,7 +285,11 @@ TEST_F(SHAMapPathProof, verify_proof_path)
uint256 rootHash;
std::vector<Blob> goodPath;
for (unsigned char c = 1; c < 100; ++c)
static constexpr unsigned char kFirstKey = 1;
static constexpr unsigned char kKeyCount = 100;
static constexpr unsigned char kLastKey = kKeyCount - 1;
for (unsigned char c = kFirstKey; c < kKeyCount; ++c)
{
uint256 k(c);
map.addItem(SHAMapNodeType::TnAccountState, makeShamapitem(k, Slice{k.data(), k.size()}));
@@ -304,7 +305,7 @@ TEST_F(SHAMapPathProof, verify_proof_path)
auto& proofPath = *path;
EXPECT_TRUE(map.verifyProofPath(root, k, proofPath));
if (c == 1)
if (c == kFirstKey)
{
// extra node
proofPath.insert(proofPath.begin(), proofPath.front());
@@ -313,7 +314,7 @@ TEST_F(SHAMapPathProof, verify_proof_path)
uint256 const wrongKey(c + 1);
EXPECT_FALSE(map.getProofPath(wrongKey));
}
if (c == 99)
if (c == kLastKey)
{
key = k;
rootHash = root;

View File

@@ -17,6 +17,7 @@
#include <shamap/common.h>
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <list>
#include <utility>
@@ -33,15 +34,17 @@ protected:
boost::intrusive_ptr<SHAMapItem>
makeRandomAS()
{
static constexpr auto kWordsPerState = 3uz;
Serializer s;
for (int d = 0; d < 3; ++d)
for (auto word = 0uz; word < kWordsPerState; ++word)
s.add32(randInt<std::uint32_t>(eng_));
return makeShamapitem(s.getSHA512Half(), s.slice());
}
bool
confuseMap(SHAMap& map, int count)
confuseMap(SHAMap& map, std::size_t count)
{
// add a bunch of random states to a map, then remove them
// map should be the same
@@ -49,7 +52,7 @@ protected:
std::list<uint256> items;
for (int i = 0; i < count; ++i)
for (auto i = 0uz; i < count; ++i)
{
auto item = makeRandomAS();
items.push_back(item->key());
@@ -86,26 +89,30 @@ TEST_F(SHAMapSyncTest, sync)
SHAMap source{SHAMapType::FREE, f};
SHAMap destination{SHAMapType::FREE, f2};
int const items = 10000;
for (int i = 0; i < items; ++i)
static constexpr auto kItemCount = 10000uz;
static constexpr auto kInvariantInterval = 100uz;
static constexpr auto kNodesToConfuse = 500uz;
static constexpr auto kMaxNodesPerRequest = 2048;
for (auto i = 0uz; i < kItemCount; ++i)
{
source.addItem(SHAMapNodeType::TnAccountState, makeRandomAS());
if (i % 100 == 0)
if (i % kInvariantInterval == 0)
source.invariants();
}
source.invariants();
ASSERT_TRUE(confuseMap(source, 500));
ASSERT_TRUE(confuseMap(source, kNodesToConfuse));
source.invariants();
source.setImmutable();
int count = 0;
std::size_t count = 0;
source.visitLeaves([&count]([[maybe_unused]] auto const& item) { ++count; });
EXPECT_EQ(count, items);
EXPECT_EQ(count, kItemCount);
std::vector<SHAMapMissingNode> missingNodes;
source.walkMap(missingNodes, 2048);
source.walkMap(missingNodes, kMaxNodesPerRequest);
EXPECT_TRUE(missingNodes.empty());
destination.setSynching();
@@ -128,7 +135,7 @@ TEST_F(SHAMapSyncTest, sync)
f.clock().advance(std::chrono::seconds(1));
// get the list of nodes we know we need
auto nodesMissing = destination.getMissingNodes(2048, nullptr);
auto nodesMissing = destination.getMissingNodes(kMaxNodesPerRequest, nullptr);
if (nodesMissing.empty())
break;