Modules/Containers/tests/testLinearRingBuffer.cpp
agent b552d7c324 Port agent-work onto master
Brings the agent-work branch tip onto master, keeping master's architecture
and putting every agent-work feature on top of it: the window/GpuDevice/
RenderTarget split, explicit per-instance profilers instead of a global, the
input layer with scroll sources and ends, the Widgets core and components
(shared SelectionModel/Commands lists, popup stack, titled panels, prompt
dialogs, file browser, kanban, outline tree, markdown, docking), the gallery
on the new UI, the Objects explorer and interpreter fixes, the Taskboard, the
Sketch2D render path and its tests and bench, and the headless Wayland
runner the UI tests drive.

No MODULES_BUILD_* switches are introduced: platform differences are plain
if (ANDROID) / if (NOT ANDROID).
2026-11-02 11:00:51 +03:00

188 lines
4.6 KiB
C++

#include "LinearRingBuffer.hpp"
#include <gtest/gtest.h>
#include <cstring>
#include <cstdint>
#include <random>
static void fill(void* ptr, size_t n, uint8_t value) { std::memset(ptr, value, n); }
static bool check(const void* ptr, size_t n, uint8_t value) {
const uint8_t* p = static_cast<const uint8_t*>(ptr);
for (size_t i = 0; i < n; ++i) {
if (p[i] != value) return false;
}
return true;
}
static bool expect_mem_eq(const void* ptr, size_t n, uint8_t value) {
const uint8_t* p = static_cast<const uint8_t*>(ptr);
for (size_t i = 0; i < n; ++i) {
if (p[i] != value) return false;
}
return true;
}
using Data = std::vector<uint8_t>;
using DataStorage = std::vector<Data>;
typedef ::testing::Types<
std::integral_constant<size_t, 64>,
std::integral_constant<size_t, 128>,
std::integral_constant<size_t, 1000>,
std::integral_constant<size_t, 4096>,
std::integral_constant<size_t, 4096 * 2>>
BufferSizes;
template <typename TypeParam>
class LinearRingBufferTest : public ::testing::Test {
protected:
static constexpr size_t HISTORY_SIZE = 10;
LinearRingBuffer rb;
LinearRingBufferTest() :
rb(size_t(TypeParam::value), HISTORY_SIZE) {}
static constexpr auto ITERATIONS = TypeParam::value * 10;
size_t messagesPushed_ = 0;
auto iterations() { return ITERATIONS; }
auto historySize() { return HISTORY_SIZE; }
size_t randomSize() {
static std::random_device rnd;
std::uniform_int_distribution<size_t> dist(0, 1000);
return dist(rnd);
}
auto write_and_advance(size_t messageSize, DataStorage* storage) {
Data pushedSample(messageSize);
for (auto idx = 0; idx < messageSize; idx++) {
pushedSample[idx] = (idx + messagesPushed_++ * 53) % 321;
}
std::memcpy(this->rb.write_data(), pushedSample.data(), pushedSample.size());
this->rb.write_advance(pushedSample.size());
if (storage) {
storage->push_back(pushedSample);
}
};
auto read_and_advance(size_t messageSize, DataStorage* storage) {
Data poppedSample(messageSize);
std::memcpy(poppedSample.data(), this->rb.read_data(), poppedSample.size());
this->rb.read_advance(poppedSample.size());
if (storage) {
storage->push_back(poppedSample);
}
};
auto reset_with_history() { this->rb.read_reset_with_history(); };
auto read_with_history(size_t messageSize, DataStorage* storage) {
Data poppedSample(messageSize);
std::memcpy(poppedSample.data(), this->rb.read_data(), poppedSample.size());
if (storage) {
storage->push_back(poppedSample);
}
};
};
TYPED_TEST_SUITE(LinearRingBufferTest, BufferSizes);
TYPED_TEST(LinearRingBufferTest, LinearWriteAcrossBoundary) {
constexpr size_t N = TypeParam::value;
if (N % 4096 != 0) {
return;
}
auto* base = this->rb.write_data();
size_t half = N - 16;
fill(base, half, 0xAA);
fill(base + half, 32, 0xBB);
EXPECT_EQ(expect_mem_eq(base, 16, 0xBB), true);
EXPECT_EQ(expect_mem_eq(base + 16, half - 16, 0xAA), true);
EXPECT_EQ(expect_mem_eq(base + half, 32, 0xBB), true);
}
TYPED_TEST(LinearRingBufferTest, Chase) {
DataStorage pushed;
DataStorage popped;
static constexpr auto MSG_SIZE = 31;
for (auto iteration = 0; iteration < this->iterations(); iteration++) {
this->write_and_advance(MSG_SIZE, &pushed);
this->read_and_advance(MSG_SIZE, &popped);
}
ASSERT_EQ(pushed.size(), popped.size());
for (auto idx = 0; idx < popped.size(); idx++) {
ASSERT_EQ(pushed[idx], popped[idx]);
}
}
Data makeMessageWithHistory(const Data& prev, const Data& current, size_t historySize) {
if (historySize > prev.size()) historySize = prev.size();
std::vector<uint8_t> result;
result.reserve(historySize + current.size());
result.insert(result.end(), prev.end() - historySize, prev.end());
result.insert(result.end(), current.begin(), current.end());
return result;
}
TYPED_TEST(LinearRingBufferTest, History) {
DataStorage pushed;
DataStorage popped;
pushed.push_back(Data(this->historySize()));
static constexpr auto MAX_MSG_SIZE = 111;
for (auto iteration = 0; iteration < this->iterations(); iteration++) {
const auto MSG_SIZE = this->historySize() + this->randomSize() % MAX_MSG_SIZE;
auto prevPushed = pushed.back();
pushed.clear();
this->reset_with_history();
this->write_and_advance(MSG_SIZE, &pushed);
auto currentPushed = pushed.back();
this->read_with_history(this->historySize() + MSG_SIZE, &popped);
auto poppedWithHistory = popped.back();
popped.clear();
auto correctResult = makeMessageWithHistory(prevPushed, currentPushed, this->historySize());
ASSERT_EQ(correctResult, poppedWithHistory);
}
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}