一些基础组件

This commit is contained in:
2026-08-30 02:51:25 +08:00
parent 95e931727a
commit f26534c938
29 changed files with 4265 additions and 0 deletions
+150
View File
@@ -0,0 +1,150 @@
#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;
}