/* test_mf_logsig.c — 宿主单测:多字体「日志跃迁签名」与门控(M52 刷屏整改)。 * * 背景:meow_font_reload_multifont() 被 launcher 主循环每 2s 调一次,旧实现每次无条件 * 打 `multi_font: enabled, ...`(真机 5297/6603 行 = 80%)。整改后只在配置签名变化时打。 * 本测试守两件事: * (1) 签名对**所有**能改变行为的输入敏感(on / global / 各类别 / distinct / truncated); * (2) 输入不变时签名恒定 —— 即 60s 空转(30 次调用)只产生 1 条日志。 * * 编译运行:gcc -I. -Wall -Wextra test_mf_logsig.c -o test_mf_logsig && ./test_mf_logsig * (不依赖 launcher 其它模块 / 不依赖设备;纯头文件逻辑) */ #include "mf_logsig.h" #include #include #define NCLS 6 static int g_pass = 0, g_fail = 0; static void check(const char *name, int got, int want) { if (got == want) { g_pass++; printf("PASS %s\n", name); } else { g_fail++; printf("FAIL %s: got %d want %d\n", name, got, want); } } /* 真机 settings.conf 的多字体形态(2026-11-11): * display.multi_font = 1 * font.file = MeowOS/fonts/ztest/regular/font.png → global = ztest * font.class_num / font.class_latin = MeowOS/fonts/google_sans/regular/font.png * → distinct = 2(ztest + google_sans) */ #define G_ZTEST "/usr/data/mnt/sd_0/MeowOS/fonts/ztest/regular/font.png" #define C_GOOGLE "/usr/data/mnt/sd_0/MeowOS/fonts/google_sans/regular/font.png" #define C_MISANS "/usr/data/mnt/sd_0/MeowOS/fonts/misans/regular/font.png" int main(void) { /* ---- 1. 真机形态:同输入 → 同签名(1000 次不变,这就是「空转不打日志」的根基)---- */ const char *base[NCLS] = { NULL, NULL, C_GOOGLE, C_GOOGLE, NULL, NULL }; uint64_t s0 = mf_logsig(1, G_ZTEST, base, NCLS, 2, 0); int stable = 1; for (int i = 0; i < 1000; i++) if (mf_logsig(1, G_ZTEST, base, NCLS, 2, 0) != s0) stable = 0; check("same config -> same sig (1000x)", stable, 1); /* ---- 2. 每一条输入变化都必须换签名 ---- */ check("on 1->0 changes sig", mf_logsig(0, G_ZTEST, base, NCLS, 2, 0) != s0, 1); check("global font changes sig", mf_logsig(1, "/usr/data/mnt/sd_0/MeowOS/fonts/default/regular/font.png", base, NCLS, 2, 0) != s0, 1); { const char *c[NCLS] = { NULL, NULL, C_MISANS, C_GOOGLE, NULL, NULL }; check("class_num changes sig", mf_logsig(1, G_ZTEST, c, NCLS, 2, 0) != s0, 1); } check("distinct 2->1 changes sig", mf_logsig(1, G_ZTEST, base, NCLS, 1, 0) != s0, 1); check("truncated 0->1 changes sig", mf_logsig(1, G_ZTEST, base, NCLS, 2, 1) != s0, 1); check("config-fail (-1) changes sig", mf_logsig(1, G_ZTEST, base, NCLS, -1, 0) != s0, 1); /* ---- 3. 空配置项形态:NULL 与 "" 等价(settings 空值 = 该类回退全局)---- */ { const char *a[NCLS] = { NULL, NULL, NULL, NULL, NULL, NULL }; const char *b[NCLS] = { "", "", "", "", "", "" }; check("NULL == \"\"", mf_logsig(1, G_ZTEST, a, NCLS, 1, 0) == mf_logsig(1, G_ZTEST, b, NCLS, 1, 0), 1); check("null cpng array tolerated", mf_logsig(1, G_ZTEST, NULL, NCLS, 1, 0) > 0, 1); } /* ---- 4. 字段边界不串味:("ab","c") 与 ("a","bc") 不能撞 ---- */ { const char *x[NCLS] = { "ab", "c", NULL, NULL, NULL, NULL }; const char *y[NCLS] = { "a", "bc", NULL, NULL, NULL, NULL }; check("field boundary no collision", mf_logsig(1, G_ZTEST, x, NCLS, 2, 0) != mf_logsig(1, G_ZTEST, y, NCLS, 2, 0), 1); } /* ---- 5. 门控:60s 空转(2s 一次 × 30)只打 1 条;改配置再打 1 条;改回来再打 1 条 ---- */ { uint64_t last = 0; int valid = 0, emits = 0; for (int i = 0; i < 30; i++) { /* 首轮 + 29 轮空转 */ uint64_t sig = mf_logsig(1, G_ZTEST, base, NCLS, 2, 0); if (mf_logsig_changed(&last, &valid, sig)) emits++; } check("60s idle @2s -> exactly 1 log line", emits, 1); { const char *c[NCLS] = { NULL, NULL, C_MISANS, C_GOOGLE, NULL, NULL }; uint64_t sig = mf_logsig(1, G_ZTEST, c, NCLS, 2, 0); if (mf_logsig_changed(&last, &valid, sig)) emits++; } check("class change -> 2nd log line", emits, 2); for (int i = 0; i < 30; i++) { /* 再空转 60s:不应再增长 */ uint64_t sig = mf_logsig(1, G_ZTEST, base, NCLS, 2, 0); if (mf_logsig_changed(&last, &valid, sig)) emits++; } check("back to original -> 3rd line, then silent", emits, 3); /* 真实行数:旧实现 60s = 30 行(每 2s 一条),新实现 60s = 0 行(稳定后) */ printf(" (旧实现 60s 空转 = 30 行;新实现稳态 = 0 行,本用例全程 %d 行)\n", emits); } printf("\n%d pass, %d fail\n", g_pass, g_fail); return g_fail ? 1 : 0; }