/* test_meow_time.c — 宿主单测:SDK 时钟换算(meow_ui_time.c / meow_time_ms_from_parts)。 * * 背景(M11/M21):mipsel 真机上 meow_ui_time_ms() 曾返回「低 32 位=秒×1000、高 32 位随机」, * 根因是 zig musl 头(time_t 64 位)与 libc 实现(o32 time32 取数)ABI 不一致,见 * sdk/CLOCK_ABI.md。修复后取数统一走 meow_time_ms_from_parts(sec, nsec),本测试把 * 换算边界(毫秒进位/截断/大秒数/负值回绕)与「真时钟单调且前进」固定在宿主上。 * * 注意:宿主(非 mips)编译时 meow_ui_time.c 走 MEOW_TIME32_KERNEL_ABI=0 分支,即普通 * clock_gettime —— 本测试**不能**证明 mipsel o32 路径正确(那条路径只靠反汇编证据)。 * * 编译(在 sdk/ 目录下): * gcc -Os -Wall -Wextra -I. -Iinclude -c meow_ui_time.c -o meow_ui_time_host.o * gcc -Os -Wall -Wextra -I. -Iinclude test_meow_time.c meow_ui_time_host.o -o test_meow_time * 运行:./test_meow_time (exit 0=PASS / 1=FAIL) */ #include #include #include #include "meow_ui.h" #include "meow_ui_internal.h" static int g_fail = 0; static unsigned long g_checks = 0; static void eq_ms(const char *name, int64_t sec, int64_t nsec, uint64_t want) { uint64_t got = meow_time_ms_from_parts(sec, nsec); g_checks++; if (got != want) { printf("FAIL %s: sec=%lld nsec=%lld got=%llu want=%llu\n", name, (long long)sec, (long long)nsec, (unsigned long long)got, (unsigned long long)want); g_fail = 1; } else { printf("ok %s = %llu\n", name, (unsigned long long)got); } } int main(void) { /* ---- 1) 换算边界:毫秒 = sec*1000 + nsec/1e6(整除截断) ---- */ eq_ms("零", 0, 0, 0); eq_ms("(sec,0) 整秒", 1, 0, 1000); eq_ms("999999ns 截断", 0, 999999, 0); eq_ms("1ms 进位", 0, 1000000, 1); eq_ms("1ns 截断", 0, 1, 0); eq_ms("开机 1135.008s", 1135, 8000000, 1135008); eq_ms("跨秒 1.999999999s", 1, 999999999, 1999); eq_ms("开机 1204.999999999s", 1204, 999999999, 1204999); eq_ms("接近 2038", 2147483647, 999999999, 2147483647999ULL); /* ---- 2) 负值:from_parts 只做无符号升位((uint64_t)sec*1000 按二补回绕),不钳制。 * 真正把内核 time32 的负 sec 钳成 0 的是 meow_ui_time.c 的 time32_clamp(),它只在 * mipsel 分支编译、宿主不可达;这里把 from_parts 的回绕语义钉住,防止有人悄悄把它 * 理解成「负值 = 0」而改掉换算。 ---- */ eq_ms("负 sec 回绕(-1s)", -1, 0, 0xFFFFFFFFFFFFFC18ULL); eq_ms("负 sec+1ms 回绕", -1, 1000000, 0xFFFFFFFFFFFFFC19ULL); /* ---- 3) 真时钟:非零、单调不减、量级合理(不上溢成「高 32 随机」) ---- */ uint64_t prev = meow_ui_time_ms(); g_checks++; if (prev == 0) { printf("FAIL 时钟返回 0(clock_gettime 失败?)\n"); g_fail = 1; } g_checks++; if (prev >= (1ULL << 40)) { printf("FAIL 时钟量级异常(>=2^40 ms):%llu\n", (unsigned long long)prev); g_fail = 1; } /* 有界采样(避免时钟停走时测试挂死):要求单调不减且确实前进 */ int advanced = 0; for (int i = 0; i < 200000 && !advanced; i++) { uint64_t now = meow_ui_time_ms(); if (now < prev) { printf("FAIL 单调倒退:%llu -> %llu\n", (unsigned long long)prev, (unsigned long long)now); g_fail = 1; break; } advanced = now > prev; prev = now; } g_checks++; if (!advanced) { printf("FAIL 时钟未前进(200000 次采样内无变化)\n"); g_fail = 1; } else { printf("ok 时钟前进且单调\n"); } /* ---- 4) 动画常用差值:两次取样的差 = 毫秒(不能是 0 恒等/整千) ---- */ uint64_t t0 = meow_ui_time_ms(); int waited = 0; for (int i = 0; i < 200000 && !waited; i++) waited = meow_ui_time_ms() != t0; uint64_t t1 = meow_ui_time_ms(); g_checks++; if (!waited || t1 <= t0 || t1 - t0 > 5000) { printf("FAIL 取样差值异常:%llu -> %llu\n", (unsigned long long)t0, (unsigned long long)t1); g_fail = 1; } else { printf("ok 取样差值 %llu ms\n", (unsigned long long)(t1 - t0)); } printf(g_fail ? "== FAIL ==\n" : "== PASS ==\n"); printf("checks=%lu\n", g_checks); return g_fail; }