#include "c_ByteRingBuffer.h" #include "c_Test.h" #include #include 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; }