* Copyright (C) 2025-2026. Huawei Technologies Co., Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include <thread>
#include <chrono>
#include <vector>
#include <memory>
#include "plugin/ipc_monitor/utils/RingBuffer.h"
using namespace dynolog_npu::ipc_monitor;
class RingBufferTest : public ::testing::Test {
protected:
void SetUp() override {}
void TearDown() override {}
};
TEST_F(RingBufferTest, ConstructorInitialization)
{
RingBuffer<int> buffer;
EXPECT_EQ(buffer.Size(), 0);
}
TEST_F(RingBufferTest, InitAndUnInit)
{
RingBuffer<int> buffer;
constexpr int capacity = 4;
EXPECT_NO_THROW(buffer.Init(capacity));
EXPECT_EQ(buffer.Size(), 0);
EXPECT_NO_THROW(buffer.UnInit());
EXPECT_EQ(buffer.Size(), 0);
}
TEST_F(RingBufferTest, BasicPushPop)
{
RingBuffer<int> buffer;
constexpr int capacity = 4;
EXPECT_NO_THROW(buffer.Init(capacity));
constexpr int value = 42;
EXPECT_TRUE(buffer.Push(value));
int popped_value;
EXPECT_TRUE(buffer.Pop(popped_value));
EXPECT_EQ(popped_value, value);
EXPECT_EQ(buffer.Size(), 0);
EXPECT_NO_THROW(buffer.UnInit());
}
TEST_F(RingBufferTest, MultiplePushPop)
{
RingBuffer<int> buffer;
constexpr int capacity = 4;
EXPECT_NO_THROW(buffer.Init(capacity));
constexpr int numValues = 3;
for (int i = 0; i < numValues; ++i) {
EXPECT_TRUE(buffer.Push(i));
}
EXPECT_EQ(buffer.Size(), numValues);
for (int i = 0; i < numValues; ++i) {
int value;
EXPECT_TRUE(buffer.Pop(value));
EXPECT_EQ(value, i);
}
EXPECT_EQ(buffer.Size(), 0);
int dummy;
EXPECT_FALSE(buffer.Pop(dummy));
EXPECT_NO_THROW(buffer.UnInit());
}
TEST_F(RingBufferTest, RingBehavior)
{
RingBuffer<int> buffer;
constexpr int capacity = 4;
EXPECT_NO_THROW(buffer.Init(capacity));
constexpr int numValues = 3;
for (int i = 0; i < numValues; ++i) {
EXPECT_TRUE(buffer.Push(i));
}
int value = 999;
EXPECT_FALSE(buffer.Push(value));
EXPECT_TRUE(buffer.Pop(value));
EXPECT_EQ(value, 0);
value = 42;
EXPECT_TRUE(buffer.Push(value));
EXPECT_TRUE(buffer.Pop(value));
EXPECT_EQ(value, 1);
EXPECT_TRUE(buffer.Pop(value));
EXPECT_EQ(value, 2);
EXPECT_TRUE(buffer.Pop(value));
EXPECT_EQ(value, 42);
EXPECT_EQ(buffer.Size(), 0);
EXPECT_NO_THROW(buffer.UnInit());
}
TEST_F(RingBufferTest, SizeCalculation)
{
RingBuffer<int> buffer;
constexpr int capacity = 4;
EXPECT_NO_THROW(buffer.Init(capacity));
EXPECT_EQ(buffer.Size(), 0);
EXPECT_TRUE(buffer.Push(1));
EXPECT_EQ(buffer.Size(), 1);
EXPECT_TRUE(buffer.Push(2));
EXPECT_EQ(buffer.Size(), 2);
int dummy;
EXPECT_TRUE(buffer.Pop(dummy));
EXPECT_EQ(buffer.Size(), 1);
EXPECT_TRUE(buffer.Pop(dummy));
EXPECT_EQ(buffer.Size(), 0);
EXPECT_NO_THROW(buffer.UnInit());
}
TEST_F(RingBufferTest, StringType)
{
RingBuffer<std::string> buffer;
constexpr int capacity = 4;
EXPECT_NO_THROW(buffer.Init(capacity));
std::string str1 = "hello";
std::string str2 = "world";
EXPECT_TRUE(buffer.Push(str1));
EXPECT_TRUE(buffer.Push(str2));
EXPECT_EQ(buffer.Size(), 2);
std::string popped_str;
EXPECT_TRUE(buffer.Pop(popped_str));
EXPECT_EQ(popped_str, "hello");
EXPECT_TRUE(buffer.Pop(popped_str));
EXPECT_EQ(popped_str, "world");
EXPECT_EQ(buffer.Size(), 0);
EXPECT_NO_THROW(buffer.UnInit());
}
TEST_F(RingBufferTest, ThreadSafetyProducerConsumer)
{
const int capacity = 128;
RingBuffer<int> buffer;
buffer.Init(capacity);
constexpr int num_items = 50;
std::thread producer([&buffer, num_items]() {
for (int i = 0; i < num_items; ++i) {
bool pushed = false;
while (!pushed) {
pushed = buffer.Push(i);
if (!pushed) {
std::this_thread::sleep_for(std::chrono::microseconds(10));
}
}
}
});
std::thread consumer([&buffer, num_items]() {
int received = 0;
while (received < num_items) {
int value;
if (buffer.Pop(value)) {
received++;
} else {
std::this_thread::sleep_for(std::chrono::microseconds(10));
}
}
});
producer.join();
consumer.join();
EXPECT_EQ(buffer.Size(), 0);
EXPECT_NO_THROW(buffer.UnInit());
}
TEST_F(RingBufferTest, FullCapacityHandling)
{
RingBuffer<int> buffer;
constexpr int capacity = 4;
EXPECT_NO_THROW(buffer.Init(capacity));
constexpr int numValues = 3;
for (int i = 0; i < numValues; ++i) {
EXPECT_TRUE(buffer.Push(i));
}
EXPECT_FALSE(buffer.Push(99));
int value;
EXPECT_TRUE(buffer.Pop(value));
EXPECT_EQ(value, 0);
EXPECT_TRUE(buffer.Push(99));
EXPECT_FALSE(buffer.Push(100));
EXPECT_NO_THROW(buffer.UnInit());
}
TEST_F(RingBufferTest, UninitializedBehavior)
{
RingBuffer<int> buffer;
EXPECT_FALSE(buffer.Push(1));
int dummy;
EXPECT_FALSE(buffer.Pop(dummy));
constexpr int capacity = 4;
EXPECT_NO_THROW(buffer.Init(capacity));
EXPECT_TRUE(buffer.Push(1));
EXPECT_TRUE(buffer.Pop(dummy));
EXPECT_NO_THROW(buffer.UnInit());
EXPECT_FALSE(buffer.Push(1));
EXPECT_FALSE(buffer.Pop(dummy));
}
TEST_F(RingBufferTest, LargeCapacityTest)
{
RingBuffer<int> buffer;
constexpr int capacity = 1024;
EXPECT_NO_THROW(buffer.Init(capacity));
constexpr int numValues = 1023;
for (int i = 0; i < numValues; ++i) {
EXPECT_TRUE(buffer.Push(i));
}
EXPECT_FALSE(buffer.Push(-1));
for (int i = 0; i < numValues; ++i) {
int value;
EXPECT_TRUE(buffer.Pop(value));
EXPECT_EQ(value, i);
}
EXPECT_EQ(buffer.Size(), 0);
EXPECT_NO_THROW(buffer.UnInit());
}
TEST_F(RingBufferTest, MoveSemantics)
{
RingBuffer<std::unique_ptr<int>> buffer;
constexpr int capacity = 4;
EXPECT_NO_THROW(buffer.Init(capacity));
auto ptr1 = std::make_unique<int>(42);
auto ptr2 = std::make_unique<int>(84);
EXPECT_TRUE(buffer.Push(std::move(ptr1)));
EXPECT_TRUE(buffer.Push(std::move(ptr2)));
EXPECT_EQ(buffer.Size(), 2);
std::unique_ptr<int> popped_ptr1, popped_ptr2;
EXPECT_TRUE(buffer.Pop(popped_ptr1));
EXPECT_TRUE(buffer.Pop(popped_ptr2));
EXPECT_EQ(*popped_ptr1, 42);
EXPECT_EQ(*popped_ptr2, 84);
EXPECT_EQ(buffer.Size(), 0);
EXPECT_NO_THROW(buffer.UnInit());
}
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}