mirror of
https://github.com/XRPLF/rippled.git
synced 2026-08-21 06:10:58 +00:00
chore: Gtest migration followups second pass (#7888)
This commit is contained in:
@@ -365,6 +365,7 @@ words:
|
||||
- xchain
|
||||
- ximinez
|
||||
- XMACRO
|
||||
- xored
|
||||
- xrpkuwait
|
||||
- xrpl
|
||||
- xrpld
|
||||
|
||||
@@ -44,6 +44,7 @@ setup_target_for_coverage_gcovr(
|
||||
EXCLUDE
|
||||
"src/test"
|
||||
"src/tests"
|
||||
"src/benchmarks"
|
||||
"include/xrpl/beast/test"
|
||||
"include/xrpl/beast/unit_test"
|
||||
"${CMAKE_BINARY_DIR}/pb-xrpl.libpb"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
@@ -156,6 +157,19 @@ public:
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* Set every byte in the buffer to the given value.
|
||||
*
|
||||
* The size is unchanged, and this is a no-op on an empty buffer.
|
||||
*
|
||||
* @param value the byte to write to every position.
|
||||
*/
|
||||
void
|
||||
fill(std::uint8_t value) noexcept
|
||||
{
|
||||
std::fill_n(p_.get(), size_, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the buffer.
|
||||
* All memory is deallocated. The resulting size is 0.
|
||||
|
||||
@@ -41,10 +41,11 @@ struct RunState
|
||||
release()
|
||||
{
|
||||
harness.reset();
|
||||
Batch{}.swap(present);
|
||||
Batch{}.swap(recent);
|
||||
std::vector<uint256>{}.swap(missing);
|
||||
std::vector<std::size_t>{}.swap(shuffle);
|
||||
present = Batch{};
|
||||
recent = Batch{};
|
||||
missing = std::vector<uint256>{};
|
||||
shuffle = std::vector<std::size_t>{};
|
||||
avgPayload = 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -239,9 +240,13 @@ registerWorkload(BackendConfig const& bc, Workload const& w)
|
||||
if (!w.pinToPool)
|
||||
{
|
||||
auto rs = std::make_shared<RunState>();
|
||||
auto* b = benchmark::RegisterBenchmark(name, makeRunner(w, cfg, rs));
|
||||
b->RangeMultiplier(10)->Range(kPoolSizes.front(), kPoolSizes.back());
|
||||
b->Threads(1)->Threads(4)->Threads(8)->UseRealTime();
|
||||
benchmark::RegisterBenchmark(name, makeRunner(w, cfg, rs))
|
||||
->RangeMultiplier(10)
|
||||
->Range(kPoolSizes.front(), kPoolSizes.back())
|
||||
->Threads(1)
|
||||
->Threads(4)
|
||||
->Threads(8)
|
||||
->UseRealTime();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -297,12 +297,11 @@ struct BackendConfig
|
||||
inline std::vector<BackendConfig> const&
|
||||
backendConfigs()
|
||||
{
|
||||
// Use factory settings for each DB
|
||||
static std::vector<BackendConfig> const kConfigs = {
|
||||
{.name = "nudb", .config = "type=nudb"},
|
||||
#if XRPL_ROCKSDB_AVAILABLE
|
||||
{.name = "rocksdb",
|
||||
.config = "type=rocksdb,open_files=2000,filter_bits=12,cache_mb=256,"
|
||||
"file_size_mb=8,file_size_mult=2"},
|
||||
{.name = "rocksdb", .config = "type=rocksdb"},
|
||||
#endif
|
||||
};
|
||||
return kConfigs;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
@@ -12,8 +13,18 @@
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
static_assert(std::is_nothrow_move_constructible_v<Buffer>);
|
||||
static_assert(std::is_nothrow_move_assignable_v<Buffer>);
|
||||
|
||||
struct BufferTest : public ::testing::Test
|
||||
{
|
||||
static constexpr auto kRandomData = std::to_array<std::uint8_t>(
|
||||
{0xa8, 0xa1, 0x38, 0x45, 0x23, 0xec, 0xe4, 0x23, 0x71, 0x6d, 0x2a,
|
||||
0x18, 0xb4, 0x70, 0xcb, 0xf5, 0xac, 0x2d, 0x89, 0x4d, 0x19, 0x9c,
|
||||
0xf0, 0x2c, 0x15, 0xd1, 0xf9, 0x9b, 0x66, 0xd2, 0x30, 0xd3});
|
||||
|
||||
static constexpr std::size_t kHalf = kRandomData.size() / 2;
|
||||
|
||||
static bool
|
||||
sane(Buffer const& b)
|
||||
{
|
||||
@@ -22,239 +33,321 @@ struct BufferTest : public ::testing::Test
|
||||
|
||||
return b.data() != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the state Buffer documents for a moved-from buffer: "the other buffer is reset", i.e.
|
||||
* empty and sane.
|
||||
*
|
||||
* Zeroing the size is not incidental tidiness. Moving the member unique_ptr nulls the data
|
||||
* pointer whether Buffer wants it or not, so a moved-from buffer that kept its old size would
|
||||
* lie about itself everywhere: alloc() would take its `n == size_` early-out and hand back a
|
||||
* null pointer while still reporting the old size, fill() would run std::fill_n over a null
|
||||
* pointer, and the Slice conversion would publish {nullptr, oldSize} to callers. A moved-from
|
||||
* Buffer has to be a usable empty Buffer rather than a landmine, which is why the tests below
|
||||
* assert this state instead of treating a moved-from buffer as untouchable.
|
||||
*/
|
||||
static void
|
||||
checkEmptyAfterMove(Buffer const& buf)
|
||||
{
|
||||
EXPECT_TRUE(sane(buf));
|
||||
EXPECT_TRUE(buf.empty());
|
||||
}
|
||||
|
||||
Buffer const emptyBuffer;
|
||||
Buffer const firstHalf{kRandomData.data(), kHalf};
|
||||
Buffer const secondHalf{kRandomData.data() + kHalf, kHalf};
|
||||
Buffer const whole{kRandomData.data(), kRandomData.size()};
|
||||
};
|
||||
|
||||
TEST_F(BufferTest, buffer)
|
||||
TEST_F(BufferTest, default_constructed_is_empty)
|
||||
{
|
||||
std::uint8_t const data[] = {0xa8, 0xa1, 0x38, 0x45, 0x23, 0xec, 0xe4, 0x23, 0x71, 0x6d, 0x2a,
|
||||
0x18, 0xb4, 0x70, 0xcb, 0xf5, 0xac, 0x2d, 0x89, 0x4d, 0x19, 0x9c,
|
||||
0xf0, 0x2c, 0x15, 0xd1, 0xf9, 0x9b, 0x66, 0xd2, 0x30, 0xd3};
|
||||
Buffer const b;
|
||||
|
||||
Buffer const b0;
|
||||
EXPECT_TRUE(sane(b0));
|
||||
EXPECT_TRUE(b0.empty());
|
||||
EXPECT_TRUE(sane(b));
|
||||
EXPECT_TRUE(b.empty());
|
||||
EXPECT_EQ(b.data(), nullptr);
|
||||
}
|
||||
|
||||
Buffer b1{0};
|
||||
EXPECT_TRUE(sane(b1));
|
||||
EXPECT_TRUE(b1.empty());
|
||||
std::memcpy(b1.alloc(16), data, 16);
|
||||
EXPECT_TRUE(sane(b1));
|
||||
EXPECT_FALSE(b1.empty());
|
||||
EXPECT_EQ(b1.size(), 16);
|
||||
TEST_F(BufferTest, zero_sized_construction_is_empty)
|
||||
{
|
||||
Buffer const b{0};
|
||||
|
||||
Buffer b2{b1.size()};
|
||||
EXPECT_TRUE(sane(b2));
|
||||
EXPECT_FALSE(b2.empty());
|
||||
EXPECT_EQ(b2.size(), b1.size());
|
||||
std::memcpy(b2.data(), data + 16, 16);
|
||||
EXPECT_TRUE(sane(b));
|
||||
EXPECT_TRUE(b.empty());
|
||||
}
|
||||
|
||||
Buffer b3{data, sizeof(data)};
|
||||
EXPECT_TRUE(sane(b3));
|
||||
EXPECT_FALSE(b3.empty());
|
||||
EXPECT_EQ(b3.size(), sizeof(data));
|
||||
EXPECT_EQ(std::memcmp(b3.data(), data, b3.size()), 0);
|
||||
TEST_F(BufferTest, alloc_grows_an_empty_buffer)
|
||||
{
|
||||
Buffer b{0};
|
||||
std::memcpy(b.alloc(kHalf), kRandomData.data(), kHalf);
|
||||
|
||||
// Check equality and inequality comparisons.
|
||||
// For code readability, we want to use general
|
||||
// EXPECT_TRUE instead of specific EXPECT_EQ etc.
|
||||
EXPECT_TRUE(b0 == b0);
|
||||
EXPECT_TRUE(b0 != b1);
|
||||
EXPECT_TRUE(b1 == b1);
|
||||
EXPECT_TRUE(b1 != b2);
|
||||
EXPECT_TRUE(b2 != b3);
|
||||
EXPECT_TRUE(sane(b));
|
||||
EXPECT_FALSE(b.empty());
|
||||
EXPECT_EQ(b.size(), kHalf);
|
||||
EXPECT_EQ(b, firstHalf);
|
||||
}
|
||||
|
||||
// Check copy constructors and copy assignments:
|
||||
{
|
||||
Buffer x{b0};
|
||||
EXPECT_EQ(x, b0);
|
||||
EXPECT_TRUE(sane(x));
|
||||
Buffer y{b1};
|
||||
EXPECT_EQ(y, b1);
|
||||
EXPECT_TRUE(sane(y));
|
||||
x = b2;
|
||||
EXPECT_EQ(x, b2);
|
||||
EXPECT_TRUE(sane(x));
|
||||
x = y;
|
||||
EXPECT_EQ(x, y);
|
||||
EXPECT_TRUE(sane(x));
|
||||
y = b3;
|
||||
EXPECT_EQ(y, b3);
|
||||
EXPECT_TRUE(sane(y));
|
||||
x = b0;
|
||||
EXPECT_EQ(x, b0);
|
||||
EXPECT_TRUE(sane(x));
|
||||
TEST_F(BufferTest, sized_construction_reserves_without_filling)
|
||||
{
|
||||
Buffer b{kHalf};
|
||||
|
||||
EXPECT_TRUE(sane(b));
|
||||
EXPECT_FALSE(b.empty());
|
||||
EXPECT_EQ(b.size(), kHalf);
|
||||
|
||||
std::memcpy(b.data(), kRandomData.data() + kHalf, kHalf);
|
||||
EXPECT_EQ(b, secondHalf);
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, construction_copies_raw_memory)
|
||||
{
|
||||
Buffer const b{kRandomData.data(), kRandomData.size()};
|
||||
|
||||
EXPECT_TRUE(sane(b));
|
||||
EXPECT_FALSE(b.empty());
|
||||
EXPECT_EQ(b.size(), kRandomData.size());
|
||||
EXPECT_EQ(std::memcmp(b.data(), kRandomData.data(), b.size()), 0);
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, equality_compares_contents)
|
||||
{
|
||||
// Uses EXPECT_TRUE rather than EXPECT_EQ/EXPECT_NE because the operators are what is under test
|
||||
// here.
|
||||
EXPECT_TRUE(emptyBuffer == emptyBuffer);
|
||||
EXPECT_TRUE(firstHalf == firstHalf);
|
||||
|
||||
EXPECT_TRUE(emptyBuffer != firstHalf);
|
||||
EXPECT_TRUE(firstHalf != secondHalf);
|
||||
EXPECT_TRUE(secondHalf != whole);
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, copy_construction)
|
||||
{
|
||||
Buffer const fromEmpty{emptyBuffer};
|
||||
EXPECT_TRUE(sane(fromEmpty));
|
||||
EXPECT_EQ(fromEmpty, emptyBuffer);
|
||||
|
||||
Buffer const fromNonEmpty{firstHalf};
|
||||
EXPECT_TRUE(sane(fromNonEmpty));
|
||||
EXPECT_EQ(fromNonEmpty, firstHalf);
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, copy_assignment)
|
||||
{
|
||||
Buffer b{emptyBuffer};
|
||||
|
||||
// empty <- non-empty
|
||||
b = secondHalf;
|
||||
EXPECT_TRUE(sane(b));
|
||||
EXPECT_EQ(b, secondHalf);
|
||||
|
||||
// non-empty <- non-empty of a different size
|
||||
b = whole;
|
||||
EXPECT_TRUE(sane(b));
|
||||
EXPECT_EQ(b, whole);
|
||||
|
||||
// non-empty <- empty
|
||||
b = emptyBuffer;
|
||||
EXPECT_TRUE(sane(b));
|
||||
EXPECT_EQ(b, emptyBuffer);
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, self_assignment_preserves_contents)
|
||||
{
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wself-assign-overloaded"
|
||||
#endif
|
||||
|
||||
x = x;
|
||||
EXPECT_EQ(x, b0);
|
||||
EXPECT_TRUE(sane(x));
|
||||
y = y;
|
||||
EXPECT_EQ(y, b3);
|
||||
EXPECT_TRUE(sane(y));
|
||||
Buffer emptyCopy{emptyBuffer};
|
||||
emptyCopy = emptyCopy;
|
||||
EXPECT_TRUE(sane(emptyCopy));
|
||||
EXPECT_EQ(emptyCopy, emptyBuffer);
|
||||
|
||||
Buffer wholeCopy{whole};
|
||||
wholeCopy = wholeCopy;
|
||||
EXPECT_TRUE(sane(wholeCopy));
|
||||
EXPECT_EQ(wholeCopy, whole);
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Check move constructor & move assignments:
|
||||
TEST_F(BufferTest, move_construct_from_empty)
|
||||
{
|
||||
Buffer source;
|
||||
Buffer const moved{std::move(source)};
|
||||
|
||||
checkEmptyAfterMove(source); // NOLINT(bugprone-use-after-move)
|
||||
EXPECT_TRUE(sane(moved));
|
||||
EXPECT_TRUE(moved.empty());
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, move_construct_from_non_empty)
|
||||
{
|
||||
Buffer source{firstHalf};
|
||||
Buffer const moved{std::move(source)};
|
||||
|
||||
checkEmptyAfterMove(source); // NOLINT(bugprone-use-after-move)
|
||||
EXPECT_TRUE(sane(moved));
|
||||
EXPECT_EQ(moved, firstHalf);
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, move_assign_empty_to_empty)
|
||||
{
|
||||
Buffer target;
|
||||
Buffer source;
|
||||
|
||||
target = std::move(source);
|
||||
|
||||
EXPECT_TRUE(sane(target));
|
||||
EXPECT_TRUE(target.empty());
|
||||
checkEmptyAfterMove(source); // NOLINT(bugprone-use-after-move)
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, move_assign_non_empty_to_empty)
|
||||
{
|
||||
Buffer target;
|
||||
Buffer source{firstHalf};
|
||||
|
||||
target = std::move(source);
|
||||
|
||||
EXPECT_TRUE(sane(target));
|
||||
EXPECT_EQ(target, firstHalf);
|
||||
checkEmptyAfterMove(source); // NOLINT(bugprone-use-after-move)
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, move_assign_empty_to_non_empty)
|
||||
{
|
||||
Buffer target{firstHalf};
|
||||
Buffer source;
|
||||
|
||||
target = std::move(source);
|
||||
|
||||
EXPECT_TRUE(sane(target));
|
||||
EXPECT_TRUE(target.empty());
|
||||
checkEmptyAfterMove(source); // NOLINT(bugprone-use-after-move)
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, move_assign_non_empty_to_non_empty)
|
||||
{
|
||||
Buffer target{firstHalf};
|
||||
Buffer sameSize{secondHalf};
|
||||
Buffer largerSize{whole};
|
||||
|
||||
target = std::move(sameSize);
|
||||
EXPECT_TRUE(sane(target));
|
||||
EXPECT_EQ(target, secondHalf);
|
||||
checkEmptyAfterMove(sameSize); // NOLINT(bugprone-use-after-move)
|
||||
|
||||
target = std::move(largerSize);
|
||||
EXPECT_TRUE(sane(target));
|
||||
EXPECT_EQ(target, whole);
|
||||
checkEmptyAfterMove(largerSize); // NOLINT(bugprone-use-after-move)
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, construction_from_slice)
|
||||
{
|
||||
Buffer const fromEmpty{static_cast<Slice>(emptyBuffer)};
|
||||
EXPECT_TRUE(sane(fromEmpty));
|
||||
EXPECT_EQ(fromEmpty, emptyBuffer);
|
||||
|
||||
Buffer const fromNonEmpty{static_cast<Slice>(whole)};
|
||||
EXPECT_TRUE(sane(fromNonEmpty));
|
||||
EXPECT_EQ(fromNonEmpty, whole);
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, assignment_from_slice)
|
||||
{
|
||||
Buffer b;
|
||||
|
||||
// empty <- empty slice
|
||||
b = static_cast<Slice>(emptyBuffer);
|
||||
EXPECT_TRUE(sane(b));
|
||||
EXPECT_EQ(b, emptyBuffer);
|
||||
|
||||
// empty <- non-empty slice
|
||||
b = static_cast<Slice>(firstHalf);
|
||||
EXPECT_TRUE(sane(b));
|
||||
EXPECT_EQ(b, firstHalf);
|
||||
|
||||
// non-empty <- non-empty slice
|
||||
b = static_cast<Slice>(secondHalf);
|
||||
EXPECT_TRUE(sane(b));
|
||||
EXPECT_EQ(b, secondHalf);
|
||||
|
||||
// non-empty <- empty slice
|
||||
b = static_cast<Slice>(emptyBuffer);
|
||||
EXPECT_TRUE(sane(b));
|
||||
EXPECT_EQ(b, emptyBuffer);
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, resize_allocates_and_clear_releases)
|
||||
{
|
||||
auto check = [](Buffer const& original, std::size_t size) {
|
||||
SCOPED_TRACE(::testing::Message() << "size: " << size);
|
||||
|
||||
Buffer b{original};
|
||||
|
||||
// Resizing to zero is equivalent to clearing.
|
||||
b(size);
|
||||
EXPECT_TRUE(sane(b));
|
||||
EXPECT_EQ(b.size(), size);
|
||||
EXPECT_EQ(b.data() == nullptr, size == 0);
|
||||
|
||||
b(size + 1);
|
||||
EXPECT_TRUE(sane(b));
|
||||
EXPECT_EQ(b.size(), size + 1);
|
||||
EXPECT_NE(b.data(), nullptr);
|
||||
|
||||
b.clear();
|
||||
EXPECT_TRUE(sane(b));
|
||||
EXPECT_TRUE(b.empty());
|
||||
EXPECT_EQ(b.data(), nullptr);
|
||||
|
||||
// clear() is idempotent.
|
||||
b.clear();
|
||||
EXPECT_TRUE(sane(b));
|
||||
EXPECT_TRUE(b.empty());
|
||||
EXPECT_EQ(b.data(), nullptr);
|
||||
};
|
||||
|
||||
for (auto size = 0uz; size < kHalf; ++size)
|
||||
{
|
||||
static_assert(std::is_nothrow_move_constructible_v<Buffer>);
|
||||
static_assert(std::is_nothrow_move_assignable_v<Buffer>);
|
||||
|
||||
{ // Move-construct from empty buf
|
||||
Buffer x;
|
||||
Buffer const y{std::move(x)};
|
||||
EXPECT_TRUE(sane(x)); // NOLINT(bugprone-use-after-move)
|
||||
EXPECT_TRUE(x.empty()); // NOLINT(bugprone-use-after-move)
|
||||
EXPECT_TRUE(sane(y));
|
||||
EXPECT_TRUE(y.empty());
|
||||
EXPECT_EQ(x, y); // NOLINT(bugprone-use-after-move)
|
||||
}
|
||||
|
||||
{ // Move-construct from non-empty buf
|
||||
Buffer x{b1};
|
||||
Buffer const y{std::move(x)};
|
||||
EXPECT_TRUE(sane(x)); // NOLINT(bugprone-use-after-move)
|
||||
EXPECT_TRUE(x.empty()); // NOLINT(bugprone-use-after-move)
|
||||
EXPECT_TRUE(sane(y));
|
||||
EXPECT_EQ(y, b1);
|
||||
}
|
||||
|
||||
{ // Move assign empty buf to empty buf
|
||||
Buffer x;
|
||||
Buffer y;
|
||||
|
||||
x = std::move(y);
|
||||
EXPECT_TRUE(sane(x));
|
||||
EXPECT_TRUE(x.empty());
|
||||
EXPECT_TRUE(sane(y)); // NOLINT(bugprone-use-after-move)
|
||||
EXPECT_TRUE(y.empty()); // NOLINT(bugprone-use-after-move)
|
||||
}
|
||||
|
||||
{ // Move assign non-empty buf to empty buf
|
||||
Buffer x;
|
||||
Buffer y{b1};
|
||||
|
||||
x = std::move(y);
|
||||
EXPECT_TRUE(sane(x));
|
||||
EXPECT_EQ(x, b1);
|
||||
EXPECT_TRUE(sane(y)); // NOLINT(bugprone-use-after-move)
|
||||
EXPECT_TRUE(y.empty()); // NOLINT(bugprone-use-after-move)
|
||||
}
|
||||
|
||||
{ // Move assign empty buf to non-empty buf
|
||||
Buffer x{b1};
|
||||
Buffer y;
|
||||
|
||||
x = std::move(y);
|
||||
EXPECT_TRUE(sane(x));
|
||||
EXPECT_TRUE(x.empty());
|
||||
EXPECT_TRUE(sane(y)); // NOLINT(bugprone-use-after-move)
|
||||
EXPECT_TRUE(y.empty()); // NOLINT(bugprone-use-after-move)
|
||||
}
|
||||
|
||||
{ // Move assign non-empty buf to non-empty buf
|
||||
Buffer x{b1};
|
||||
Buffer y{b2};
|
||||
Buffer z{b3};
|
||||
|
||||
x = std::move(y);
|
||||
EXPECT_TRUE(sane(x));
|
||||
EXPECT_FALSE(x.empty());
|
||||
EXPECT_TRUE(sane(y)); // NOLINT(bugprone-use-after-move)
|
||||
EXPECT_TRUE(y.empty()); // NOLINT(bugprone-use-after-move)
|
||||
|
||||
x = std::move(z);
|
||||
EXPECT_TRUE(sane(x));
|
||||
EXPECT_FALSE(x.empty());
|
||||
EXPECT_TRUE(sane(z)); // NOLINT(bugprone-use-after-move)
|
||||
EXPECT_TRUE(z.empty()); // NOLINT(bugprone-use-after-move)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Buffer w{static_cast<Slice>(b0)};
|
||||
EXPECT_TRUE(sane(w));
|
||||
EXPECT_EQ(w, b0);
|
||||
|
||||
Buffer x{static_cast<Slice>(b1)};
|
||||
EXPECT_TRUE(sane(x));
|
||||
EXPECT_EQ(x, b1);
|
||||
|
||||
Buffer y{static_cast<Slice>(b2)};
|
||||
EXPECT_TRUE(sane(y));
|
||||
EXPECT_EQ(y, b2);
|
||||
|
||||
Buffer z{static_cast<Slice>(b3)};
|
||||
EXPECT_TRUE(sane(z));
|
||||
EXPECT_EQ(z, b3);
|
||||
|
||||
// Assign empty slice to empty buffer
|
||||
w = static_cast<Slice>(b0);
|
||||
EXPECT_TRUE(sane(w));
|
||||
EXPECT_EQ(w, b0);
|
||||
|
||||
// Assign non-empty slice to empty buffer
|
||||
w = static_cast<Slice>(b1);
|
||||
EXPECT_TRUE(sane(w));
|
||||
EXPECT_EQ(w, b1);
|
||||
|
||||
// Assign non-empty slice to non-empty buffer
|
||||
x = static_cast<Slice>(b2);
|
||||
EXPECT_TRUE(sane(x));
|
||||
EXPECT_EQ(x, b2);
|
||||
|
||||
// Assign non-empty slice to non-empty buffer
|
||||
y = static_cast<Slice>(z);
|
||||
EXPECT_TRUE(sane(y));
|
||||
EXPECT_EQ(y, z);
|
||||
|
||||
// Assign empty slice to non-empty buffer:
|
||||
z = static_cast<Slice>(b0);
|
||||
EXPECT_TRUE(sane(z));
|
||||
EXPECT_EQ(z, b0);
|
||||
}
|
||||
|
||||
{
|
||||
auto test = [](Buffer const& b, std::size_t i) {
|
||||
Buffer x{b};
|
||||
|
||||
// Try to allocate some number of bytes, possibly
|
||||
// zero (which means clear) and sanity check
|
||||
x(i);
|
||||
EXPECT_TRUE(sane(x));
|
||||
EXPECT_EQ(x.size(), i);
|
||||
EXPECT_EQ((x.data() == nullptr), (i == 0));
|
||||
|
||||
// Try to allocate some more data (always non-zero)
|
||||
x(i + 1);
|
||||
EXPECT_TRUE(sane(x));
|
||||
EXPECT_EQ(x.size(), i + 1);
|
||||
EXPECT_NE(x.data(), nullptr);
|
||||
|
||||
// Try to clear:
|
||||
x.clear();
|
||||
EXPECT_TRUE(sane(x));
|
||||
EXPECT_TRUE(x.empty());
|
||||
EXPECT_EQ(x.data(), nullptr);
|
||||
|
||||
// Try to clear again:
|
||||
x.clear();
|
||||
EXPECT_TRUE(sane(x));
|
||||
EXPECT_TRUE(x.empty());
|
||||
EXPECT_EQ(x.data(), nullptr);
|
||||
};
|
||||
|
||||
for (std::size_t i = 0; i < 16; ++i)
|
||||
{
|
||||
test(b0, i);
|
||||
test(b1, i);
|
||||
}
|
||||
check(emptyBuffer, size);
|
||||
check(firstHalf, size);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, fill_sets_every_byte)
|
||||
{
|
||||
Buffer b{4};
|
||||
b.fill(0xab);
|
||||
|
||||
EXPECT_EQ(b.size(), 4);
|
||||
for (auto const byte : Slice{b})
|
||||
EXPECT_EQ(byte, 0xab);
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, fill_overwrites_and_keeps_size)
|
||||
{
|
||||
Buffer b{4};
|
||||
b.fill(0xab);
|
||||
b.fill(0x00);
|
||||
|
||||
EXPECT_EQ(b.size(), 4);
|
||||
for (auto const byte : Slice{b})
|
||||
EXPECT_EQ(byte, 0x00);
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, fill_on_empty_buffer_is_a_noop)
|
||||
{
|
||||
Buffer empty;
|
||||
empty.fill(0xff);
|
||||
|
||||
EXPECT_TRUE(empty.empty());
|
||||
EXPECT_EQ(empty.data(), nullptr);
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
|
||||
@@ -92,6 +92,7 @@ public:
|
||||
static constexpr std::size_t kMaxStates = 128;
|
||||
static std::array<std::atomic<TrackedState>, kMaxStates> state;
|
||||
static std::atomic<std::size_t> nextId;
|
||||
|
||||
static TrackedState
|
||||
getState(std::size_t id)
|
||||
{
|
||||
@@ -100,13 +101,12 @@ public:
|
||||
|
||||
return state[id].load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
static void
|
||||
resetStates(bool resetCallback)
|
||||
{
|
||||
for (std::size_t i = 0; i < kMaxStates; ++i)
|
||||
{
|
||||
state[i].store(TrackedState::Uninitialized, std::memory_order_release);
|
||||
}
|
||||
nextId.store(0, std::memory_order_release);
|
||||
if (resetCallback)
|
||||
TIBase::tracingCallback = [](TrackedState, std::optional<TrackedState>) {};
|
||||
@@ -120,6 +120,7 @@ public:
|
||||
{
|
||||
TIBase::resetStates(resetCallback);
|
||||
}
|
||||
|
||||
~ResetStatesGuard()
|
||||
{
|
||||
TIBase::resetStates(resetCallback);
|
||||
@@ -130,6 +131,7 @@ public:
|
||||
{
|
||||
state[id].store(TrackedState::Alive, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
~TIBase() override
|
||||
{
|
||||
using enum TrackedState;
|
||||
@@ -218,9 +220,7 @@ TEST(IntrusiveSharedTest, basics)
|
||||
EXPECT_EQ(TIBase::getState(id), Alive);
|
||||
EXPECT_EQ(b->useCount(), 1);
|
||||
for (auto i = 0uz; i < 10; ++i)
|
||||
{
|
||||
strong.push_back(b);
|
||||
}
|
||||
b.reset();
|
||||
EXPECT_EQ(TIBase::getState(id), Alive);
|
||||
strong.resize(strong.size() - 1);
|
||||
@@ -244,8 +244,7 @@ TEST(IntrusiveSharedTest, basics)
|
||||
EXPECT_EQ(TIBase::getState(id), PartiallyDeleted);
|
||||
while (!weak.empty())
|
||||
{
|
||||
weak.resize(weak.size() - 1);
|
||||
if (!weak.empty())
|
||||
if (weak.resize(weak.size() - 1); !weak.empty())
|
||||
{
|
||||
EXPECT_EQ(TIBase::getState(id), PartiallyDeleted);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <boost/endian/detail/order.hpp>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <array>
|
||||
@@ -205,125 +206,119 @@ TEST_F(BaseUintTest, base_uint)
|
||||
Blob const raw{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||
EXPECT_EQ(BaseUInt96::kBytes, raw.size());
|
||||
|
||||
BaseUInt96 u = BaseUInt96::fromRaw(raw);
|
||||
uset.insert(u);
|
||||
EXPECT_EQ(raw.size(), u.size());
|
||||
EXPECT_EQ(to_string(u), "0102030405060708090A0B0C");
|
||||
EXPECT_EQ(toShortString(u), "01020304...");
|
||||
EXPECT_EQ(*u.data(), 1);
|
||||
EXPECT_EQ(u.signum(), 1);
|
||||
EXPECT_FALSE(!u);
|
||||
EXPECT_FALSE(u.isZero());
|
||||
EXPECT_TRUE(u.isNonZero());
|
||||
unsigned char t = 0;
|
||||
for (auto& d : u)
|
||||
{
|
||||
EXPECT_EQ(d, ++t);
|
||||
}
|
||||
BaseUInt96 ascending = BaseUInt96::fromRaw(raw);
|
||||
uset.insert(ascending);
|
||||
EXPECT_EQ(raw.size(), ascending.size());
|
||||
EXPECT_EQ(to_string(ascending), "0102030405060708090A0B0C");
|
||||
EXPECT_EQ(toShortString(ascending), "01020304...");
|
||||
EXPECT_EQ(*ascending.data(), 1);
|
||||
EXPECT_EQ(ascending.signum(), 1);
|
||||
EXPECT_FALSE(!ascending);
|
||||
EXPECT_FALSE(ascending.isZero());
|
||||
EXPECT_TRUE(ascending.isNonZero());
|
||||
unsigned char expectedByte = 0;
|
||||
for (auto& byte : ascending)
|
||||
EXPECT_EQ(byte, ++expectedByte);
|
||||
|
||||
// Test hash_append by "hashing" with a no-op hasher (h)
|
||||
// Test hash_append by "hashing" with a no-op hasher (hasher)
|
||||
// and then extracting the bytes that were written during hashing
|
||||
// back into another base_uint (w) for comparison with the original
|
||||
Nonhash<96> h{};
|
||||
hash_append(h, u);
|
||||
BaseUInt96 const w =
|
||||
BaseUInt96::fromRaw(std::vector<std::uint8_t>(h.data.begin(), h.data.end()));
|
||||
EXPECT_EQ(w, u);
|
||||
// back into another base_uint (rehashed) for comparison with the original
|
||||
Nonhash<96> hasher{};
|
||||
hash_append(hasher, ascending);
|
||||
BaseUInt96 const rehashed =
|
||||
BaseUInt96::fromRaw(std::vector<std::uint8_t>(hasher.data.begin(), hasher.data.end()));
|
||||
EXPECT_EQ(rehashed, ascending);
|
||||
|
||||
BaseUInt96 v{~u};
|
||||
uset.insert(v);
|
||||
EXPECT_EQ(to_string(v), "FEFDFCFBFAF9F8F7F6F5F4F3");
|
||||
EXPECT_EQ(toShortString(v), "FEFDFCFB...");
|
||||
EXPECT_EQ(*v.data(), 0xfe);
|
||||
EXPECT_EQ(v.signum(), 1);
|
||||
EXPECT_FALSE(!v);
|
||||
EXPECT_FALSE(v.isZero());
|
||||
EXPECT_TRUE(v.isNonZero());
|
||||
BaseUInt96 complement{~ascending};
|
||||
uset.insert(complement);
|
||||
EXPECT_EQ(to_string(complement), "FEFDFCFBFAF9F8F7F6F5F4F3");
|
||||
EXPECT_EQ(toShortString(complement), "FEFDFCFB...");
|
||||
EXPECT_EQ(*complement.data(), 0xfe);
|
||||
EXPECT_EQ(complement.signum(), 1);
|
||||
EXPECT_FALSE(!complement);
|
||||
EXPECT_FALSE(complement.isZero());
|
||||
EXPECT_TRUE(complement.isNonZero());
|
||||
|
||||
t = 0xff;
|
||||
for (auto& d : v)
|
||||
{
|
||||
EXPECT_EQ(d, --t);
|
||||
}
|
||||
expectedByte = 0xff;
|
||||
for (auto& byte : complement)
|
||||
EXPECT_EQ(byte, --expectedByte);
|
||||
|
||||
EXPECT_LT(u, v);
|
||||
EXPECT_GT(v, u);
|
||||
EXPECT_LT(ascending, complement);
|
||||
EXPECT_GT(complement, ascending);
|
||||
|
||||
v = u;
|
||||
EXPECT_EQ(v, u);
|
||||
complement = ascending;
|
||||
EXPECT_EQ(complement, ascending);
|
||||
|
||||
BaseUInt96 z{beast::kZero};
|
||||
uset.insert(z);
|
||||
EXPECT_EQ(to_string(z), "000000000000000000000000");
|
||||
EXPECT_EQ(toShortString(z), "00000000...");
|
||||
EXPECT_EQ(*z.data(), 0);
|
||||
EXPECT_EQ(*z.begin(), 0);
|
||||
EXPECT_EQ(*std::prev(z.end(), 1), 0);
|
||||
EXPECT_EQ(z.signum(), 0);
|
||||
EXPECT_TRUE(!z);
|
||||
EXPECT_TRUE(z.isZero());
|
||||
EXPECT_FALSE(z.isNonZero());
|
||||
for (auto& d : z)
|
||||
{
|
||||
EXPECT_EQ(d, 0);
|
||||
}
|
||||
BaseUInt96 zero{beast::kZero};
|
||||
uset.insert(zero);
|
||||
EXPECT_EQ(to_string(zero), "000000000000000000000000");
|
||||
EXPECT_EQ(toShortString(zero), "00000000...");
|
||||
EXPECT_EQ(*zero.data(), 0);
|
||||
EXPECT_EQ(*zero.begin(), 0);
|
||||
EXPECT_EQ(*std::prev(zero.end(), 1), 0);
|
||||
EXPECT_EQ(zero.signum(), 0);
|
||||
EXPECT_TRUE(!zero);
|
||||
EXPECT_TRUE(zero.isZero());
|
||||
EXPECT_FALSE(zero.isNonZero());
|
||||
for (auto& byte : zero)
|
||||
EXPECT_EQ(byte, 0);
|
||||
|
||||
{
|
||||
// There are several ways to create a zero. beast::kZero is tested above. Test some
|
||||
// others.
|
||||
BaseUInt96 const z1;
|
||||
EXPECT_EQ(z1, z) << to_string(z1);
|
||||
BaseUInt96 const defaultZero;
|
||||
EXPECT_EQ(defaultZero, zero) << to_string(defaultZero);
|
||||
|
||||
BaseUInt96 const z2{};
|
||||
EXPECT_EQ(z2, z) << to_string(z2);
|
||||
BaseUInt96 const bracedZero{};
|
||||
EXPECT_EQ(bracedZero, zero) << to_string(bracedZero);
|
||||
|
||||
BaseUInt96 const z3{0u};
|
||||
EXPECT_EQ(z3, z) << to_string(z3);
|
||||
BaseUInt96 const zeroFromUInt{0u};
|
||||
EXPECT_EQ(zeroFromUInt, zero) << to_string(zeroFromUInt);
|
||||
}
|
||||
|
||||
BaseUInt96 n{z};
|
||||
n++;
|
||||
EXPECT_EQ(n, BaseUInt96(1));
|
||||
n--;
|
||||
EXPECT_EQ(n, beast::kZero);
|
||||
EXPECT_EQ(n, z);
|
||||
n--;
|
||||
EXPECT_EQ(to_string(n), "FFFFFFFFFFFFFFFFFFFFFFFF");
|
||||
EXPECT_EQ(toShortString(n), "FFFFFFFF...");
|
||||
n = beast::kZero;
|
||||
EXPECT_EQ(n, z);
|
||||
BaseUInt96 counter{zero};
|
||||
counter++;
|
||||
EXPECT_EQ(counter, BaseUInt96(1));
|
||||
counter--;
|
||||
EXPECT_EQ(counter, beast::kZero);
|
||||
EXPECT_EQ(counter, zero);
|
||||
counter--;
|
||||
EXPECT_EQ(to_string(counter), "FFFFFFFFFFFFFFFFFFFFFFFF");
|
||||
EXPECT_EQ(toShortString(counter), "FFFFFFFF...");
|
||||
counter = beast::kZero;
|
||||
EXPECT_EQ(counter, zero);
|
||||
|
||||
BaseUInt96 zp1{z};
|
||||
zp1++;
|
||||
BaseUInt96 zm1{z};
|
||||
zm1--;
|
||||
BaseUInt96 const x{zm1 ^ zp1};
|
||||
uset.insert(x);
|
||||
EXPECT_EQ(to_string(x), "FFFFFFFFFFFFFFFFFFFFFFFE") << to_string(x);
|
||||
EXPECT_EQ(toShortString(x), "FFFFFFFF...") << toShortString(x);
|
||||
BaseUInt96 zeroPlusOne{zero};
|
||||
zeroPlusOne++;
|
||||
BaseUInt96 zeroMinusOne{zero};
|
||||
zeroMinusOne--;
|
||||
BaseUInt96 const xored{zeroMinusOne ^ zeroPlusOne};
|
||||
uset.insert(xored);
|
||||
EXPECT_EQ(to_string(xored), "FFFFFFFFFFFFFFFFFFFFFFFE") << to_string(xored);
|
||||
EXPECT_EQ(toShortString(xored), "FFFFFFFF...") << toShortString(xored);
|
||||
|
||||
EXPECT_EQ(uset.size(), 4);
|
||||
|
||||
BaseUInt96 tmp;
|
||||
EXPECT_TRUE(tmp.parseHex(to_string(u)));
|
||||
EXPECT_EQ(tmp, u);
|
||||
tmp = z;
|
||||
BaseUInt96 parsed;
|
||||
EXPECT_TRUE(parsed.parseHex(to_string(ascending)));
|
||||
EXPECT_EQ(parsed, ascending);
|
||||
parsed = zero;
|
||||
|
||||
// fails with extra char
|
||||
EXPECT_FALSE(tmp.parseHex("A" + to_string(u)));
|
||||
tmp = z;
|
||||
EXPECT_FALSE(parsed.parseHex("A" + to_string(ascending)));
|
||||
parsed = zero;
|
||||
|
||||
// fails with extra char at end
|
||||
EXPECT_FALSE(tmp.parseHex(to_string(u) + "A"));
|
||||
EXPECT_FALSE(parsed.parseHex(to_string(ascending) + "A"));
|
||||
|
||||
// fails with a non-hex character at some point in the string:
|
||||
tmp = z;
|
||||
parsed = zero;
|
||||
|
||||
for (std::size_t i = 0; i != 24; ++i)
|
||||
{
|
||||
std::string x = to_string(z);
|
||||
x[i] = ('G' + (i % 10));
|
||||
EXPECT_FALSE(tmp.parseHex(x));
|
||||
std::string xored = to_string(zero);
|
||||
xored[i] = ('G' + (i % 10));
|
||||
EXPECT_FALSE(parsed.parseHex(xored));
|
||||
}
|
||||
|
||||
// Walking 1s:
|
||||
@@ -332,8 +327,8 @@ TEST_F(BaseUintTest, base_uint)
|
||||
std::string s1 = "000000000000000000000000";
|
||||
s1[i] = '1';
|
||||
|
||||
EXPECT_TRUE(tmp.parseHex(s1));
|
||||
EXPECT_EQ(to_string(tmp), s1);
|
||||
EXPECT_TRUE(parsed.parseHex(s1));
|
||||
EXPECT_EQ(to_string(parsed), s1);
|
||||
}
|
||||
|
||||
// Walking 0s:
|
||||
@@ -342,8 +337,8 @@ TEST_F(BaseUintTest, base_uint)
|
||||
std::string s1 = "111111111111111111111111";
|
||||
s1[i] = '0';
|
||||
|
||||
EXPECT_TRUE(tmp.parseHex(s1));
|
||||
EXPECT_EQ(to_string(tmp), s1);
|
||||
EXPECT_TRUE(parsed.parseHex(s1));
|
||||
EXPECT_EQ(to_string(parsed), s1);
|
||||
}
|
||||
|
||||
// Constexpr constructors
|
||||
@@ -357,39 +352,27 @@ TEST_F(BaseUintTest, base_uint)
|
||||
// Using the constexpr constructor in a non-constexpr context
|
||||
// with an error in the parsing throws an exception.
|
||||
{
|
||||
// Invalid length for string.
|
||||
bool caught = false;
|
||||
try
|
||||
{
|
||||
// Try to prevent constant evaluation.
|
||||
std::vector<char> str(23, '7');
|
||||
// Invalid length for string. The vector keeps this out of a constant
|
||||
// expression, so the constructor throws instead of failing to compile.
|
||||
auto tooShort = [] {
|
||||
std::vector<char> const str(23, '7');
|
||||
std::string_view const sView(str.data(), str.size());
|
||||
[[maybe_unused]] BaseUInt96 const t96(sView);
|
||||
}
|
||||
catch (std::invalid_argument const& e)
|
||||
{
|
||||
EXPECT_EQ(e.what(), std::string("invalid length for hex string"));
|
||||
caught = true;
|
||||
}
|
||||
EXPECT_TRUE(caught);
|
||||
};
|
||||
EXPECT_THAT(
|
||||
tooShort,
|
||||
::testing::ThrowsMessage<std::invalid_argument>("invalid length for hex string"));
|
||||
}
|
||||
{
|
||||
// Invalid character in string.
|
||||
bool caught = false;
|
||||
try
|
||||
{
|
||||
// Try to prevent constant evaluation.
|
||||
auto badCharacter = [] {
|
||||
std::vector<char> str(23, '7');
|
||||
str.push_back('G');
|
||||
std::string_view const sView(str.data(), str.size());
|
||||
[[maybe_unused]] BaseUInt96 const t96(sView);
|
||||
}
|
||||
catch (std::range_error const& e)
|
||||
{
|
||||
EXPECT_EQ(e.what(), std::string("invalid hex character"));
|
||||
caught = true;
|
||||
}
|
||||
EXPECT_TRUE(caught);
|
||||
};
|
||||
EXPECT_THAT(
|
||||
badCharacter, ::testing::ThrowsMessage<std::range_error>("invalid hex character"));
|
||||
}
|
||||
|
||||
// Verify that constexpr base_uints interpret a string the same
|
||||
@@ -412,11 +395,11 @@ TEST_F(BaseUintTest, base_uint)
|
||||
"fFfFfFfFfFfFfFfFfFfFfFfF",
|
||||
});
|
||||
|
||||
for (StrBaseUInt const& t : kTestCases)
|
||||
for (StrBaseUInt const& expectedByte : kTestCases)
|
||||
{
|
||||
BaseUInt96 t96;
|
||||
EXPECT_TRUE(t96.parseHex(t.str));
|
||||
EXPECT_EQ(t96, t.tst);
|
||||
EXPECT_TRUE(t96.parseHex(expectedByte.str));
|
||||
EXPECT_EQ(t96, expectedByte.tst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <helpers/TestSink.h>
|
||||
#include <shamap/common.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
@@ -113,7 +112,7 @@ protected:
|
||||
intToVuc(std::uint8_t v)
|
||||
{
|
||||
Buffer vuc{32};
|
||||
std::fill_n(vuc.data(), vuc.size(), v);
|
||||
vuc.fill(v);
|
||||
return vuc;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user