Files
cKit/Foundation/c_ByteRingBuffer.t.c
T
2026-08-30 02:51:25 +08:00

150 lines
7.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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); // 消费 0xAAhead 变为 1
c_ByteRingBuffer_ReadByte(&rb, &dummy); // 消费 0xBBhead 变为 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;
}