This commit is contained in:
2026-08-31 22:49:42 +08:00
parent 109e8af3d5
commit 4e5ae52e54
35 changed files with 3606 additions and 22 deletions
+147
View File
@@ -0,0 +1,147 @@
#include "c_TrieST.h"
#include "c_Test.h"
#include <stdlib.h>
#include <stdio.h>
typedef struct {
uint32_t gateway_id;
char protocol_tag[16];
} RouteConfig_t;
static void* test_trie_val_cp(const void* data, void* arg) {
(void)arg;
const RouteConfig_t* src = (const RouteConfig_t*)data;
RouteConfig_t* clone = (RouteConfig_t*)malloc(sizeof(RouteConfig_t)); // 模拟独立动态开辟
if (clone) {
clone->gateway_id = src->gateway_id;
strcpy(clone->protocol_tag, src->protocol_tag);
}
return (void*)clone;
}
static void test_trie_val_free(void* data, void* arg) {
(void)arg;
if (data) {
free(data); // 原路深层爆破销毁
}
}
TEST_CASE(test_c_TrieST_Extreme_O_W_CRUD) {
c_TrieST_t trie;
// 初始化多态单词查找树,绑定虚操作,且传递 NULL 检验默认 Fallback 降级分配器机制
c_err_t err = c_TrieST_Init(&trie, test_trie_val_cp, test_trie_val_free, NULL, NULL);
ASSERT_INT_EQ(C_ERR_OK, err);
// 构建测试密集变长前缀树丛:"sea", "seashells", "she"
RouteConfig_t config_sea = { 101, "HTTP" };
RouteConfig_t config_shells = { 202, "MQTT" };
RouteConfig_t config_she = { 303, "gRPC" };
// 1. Put 基础写入断言
ASSERT_INT_EQ(C_ERR_OK, c_TrieST_Put(&trie, "sea", &config_sea));
ASSERT_INT_EQ(C_ERR_OK, c_TrieST_Put(&trie, "seashells", &config_shells));
ASSERT_INT_EQ(C_ERR_OK, c_TrieST_Put(&trie, "she", &config_she));
ASSERT_INT_EQ(3, (int)trie.size);
// Contains 与符号模糊隔离断言
ASSERT_TRUE(c_TrieST_Contains(&trie, "seashells"));
ASSERT_TRUE(!c_TrieST_Contains(&trie, "seash")); // 前缀虽通,但非完整独立有效键,必须返回 false
// 2. Get 常数时间穿透读取与多态结构体字段验证
void* fetched_ptr = c_TrieST_Get(&trie, "seashells");
ASSERT_TRUE(fetched_ptr != NULL);
RouteConfig_t* match_conf = (RouteConfig_t*)fetched_ptr;
ASSERT_INT_EQ(202, (int)match_conf->gateway_id);
ASSERT_TRUE(strcmp("MQTT", match_conf->protocol_tag) == 0);
// 3. Put 相同键下的覆写更新(Overwrite)特性核验
RouteConfig_t config_update = { 202, "HTTP/3" };
ASSERT_INT_EQ(C_ERR_OK, c_TrieST_Put(&trie, "seashells", &config_update));
ASSERT_INT_EQ(3, (int)trie.size); // 全局大小强力守恒
match_conf = (RouteConfig_t*)c_TrieST_Get(&trie, "seashells");
ASSERT_TRUE(strcmp("HTTP/3", match_conf->protocol_tag) == 0); // 覆写完全奏效
// 4. Delete 惰性级联剪枝删除绝对安全验证
// 斩断移出带有深度嵌套延伸子代路径的父节点 "sea"
ASSERT_INT_EQ(C_ERR_OK, c_TrieST_Delete(&trie, "sea"));
ASSERT_INT_EQ(2, (int)trie.size);
ASSERT_TRUE(c_TrieST_Get(&trie, "sea") == NULL);
// 🌟【硬核级联完整性验证】:虽然 "sea" 节点对应的 val 被剥离,
// 但因为它的后方还延伸驻留着有效长字符串分支 "seashells"
// 逆向惰性剪枝控制流应当自适应保留后面的子孙拓扑!断言 "seashells" 必须依然可以被完美高并发检索!
ASSERT_TRUE(c_TrieST_Contains(&trie, "seashells"));
// 5. 移出完全孤立的悬空分支节点 "she"
ASSERT_INT_EQ(C_ERR_OK, c_TrieST_Delete(&trie, "she"));
ASSERT_INT_EQ(1, (int)trie.size);
// 6. 统一解构注销,原路物理洗刷洗净所有残存节点与多态对象空间
c_TrieST_Destroy(&trie);
}
TEST_CASE(test_c_TrieST_ParamConstraints) {
c_TrieST_t local_trie;
c_TrieST_Init(&local_trie, NULL, NULL, NULL, &c_DefaultAllocator);
RouteConfig_t dummy = { 999, "RAW" };
// 5. 验证各类极值边界及非法参数的强拦截
ASSERT_INT_EQ(C_ERR_PARAM, c_TrieST_Init(NULL, NULL, NULL, NULL, NULL));
ASSERT_INT_EQ(C_ERR_PARAM, c_TrieST_Put(NULL, "toxic", &dummy));
ASSERT_INT_EQ(C_ERR_EMPTY, c_TrieST_Delete(&local_trie, "toxic")); // 空仓删除安全返回 C_ERR_EMPTY
c_TrieST_Destroy(&local_trie);
}
TEST_CASE(test_c_TrieST_StringBuffer_HighLevelPipeline) {
c_TrieST_t trie;
c_TrieST_Init(&trie, NULL, NULL, NULL, &c_DefaultAllocator);
int dummy_v = 1;
c_TrieST_Put(&trie, "api/v1/user", &dummy_v);
c_TrieST_Put(&trie, "api/v1/user/profile", &dummy_v);
c_TrieST_Put(&trie, "api/v1/user/profile/avatar", &dummy_v);
c_TrieST_Put(&trie, "api/v2/auth", &dummy_v);
c_TrieST_Put(&trie, "app/v1/user", &dummy_v);
c_StringList_t result_list;
c_StringList_Init(&result_list, 4, 0);
// 1. KeysWithPrefix 断言(前缀拼写补全联想)
c_err_t err = c_TrieST_KeysWithPrefix(&trie, "api/v1/user", &result_list);
ASSERT_INT_EQ(C_ERR_OK, err);
ASSERT_INT_EQ(3, (int)c_StringList_Size(&result_list));
ASSERT_TRUE(strcmp("api/v1/user", c_StringList_Get(&result_list, 0)) == 0);
ASSERT_TRUE(strcmp("api/v1/user/profile/avatar", c_StringList_Get(&result_list, 2)) == 0);
// 2. KeysThatMatch 断言(通配符并发拦截)
c_StringList_Clear(&result_list);
err = c_TrieST_KeysThatMatch(&trie, "ap./v1/user", &result_list);
ASSERT_INT_EQ(C_ERR_OK, err);
ASSERT_INT_EQ(2, (int)c_StringList_Size(&result_list));
ASSERT_TRUE(strcmp("api/v1/user", c_StringList_Get(&result_list, 0)) == 0);
// 3. LongestPrefixOf 断言(最长分级掩码前缀寻址)
c_StringList_Clear(&result_list);
const char* network_url = "api/v1/user/profile/settings/security_token";
err = c_TrieST_LongestPrefixOf(&trie, network_url, &result_list);
ASSERT_INT_EQ(C_ERR_OK, err);
ASSERT_INT_EQ(1, (int)c_StringList_Size(&result_list));
ASSERT_TRUE(strcmp("api/v1/user/profile", c_StringList_Get(&result_list, 0)) == 0);
c_StringList_Destroy(&result_list);
c_TrieST_Destroy(&trie);
}
// ==========================================
// 5. 主集成入口
// ==========================================
int main(void) {
TEST_START(C_TrieST_R_waySymbolTable_TestSuite);
RUN_TEST(test_c_TrieST_Extreme_O_W_CRUD);
RUN_TEST(test_c_TrieST_ParamConstraints);
RUN_TEST(test_c_TrieST_StringBuffer_HighLevelPipeline);
TEST_REPORT();
return (g_test_registry.failed_count > 0 ? 1 : 0);
}