147 lines
6.0 KiB
C
147 lines
6.0 KiB
C
#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);
|
||
} |