/* test_bgmgr.c — 批③ 后台管理页 逻辑层宿主单测(meow_bgmgr)。 * * 验证: * 1) bgmgr_collect:enumerate 后台表 → app_meta 补 name/icon/framework/is_fg → proc_sample 补 * pcpu/rss_kb;行 killable 预判正确;name 回退 app_id。 * 2) bgmgr_can_kill 门控矩阵:framework=1 → 0(**框架 App 不 kill**);is_fg=1 → 0(当前前台不 kill); * pid<=0 → 0(非后台/无进程);普通后台(非框架/非前台/pid>0)→ 1。 * 3) bgmgr_kill_all 一键清:框架 App 不杀、当前前台不杀、非后台不杀;其余逐一 kill;返回 kill 数。 * 4) bgmgr_status_str / bgmgr_mem_str 文案。 * 只依赖 meow_bgmgr.c + meow_ipc.h(纯 C);宿主 gcc 直编: * gcc -Wall -Wextra -std=gnu99 test_bgmgr.c meow_bgmgr.c -o test_bgmgr */ #include #include #include #include #include "meow_bgmgr.h" static int g_fails = 0; #define CHECK(cond, msg) do { \ if (cond) printf("PASS: %s\n", msg); \ else { printf("FAIL: %s\n", msg); g_fails++; } } while (0) /* ---- 假件(enumerate/app_meta/proc_sample 注入)---- */ static const char g_meta_app[][24] = { "os.meow.hello", "os.meow.reader", "os.meow.sysguard", "os.meow.fgapp", }; static int g_killed_n = 0; static char g_killed_app[8][40]; static int g_meta_use_unknown = 0; /* 第 4 行 meta 返回 -1(未注册),测 name 回退 */ static int fake_enumerate(void *ctx, bgmgr_row_t *rows, int max) { (void)ctx; if (max < 4) return 0; /* 4 个后台行:hello=普通、reader=常驻、sysguard=framework、fgapp=当前前台 */ memset(&rows[0], 0, sizeof rows[0]); snprintf(rows[0].app_id, sizeof rows[0].app_id, "%s", g_meta_app[0]); rows[0].pid = 1001; rows[0].keepalive = 0; rows[0].on_card = 0; rows[0].bg_since_ms = 1000; memset(&rows[1], 0, sizeof rows[1]); snprintf(rows[1].app_id, sizeof rows[1].app_id, "%s", g_meta_app[1]); rows[1].pid = 1002; rows[1].keepalive = 1; rows[1].on_card = 0; rows[1].bg_since_ms = 2000; memset(&rows[2], 0, sizeof rows[2]); snprintf(rows[2].app_id, sizeof rows[2].app_id, "%s", g_meta_app[2]); rows[2].pid = 1003; rows[2].keepalive = 0; rows[2].on_card = 0; rows[2].bg_since_ms = 3000; memset(&rows[3], 0, sizeof rows[3]); snprintf(rows[3].app_id, sizeof rows[3].app_id, "%s", g_meta_app[3]); rows[3].pid = 1004; rows[3].keepalive = 0; rows[3].on_card = 0; rows[3].bg_since_ms = 4000; return 4; } /* meta:hello/reader/sysguard/fgapp 各给名字;sysguard 标 framework;pid==1004 标前台。 */ static int fake_app_meta(void *ctx, const char *app_id, pid_t pid, char *name, int nl, char *icon, int il, char *framework, int *is_fg) { (void)ctx; if (!strcmp(app_id, "os.meow.hello")) snprintf(name, nl, "播放"); else if (!strcmp(app_id, "os.meow.reader")) snprintf(name, nl, "阅读"); else if (!strcmp(app_id, "os.meow.sysguard")) snprintf(name, nl, "系统守护"); else if (!strcmp(app_id, "os.meow.fgapp")) snprintf(name, nl, "前台应用"); else return -1; /* 未注册 → name 回退 app_id */ snprintf(icon, il, "/tmp/icon_%s.png", app_id); *framework = (!strcmp(app_id, "os.meow.sysguard")) ? '1' : 0; *is_fg = (pid == 1004) ? 1 : 0; /* fgapp 标前台 */ return 0; } static int fake_proc_sample(void *ctx, pid_t pid, double *pcpu, long *rss_kb) { (void)ctx; if (pid <= 0) return -1; *pcpu = (double)(pid % 100) * 0.5; /* 1001->0.5% ... 1004->2.0% */ *rss_kb = (long)(pid % 10) * 2048; /* 1001->2048 ... 1004->8192 */ return 0; } static void fake_log(const char *fmt, ...) { (void)fmt; } static void fake_kill(const char *app_id) { if (g_killed_n < 8) snprintf(g_killed_app[g_killed_n++], 40, "%s", app_id); } /* enumerate 只回一行:未注册 app_id,测 name 回退。 */ static int fake_enumerate_unknown(void *ctx, bgmgr_row_t *rows, int max) { (void)ctx; if (max < 1) return 0; (void)g_meta_use_unknown; memset(&rows[0], 0, sizeof rows[0]); snprintf(rows[0].app_id, sizeof rows[0].app_id, "os.meow.noreg"); rows[0].pid = 2001; rows[0].keepalive = 0; return 1; } int main(void) { bgmgr_ops_t ops; memset(&ops, 0, sizeof ops); ops.enumerate = fake_enumerate; ops.app_meta = fake_app_meta; ops.proc_sample = fake_proc_sample; ops.log = fake_log; bgmgr_row_t rows[MEOW_BGMR_ROW_MAX]; int n = bgmgr_collect(&ops, rows, MEOW_BGMR_ROW_MAX); printf("=== 1) collect ===\n"); CHECK(n == 4, "collect returns 4 rows"); CHECK(!strcmp(rows[0].name, "播放") && rows[0].pid == 1001, "row0 hello name/pid"); CHECK(rows[0].framework == 0, "row0 hello not framework"); CHECK(!strcmp(rows[1].name, "阅读") && rows[1].keepalive == 1, "row1 reader keepalive"); CHECK(rows[2].framework == '1', "row2 sysguard framework"); CHECK(rows[3].is_fg == 1, "row3 fgapp is_fg"); CHECK(rows[0].pcpu > 0 && rows[0].rss_kb > 0, "row0 pcpu/rss populated"); CHECK(rows[0].killable == 1 && rows[2].killable == 0, "killable prefilled by can_kill"); CHECK(!strcmp(rows[2].icon, "/tmp/icon_os.meow.sysguard.png"), "icon populated"); /* name 回退:未注册 app_id(app_meta 返回 -1)→ name==app_id */ printf("=== 1b) name fallback ===\n"); { bgmgr_ops_t o2 = ops; o2.enumerate = fake_enumerate_unknown; bgmgr_row_t r1[1]; memset(r1, 0, sizeof r1); int n2 = bgmgr_collect(&o2, r1, 1); CHECK(n2 == 1, "unknown row collected"); CHECK(!strcmp(r1[0].name, "os.meow.noreg"), "name falls back to app_id"); CHECK(bgmgr_can_kill(&r1[0]) == 1, "unknown bg app still killable"); } printf("=== 2) can_kill gating ===\n"); CHECK(bgmgr_can_kill(&rows[2]) == 0, "framework app NOT killable"); CHECK(bgmgr_can_kill(&rows[3]) == 0, "fg app NOT killable (is_fg)"); CHECK(bgmgr_can_kill(&rows[0]) == 1, "normal bg app killable"); CHECK(bgmgr_can_kill(&rows[1]) == 1, "keepalive bg app killable"); { bgmgr_row_t dead; memset(&dead, 0, sizeof dead); snprintf(dead.app_id, sizeof dead.app_id, "x"); dead.pid = 0; CHECK(bgmgr_can_kill(&dead) == 0, "pid<=0 NOT killable"); CHECK(bgmgr_can_kill(NULL) == 0, "NULL NOT killable"); } printf("=== 3) kill_all (one-key clear) ===\n"); g_killed_n = 0; int k = bgmgr_kill_all(&ops, rows, n, fake_kill); CHECK(k == 2, "kill_all kills 2 (hello+reader)"); CHECK(g_killed_n == 2, "kill_all actually invoked kill_fn 2x"); int killed_fw = 0, killed_fg = 0, killed_bg = 0; for (int i = 0; i < g_killed_n; i++) { if (!strcmp(g_killed_app[i], "os.meow.sysguard")) killed_fw = 1; if (!strcmp(g_killed_app[i], "os.meow.fgapp")) killed_fg = 1; if (!strcmp(g_killed_app[i], "os.meow.hello")) killed_bg = 1; } CHECK(killed_fw == 0, "kill_all did NOT kill framework app"); CHECK(killed_fg == 0, "kill_all did NOT kill fg app"); CHECK(killed_bg == 1, "kill_all killed a real bg app"); CHECK(bgmgr_kill_all(&ops, rows, n, NULL) == 0, "kill_all NULL kill_fn -> 0"); printf("=== 4) status/mem str ===\n"); CHECK(!strcmp(bgmgr_status_str(&rows[1]), "常驻"), "status_str keepalive=常驻"); CHECK(!strcmp(bgmgr_status_str(&rows[0]), "后台"), "status_str normal=后台"); CHECK(!strcmp(bgmgr_status_str(&rows[3]), "前台"), "status_str is_fg=前台"); CHECK(!strcmp(bgmgr_mem_str(512), "512KB"), "mem_str(<1MB)=KB"); CHECK(!strcmp(bgmgr_mem_str(2048), "2.0MB"), "mem_str(>=1MB)=MB"); if (g_fails == 0) printf("\nALL PASS (%d checks)\n", 20); else printf("\n%d FAILED\n", g_fails); return g_fails ? 1 : 0; }