Files
MeowOS-For-R3P2/patch_v2/meow_launcherd/test_mf_logsig.c
T
AskaEth 0d6c56100f fix(m52): r1 评审 P2-1 class 缺失 WARN 去刷屏 + 两个 nit(snprintf clamp / 恒真断言)
P2-1(必修):`multi_font: class %s font %s missing, fallback global` 与上一轮修掉的
enabled 行同在 meow_font_reload_multifont() 里、被 main_menu.c:1385 每 2s 调一次;
命中「某个 font.class_* 非空但文件缺失/不可读」时最多 6 行/2s(3 行/s),比 enabled
行凶 6 倍,会让「空转 60s 日志不增长」在 class 缺失形态下失效。
改法:循环内只记「本轮缺失类别位图」,循环外经新纯函数 mf_missing_warn_mask() 做跃迁
判定(缺失集合不变 → 静默;新类别缺失 → 1 条;恢复后再缺失 → 再 1 条)。回退行为不变
(缺失类别照旧回退全局),日志文本/参数不变。另加 _Static_assert 钉住类别数 ≤32(位图宽度)。

nit:wd_log() 的 snprintf 返回值显式 clamp(原「buf≤511+前缀≤23<544」是隐式不变量);
test_wd_fw 的 "scan finds self" 原断言带 `|| np > 0` 恒真、等于没测 → 改为真查表断言
getpid() 在 wd_rg_pid[] 中且 comm 非空、并与 /proc/self/stat 的 pid/ppid 交叉核对。

验证:test_wd_fw 128 pass/0 fail(原 124,+4 来自强化后的自扫断言);
test_mf_logsig 21 pass/0 fail(原 13,+8 为 P2-1 验收:单类缺失 60s@2s 只 1 条、
缺失集合变化再 1 条、恢复后再缺失再 1 条);launcher 宿主测试 ALL PASS;
三处交叉编译 0 warning(watchdog 100,116 B/25f76950、launcherd 902,044 B/75629078、
audiod 68,732 B/ebb9a7ac 未变=bind hunk 未动)。
2026-11-12 08:02:22 +08:00

137 lines
6.9 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_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 <stdio.h>
#include <string.h>
#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);
}
/* ---- 6. 「class 字体缺失」WARN 的跃迁门控(r1 评审 P2-1 的验收断言)----
* 场景:某个 font.class_* 配置了但字体文件缺失 → 该类别回退全局(行为不变),
* 旧实现每 2s 每类各打一条(最多 6 行/2s = 3 行/s)。要求:
* 缺失集合不变 → 60s(30 次) 只出现 1 次;
* 缺失的类别变了(另一个 class 也缺失)→ 再出现 1 次(不是一次性闩锁);
* 某类恢复后再缺失 → 也算新跃迁,再 1 次。 */
{
unsigned logged = 0;
int warns = 0;
/* (a) 只有 class_num(2) 缺失:连续 30 次(60s @2s) */
for (int i = 0; i < 30; i++)
if (mf_missing_warn_mask(&logged, 1u << 2)) warns++;
check("class missing 60s @2s -> exactly 1 WARN", warns, 1);
/* (b) 缺失集合不变(再 30 次):不增长 */
for (int i = 0; i < 30; i++)
if (mf_missing_warn_mask(&logged, 1u << 2)) warns++;
check("class missing unchanged -> no new WARN", warns, 1);
/* (c) class_latin(3) 也变缺失:只多 1 次(且只针对新缺失的那一类) */
{
unsigned fresh = mf_missing_warn_mask(&logged, (1u << 2) | (1u << 3));
warns += fresh ? 1 : 0;
check("new missing class -> exactly 1 more WARN", fresh, 1u << 3);
}
check("total WARN after set change", warns, 2);
/* (d) class_num(2) 恢复 → 位图缩小但不再打;再次缺失 → 重新打一次 */
check("recovered class -> no WARN", mf_missing_warn_mask(&logged, 1u << 3), 0);
check("re-missing after recovery -> WARN again",
mf_missing_warn_mask(&logged, (1u << 2) | (1u << 3)), 1u << 2);
/* (e) 全部恢复 → 位图清零、静默 */
check("none missing -> no WARN", mf_missing_warn_mask(&logged, 0), 0);
check("logged mask reset", logged, 0);
printf(" (旧实现 60s @2s 单类缺失 = 30 行;新实现 = 1 行)\n");
}
printf("\n%d pass, %d fail\n", g_pass, g_fail);
return g_fail ? 1 : 0;
}