#include "LinearRingBuffer.hpp" #include #include #include #include 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(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(ptr); for (size_t i = 0; i < n; ++i) { if (p[i] != value) return false; } return true; } using Data = std::vector; using DataStorage = std::vector; typedef ::testing::Types< std::integral_constant, std::integral_constant, std::integral_constant, std::integral_constant, std::integral_constant> BufferSizes; template class LinearRingBufferTest : public ::testing::Test { protected: LinearRingBuffer rb; LinearRingBufferTest() : historySize_(10), rb(size_t(TypeParam::value), size_t(historySize_)) {} static constexpr auto ITERATIONS = TypeParam::value * 10; size_t messagesPushed_ = 0; size_t historySize_ = 0; auto iterations() { return ITERATIONS; } auto historySize() { return historySize_; } size_t randomSize() { static std::random_device rnd; std::uniform_int_distribution 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 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(); }