/* test_utf8_name.c — 问题2(主界面应用名截断)宿主单测:UTF-8 整序列有界拷贝 / 字符步进。 * * 背景(M6.3 真机):主界面应用名「流媒体客户端」被截成 5 字 + 半个字。真因 = app_launcher.c * `strncpy(a->name, name, 16)` 仍把显示名硬截 16 字节(UTF-8 下 16B = 5 汉字 + 「端」首字节),且 * main_menu.c `menu_name_fit` 按字节回退停在半截字符、加 "..." 又溢出 maxw。本测试验证 meow_utf8.h * 的整序列有界拷贝:绝不劈开多字节字符、给出完整汉字序列(修复 strncpy(16) 与 menu_name_fit)。 * * 编译运行(在 patch_v2/meow_launcherd 下): * gcc -Wall -Wextra -o test_utf8_name test_utf8_name.c && ./test_utf8_name * 全 PASS -> exit 0。 */ #include #include #include "meow_utf8.h" static int g_pass = 0, g_fail = 0; #define CHECK(cond, msg) do { \ if (cond) { g_pass++; printf("PASS %s\n", msg); } \ else { g_fail++; printf("FAIL %s\n", msg); } \ } while (0) int main(void) { /* meow_utf8_char_len:由首字节求整字符长。 */ CHECK(meow_utf8_char_len('A') == 1, "char_len ASCII = 1"); CHECK(meow_utf8_char_len((unsigned char)0xC3) == 2, "char_len 2-byte lead = 2"); CHECK(meow_utf8_char_len((unsigned char)0xE6) == 3, "char_len 3-byte lead = 3"); CHECK(meow_utf8_char_len((unsigned char)0xF0) == 4, "char_len 4-byte lead = 4"); CHECK(meow_utf8_char_len((unsigned char)0x80) == 1, "char_len lone continuation = 1 (no merge)"); /* meow_utf8_copy_bounded:不劈多字节字符。 */ char buf[64]; /* 源「流媒体客户端」= 18B(6×3B)。cap=49 → 全量(修复 strncpy(16) 后的正确行为)。 */ meow_utf8_copy_bounded(buf, (int)sizeof buf, "流媒体客户端"); CHECK(strcmp(buf, "流媒体客户端") == 0, "copy cap=49 keeps full '流媒体客户端'"); CHECK(strlen(buf) == 18, "copy cap=49 len=18 (6 chars)"); /* cap=16(旧 bug 的容量):旧 strncpy(16) 给 5 汉字+半个字+无NUL;现应给 5 整汉字+ NUL。 */ meow_utf8_copy_bounded(buf, 16, "流媒体客户端"); CHECK(strcmp(buf, "流媒体客户") == 0, "copy cap=16 -> 5 whole chars '流媒体客户'"); CHECK(strlen(buf) == 15, "copy cap=16 -> 15 bytes (5 CJK, no partial 6th)"); /* cap=17:尾部「端」首字节越界 → 整字符去掉,仍 5 整汉字,绝不半字残形。 */ meow_utf8_copy_bounded(buf, 17, "流媒体客户端"); CHECK(strcmp(buf, "流媒体客户") == 0, "copy cap=17 -> still 5 whole chars (no partial)"); /* cap=12:缓冲区 12B 含 NUL → 内容上限 11B,4 整汉字(12B)放不下 → 截到 3 整汉字(绝非半字)。 * 注:snprintf 语义 = cap 字节含 NUL,故内容 ≤ cap-1(旧 strncpy(dst,src,12) 拷 12B 无 NUL, * 有越界读风险;此处改为安全 NUL 结尾,代价是内容少 1B——正确取舍)。 */ meow_utf8_copy_bounded(buf, 12, "流媒体客户端"); CHECK(strcmp(buf, "流媒体") == 0, "copy cap=12 -> 3 whole chars '流媒体' (no partial 4th)"); /* ASCII / 混合:不劈 ASCII。 */ meow_utf8_copy_bounded(buf, (int)sizeof buf, "Hello App"); CHECK(strcmp(buf, "Hello App") == 0, "copy ASCII unchanged"); /* NULL/空源安全性。 */ meow_utf8_copy_bounded(buf, (int)sizeof buf, NULL); CHECK(buf[0] == 0, "copy NULL src -> empty"); meow_utf8_copy_bounded(buf, 1, "流媒体客户端"); CHECK(buf[0] == 0, "copy cap=1 -> empty (no write overflow)"); printf("\n%s (%d passed, %d failed)\n", g_fail ? "SOME TESTS FAILED" : "ALL PASS", g_pass, g_fail); return g_fail ? 1 : 0; }