/* test_bg_keep.c — 批①`background_keepalive` 声明层宿主单测。 * * 验证 meow_parse_app_json 对 app.json 后台三位(background / background_audio / * background_keepalive)的解析与 meow_acct_sync 透传,重点覆盖**前缀不串扰**: * - "background_keepalive":true → a->background_keepalive=='1';且 background/background_audio * 在该行不被误命中(分别是 0/0); * - background:true → a->background=='1'(独立键匹配不受影响); * - background_audio:true → a->background_audio=='1'; * - 一行三键并存:三者各归其位; * - meow_acct_sync 透传 background_keepalive 到注册表。 * 实现手法同 test_fg_act.c:真实 include app_launcher.c,-ffunction-sections -Wl,--gc-sections * 只保留 parseInt/acct_sync/upsert/find 触及函数;json_str/meow_parse_depends/logmsg 由本文件提供 * 忠实桩(json_str 复刻 util.c 语义,含键前缀独立 ident_ch + 整体 UTF-8 截断)。 * * 运行(patch_v2/meow_launcherd 下): * gcc -D_GNU_SOURCE -Wall -Wextra -ffunction-sections -Wl,--gc-sections \ * -I. -o test_bg_keep test_bg_keep.c && ./test_bg_keep * 全 PASS -> exit 0。 */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include /* ---- logmsg:app_launcher.c 依赖,minimal 桩 ---- */ void logmsg(const char *fmt, ...) { (void)fmt; } /* ---- json_str:复刻 util.c 语义(键前缀独立 + 值提取 + UTF-8 截断)---- */ static int ident_ch(char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '.'; } static void utf8_trim(char *s) { size_t n = strlen(s), i = 0, last_good = 0; while (i < n) { unsigned char c = (unsigned char)s[i]; int len = (c < 0x80) ? 1 : (c >= 0xF0) ? 4 : (c >= 0xE0) ? 3 : (c >= 0xC0) ? 2 : 1; if (i + (size_t)len > n) break; i += (size_t)len; last_good = i; } s[last_good] = '\0'; } int json_str(const char *buf, const char *key, char *out, int olen) { out[0] = 0; if (!buf || !key || olen <= 0) return 0; const char *p = strstr(buf, key); if (!p) return 0; if (p > buf && ident_ch((unsigned char)p[-1])) return 0; /* 键前缀需独立 */ p += strlen(key); if (*p == '"') p++; /* JSON 键自身右引号 */ while (*p && (*p == ':' || *p == '=')) p++; while (*p == ' ' || *p == '\t') p++; if (*p == '"') p++; /* 值左引号 */ int i = 0; while (*p && *p != '"' && *p != ',' && *p != '\n' && *p != '\r' && i < olen - 1) out[i++] = *p++; out[i] = 0; while (i > 0 && (out[i - 1] == ' ' || out[i - 1] == '\t')) out[--i] = 0; utf8_trim(out); return (int)strlen(out); } #include "app_launcher.c" /* 真实实现:meow_parse_app_json / meow_acct_sync / meow_acct_upsert */ /* meow_parse_depends:本测试 app.json 无 depends 行,桩返回 0(struct meow_dep 此时已可见)。 */ int meow_parse_depends(const char *val, struct meow_dep *deps, int max) { (void)val; (void)deps; (void)max; return 0; } static int g_fail = 0; #define CHECK(cond, msg) do { \ if (!(cond)) { fprintf(stderr, "FAIL: %s (%s:%d)\n", msg, __FILE__, __LINE__); g_fail++; } \ else fprintf(stderr, "ok: %s\n", msg); \ } while (0) /* 用一段 app.json 内容解析出 struct app。返回 0=成功。 */ static int parse_json(const char *content, struct app *a) { FILE *f = tmpfile(); if (!f) return -1; fputs(content, f); rewind(f); memset(a, 0, sizeof *a); meow_parse_app_json(f, a); fclose(f); return 0; } int main(void) { /* ---- 1) 单独 background_keepalive:true ---- */ { struct app a; parse_json("{\n\"name\":\"X\",\n\"exec\":\"/usr/bin/x\",\n\"background_keepalive\":true\n}", &a); CHECK(a.background_keepalive == '1', "background_keepalive:true -> '1'"); CHECK(a.background == 0, "keepalive 行不误命中 background (==0)"); CHECK(a.background_audio == 0, "keepalive 行不误命中 background_audio (==0)"); } /* ---- 2) 单独 background:true ---- */ { struct app a; parse_json("{\n\"name\":\"X\",\n\"exec\":\"/usr/bin/x\",\n\"background\":true\n}", &a); CHECK(a.background == '1', "background:true -> '1'(独立键匹配不受影响)"); CHECK(a.background_keepalive == 0, "background 行不串 to keepalive (==0)"); CHECK(a.background_audio == 0, "background 行不串 to background_audio (==0)"); } /* ---- 3) 单独 background_audio:true ---- */ { struct app a; parse_json("{\n\"name\":\"X\",\n\"exec\":\"/usr/bin/x\",\n\"background_audio\":true\n}", &a); CHECK(a.background_audio == '1', "background_audio:true -> '1'"); CHECK(a.background == 0, "background_audio 行不误命中 background (==0)"); CHECK(a.background_keepalive == 0, "background_audio 行不串 to keepalive (==0)"); } /* ---- 4) 三键并存:各归其位(逐行格式,值后跟 , 或换行,同真实 app.json) ---- */ { struct app a; parse_json("{\n\"name\":\"X\",\n\"exec\":\"/usr/bin/x\",\n\"background\":true,\n" "\"background_audio\":true,\n\"background_keepalive\":true\n}", &a); CHECK(a.background == '1', "三键并存 background=='1'"); CHECK(a.background_audio == '1', "三键并存 background_audio=='1'"); CHECK(a.background_keepalive == '1', "三键并存 background_keepalive=='1'"); } /* ---- 5) 假值 / 前导噪声不应置位 ---- */ { struct app a; parse_json("{\n\"name\":\"X\",\n\"exec\":\"/usr/bin/x\",\n\"background_keepalive\":false,\n" "\"background_audio\":0\n}", &a); CHECK(a.background_keepalive == 0, "background_keepalive:false -> 0"); CHECK(a.background_audio == 0, "background_audio:0 -> 0"); CHECK(a.background == 0, "无 background 键 -> 0"); } /* ---- 6) meow_acct_sync 透传 ---- */ { struct app a; parse_json("{\n\"name\":\"X\",\n\"exec\":\"/usr/bin/x\",\n" "\"background_keepalive\":true,\n\"background_audio\":true\n}", &a); meow_acct_sync("dev.test.keep", &a); /* 以 app_id 建/更注册表项 */ struct meow_acct *ac = meow_acct_find("dev.test.keep"); CHECK(ac != NULL, "meow_acct_sync 建注册表项"); CHECK(ac && ac->background_keepalive == '1', "透传 background_keepalive=='1'"); CHECK(ac && ac->background_audio == '1', "透传 background_audio=='1'"); CHECK(ac && ac->background == 0, "透传 background==0"); } if (g_fail) { fprintf(stderr, "\n== %d assertion(s) FAILED ==\n", g_fail); return 1; } fprintf(stderr, "\n== test_bg_keep ALL PASS ==\n"); return 0; }