Init: Migrate SimpleRemoter (Since v1.3.1) to Gitea

This commit is contained in:
yuanyuanxiang
2026-04-19 19:55:01 +02:00
commit 5a325a202b
744 changed files with 235562 additions and 0 deletions

View File

@@ -0,0 +1,912 @@
/**
* @file BufferTest.cpp
* @brief 服务端 CBuffer 类单元测试
*
* 测试覆盖:
* - 基本读写操作
* - 延迟读取偏移机制 (m_ulReadOffset)
* - 压缩/紧凑策略 (CompactBuffer)
* - 边界条件和下溢防护
* - 线程安全(并发读写)
* - 零拷贝写入接口
*/
#include <gtest/gtest.h>
#include <thread>
#include <atomic>
#include <chrono>
#include <vector>
#include <string>
// Windows 头文件
#ifdef _WIN32
#include <Windows.h>
#else
// Linux 模拟 Windows API
#include <cstring>
#include <cstdlib>
#include <pthread.h>
typedef unsigned char BYTE;
typedef BYTE* PBYTE;
typedef BYTE* LPBYTE;
typedef unsigned long ULONG;
typedef void VOID;
typedef int BOOL;
typedef void* PVOID;
#define TRUE 1
#define FALSE 0
#define MEM_COMMIT 0x1000
#define MEM_RELEASE 0x8000
#define PAGE_READWRITE 0x04
struct CRITICAL_SECTION {
pthread_mutex_t mutex;
};
inline void InitializeCriticalSection(CRITICAL_SECTION* cs) {
pthread_mutex_init(&cs->mutex, NULL);
}
inline void DeleteCriticalSection(CRITICAL_SECTION* cs) {
pthread_mutex_destroy(&cs->mutex);
}
inline void EnterCriticalSection(CRITICAL_SECTION* cs) {
pthread_mutex_lock(&cs->mutex);
}
inline void LeaveCriticalSection(CRITICAL_SECTION* cs) {
pthread_mutex_unlock(&cs->mutex);
}
inline void* VirtualAlloc(void*, size_t size, int, int) {
return malloc(size);
}
inline void VirtualFree(void* ptr, size_t, int) {
free(ptr);
}
inline void CopyMemory(void* dst, const void* src, size_t len) {
memcpy(dst, src, len);
}
inline void MoveMemory(void* dst, const void* src, size_t len) {
memmove(dst, src, len);
}
#endif
#include <cmath>
// 服务端 Buffer 实现(测试专用内联版本)
namespace ServerBuffer {
#define U_PAGE_ALIGNMENT 4096
#define F_PAGE_ALIGNMENT 4096.0
#define COMPACT_THRESHOLD 0.5
// 简化的 Buffer 类(用于 GetMyBuffer 返回)
class Buffer {
private:
PBYTE buf;
ULONG len;
public:
Buffer() : buf(NULL), len(0) {}
Buffer(const BYTE* b, ULONG n) : len(n) {
if (n > 0 && b) {
buf = new BYTE[n];
memcpy(buf, b, n);
} else {
buf = NULL;
}
}
~Buffer() {
if (buf) {
delete[] buf;
buf = NULL;
}
}
Buffer(const Buffer& o) : len(o.len) {
if (o.buf && o.len > 0) {
buf = new BYTE[o.len];
memcpy(buf, o.buf, o.len);
} else {
buf = NULL;
}
}
ULONG length() const { return len; }
LPBYTE GetBuffer(int idx = 0) const {
return (idx >= (int)len) ? NULL : buf + idx;
}
};
class CBuffer {
public:
CBuffer() : m_ulMaxLength(0), m_ulReadOffset(0), m_Base(NULL), m_Ptr(NULL) {
InitializeCriticalSection(&m_cs);
}
~CBuffer() {
if (m_Base) {
VirtualFree(m_Base, 0, MEM_RELEASE);
m_Base = NULL;
}
DeleteCriticalSection(&m_cs);
m_Base = m_Ptr = NULL;
m_ulMaxLength = 0;
m_ulReadOffset = 0;
}
ULONG RemoveCompletedBuffer(ULONG ulLength) {
EnterCriticalSection(&m_cs);
ULONG totalDataLen = (ULONG)(m_Ptr - m_Base);
ULONG effectiveDataLen = (totalDataLen > m_ulReadOffset) ? (totalDataLen - m_ulReadOffset) : 0;
if (ulLength > effectiveDataLen) {
ulLength = effectiveDataLen;
}
if (ulLength) {
m_ulReadOffset += ulLength;
if (m_ulReadOffset > (ULONG)(m_ulMaxLength * COMPACT_THRESHOLD)) {
CompactBuffer();
}
}
LeaveCriticalSection(&m_cs);
return ulLength;
}
VOID CompactBuffer() {
if (m_ulReadOffset > 0 && m_Base) {
ULONG totalDataLen = (ULONG)(m_Ptr - m_Base);
ULONG remainingData = (totalDataLen > m_ulReadOffset) ? (totalDataLen - m_ulReadOffset) : 0;
if (remainingData > 0) {
MoveMemory(m_Base, m_Base + m_ulReadOffset, remainingData);
}
m_Ptr = m_Base + remainingData;
m_ulReadOffset = 0;
DeAllocateBuffer(remainingData);
}
}
ULONG ReadBuffer(PBYTE Buffer, ULONG ulLength) {
EnterCriticalSection(&m_cs);
ULONG totalDataLen = (ULONG)(m_Ptr - m_Base);
ULONG effectiveDataLen = (totalDataLen > m_ulReadOffset) ? (totalDataLen - m_ulReadOffset) : 0;
if (ulLength > effectiveDataLen) {
ulLength = effectiveDataLen;
}
if (ulLength) {
CopyMemory(Buffer, m_Base + m_ulReadOffset, ulLength);
m_ulReadOffset += ulLength;
if (m_ulReadOffset > (ULONG)(m_ulMaxLength * COMPACT_THRESHOLD)) {
CompactBuffer();
}
}
LeaveCriticalSection(&m_cs);
return ulLength;
}
ULONG DeAllocateBuffer(ULONG ulLength) {
if (ulLength < (ULONG)(m_Ptr - m_Base))
return 0;
ULONG ulNewMaxLength = (ULONG)(ceil(ulLength / F_PAGE_ALIGNMENT) * U_PAGE_ALIGNMENT);
if (m_ulMaxLength <= ulNewMaxLength) {
return 0;
}
PBYTE NewBase = (PBYTE)VirtualAlloc(NULL, ulNewMaxLength, MEM_COMMIT, PAGE_READWRITE);
ULONG ulv1 = (ULONG)(m_Ptr - m_Base);
CopyMemory(NewBase, m_Base, ulv1);
VirtualFree(m_Base, 0, MEM_RELEASE);
m_Base = NewBase;
m_Ptr = m_Base + ulv1;
m_ulMaxLength = ulNewMaxLength;
return m_ulMaxLength;
}
BOOL WriteBuffer(PBYTE Buffer, ULONG ulLength) {
EnterCriticalSection(&m_cs);
if (ReAllocateBuffer(ulLength + (ULONG)(m_Ptr - m_Base)) == (ULONG)-1) {
LeaveCriticalSection(&m_cs);
return FALSE;
}
CopyMemory(m_Ptr, Buffer, ulLength);
m_Ptr += ulLength;
LeaveCriticalSection(&m_cs);
return TRUE;
}
ULONG ReAllocateBuffer(ULONG ulLength) {
if (ulLength < m_ulMaxLength)
return 0;
ULONG ulNewMaxLength = (ULONG)(ceil(ulLength / F_PAGE_ALIGNMENT) * U_PAGE_ALIGNMENT);
PBYTE NewBase = (PBYTE)VirtualAlloc(NULL, ulNewMaxLength, MEM_COMMIT, PAGE_READWRITE);
if (NewBase == NULL) {
return (ULONG)-1;
}
ULONG ulv1 = (ULONG)(m_Ptr - m_Base);
CopyMemory(NewBase, m_Base, ulv1);
if (m_Base) {
VirtualFree(m_Base, 0, MEM_RELEASE);
}
m_Base = NewBase;
m_Ptr = m_Base + ulv1;
m_ulMaxLength = ulNewMaxLength;
return m_ulMaxLength;
}
VOID ClearBuffer() {
EnterCriticalSection(&m_cs);
m_Ptr = m_Base;
m_ulReadOffset = 0;
DeAllocateBuffer(1024);
LeaveCriticalSection(&m_cs);
}
ULONG GetBufferLength() {
EnterCriticalSection(&m_cs);
if (m_Base == NULL) {
LeaveCriticalSection(&m_cs);
return 0;
}
ULONG totalDataLen = (ULONG)(m_Ptr - m_Base);
ULONG len = (totalDataLen > m_ulReadOffset) ? (totalDataLen - m_ulReadOffset) : 0;
LeaveCriticalSection(&m_cs);
return len;
}
std::string Skip(ULONG ulPos) {
if (ulPos == 0)
return "";
EnterCriticalSection(&m_cs);
ULONG totalDataLen = (ULONG)(m_Ptr - m_Base);
ULONG effectiveDataLen = (totalDataLen > m_ulReadOffset) ? (totalDataLen - m_ulReadOffset) : 0;
if (ulPos > effectiveDataLen) {
ulPos = effectiveDataLen;
}
std::string ret((char*)(m_Base + m_ulReadOffset), (char*)(m_Base + m_ulReadOffset + ulPos));
m_ulReadOffset += ulPos;
if (m_ulReadOffset > (ULONG)(m_ulMaxLength * COMPACT_THRESHOLD)) {
CompactBuffer();
}
LeaveCriticalSection(&m_cs);
return ret;
}
LPBYTE GetBuffer(ULONG ulPos = 0) {
EnterCriticalSection(&m_cs);
ULONG totalDataLen = (ULONG)(m_Ptr - m_Base);
ULONG effectiveDataLen = (totalDataLen > m_ulReadOffset) ? (totalDataLen - m_ulReadOffset) : 0;
if (m_Base == NULL || ulPos >= effectiveDataLen) {
LeaveCriticalSection(&m_cs);
return NULL;
}
LPBYTE result = m_Base + m_ulReadOffset + ulPos;
LeaveCriticalSection(&m_cs);
return result;
}
Buffer GetMyBuffer(ULONG ulPos = 0) {
EnterCriticalSection(&m_cs);
ULONG totalDataLen = (ULONG)(m_Ptr - m_Base);
ULONG effectiveDataLen = (totalDataLen > m_ulReadOffset) ? (totalDataLen - m_ulReadOffset) : 0;
if (m_Base == NULL || ulPos >= effectiveDataLen) {
LeaveCriticalSection(&m_cs);
return Buffer();
}
Buffer result(m_Base + m_ulReadOffset + ulPos, effectiveDataLen - ulPos);
LeaveCriticalSection(&m_cs);
return result;
}
BYTE GetBYTE(ULONG ulPos) {
EnterCriticalSection(&m_cs);
ULONG totalDataLen = (ULONG)(m_Ptr - m_Base);
ULONG effectiveDataLen = (totalDataLen > m_ulReadOffset) ? (totalDataLen - m_ulReadOffset) : 0;
if (m_Base == NULL || ulPos >= effectiveDataLen) {
LeaveCriticalSection(&m_cs);
return 0;
}
BYTE p = *(m_Base + m_ulReadOffset + ulPos);
LeaveCriticalSection(&m_cs);
return p;
}
BOOL CopyBuffer(PVOID pDst, ULONG nLen, ULONG ulPos) {
EnterCriticalSection(&m_cs);
ULONG totalDataLen = (ULONG)(m_Ptr - m_Base);
ULONG effectiveDataLen = (totalDataLen > m_ulReadOffset) ? (totalDataLen - m_ulReadOffset) : 0;
if (m_Base == NULL || pDst == NULL || ulPos >= effectiveDataLen || (effectiveDataLen - ulPos) < nLen) {
LeaveCriticalSection(&m_cs);
return FALSE;
}
memcpy(pDst, m_Base + m_ulReadOffset + ulPos, nLen);
LeaveCriticalSection(&m_cs);
return TRUE;
}
LPBYTE GetWriteBuffer(ULONG requiredSize, ULONG& availableSize) {
EnterCriticalSection(&m_cs);
if (m_ulReadOffset > 0) {
CompactBuffer();
}
ULONG currentDataLen = (ULONG)(m_Ptr - m_Base);
if (ReAllocateBuffer(currentDataLen + requiredSize) == (ULONG)-1) {
LeaveCriticalSection(&m_cs);
availableSize = 0;
return NULL;
}
availableSize = m_ulMaxLength - currentDataLen;
LPBYTE result = m_Ptr;
LeaveCriticalSection(&m_cs);
return result;
}
VOID CommitWrite(ULONG writtenSize) {
EnterCriticalSection(&m_cs);
m_Ptr += writtenSize;
LeaveCriticalSection(&m_cs);
}
// 测试辅助:获取内部状态
ULONG GetReadOffset() const { return m_ulReadOffset; }
ULONG GetMaxLength() const { return m_ulMaxLength; }
protected:
PBYTE m_Base;
PBYTE m_Ptr;
ULONG m_ulMaxLength;
ULONG m_ulReadOffset;
CRITICAL_SECTION m_cs;
};
} // namespace ServerBuffer
using ServerBuffer::CBuffer;
using ServerBuffer::Buffer;
// ============================================
// 测试夹具
// ============================================
class ServerBufferTest : public ::testing::Test {
protected:
CBuffer buffer;
void SetUp() override {}
void TearDown() override {}
void WriteFillData(ULONG length, BYTE fillValue = 0x42) {
std::vector<BYTE> data(length, fillValue);
buffer.WriteBuffer(data.data(), length);
}
};
// ============================================
// 构造/析构测试
// ============================================
TEST_F(ServerBufferTest, Constructor_InitializesEmpty) {
CBuffer newBuffer;
EXPECT_EQ(newBuffer.GetBufferLength(), 0u);
EXPECT_EQ(newBuffer.GetBuffer(), nullptr);
}
// ============================================
// WriteBuffer 测试
// ============================================
TEST_F(ServerBufferTest, WriteBuffer_ValidData_ReturnsTrue) {
BYTE data[] = {1, 2, 3, 4, 5};
EXPECT_TRUE(buffer.WriteBuffer(data, 5));
EXPECT_EQ(buffer.GetBufferLength(), 5u);
}
TEST_F(ServerBufferTest, WriteBuffer_MultipleWrites_AccumulatesData) {
BYTE data1[] = {1, 2, 3};
BYTE data2[] = {4, 5};
buffer.WriteBuffer(data1, 3);
buffer.WriteBuffer(data2, 2);
EXPECT_EQ(buffer.GetBufferLength(), 5u);
}
TEST_F(ServerBufferTest, WriteBuffer_LargeData_HandlesCorrectly) {
const ULONG largeSize = 100000;
std::vector<BYTE> data(largeSize, 0xAB);
EXPECT_TRUE(buffer.WriteBuffer(data.data(), largeSize));
EXPECT_EQ(buffer.GetBufferLength(), largeSize);
}
// ============================================
// ReadBuffer 测试
// ============================================
TEST_F(ServerBufferTest, ReadBuffer_EmptyBuffer_ReturnsZero) {
BYTE result[10];
EXPECT_EQ(buffer.ReadBuffer(result, 10), 0u);
}
TEST_F(ServerBufferTest, ReadBuffer_ExactLength_ReturnsAll) {
BYTE data[] = {1, 2, 3, 4, 5};
buffer.WriteBuffer(data, 5);
BYTE result[5];
ULONG bytesRead = buffer.ReadBuffer(result, 5);
EXPECT_EQ(bytesRead, 5u);
EXPECT_EQ(buffer.GetBufferLength(), 0u);
}
TEST_F(ServerBufferTest, ReadBuffer_PartialRead_UsesReadOffset) {
BYTE data[] = {1, 2, 3, 4, 5};
buffer.WriteBuffer(data, 5);
BYTE result[2];
buffer.ReadBuffer(result, 2);
// 使用延迟偏移,不立即移动数据
EXPECT_EQ(buffer.GetBufferLength(), 3u);
EXPECT_GT(buffer.GetReadOffset(), 0u);
}
TEST_F(ServerBufferTest, ReadBuffer_RequestExceedsAvailable_ReturnsAvailableOnly) {
BYTE data[] = {1, 2, 3};
buffer.WriteBuffer(data, 3);
BYTE result[10];
ULONG bytesRead = buffer.ReadBuffer(result, 10);
EXPECT_EQ(bytesRead, 3u);
EXPECT_EQ(buffer.GetBufferLength(), 0u);
}
// ============================================
// RemoveCompletedBuffer 测试
// ============================================
TEST_F(ServerBufferTest, RemoveCompletedBuffer_PartialRemove_UpdatesOffset) {
BYTE data[] = {1, 2, 3, 4, 5};
buffer.WriteBuffer(data, 5);
ULONG removed = buffer.RemoveCompletedBuffer(2);
EXPECT_EQ(removed, 2u);
EXPECT_EQ(buffer.GetBufferLength(), 3u);
}
TEST_F(ServerBufferTest, RemoveCompletedBuffer_ExceedsLength_ClampsToAvailable) {
BYTE data[] = {1, 2, 3};
buffer.WriteBuffer(data, 3);
ULONG removed = buffer.RemoveCompletedBuffer(100);
EXPECT_EQ(removed, 3u);
EXPECT_EQ(buffer.GetBufferLength(), 0u);
}
// ============================================
// Skip 测试
// ============================================
TEST_F(ServerBufferTest, Skip_ReturnsSkippedData) {
BYTE data[] = {'H', 'e', 'l', 'l', 'o'};
buffer.WriteBuffer(data, 5);
std::string skipped = buffer.Skip(3);
EXPECT_EQ(skipped, "Hel");
EXPECT_EQ(buffer.GetBufferLength(), 2u);
}
TEST_F(ServerBufferTest, Skip_ExceedsLength_ClampsToAvailable) {
BYTE data[] = {'A', 'B', 'C'};
buffer.WriteBuffer(data, 3);
std::string skipped = buffer.Skip(100);
EXPECT_EQ(skipped, "ABC");
EXPECT_EQ(buffer.GetBufferLength(), 0u);
}
TEST_F(ServerBufferTest, Skip_ZeroLength_ReturnsEmpty) {
BYTE data[] = {1, 2, 3};
buffer.WriteBuffer(data, 3);
std::string skipped = buffer.Skip(0);
EXPECT_EQ(skipped, "");
EXPECT_EQ(buffer.GetBufferLength(), 3u);
}
// ============================================
// GetBuffer 测试
// ============================================
TEST_F(ServerBufferTest, GetBuffer_RespectsReadOffset) {
BYTE data[] = {10, 20, 30, 40, 50};
buffer.WriteBuffer(data, 5);
// 读取前两个字节,更新偏移
BYTE temp[2];
buffer.ReadBuffer(temp, 2);
// GetBuffer(0) 应该返回第三个字节30
EXPECT_EQ(*buffer.GetBuffer(0), 30);
EXPECT_EQ(*buffer.GetBuffer(1), 40);
EXPECT_EQ(*buffer.GetBuffer(2), 50);
}
TEST_F(ServerBufferTest, GetBuffer_PositionExceedsEffectiveLength_ReturnsNull) {
BYTE data[] = {1, 2, 3, 4, 5};
buffer.WriteBuffer(data, 5);
BYTE temp[3];
buffer.ReadBuffer(temp, 3); // 有效长度变为 2
EXPECT_NE(buffer.GetBuffer(0), nullptr);
EXPECT_NE(buffer.GetBuffer(1), nullptr);
EXPECT_EQ(buffer.GetBuffer(2), nullptr); // 超出有效范围
}
// ============================================
// GetMyBuffer 测试
// ============================================
TEST_F(ServerBufferTest, GetMyBuffer_ReturnsCorrectBuffer) {
BYTE data[] = {1, 2, 3, 4, 5};
buffer.WriteBuffer(data, 5);
Buffer buf = buffer.GetMyBuffer(0);
EXPECT_EQ(buf.length(), 5u);
}
TEST_F(ServerBufferTest, GetMyBuffer_RespectsReadOffset) {
BYTE data[] = {1, 2, 3, 4, 5};
buffer.WriteBuffer(data, 5);
BYTE temp[2];
buffer.ReadBuffer(temp, 2);
Buffer buf = buffer.GetMyBuffer(0);
EXPECT_EQ(buf.length(), 3u);
EXPECT_EQ(*buf.GetBuffer(0), 3);
}
// ============================================
// GetBYTE 测试
// ============================================
TEST_F(ServerBufferTest, GetBYTE_ReturnsCorrectByte) {
BYTE data[] = {10, 20, 30, 40, 50};
buffer.WriteBuffer(data, 5);
EXPECT_EQ(buffer.GetBYTE(0), 10);
EXPECT_EQ(buffer.GetBYTE(2), 30);
EXPECT_EQ(buffer.GetBYTE(4), 50);
}
TEST_F(ServerBufferTest, GetBYTE_RespectsReadOffset) {
BYTE data[] = {10, 20, 30, 40, 50};
buffer.WriteBuffer(data, 5);
BYTE temp[2];
buffer.ReadBuffer(temp, 2);
EXPECT_EQ(buffer.GetBYTE(0), 30);
EXPECT_EQ(buffer.GetBYTE(1), 40);
}
TEST_F(ServerBufferTest, GetBYTE_OutOfRange_ReturnsZero) {
BYTE data[] = {1, 2, 3};
buffer.WriteBuffer(data, 3);
EXPECT_EQ(buffer.GetBYTE(100), 0);
}
// ============================================
// CopyBuffer 测试
// ============================================
TEST_F(ServerBufferTest, CopyBuffer_ValidRange_ReturnsTrue) {
BYTE data[] = {1, 2, 3, 4, 5};
buffer.WriteBuffer(data, 5);
BYTE dest[3];
EXPECT_TRUE(buffer.CopyBuffer(dest, 3, 1));
EXPECT_EQ(dest[0], 2);
EXPECT_EQ(dest[1], 3);
EXPECT_EQ(dest[2], 4);
}
TEST_F(ServerBufferTest, CopyBuffer_RespectsReadOffset) {
BYTE data[] = {1, 2, 3, 4, 5};
buffer.WriteBuffer(data, 5);
BYTE temp[2];
buffer.ReadBuffer(temp, 2);
BYTE dest[2];
EXPECT_TRUE(buffer.CopyBuffer(dest, 2, 0));
EXPECT_EQ(dest[0], 3);
EXPECT_EQ(dest[1], 4);
}
TEST_F(ServerBufferTest, CopyBuffer_ExceedsRange_ReturnsFalse) {
BYTE data[] = {1, 2, 3};
buffer.WriteBuffer(data, 3);
BYTE dest[10];
EXPECT_FALSE(buffer.CopyBuffer(dest, 10, 0));
}
// ============================================
// 零拷贝写入测试
// ============================================
TEST_F(ServerBufferTest, GetWriteBuffer_ReturnsValidPointer) {
ULONG availableSize = 0;
LPBYTE writePtr = buffer.GetWriteBuffer(100, availableSize);
EXPECT_NE(writePtr, nullptr);
EXPECT_GE(availableSize, 100u);
}
TEST_F(ServerBufferTest, CommitWrite_UpdatesLength) {
ULONG availableSize = 0;
LPBYTE writePtr = buffer.GetWriteBuffer(100, availableSize);
// 直接写入
for (int i = 0; i < 50; i++) {
writePtr[i] = (BYTE)i;
}
buffer.CommitWrite(50);
EXPECT_EQ(buffer.GetBufferLength(), 50u);
EXPECT_EQ(buffer.GetBYTE(0), 0);
EXPECT_EQ(buffer.GetBYTE(49), 49);
}
// ============================================
// ClearBuffer 测试
// ============================================
TEST_F(ServerBufferTest, ClearBuffer_ResetsEverything) {
BYTE data[] = {1, 2, 3, 4, 5};
buffer.WriteBuffer(data, 5);
BYTE temp[2];
buffer.ReadBuffer(temp, 2); // 创建读取偏移
buffer.ClearBuffer();
EXPECT_EQ(buffer.GetBufferLength(), 0u);
EXPECT_EQ(buffer.GetReadOffset(), 0u);
}
// ============================================
// 下溢防护测试
// ============================================
TEST_F(ServerBufferTest, UnderflowProtection_ReadMoreThanLength_NoUnderflow) {
BYTE data[] = {1, 2, 3};
buffer.WriteBuffer(data, 3);
BYTE result[1000];
ULONG bytesRead = buffer.ReadBuffer(result, ULONG_MAX - 1);
EXPECT_EQ(bytesRead, 3u);
}
TEST_F(ServerBufferTest, UnderflowProtection_SkipMoreThanLength_NoUnderflow) {
BYTE data[] = {1, 2, 3};
buffer.WriteBuffer(data, 3);
std::string skipped = buffer.Skip(ULONG_MAX - 1);
EXPECT_EQ(skipped.length(), 3u);
EXPECT_EQ(buffer.GetBufferLength(), 0u);
}
TEST_F(ServerBufferTest, UnderflowProtection_RemoveMoreThanLength_NoUnderflow) {
BYTE data[] = {1, 2, 3};
buffer.WriteBuffer(data, 3);
ULONG removed = buffer.RemoveCompletedBuffer(ULONG_MAX - 1);
EXPECT_EQ(removed, 3u);
}
TEST_F(ServerBufferTest, UnderflowProtection_GetByteOutOfRange_ReturnsZero) {
BYTE data[] = {1, 2, 3};
buffer.WriteBuffer(data, 3);
EXPECT_EQ(buffer.GetBYTE(ULONG_MAX - 1), 0);
}
// ============================================
// 压缩策略测试
// ============================================
TEST_F(ServerBufferTest, Compaction_TriggersAtThreshold) {
// 写入足够数据
// m_ulMaxLength 会被页对齐到 ceil(10000/4096)*4096 = 12288
// 压缩阈值 = 12288 * 0.5 = 6144
WriteFillData(10000);
ULONG initialOffset = buffer.GetReadOffset();
EXPECT_EQ(initialOffset, 0u);
// 读取超过阈值的数据(需要 > 6144
std::vector<BYTE> temp(7000);
buffer.ReadBuffer(temp.data(), 7000);
// 压缩后偏移应该重置
EXPECT_EQ(buffer.GetReadOffset(), 0u);
EXPECT_EQ(buffer.GetBufferLength(), 3000u);
}
// ============================================
// 线程安全测试
// ============================================
TEST_F(ServerBufferTest, ThreadSafety_ConcurrentReadWrite_NoDataCorruption) {
std::atomic<bool> running{true};
std::atomic<int> writeCount{0};
std::atomic<int> readCount{0};
// 写线程
std::thread writer([&]() {
BYTE data[100];
for (int i = 0; i < 100; i++) {
data[i] = (BYTE)i;
}
while (running) {
if (buffer.WriteBuffer(data, 100)) {
writeCount++;
}
std::this_thread::yield();
}
});
// 读线程
std::thread reader([&]() {
BYTE result[50];
while (running) {
if (buffer.ReadBuffer(result, 50) > 0) {
readCount++;
}
std::this_thread::yield();
}
});
// 运行一段时间
std::this_thread::sleep_for(std::chrono::milliseconds(100));
running = false;
writer.join();
reader.join();
// 验证无崩溃,且有数据交换
EXPECT_GT(writeCount.load(), 0);
EXPECT_GT(readCount.load(), 0);
}
TEST_F(ServerBufferTest, ThreadSafety_MultipleReaders_NoDeadlock) {
// 预填充数据
WriteFillData(10000);
std::atomic<bool> running{true};
std::vector<std::thread> readers;
for (int i = 0; i < 4; i++) {
readers.emplace_back([&]() {
while (running) {
buffer.GetBufferLength();
buffer.GetBYTE(0);
buffer.GetBuffer(0);
std::this_thread::yield();
}
});
}
std::this_thread::sleep_for(std::chrono::milliseconds(50));
running = false;
for (auto& t : readers) {
t.join();
}
// 无死锁即为成功
SUCCEED();
}
// ============================================
// 数据完整性测试
// ============================================
TEST_F(ServerBufferTest, DataIntegrity_WriteReadCycle_PreservesData) {
std::vector<BYTE> data(256);
for (int i = 0; i < 256; i++) {
data[i] = (BYTE)i;
}
buffer.WriteBuffer(data.data(), 256);
std::vector<BYTE> result(256);
ULONG bytesRead = buffer.ReadBuffer(result.data(), 256);
EXPECT_EQ(bytesRead, 256u);
for (int i = 0; i < 256; i++) {
EXPECT_EQ(result[i], data[i]) << "Mismatch at index " << i;
}
}
TEST_F(ServerBufferTest, DataIntegrity_PartialReads_PreservesSequence) {
// 写入 1-100
std::vector<BYTE> data(100);
for (int i = 0; i < 100; i++) {
data[i] = (BYTE)(i + 1);
}
buffer.WriteBuffer(data.data(), 100);
// 分多次读取
BYTE result[100];
ULONG totalRead = 0;
totalRead += buffer.ReadBuffer(result, 30);
totalRead += buffer.ReadBuffer(result + 30, 30);
totalRead += buffer.ReadBuffer(result + 60, 40);
EXPECT_EQ(totalRead, 100u);
for (int i = 0; i < 100; i++) {
EXPECT_EQ(result[i], (BYTE)(i + 1));
}
}
// ============================================
// 参数化测试
// ============================================
class ServerBufferParameterizedTest
: public ::testing::TestWithParam<std::tuple<size_t, size_t, size_t>> {
protected:
CBuffer buffer;
};
TEST_P(ServerBufferParameterizedTest, ReadBuffer_VariousLengths) {
auto [writeLen, readLen, expectedRead] = GetParam();
std::vector<BYTE> data(writeLen, 0x42);
if (writeLen > 0) {
buffer.WriteBuffer(data.data(), (ULONG)writeLen);
}
std::vector<BYTE> result(readLen > 0 ? readLen : 1);
ULONG actual = buffer.ReadBuffer(result.data(), (ULONG)readLen);
EXPECT_EQ(actual, expectedRead);
}
INSTANTIATE_TEST_SUITE_P(
ReadLengths,
ServerBufferParameterizedTest,
::testing::Values(
std::make_tuple(10, 5, 5),
std::make_tuple(5, 10, 5),
std::make_tuple(0, 5, 0),
std::make_tuple(100, 0, 0),
std::make_tuple(10000, 5000, 5000)
)
);