Files
ligent/tests/test_capability.c
T
2026-10-03 14:13:21 +08:00

93 lines
4.3 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.
/* test_capability.c - 能力探测的纯逻辑部分
*
* 探测序列本身(基线 -> 合并 -> 拆开)要发 HTTP,属于端到端范畴,
* 由 e2e 第 51 段对着 mock 覆盖:正常模型 / 不收图片 / 不收 tools /
* 探测失败(401)/ --no-probe 五种走法都在那儿验。
*
* 这里只测不需要网络的:名字映射、关闭探测时的语义、缓存查询。
* 其中"关闭探测必须给未测而不是不支持"那条是回归测试 —— 那句话看着像废话,
* 但 CAP_NO 恰好是 0,而 Agent 是 memset 出来的,忘了显式初始化就会一声不响地
* 把所有工具摘掉。这个 bug 真的发生过一次。
*/
#include "capability.h"
#include "llm.h"
#include <stdio.h>
#include <string.h>
static int failures = 0;
static int checks = 0;
#define CHECK(cond, ...) \
do { \
checks++; \
if (!(cond)) { \
failures++; \
printf(" ✗ %s:%d: ", __FILE__, __LINE__); \
printf(__VA_ARGS__); \
printf("\n"); \
} \
} while (0)
int main(void)
{
/* CAP_NO 必须是 0 —— Agent 是 memset 出来的,整个 capability 模块的
* 设计都建立在"零值不能是某个真实结论"之上。这条断言是那个 bug 的护栏。 */
CHECK(CAP_NO == 0, "CAP_NO 应为 0(零值即'不支持'是事故的根源)");
CHECK(CAP_UNKNOWN != CAP_NO, "未知与不支持必须是两个不同的值");
CHECK(CAP_UNKNOWN != CAP_YES, "未知与支持必须是两个不同的值");
puts("名字映射");
CHECK(strcmp(cap_name(CAP_YES), "支持") == 0, "YES");
CHECK(strcmp(cap_name(CAP_NO), "不支持") == 0, "NO");
CHECK(strcmp(cap_name(CAP_UNKNOWN), "未测") == 0, "UNKNOWN");
/* 任何不是 YES/NO 的值都该落到"未测",而不是碰巧落到某一个 */
CHECK(strcmp(cap_name(42), "未测") == 0, "越界值应落到未测");
puts("关掉探测:一律未测,绝不冒充结论");
/* 用可变数组而不是字面量:LlmConfig 的这些字段是 char *(真要释放的),
* 而 -Wwrite-strings 下 "字面量" 是 const char * —— 直接赋值会被警告。 */
char model[] = "some-model";
char base_url[] = "http://127.0.0.1:1/v1";
LlmConfig cfg;
memset(&cfg, 0, sizeof cfg);
cfg.model = model;
cfg.base_url = base_url;
cfg.timeout = 1;
cap_cache_clear();
Capabilities c;
memset(&c, 0xAB, sizeof c); /* 故意填脏,验证会被完整覆盖 */
int probed = cap_get(&cfg, 0, &c, 0, NULL, 0);
CHECK(probed == 0, "被禁用时不该声称探测过");
CHECK(c.probed == 0, "probed 应为 0");
CHECK(c.vision == CAP_UNKNOWN, "禁用时 vision 应为未测,实际 %d", c.vision);
CHECK(c.tools == CAP_UNKNOWN, "禁用时 tools 应为未测,实际 %d", c.tools);
CHECK(c.conclusive == 0, "禁用时不该声称有结论");
/* 关键回归:禁用时的结果拿去决定工具表,必须"全都留着" */
CHECK(c.vision != CAP_NO, "禁用时不能表现为不支持(否则会藏掉 read_image)");
CHECK(c.tools != CAP_NO, "禁用时不能表现为不支持(否则会摘掉整张工具表)");
puts("缓存查询");
Capabilities got;
memset(&got, 0xAB, sizeof got);
CHECK(cap_cached(&cfg, &got) == 0, "没测过时缓存应未命中");
/* 关掉探测不会写入缓存 */
CHECK(cap_cached(&cfg, NULL) == 0, "禁用不该往缓存里写东西");
cap_cache_clear();
CHECK(cap_cached(&cfg, &got) == 0, "清空之后仍应未命中");
/* 空指针不该崩 */
cap_get(NULL, 0, &c, 0, NULL, 0);
CHECK(c.vision == CAP_UNKNOWN, "cfg 为空也要给未测");
cap_get(&cfg, 0, NULL, 0, NULL, 0);
cap_cache_clear();
CHECK(1, "空指针路径没有崩");
printf("\n%d 项检查,%d 项失败\n", checks, failures);
return failures ? 1 : 0;
}