150 lines
7.8 KiB
C
150 lines
7.8 KiB
C
#include "c_ByteRingBuffer.h"
|
||||
|
|
#include "c_Test.h"
|
|||
|
|
|
|||
|
|
#include <stdlib.h>
|
|||
|
|
#include <stdio.h>
|
|||
|
|
|
|||
|
|
TEST_CASE(test_ring_buffer_is_mechanics) {
|
|||
|
|
c_ByteRingBuffer_t rb;
|
|||
|
|
// 初始化容量为 4 的环形缓冲区
|
|||
|
|
ASSERT_INT_EQ(C_ERR_OK, c_ByteRingBuffer_Init(&rb, 4, &c_DefaultAllocator));
|
|||
|
|
|
|||
|
|
// 1. 基础空态与高危参数测试
|
|||
|
|
ASSERT_INT_EQ(C_FALSE, c_ByteRingBuffer_Is(NULL, 0, 'A')); // 实例为空
|
|||
|
|
ASSERT_INT_EQ(C_FALSE, c_ByteRingBuffer_Is(&rb, -1, 'A')); // 相对偏移为负
|
|||
|
|
ASSERT_INT_EQ(C_FALSE, c_ByteRingBuffer_Is(&rb, 0, 0x00)); // 空态下的读取
|
|||
|
|
|
|||
|
|
// 2. 写入数据:使缓冲区进入常规状态
|
|||
|
|
c_ByteRingBuffer_WriteByte(&rb, 0xAA);
|
|||
|
|
c_ByteRingBuffer_WriteByte(&rb, 0xBB);
|
|||
|
|
|
|||
|
|
ASSERT_INT_EQ(C_TRUE, c_ByteRingBuffer_Is(&rb, 0, 0xAA));
|
|||
|
|
ASSERT_INT_EQ(C_TRUE, c_ByteRingBuffer_Is(&rb, 1, 0xBB));
|
|||
|
|
ASSERT_INT_EQ(C_FALSE, c_ByteRingBuffer_Is(&rb, 0, 0xFF)); // 值不匹配
|
|||
|
|
ASSERT_INT_EQ(C_FALSE, c_ByteRingBuffer_Is(&rb, 2, 0x00)); // 索引越界
|
|||
|
|
|
|||
|
|
// 3. 核心:构造“回绕状态(Wrapped-around)”下的 Is 判定
|
|||
|
|
uint8_t dummy;
|
|||
|
|
c_ByteRingBuffer_ReadByte(&rb, &dummy); // 消费 0xAA,head 变为 1
|
|||
|
|
c_ByteRingBuffer_ReadByte(&rb, &dummy); // 消费 0xBB,head 变为 2
|
|||
|
|
|
|||
|
|
// 连续写入,迫使 tail 翻越物理末尾(容量4)回绕到索引 0
|
|||
|
|
c_ByteRingBuffer_WriteByte(&rb, 0x11); // 物理位置 2
|
|||
|
|
c_ByteRingBuffer_WriteByte(&rb, 0x22); // 物理位置 3
|
|||
|
|
c_ByteRingBuffer_WriteByte(&rb, 0x33); // 物理位置 0 (回绕)
|
|||
|
|
|
|||
|
|
// 此时队列相对 head(位置2) 的顺序为: 0x11, 0x22, 0x33
|
|||
|
|
ASSERT_INT_EQ(C_TRUE, c_ByteRingBuffer_Is(&rb, 0, 0x11));
|
|||
|
|
ASSERT_INT_EQ(C_TRUE, c_ByteRingBuffer_Is(&rb, 1, 0x22));
|
|||
|
|
ASSERT_INT_EQ(C_TRUE, c_ByteRingBuffer_Is(&rb, 2, 0x33)); // 物理跨越边界验证成功
|
|||
|
|
ASSERT_INT_EQ(C_FALSE, c_ByteRingBuffer_Is(&rb, 3, 0x00)); // 依然能精准卡住边界
|
|||
|
|
|
|||
|
|
c_ByteRingBuffer_Destroy(&rb);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================================================================================================================
|
|||
|
|
// 测试二:c_ByteRingBuffer_Memcmp 词典序与加法回绕溢出验证
|
|||
|
|
// ==================================================================================================================
|
|||
|
|
TEST_CASE(test_ring_buffer_memcmp_lexicographical) {
|
|||
|
|
c_ByteRingBuffer_t rb;
|
|||
|
|
ASSERT_INT_EQ(C_ERR_OK, c_ByteRingBuffer_Init(&rb, 8, &c_DefaultAllocator));
|
|||
|
|
|
|||
|
|
uint8_t src[] = {'A', 'B', 'C', 'D'};
|
|||
|
|
c_ByteRingBuffer_WriteBuffer(&rb, src, 4);
|
|||
|
|
|
|||
|
|
uint8_t flat_match[] = {'B', 'C'};
|
|||
|
|
uint8_t flat_smaller[] = {'B', 'A'}; // 词典序较小
|
|||
|
|
uint8_t flat_larger[] = {'B', 'Z'}; // 词典序较大
|
|||
|
|
|
|||
|
|
// 1. 正常区间匹配
|
|||
|
|
ASSERT_INT_EQ(0, c_ByteRingBuffer_Memcmp(&rb, 1, flat_match, 2));
|
|||
|
|
|
|||
|
|
// 2. 词典序正负号健壮性验证(切断减法溢出隐患)
|
|||
|
|
ASSERT_INT_EQ(1, c_ByteRingBuffer_Memcmp(&rb, 1, flat_smaller, 2)); // 环形区 'C' > 外部 'A',返回 1
|
|||
|
|
ASSERT_INT_EQ(-1, c_ByteRingBuffer_Memcmp(&rb, 1, flat_larger, 2)); // 环形区 'C' < 外部 'Z',返回 -1
|
|||
|
|
|
|||
|
|
// 3. 【核心加固点】:高危整型加法回绕攻击防御检查
|
|||
|
|
// 在 32/64位系统下,传入接近最大值的 len,若内部直接执行 offset + len,会发生整型溢出回绕变成一个小数字,从而绕过越界判定
|
|||
|
|
c_size_t attack_len = (c_size_t)-1;
|
|||
|
|
int res = c_ByteRingBuffer_Memcmp(&rb, 1, flat_match, attack_len);
|
|||
|
|
ASSERT_INT_EQ(C_ERR_OUTOFBOUND, res); // 必须被溢出隔离墙强行拦截,安全返回错误码
|
|||
|
|
|
|||
|
|
c_ByteRingBuffer_Destroy(&rb);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================================================================================================================
|
|||
|
|
// 测试三:c_ByteRingBuffer_Strtoul 状态机大数溢出与流式连续解析验证
|
|||
|
|
// ==================================================================================================================
|
|||
|
|
TEST_CASE(test_ring_buffer_strtoul_state_machine) {
|
|||
|
|
c_ByteRingBuffer_t rb;
|
|||
|
|
ASSERT_INT_EQ(C_ERR_OK, c_ByteRingBuffer_Init(&rb, 64, NULL));
|
|||
|
|
|
|||
|
|
// 写入一段极其复杂的、模拟 AT 指令应答流的混合文本
|
|||
|
|
// 包含了:前导空白、十六进制前缀、正负号、八进制以及尾部垃圾包
|
|||
|
|
const char* stream = " \r\n -0x1A7F,0755,9999999999999999999999999999999999999999,END";
|
|||
|
|
c_ByteRingBuffer_WriteBuffer(&rb, (const uint8_t*)stream, strlen(stream));
|
|||
|
|
|
|||
|
|
unsigned long parsed_val = 0;
|
|||
|
|
c_size_t end_offset = 0;
|
|||
|
|
c_err_t err;
|
|||
|
|
|
|||
|
|
// -------------------------------------------------------------------------
|
|||
|
|
// 阶段 A: 验证 16 进制智能嗅探、前导空白跳过、补码取负机制
|
|||
|
|
// -------------------------------------------------------------------------
|
|||
|
|
// 期望:跳过空白,识别出 '-' 和 '0x',解析出 1A7F,并正确强转取负。base 设为 0 (自动侦测)
|
|||
|
|
err = c_ByteRingBuffer_Strtoul(&rb, 0, 0, &parsed_val, &end_offset);
|
|||
|
|
|
|||
|
|
ASSERT_INT_EQ(C_ERR_OK, err);
|
|||
|
|
// 0x1A7F = 6783。由于有负号,其无符号长整型等同于 (unsigned long)(-6783)
|
|||
|
|
ASSERT_TRUE(parsed_val == (unsigned long)(-6783));
|
|||
|
|
// 状态机应当精准停留在第一个非合法十六进制字符(也就是逗号 ',')的相对偏移位置
|
|||
|
|
ASSERT_INT_EQ(12, end_offset);
|
|||
|
|
|
|||
|
|
// -------------------------------------------------------------------------
|
|||
|
|
// 阶段 B: 验证 8 进制自动探测与非阻塞流式“接力解析”能力
|
|||
|
|
// -------------------------------------------------------------------------
|
|||
|
|
// 利用上一轮抛出的 end_offset + 1 (跳过逗号),直接在原位向后接力解析下一个数字
|
|||
|
|
err = c_ByteRingBuffer_Strtoul(&rb, end_offset + 1, 0, &parsed_val, &end_offset);
|
|||
|
|
|
|||
|
|
ASSERT_INT_EQ(C_ERR_OK, err);
|
|||
|
|
// 0755 以 0 开头被自动嗅探为 8 进制:7*64 + 5*8 + 5 = 448 + 40 + 5 = 493
|
|||
|
|
ASSERT_INT_EQ(493, parsed_val);
|
|||
|
|
ASSERT_INT_EQ(17, end_offset); // 停留在第二个逗号处
|
|||
|
|
|
|||
|
|
// -------------------------------------------------------------------------
|
|||
|
|
// 阶段 C: 验证超级大数输入的 ULONG_MAX 防回绕饱和截断机制
|
|||
|
|
// -------------------------------------------------------------------------
|
|||
|
|
// 接力解析那串长达几十位的恐怖数字,测试乘法防溢出墙
|
|||
|
|
err = c_ByteRingBuffer_Strtoul(&rb, end_offset + 1, 10, &parsed_val, &end_offset);
|
|||
|
|
|
|||
|
|
ASSERT_INT_EQ(C_ERR_OUTOFBOUND, err);
|
|||
|
|
// 必须稳定截断输出 ULONG_MAX,绝对不能因为发生底层相乘回绕而变成一个小数字
|
|||
|
|
ASSERT_TRUE(parsed_val == ULONG_MAX);
|
|||
|
|
// 状态机遇到非 10 进制字符(逗号 ',')安全收敛退出
|
|||
|
|
ASSERT_INT_EQ(58, end_offset);
|
|||
|
|
|
|||
|
|
// -------------------------------------------------------------------------
|
|||
|
|
// 阶段 D: 防御测试:向后探测完全没有数字的纯文本区
|
|||
|
|
// -------------------------------------------------------------------------
|
|||
|
|
// 从 57 + 1 处向后解析 "END",状态机应当识别出无数字可解析,优雅报错拒绝
|
|||
|
|
err = c_ByteRingBuffer_Strtoul(&rb, end_offset + 1, 10, &parsed_val, NULL);
|
|||
|
|
ASSERT_INT_EQ(C_ERR_PARAM, err);
|
|||
|
|
|
|||
|
|
c_ByteRingBuffer_Destroy(&rb);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================================================================================================================
|
|||
|
|
// 主测试入口
|
|||
|
|
// ==================================================================================================================
|
|||
|
|
int main(void) {
|
|||
|
|
TEST_START(C_ByteRingBuffer_Advanced_Extension_Tests);
|
|||
|
|
|
|||
|
|
// 运行加固后的全量测试集
|
|||
|
|
RUN_TEST(test_ring_buffer_is_mechanics);
|
|||
|
|
RUN_TEST(test_ring_buffer_memcmp_lexicographical);
|
|||
|
|
RUN_TEST(test_ring_buffer_strtoul_state_machine);
|
|||
|
|
|
|||
|
|
TEST_REPORT();
|
|||
|
|
|
|||
|
|
RETURN_TEST_STATUS;
|
|||
|
|
}
|