test(host): 断言字面量统一纯 ASCII,30 文件 1535 行

用户裁定「统一」。口径就是 AGENTS 铁律:字符串字面量必须纯 ASCII
(无 BOM 文件里奇数个汉字会吞掉结束引号,偶数才侥幸通过),中文只写注释。
四名队友按目录分四组并行、写范围互斥:net_socket 418 行(6 文件)、
console_log/sys_log_mcu/soe_store/cfg_file_store_mcu 268 行(4 文件)、
11 个存量套件 404 行 + adc_input 89 行、iec104 与 lftpd 与 NET 四套等 356 行
(9 文件)。runner 的 .py 文档串不在口径内(Python 源不经 ARMCC 代码页)。

两套口径必须分清:粗口径(按行切引号)普查 = 34 文件 / 1,552 行;严格口径
(状态机剥掉块/行注释与字符常量后再取字符串字面量)= 30 文件 / 1,535 行。
差值那 4 个文件的命中全在注释里(ns_peers.c、net_socket/stub/ns_rtos.h、
common/ch395f_fake.h、common/fatfs_fake.c)——按口径一处都不该改,改了等于
把中文从注释里搬走、正好违背口径。粗口径绝不能当交付判据,否则要么白改
注释、要么留下「这行为什么没改」的悬案。

Lead 独立终检(不采信自报)五条硬判据,结果 30 文件漂移 0:① 每文件 TC 号
集合与 HEAD 逐字相同 ② 断言宏调用点数不变 ③ 行数与 HEAD 完全相等(专抓
整文件回写把尾部含 main() 吃掉的截断,第 1 轮真发生过两次)④ 剥注释后代码区
非 ASCII 字符 = 0 ⑤ 字节卫生(BOM 与 HEAD 一致、无 CR、无 U+FFFD、单尾换行)。
另用「逐行把字面量整体替换成空串后与 HEAD 必须逐行相等」机械证明只改了字面量;
各套 --module 覆盖率与断言数逐字不变(net_socket 887/889·53/53、console_log
199/200·16/16、sys_log_mcu 324/326·13/13、adc_input 103/103、sys_clock 100/100)
→ 生产码零改动,基线不需重登。

闸拦下一处真实回归(我的验收器没抓到):ns_s6_edges.c 翻译时把一个上一轮
已整改成平实描述的编号又写回了 CHECK 标签。原因很清楚:「只改字面量」并不
等于「只改无害内容」,标签里完全可以带进未登记族的编号形态;而 Lead 的自动
验收器只比对了 TC 形 id 集合,未覆盖 L/E/N/S/TRAP 等族。教训:批量改标签的
守卫必须加一条「新串不得出现任何已登记前缀族之外的编号形态」,且结构不变式
只覆盖自己想到的维度时不能替代真闸。
Lead 自查另清掉 126 处写坏的反斜杠(JS→Python 转义层数翻倍,把 markdown
反引号写成反斜杠+反引号),恰好发生在记录这条教训的那一节里。

文档:docs/测试说明/主机单测覆盖率口径.md §9 新增「第 2 轮」小节(两套口径对照
表、五条终检判据、六条手法含「转换说明符序列必须逐位相同」取代「禁止裸 %」、
三条协作纪律含先改板再派工与临时文件带组前缀、后续项 3 条)+ 变更记录一行。

后续项(本轮不做):把剥注释词法扫描器收进 scripts 当门禁(需用户点头并先定
test/ 是否纳入 coding-standard);iec104 的简写编号归族(牵 id_registry,
不能顺手做);替换器加「编号形态白名单」校验。

gate: pre-commit run --all-files -> 39 hooks, 37 Passed; failed = mem-numbers +
mem-budget(受管快照与本树 .map 的漂移,属第 1 轮生产码改动的遗留,非本批
增量)。本批只碰 test/host/**,不进 Keil 编译面也不进模拟器 CMake,**RAM/Flash
增量 = 0**;实测水位 RW_IRAM1 57.4%、RW_CCM 87.9%,均低于 92% 红线。
id-check 0 台账外新账(可判定 84.63% > 基线 82.6%);test-coverage 33/33 全绿;
cppcheck / coding-standard / bsp-err / layer-deps / doc-links 全 Passed。
按仓内分支约定 --no-verify 提交,台账 --write 回填留待主工作树合并后。
This commit is contained in:
2026-10-24 20:57:46 +08:00
parent 5a806d8a26
commit 924ac3d428
31 changed files with 1626 additions and 1542 deletions
+77 -77
View File
@@ -538,7 +538,7 @@ static void tc_format(void)
int ok;
uint32_t i;
printf("-- TC-SYSLOG-001..004 记录格式(64B 定长)--\n");
printf("-- TC-SYSLOG-001..004 record format (fixed 64B) --\n");
/* 001 布局 */
reset_all();
@@ -551,14 +551,14 @@ static void tc_format(void)
&& (rec[SYSLOG_EPOCH_OFFS - 1u] == ' ')
&& (memcmp(rec + SYSLOG_DESC_OFFS, "hello", 5u) == 0)
&& (rec[SYSLOG_DESC_OFFS + 5u] == '\0');
CHECK(ok, "TC-SYSLOG-001 [0..18]ts / [19]空格 / [20..29]epoch / [30]空格 / [31..]desc");
CHECK(ok, "TC-SYSLOG-001 [0..18]ts / [19]space / [20..29]epoch / [30]space / [31..]desc");
ok = 1;
for (i = SYSLOG_DESC_OFFS + 6u; i < SYSLOG_REC_SIZE; i++) {
if (rec[i] != 0u) {
ok = 0;
}
}
CHECK(ok, "TC-SYSLOG-001b 尾部 NUL 填充到 64B(定长解析的地基)");
CHECK(ok, "TC-SYSLOG-001b tail padded with NUL to 64B (basis of fixed-length parsing)");
/* 002 描述截断 */
reset_all();
@@ -575,7 +575,7 @@ static void tc_format(void)
}
CHECK(ok && (rec[SYSLOG_DESC_OFFS + SYSLOG_DESC_MAX] == 0u)
&& (rec[SYSLOG_REC_SIZE - 1u] == 0u),
"TC-SYSLOG-002 超长描述截到 28B,不越 64B 边界");
"TC-SYSLOG-002 over-long desc truncated to 28B, never crossing the 64B boundary");
}
/* 003 墙钟未建立 */
@@ -584,7 +584,7 @@ static void tc_format(void)
s_format_rec(SYSLOG_RUN, "x", rec);
CHECK((memcmp(rec, "1970-01-01 08:00:00", SYSLOG_TS_LEN) == 0)
&& (memcmp(rec + SYSLOG_EPOCH_OFFS, "0000000000", SYSLOG_EPOCH_LEN) == 0),
"TC-SYSLOG-003 无墙钟 -> 占位时间戳 + epoch 全 0(不造假时标)");
"TC-SYSLOG-003 no wall clock -> placeholder timestamp + epoch all zero (never fake a time stamp)");
/* 004 单条 vs 批量逐字节相同 */
reset_all();
@@ -594,7 +594,7 @@ static void tc_format(void)
(void)memset(b, 0, sizeof(b));
s_format_rec(SYSLOG_RUN, "same-content", b);
CHECK(memcmp(rec, b, SYSLOG_REC_SIZE) == 0,
"TC-SYSLOG-004 同一输入两次格式化逐字节一致(UI 定长偏移解析的前提)");
"TC-SYSLOG-004 same input formats byte-identical twice (premise of UI fixed-offset parsing)");
reset_all();
s_now = 1700000000u;
ready_only();
@@ -606,7 +606,7 @@ static void tc_format(void)
s_format_rec(SYSLOG_RUN, "ab", batch + SYSLOG_REC_SIZE);
CHECK((memcmp(rec, batch, SYSLOG_REC_SIZE) == 0)
&& (memcmp(rec, batch + SYSLOG_REC_SIZE, SYSLOG_REC_SIZE) == 0),
"TC-SYSLOG-004b 批量路径复用同一 s_format_rec(两条都等于单条)");
"TC-SYSLOG-004b batch path reuses the same s_format_rec (both equal the single-record result)");
}
}
@@ -617,7 +617,7 @@ static void tc_write_single(void)
uint8_t rec[SYSLOG_REC_SIZE];
int ok;
printf("-- TC-SYSLOG-010..019 单条写路径 --\n");
printf("-- TC-SYSLOG-010..019 single-record write path --\n");
/* 010 成功 + 打开模式 */
reset_all();
@@ -630,7 +630,7 @@ static void tc_write_single(void)
&& (g_ff_obs.calls[FF_FAKE_OP_CLOSE] == 1)
&& (s_lock_releases == 1) && (s_lock_seq_err == 0)
&& (g_sys_err_count == 0);
CHECK(ok, "TC-SYSLOG-010 单条落盘成功:模式带写位 + open/write/close 各一次 + 放锁");
CHECK(ok, "TC-SYSLOG-010 single write ok: mode carries the write bit + open/write/close once each + lock released");
/* 011 陷阱一保真对照 */
reset_all();
@@ -644,7 +644,7 @@ static void tc_write_single(void)
fr2 = f_write(&probe, rec, SYSLOG_REC_SIZE, &bw);
(void)f_close(&probe);
CHECK((fr1 == FR_OK) && (fr2 == FR_DENIED) && (bw == 0u),
"TC-SYSLOG-011 只给 FA_OPEN_APPEND -> f_write 恒 FR_DENIED(2026-09-20 真根因)");
"TC-SYSLOG-011 FA_OPEN_APPEND alone -> f_write is always FR_DENIED (real root cause 2026-09-20)");
}
/* 012 卷忙 */
@@ -655,7 +655,7 @@ static void tc_write_single(void)
CHECK(ok && (g_ff_obs.calls[FF_FAKE_OP_OPEN] == 0)
&& (g_ff_obs.calls[FF_FAKE_OP_WRITE] == 0)
&& (s_lock_releases == 0) && (s_lock_seq_err == 0) && (g_sys_err_count == 0),
"TC-SYSLOG-012 卷忙 = 顺延:不碰盘、不 release、不计故障(喂狗点绝不阻塞)");
"TC-SYSLOG-012 volume busy means defer: no disk touch, no release, no fault counted (feed point never blocks)");
/* 013 短写 -> 自愈 */
reset_all();
@@ -665,7 +665,7 @@ static void tc_write_single(void)
CHECK(ok && (ff_fake_size(P_RUN) == SYSLOG_REC_SIZE)
&& (g_ff_obs.calls[FF_FAKE_OP_UNLINK] == 1)
&& (g_ff_obs.last_write_bw == SYSLOG_REC_SIZE),
"TC-SYSLOG-013 FR_OK+短写 63B 被判失败 -> unlink 重建 -> 恰好 64 字节");
"TC-SYSLOG-013 FR_OK + short write 63B treated as failure -> unlink and rebuild -> exactly 64 bytes");
/* 014 容量满 -> 删除重建 */
reset_all();
@@ -675,7 +675,7 @@ static void tc_write_single(void)
CHECK(ok && (g_ff_obs.calls[FF_FAKE_OP_UNLINK] == 1)
&& (ff_fake_size(P_RUN) == SYSLOG_REC_SIZE)
&& (syslog_count(SYSLOG_RUN) == 1u),
"TC-SYSLOG-014 满 1024 条 -> 先 unlink 再写,新文件只剩本次一条");
"TC-SYSLOG-014 at 1024 records -> unlink first then write, new file holds only this record");
/* 015 满 + unlink 真失败 */
reset_all();
@@ -685,7 +685,7 @@ static void tc_write_single(void)
ok = (s_append(SYSLOG_RUN, "x") == -1);
CHECK(ok && (g_ff_obs.calls[FF_FAKE_OP_OPEN] == 0)
&& (s_lock_releases == 1) && (s_lock_seq_err == 0),
"TC-SYSLOG-015 容量轮转时 unlink 失败 -> 返回 -1 且**已释放卷锁**(漏放 = FTP 永久拿不到卷)");
"TC-SYSLOG-015 unlink failure during rotation -> -1 and **the volume lock is released** (leak = FTP never gets the volume)");
/* 016 满 + unlink 返 FR_NO_FILE 无害 */
reset_all();
@@ -698,7 +698,7 @@ static void tc_write_single(void)
ok = (s_append(SYSLOG_RUN, "gone") == 0);
CHECK(ok && (g_ff_obs.calls[FF_FAKE_OP_UNLINK] == 1)
&& (g_ff_obs.calls[FF_FAKE_OP_WRITE] == 1) && (g_sys_err_count == 0),
"TC-SYSLOG-016 unlink 返 FR_NO_FILE 被当无害:不进错误分支、不留痕、继续写");
"TC-SYSLOG-016 unlink returning FR_NO_FILE is harmless: no error branch, no trace, write continues");
/* 017 入参守卫 */
reset_all();
@@ -708,7 +708,7 @@ static void tc_write_single(void)
&& (s_append(SYSLOG_RUN, NULL) == -1)
&& (s_append_rec((syslog_id_t)9u, rec) == -1);
CHECK(ok && (g_ff_obs.calls[FF_FAKE_OP_OPEN] == 0),
"TC-SYSLOG-017 id 越界 / 空 rec / 空 desc -> -1 且不碰卷锁与盘");
"TC-SYSLOG-017 id out of range / empty rec / empty desc -> -1 without touching the lock or the disk");
/* 018 写成功 -> 读侧代数自增 */
reset_all();
@@ -717,7 +717,7 @@ static void tc_write_single(void)
ok = (s_rd_gen[SYSLOG_RUN] == 1u) && (s_rd_gen[SYSLOG_SELFTEST] == 0u);
(void)s_append(SYSLOG_SELFTEST, "b");
CHECK(ok && (s_rd_gen[SYSLOG_SELFTEST] == 1u),
"TC-SYSLOG-018 每次落盘只自增本 id 的代数(另一文件的窗口不被误失效)");
"TC-SYSLOG-018 each write bumps only this id's generation (the other file's window stays valid)");
/* 019 留痕去重 */
reset_all();
@@ -730,7 +730,7 @@ static void tc_write_single(void)
ff_fake_inject_write_short(P_RUN, 0u, 2);
(void)s_append(SYSLOG_RUN, "e3"); /* 再失败 -> 再留痕 */
CHECK(ok && (g_sys_err_count == 2),
"TC-SYSLOG-019 持续故障只报第一次;恢复后再失败必须重新留痕");
"TC-SYSLOG-019 a persistent fault reports once; a failure after recovery must trace again");
}
static void tc_write_many(void)
@@ -739,7 +739,7 @@ static void tc_write_many(void)
uint32_t i;
int ok;
printf("-- TC-SYSLOG-020..024 批量写路径(N-24)--\n");
printf("-- TC-SYSLOG-020..024 batch write path (N-24) --\n");
/* 020 8 条一次 I/O */
reset_all();
@@ -752,7 +752,7 @@ static void tc_write_many(void)
&& (g_ff_obs.last_write_btw == SYSLOG_BATCH_MAX * SYSLOG_REC_SIZE)
&& (g_ff_obs.last_write_bw == SYSLOG_BATCH_MAX * SYSLOG_REC_SIZE)
&& (g_ff_obs.calls[FF_FAKE_OP_CLOSE] == 1),
"TC-SYSLOG-020 一批 8 条 = 一次 open + 一次 512B write + 一次 close(旧实现 8 轮)");
"TC-SYSLOG-020 a batch of 8 = one open + one 512B write + one close (old code needed 8 rounds)");
/* 021 入参守卫 */
reset_all();
@@ -762,7 +762,7 @@ static void tc_write_many(void)
&& (s_append_many(SYSLOG_RUN, NULL, 1u) == -1)
&& (s_append_many((syslog_id_t)SYSLOG_COUNT, batch, 1u) == -1);
CHECK(ok && (s_lock_waits == 0) && (g_ff_obs.calls[FF_FAKE_OP_OPEN] == 0),
"TC-SYSLOG-021 批量入参守卫在**取卷锁之前**(越界 n 不占用卷)");
"TC-SYSLOG-021 batch argument guards run **before taking the volume lock** (bad n never occupies it)");
/* 022 容量不足 -> -3 且不 unlink */
reset_all();
@@ -773,7 +773,7 @@ static void tc_write_many(void)
&& (g_ff_obs.calls[FF_FAKE_OP_OPEN] == 0)
&& (s_lock_releases == 1) && (s_lock_seq_err == 0)
&& (ff_fake_size(P_RUN) == ((uint32_t)SYSLOG_RUN_MAX - 3u) * SYSLOG_REC_SIZE),
"TC-SYSLOG-022 装不下一批 -> -3 交回慢路径;批量路径**绝不**自己 unlink 重建");
"TC-SYSLOG-022 batch does not fit -> -3 back to the slow path; the batch path **never** unlinks itself");
/* 023 批量卷忙 / 短写自愈 */
reset_all();
@@ -785,7 +785,7 @@ static void tc_write_many(void)
CHECK(ok && (ff_fake_size(P_RUN) == 4u * SYSLOG_REC_SIZE)
&& (g_ff_obs.calls[FF_FAKE_OP_UNLINK] == 1)
&& (g_sys_err_count == 0),
"TC-SYSLOG-023 批量卷忙 -> -2;短写(256 只回 100)-> 自愈重建后整批落全");
"TC-SYSLOG-023 batch with busy volume -> -2; short write (256 asked, 100 back) -> rebuild, whole batch lands");
/* 024 批量持续失败 + 去重 */
reset_all();
@@ -794,7 +794,7 @@ static void tc_write_many(void)
ok = (s_append_many(SYSLOG_RUN, batch, 2u) == -1);
(void)s_append_many(SYSLOG_RUN, batch, 2u);
CHECK(ok && (g_sys_err_count == 1) && (s_rd_gen[SYSLOG_RUN] == 2u),
"TC-SYSLOG-024 批量持续失败留痕去重;代数照样自增(宁多失效一轮也不读脏窗)");
"TC-SYSLOG-024 batch failure trace de-duplicated; generation still bumps (invalidate a window rather than read stale)");
(void)i;
}
@@ -806,7 +806,7 @@ static void tc_drain(void)
uint32_t i;
int ok;
printf("-- TC-SYSLOG-030..041 syslog_drain 排空 --\n");
printf("-- TC-SYSLOG-030..041 syslog_drain --\n");
/* 030 卷未就绪:条目滞留 preboot,drain 直接返回。
* 注意两条容易被读漏的事实:
@@ -821,7 +821,7 @@ static void tc_drain(void)
syslog_drain();
CHECK(ok && (s_q_new_calls == 1) && (s_preboot_cnt == 1u)
&& (g_ff_obs.calls[FF_FAKE_OP_OPEN] == 0) && (s_soe_drain_calls == 0),
"TC-SYSLOG-030 卷未就绪 -> 队列先建成、条目滞留 preboot、不落盘也不调 SOE");
"TC-SYSLOG-030 volume not ready -> queue created, entries stay in preboot, nothing written and no SOE call");
/* 031 惰性建队列 */
reset_all();
@@ -829,7 +829,7 @@ static void tc_drain(void)
ok = (s_queue == NULL);
syslog_drain();
CHECK(ok && (s_queue != NULL) && (s_q_new_calls == 1) && (s_q_msgsz == sizeof(syslog_entry_t)),
"TC-SYSLOG-031 队列在**首次 drain**(defaultTask 上下文)才创建(内核前建对象 = 启动失败)");
"TC-SYSLOG-031 the queue is created at the **first drain** (defaultTask context); creating objects pre-kernel kills boot");
/* 032 preboot 8 条一批落 */
reset_all();
@@ -837,12 +837,12 @@ static void tc_drain(void)
for (i = 0u; i < SYSLOG_QUEUE_MAX; i++) {
syslog_post(SYSLOG_RUN, "pre");
}
CHECK(s_preboot_cnt == SYSLOG_QUEUE_MAX, "TC-SYSLOG-032a 内核未运行:8 条全进 preboot 数组");
CHECK(s_preboot_cnt == SYSLOG_QUEUE_MAX, "TC-SYSLOG-032a kernel not running: all 8 entries go to the preboot array");
syslog_drain();
ok = (s_preboot_cnt == 0u) && (syslog_count(SYSLOG_RUN) == SYSLOG_BATCH_MAX)
&& (g_ff_obs.calls[FF_FAKE_OP_WRITE] == 1)
&& (g_ff_obs.last_write_btw == SYSLOG_BATCH_MAX * SYSLOG_REC_SIZE);
CHECK(ok, "TC-SYSLOG-032b preboot 8 条同文件 -> 一次 512B 合并写(数组下标看而不删)");
CHECK(ok, "TC-SYSLOG-032b 8 preboot entries of one file -> one merged 512B write (index inspected, not deleted)");
/* 033 + 034 两文件混排:换文件那条不消耗 */
reset_all();
@@ -864,7 +864,7 @@ static void tc_drain(void)
CHECK(ok && (s_preboot_cnt == 0u)
&& (g_ff_obs.calls[FF_FAKE_OP_OPEN] == 3)
&& (g_ff_obs.calls[FF_FAKE_OP_WRITE] == 3),
"TC-SYSLOG-033/034 换文件即分批(run 被切成两批 = 共 3 轮 I/O)+ 顺序不乱");
"TC-SYSLOG-033/034 a file change splits the batch (run split in two = 3 I/O rounds) + order preserved");
/* 035【A 项已修 2026-10-24:正向断言】卷忙 -> **整批回投队列**,一条不丢。
* 生产侧修法:syslog_drain 批量路径补 else if (rc == -2) { done = 0u; },
@@ -913,7 +913,7 @@ static void tc_drain(void)
syslog_drain();
CHECK((s_q_cnt == 3u) && (syslog_count(SYSLOG_RUN) == SYSLOG_RUN_MAX - 1u)
&& (g_ff_obs.calls[FF_FAKE_OP_OPEN] == 0),
"TC-SYSLOG-035b 慢路径遇卷忙 -> 3 条**整批回投**(同一码在两条路径上行为相反)");
"TC-SYSLOG-035b slow path meets busy volume -> all 3 **requeued whole** (same code, opposite behaviour per path)");
/* 035c 一整批(8 条)在卷忙时全部回投,不是只保住一条 */
reset_all();
@@ -966,7 +966,7 @@ static void tc_drain(void)
syslog_drain();
CHECK(ok && (s_q_cnt == SYSLOG_QUEUE_MAX) && (s_preboot_cnt == 0u)
&& (g_sys_err_count == 1 + 5 + 1),
"TC-SYSLOG-036 回投装不下 -> 5 次 hold-over drop + drop/wfail 各 1 条留痕");
"TC-SYSLOG-036 requeue does not fit -> 5 hold-over drops + one drop trace and one wfail trace");
/* 037 -3 退回慢路径:容量轮转只发生一次 */
reset_all();
@@ -982,7 +982,7 @@ static void tc_drain(void)
&& (g_ff_obs.calls[FF_FAKE_OP_UNLINK] == 1)
&& (g_ff_obs.calls[FF_FAKE_OP_WRITE] >= 4);
CHECK(ok && (s_q_cnt == 0u),
"TC-SYSLOG-037 -3 -> 逐条慢路径:装满剩位 -> 满 -> unlink 重建 -> 继续,全程 unlink 恰一次");
"TC-SYSLOG-037 -3 -> per-record slow path: fill the rest -> full -> unlink rebuild -> continue, unlink exactly once");
/* 038 慢路径中途写失败 -> 该条丢 + 尾部回投 */
reset_all();
@@ -999,7 +999,7 @@ static void tc_drain(void)
ok = (s_q_cnt == 2u) && (ff_fake_size(P_RUN) == 0u) && (g_sys_err_count >= 2);
syslog_drain(); /* 之后成功 */
CHECK(ok && (s_q_cnt == 0u) && (syslog_count(SYSLOG_RUN) == 2u),
"TC-SYSLOG-038 慢路径写失败:只丢**当前那一条**,尾部 2 条下轮补齐");
"TC-SYSLOG-038 slow-path write failure: only **that one record** is lost, the last 2 land next round");
/* 039【B 项已修 2026-10-24:正向断言】rc == -1:整批回投 + 留痕文案如实
* (旧版这里打 "drop %lu entries" 但一条没丢,文案与行为相反)。
@@ -1038,7 +1038,7 @@ static void tc_drain(void)
ok = (s_soe_drain_calls == 1);
syslog_drain();
CHECK(ok && (s_soe_drain_calls == 2),
"TC-SYSLOG-040 drain 尾部必调 soe_store_drain(同写者、同卷就绪门)");
"TC-SYSLOG-040 drain must call soe_store_drain (same writer, same volume-ready gate)");
/* 041 post 分流与守卫 */
reset_all();
@@ -1046,7 +1046,7 @@ static void tc_drain(void)
syslog_post((syslog_id_t)SYSLOG_COUNT, "bad-id");
syslog_post(SYSLOG_RUN, NULL);
CHECK((s_preboot_cnt == 0u) && (s_q_cnt == 0u),
"TC-SYSLOG-041a id 越界 / NULL 描述 -> 静默丢弃(不占待发位)");
"TC-SYSLOG-041a id out of range / NULL desc -> silently dropped (does not occupy a pending slot)");
reset_all();
ready_only();
for (i = 0u; i < SYSLOG_QUEUE_MAX + 2u; i++) {
@@ -1087,7 +1087,7 @@ static void tc_drain(void)
syslog_post(SYSLOG_RUN, "q2");
syslog_post(SYSLOG_RUN, "q3");
CHECK((s_q_cnt == 2u) && (g_sys_err_count == 1),
"TC-SYSLOG-041c 内核运行 -> 走队列;队列满丢弃 + 留痕");
"TC-SYSLOG-041c kernel running -> queue path; queue full drops with a trace");
}
/* ===================== D 读侧 ===================== */
@@ -1100,17 +1100,17 @@ static void tc_read(void)
uint32_t i;
int ok;
printf("-- TC-SYSLOG-050..058 读侧(N-24 滑动窗口)--\n");
printf("-- TC-SYSLOG-050..058 read side (N-24 sliding window) --\n");
/* 050 count */
reset_all();
ready_only();
CHECK(syslog_count(SYSLOG_RUN) == 0u, "TC-SYSLOG-050a 文件缺失 -> count 0");
CHECK(syslog_count(SYSLOG_RUN) == 0u, "TC-SYSLOG-050a missing file -> count 0");
for (i = 0u; i < 3u; i++) {
(void)s_append(SYSLOG_RUN, "c");
}
ok = (syslog_count(SYSLOG_RUN) == 3u) && (syslog_count((syslog_id_t)7u) == 0u);
CHECK(ok, "TC-SYSLOG-050b count = filesize/64(O(1),不读盘内容);id 越界 -> 0");
CHECK(ok, "TC-SYSLOG-050b count = filesize/64 (O(1), no content read); id out of range -> 0");
/* 051 窗口命中零 I/O */
reset_all();
@@ -1131,7 +1131,7 @@ static void tc_read(void)
&& (g_ff_obs.calls[FF_FAKE_OP_OPEN] == opens_after) /* 命中 -> 零 I/O */
&& (g_ff_obs.calls[FF_FAKE_OP_READ] == reads_base + 1);
}
CHECK(ok, "TC-SYSLOG-051 窗口命中 -> 第二次读**零 FatFs 调用**(UI 翻页不再逐条开合)");
CHECK(ok, "TC-SYSLOG-051 window hit -> the second read makes **zero FatFs calls** (UI paging no longer opens per record)");
/* 052 写者代数失效 */
reset_all();
@@ -1142,7 +1142,7 @@ static void tc_read(void)
(void)s_append(SYSLOG_RUN, "new"); /* 代数 +1 -> 窗口必须重填 */
ok = ok && (syslog_get_record(SYSLOG_RUN, 1u, ts, sizeof(ts), desc, sizeof(desc)) == 0)
&& (strcmp(desc, "new") == 0);
CHECK(ok, "TC-SYSLOG-052 写者一落地代数就变 -> 窗口重填,绝不返回陈旧内容");
CHECK(ok, "TC-SYSLOG-052 once the writer lands the generation changes -> window refills, never returns stale content");
/* 053 跨窗口 */
reset_all();
@@ -1158,7 +1158,7 @@ static void tc_read(void)
&& (g_ff_obs.last_lseek_ofs == (FSIZE_t)(SYSLOG_RD_WINDOW * SYSLOG_REC_SIZE))
&& (g_ff_obs.last_read_btr == SYSLOG_REC_SIZE);
}
CHECK(ok, "TC-SYSLOG-053 idx=8 跨窗 -> 一次 open + lseek(8*64) + read(1 条)(窗口按 8 对齐)");
CHECK(ok, "TC-SYSLOG-053 idx=8 crosses the window -> one open + lseek(8*64) + read(1 record) (window aligned to 8)");
/* 054 越界 */
reset_all();
@@ -1169,7 +1169,7 @@ static void tc_read(void)
reset_all();
ready_only();
ok = ok && (syslog_get_record(SYSLOG_RUN, 0u, ts, sizeof(ts), desc, sizeof(desc)) == -1);
CHECK(ok, "TC-SYSLOG-054 越界 idx / 空文件 -> -1(等锁前后各校验一次 count)");
CHECK(ok, "TC-SYSLOG-054 out-of-range idx / empty file -> -1 (count checked before and after taking the lock)");
/* 055 读时卷忙 */
reset_all();
@@ -1181,7 +1181,7 @@ static void tc_read(void)
lock_busy_next(1);
ok = (syslog_get_record(SYSLOG_SELFTEST, 0u, ts, sizeof(ts), desc, sizeof(desc)) == -1)
&& (g_ff_obs.calls[FF_FAKE_OP_OPEN] >= 1) && (s_lock_seq_err == 0);
CHECK(ok, "TC-SYSLOG-055 读时卷忙 -> -1(读窗口 try 语义:uiTask 也绝不阻塞等锁,下轮刷新重读)");
CHECK(ok, "TC-SYSLOG-055 busy volume while reading -> -1 (try semantics: uiTask never blocks for the lock, retry next refresh)");
/* 056 短读作废窗口 */
reset_all();
@@ -1193,7 +1193,7 @@ static void tc_read(void)
ff_fake_inject_read_short(P_RUN, 1u, 1);
ok = (s_read_raw(SYSLOG_RUN, 0u, (uint8_t *)desc) == -1)
&& (s_rd_win_cnt == 0u) && (s_rd_win_id == -1);
CHECK(ok, "TC-SYSLOG-056 短读 -> 窗口作废(半窗当有效命中 = UI 显示半条脏记录)");
CHECK(ok, "TC-SYSLOG-056 short read -> window invalidated (a half window treated as valid = UI shows half a stale record)");
/* 057 get_record 守卫与截断 */
reset_all();
@@ -1213,7 +1213,7 @@ static void tc_read(void)
* 整 28 字符而不是截断结果 —— 即"传刚够的缓冲会被拒、传更小的也被拒,
* 从来没有截断"。登记为死分支,见文件头"本套照出的现状"。 */
&& (strlen(desc) == (size_t)SYSLOG_DESC_MAX);
CHECK(ok, "TC-SYSLOG-057 守卫:ts_len<=19 或 desc_len<=28 一律 -1;29 才读得到整 28 字符");
CHECK(ok, "TC-SYSLOG-057 guards: ts_len<=19 or desc_len<=28 always -1; only 29 reads the full 28 characters");
/* C 项整改(2026-10-24):容量不足一律拒绝,且**不得**碰调用方缓冲——
* 上面每次被拒的调用都用了同一对缓冲,哨兵还在就说明没写进去 */
reset_all();
@@ -1243,7 +1243,7 @@ static void tc_read(void)
s_now = 1700000123u;
(void)s_append(SYSLOG_RUN, "e");
ok = ok && (syslog_last_epoch(SYSLOG_RUN, &epoch) == 0) && (epoch == 1700000123u);
CHECK(ok, "TC-SYSLOG-058 last_epoch:无记录 -1;有记录解析 10 位 ASCII");
CHECK(ok, "TC-SYSLOG-058 last_epoch: no record -> -1; with a record parse the 10 ASCII digits");
}
/* ===================== E mounted / 上电重启分类 ===================== */
@@ -1253,7 +1253,7 @@ static void tc_mounted(void)
uint8_t rec[SYSLOG_REC_SIZE];
int ok;
printf("-- TC-SYSLOG-060..064 挂载后处理(挂载幂等 + 上电/重启分类)--\n");
printf("-- TC-SYSLOG-060..064 post-mount handling (idempotent mount + power/reboot classification) --\n");
/* 060 /log 不在 -> 建目录 + 写上电记录;第二次调用完全静默 */
reset_all();
@@ -1264,7 +1264,7 @@ static void tc_mounted(void)
syslog_mcu_mounted();
ok = ok && (s_fs_ready == 1u) && (syslog_count(SYSLOG_RUN) == 1u);
CHECK(ok && (g_ff_obs.calls[FF_FAKE_OP_MKDIR] == 0) && (g_sys_err_count == 0),
"TC-SYSLOG-060a /log 已存在 -> 只写上电/重启记录一条");
"TC-SYSLOG-060a /log exists -> write only the one power/reboot record");
/* 060b 幂等:再来一次既不建目录也不写第二条 */
reset_all();
s_fs_ready = 0u;
@@ -1275,7 +1275,7 @@ static void tc_mounted(void)
syslog_mcu_mounted(); /* 第二次:应完全静默 */
CHECK((s_fs_ready == 1u) && (syslog_count(SYSLOG_RUN) == cnt1)
&& (g_ff_obs.calls[FF_FAKE_OP_MKDIR] == mkdirs1),
"TC-SYSLOG-060b 幂等再调用:不再建目录、不再写上电记录(2s 复查不刷屏)");
"TC-SYSLOG-060b idempotent re-entry: no mkdir, no second power-on record (the 2s recheck must not flood)");
}
(void)rec;
@@ -1291,7 +1291,7 @@ static void tc_mounted(void)
ok = ok && (g_sys_err_count == 1) && (s_lock_releases == 2) && (s_lock_seq_err == 0);
syslog_mcu_mounted(); /* 注入耗尽 -> 成功 */
CHECK(ok && (s_fs_ready == 1u) && (s_mount_fail_reported == 0u),
"TC-SYSLOG-061 mkdir 失败:不就绪、留痕一次(防 2s 刷屏)、第三轮自愈并复位标志");
"TC-SYSLOG-061 mkdir failure: not ready, trace once (no 2s flooding), third round self-heals and resets the flag");
/* 062 卷忙:本轮顺延,不置就绪、不碰盘 */
reset_all();
@@ -1300,7 +1300,7 @@ static void tc_mounted(void)
syslog_mcu_mounted();
CHECK((s_fs_ready == 0u) && (g_ff_obs.calls[FF_FAKE_OP_STAT] == 0)
&& (g_ff_obs.calls[FF_FAKE_OP_OPEN] == 0) && (s_lock_releases == 0),
"TC-SYSLOG-062 卷忙 -> 直接返回(try 失败不 release,下轮 2s 后再试)");
"TC-SYSLOG-062 busy volume -> return at once (a failed try must not release; retry after the next 2s)");
/* 063 上电 / 重启分类:阈值 SYSLOG_REBOOT_WINDOW_S 两侧 + 墙钟无效 */
reset_all();
@@ -1320,7 +1320,7 @@ static void tc_mounted(void)
syslog_mcu_mounted();
ok = raw_at(P_RUN, 1u, rec) && (memcmp(rec + SYSLOG_DESC_OFFS, "reboot", 6u) == 0)
&& (rec[SYSLOG_DESC_OFFS + 6u] == '\0');
CHECK(ok, "TC-SYSLOG-063a 末条 epoch 距 now 300s(<600) -> 描述落 \"reboot\"");
CHECK(ok, "TC-SYSLOG-063a last epoch 300s(<600) before now -> desc is \"reboot\"");
reset_all();
s_fs_ready = 0u;
@@ -1335,7 +1335,7 @@ static void tc_mounted(void)
}
syslog_mcu_mounted();
ok = raw_at(P_RUN, 1u, rec) && (memcmp(rec + SYSLOG_DESC_OFFS, "power on", 8u) == 0);
CHECK(ok, "TC-SYSLOG-063b 间隔 >=600s -> \"power on\"(掉电超过 10 分钟算重新上电)");
CHECK(ok, "TC-SYSLOG-063b gap >=600s -> \"power on\" (over ten minutes off counts as a fresh power-up)");
reset_all();
s_fs_ready = 0u;
@@ -1348,14 +1348,14 @@ static void tc_mounted(void)
}
syslog_mcu_mounted();
ok = raw_at(P_RUN, 1u, rec) && (memcmp(rec + SYSLOG_DESC_OFFS, "power on", 8u) == 0);
CHECK(ok, "TC-SYSLOG-063c 墙钟无效(UINT32_MAX)-> 保守判 \"power on\",不拿假差值判重启");
CHECK(ok, "TC-SYSLOG-063c wall clock invalid (UINT32_MAX) -> conservatively \"power on\", never judge a reboot from a fake delta");
/* 064 幂等靠 stat,不靠状态位:/log 已在就不再 mkdir */
reset_all();
s_fs_ready = 0u;
syslog_mcu_mounted();
ok = (g_ff_obs.calls[FF_FAKE_OP_MKDIR] == 0) && (g_ff_obs.calls[FF_FAKE_OP_STAT] >= 1);
CHECK(ok, "TC-SYSLOG-064 /log 已存在时靠 f_stat 短路,f_mkdir 一次都不调");
CHECK(ok, "TC-SYSLOG-064 with /log present f_stat short-circuits, f_mkdir is never called");
}
/* ===================== F 取证通道 sys_log_evidence ===================== */
@@ -1365,7 +1365,7 @@ static void tc_evidence(void)
uint8_t raw[8u * SYSLOG_REC_SIZE];
int ok;
printf("-- TC-SYSLOG-070..074 sys_log_evidence(wdev.log 取证通道)--\n");
printf("-- TC-SYSLOG-070..074 sys_log_evidence (wdev.log forensics channel) --\n");
/* 070 变长行 + 第二条 run.log */
reset_all();
@@ -1379,14 +1379,14 @@ static void tc_evidence(void)
&& raw_at(P_RUN, 0u, raw)
&& (memcmp(raw + SYSLOG_DESC_OFFS, "wd stall declared", 17u) == 0);
}
CHECK(ok, "TC-SYSLOG-070 wdev.log 写变长行(带 CRLF),并补一条 run.log 独立证据");
CHECK(ok, "TC-SYSLOG-070 wdev.log writes a variable-length line (with CRLF) plus a separate run.log evidence record");
/* 071 卷锁顺序:第二条写必须在释放之后(非递归锁,反了 = 自死锁) */
reset_all();
(void)sys_log_evidence("order probe");
CHECK((s_lock_waits == 2) && (s_lock_releases == 2) && (s_lock_seq_err == 0)
&& (s_lock_held == 0),
"TC-SYSLOG-071 取锁两次各放一次(在持锁状态下调 s_append 会永远拿不到锁)");
"TC-SYSLOG-071 the lock is taken twice and released twice (calling s_append while holding it would deadlock)");
/* 072 >8192B 护栏 */
reset_all();
@@ -1394,7 +1394,7 @@ static void tc_evidence(void)
ok = (sys_log_evidence("after rotate") == 0);
CHECK(ok && (g_ff_obs.calls[FF_FAKE_OP_UNLINK] == 1)
&& (ff_fake_size(P_WDEV) > 0u) && (ff_fake_size(P_WDEV) < 200u),
"TC-SYSLOG-072 超过 8KB -> 先 unlink 再写(长跑不被无界撑爆)");
"TC-SYSLOG-072 beyond 8KB -> unlink first then write (a long run must not grow without bound)");
/* 073 卷忙 */
reset_all();
@@ -1402,14 +1402,14 @@ static void tc_evidence(void)
ok = (sys_log_evidence("busy probe") == -1);
CHECK(ok && (ff_fake_exists(P_WDEV) == 0) && (syslog_count(SYSLOG_RUN) == 0u)
&& (s_lock_releases == 0) && (s_lock_seq_err == 0),
"TC-SYSLOG-073 卷忙 -> -1 且**两条写都没发生**(喂狗点绝不阻塞等锁)");
"TC-SYSLOG-073 busy volume -> -1 and **neither write happened** (feed point never blocks for the lock)");
/* 074 wdev 写失败:返回 -1,但第二条仍写("独立证据"语义) */
reset_all();
ff_fake_inject_rc(P_WDEV, FF_FAKE_OP_OPEN, FR_DISK_ERR, 1);
ok = (sys_log_evidence("second write still") == -1);
CHECK(ok && (syslog_count(SYSLOG_RUN) == 1u) && (g_sys_err_count == 0),
"TC-SYSLOG-074 wdev 写失败不阻断第二条 run.log(多一条独立证据的原始意图)");
"TC-SYSLOG-074 a wdev write failure does not block the second run.log record (the intent of extra evidence)");
}
/* ===================== G 陷阱二:名字/参数类错误码严禁升级成卷操作 ===================== */
@@ -1425,7 +1425,7 @@ static void tc_name_rules(void)
int ok;
uint32_t i;
printf("-- TC-SYSLOG-080..082 陷阱二分档与「绝不升级」 --\n");
printf("-- TC-SYSLOG-080..082 name class split and never escalate --\n");
/* 080 短名违规**分档**:每条都落到 FR_INVALID_NAME;':' 落到 FR_INVALID_DRIVE */
reset_all();
@@ -1442,7 +1442,7 @@ static void tc_name_rules(void)
CHECK((fr_body == FR_INVALID_NAME) && (fr_ext == FR_INVALID_NAME)
&& (fr_bad == FR_INVALID_NAME) && (fr_dot == FR_INVALID_NAME)
&& (fr_colon == FR_INVALID_DRIVE),
"TC-SYSLOG-080 分档:体>8 / 扩展>3 / 非法字符 / 点开头 -> FR_INVALID_NAME;':' -> FR_INVALID_DRIVE");
"TC-SYSLOG-080 classes: body>8 / ext>3 / bad char / leading dot -> FR_INVALID_NAME; ':' -> FR_INVALID_DRIVE");
/* 081 生产实际用的每个名字都必须过严格 8.3(改名 = 静默写失败的第一道防线) */
reset_all();
@@ -1452,7 +1452,7 @@ static void tc_name_rules(void)
ok = ok && (f_open(&probe, P_WDEV, FA_WRITE | FA_OPEN_APPEND) == FR_OK)
&& (f_close(&probe) == FR_OK);
ok = ok && (f_stat("/log", NULL) == FR_OK);
CHECK(ok, "TC-SYSLOG-081 生产路径 /log、run.log、selftest.log、wdev.log 全部 8.3 合规");
CHECK(ok, "TC-SYSLOG-081 production paths /log, run.log, selftest.log, wdev.log are all valid 8.3 names");
/* 082 名字类错误码不得升级成卷操作:反复失败也只动自己的文件 */
reset_all();
@@ -1485,7 +1485,7 @@ static void tc_extra_branches(void)
uint32_t i;
int ok;
printf("-- TC-SYSLOG-090..100 补齐分支 --\n");
printf("-- TC-SYSLOG-090..100 remaining branch coverage --\n");
/* 090 批量路径的 L1 自愈:open 失败一次 -> unlink + 重开 -> 整批照常落盘
* (这条钉的是 s_append_many 里那段"和单条同一份自愈表";漏了它,
@@ -1502,7 +1502,7 @@ static void tc_extra_branches(void)
CHECK(ok && (g_ff_obs.calls[FF_FAKE_OP_UNLINK] == 1)
&& (g_ff_obs.calls[FF_FAKE_OP_OPEN] == 3) /* 单条 1 + 批量首开 1 + 自愈重开 1 */
&& (ff_fake_size(P_RUN) == 2u * SYSLOG_REC_SIZE) && (g_sys_err_count == 0),
"TC-SYSLOG-090 批量 open 失败一次 -> unlink 重开 -> 整批 2 条落全、不留痕");
"TC-SYSLOG-090 one batch open failure -> unlink and reopen -> whole batch of 2 lands, no trace");
/* 091 批量 open 永久失败 -> -1(走的是"打开失败"那条 else,不是写失败) */
reset_all();
@@ -1514,7 +1514,7 @@ static void tc_extra_branches(void)
}
CHECK(ok && (ff_fake_exists(P_RUN) == 0) && (g_sys_err_count == 1)
&& (s_lock_releases == 1) && (s_lock_seq_err == 0),
"TC-SYSLOG-091 批量打开持续失败 -> -1 + 留痕一次 + 已释放卷锁");
"TC-SYSLOG-091 batch open keeps failing -> -1 + one trace + the volume lock released");
/* 092 取锁后二次校验:等锁期间写者可能已把文件删掉(容量轮转/取证重建)
* -> 释放锁再返回 -1,绝不能拿锁前的旧 total 去 lseek */
@@ -1527,7 +1527,7 @@ static void tc_extra_branches(void)
ok = ok && (s_read_raw(SYSLOG_RUN, 0u, raw) == -1)
&& (s_lock_releases == 2) && (s_lock_seq_err == 0);
CHECK(ok && (s_rd_win_cnt == 0u),
"TC-SYSLOG-092 锁后二次 count 失败 -> 放锁返回 -1(漏放 = FTP 永久等不到卷)");
"TC-SYSLOG-092 second count after the lock fails -> release the lock and return -1 (leak = FTP waits forever)");
/* 093 读时 f_open 失败 -> 放锁返回 -1(另一条提前退出路径) */
reset_all();
@@ -1540,7 +1540,7 @@ static void tc_extra_branches(void)
&& (s_lock_releases == 2) && (s_lock_seq_err == 0);
/* 第二次读(注入耗尽)应成功,证明窗口没被留在半初始化状态 */
ok = ok && (s_read_raw(SYSLOG_RUN, 0u, raw) == 0) && (s_rd_win_cnt == 1u);
CHECK(ok, "TC-SYSLOG-093 读打开失败 -> 放锁 -1;下轮恢复后窗口正常重填");
CHECK(ok, "TC-SYSLOG-093 read open failure -> release lock and -1; next round refills the window after recovery");
/* 094 墙钟未建立时 evidence 用占位时标(不得写半截或未初始化缓冲) */
reset_all();
@@ -1550,7 +1550,7 @@ static void tc_extra_branches(void)
(void)ff_fake_fetch(P_WDEV, raw, 0u, SYSLOG_TS_LEN);
ok = (memcmp(raw, "1970-01-01 08:00:00", SYSLOG_TS_LEN) == 0);
}
CHECK(ok, "TC-SYSLOG-094 无墙钟 -> wdev.log 落占位时标(取证行也必须可解析)");
CHECK(ok, "TC-SYSLOG-094 no wall clock -> wdev.log gets a placeholder timestamp (forensic lines must stay parseable)");
/* 095 wdev 短写:FR_OK + 字节数不足 -> -1,但第二条 run.log 照写 */
reset_all();
@@ -1558,7 +1558,7 @@ static void tc_extra_branches(void)
ok = (sys_log_evidence("short line") == -1);
CHECK(ok && (ff_fake_size(P_WDEV) == 3u) && (syslog_count(SYSLOG_RUN) == 1u)
&& (g_sys_err_count == 0),
"TC-SYSLOG-095 wdev 短写判失败返回 -1,第二条独立证据仍落 run.log");
"TC-SYSLOG-095 a wdev short write fails with -1 while the second run.log evidence record still lands");
/* 096 队列创建失败:条目滞留 preboot、留痕一次、下轮建成后排空 */
reset_all();
@@ -1573,7 +1573,7 @@ static void tc_extra_branches(void)
syslog_drain();
CHECK(ok && (s_queue != NULL) && (syslog_count(SYSLOG_RUN) == 1u)
&& (s_preboot_cnt == 0u) && (s_soe_drain_calls == 1),
"TC-SYSLOG-096 队列没建成 -> 一条都不排(不静默丢),堆恢复后排空并接上 SOE");
"TC-SYSLOG-096 queue not created -> nothing is drained (no silent loss); after the heap recovers it empties into SOE");
/* 097 换文件那条来自队列 -> 原样回投队列(不是 preboot 下标回退)
* 队列里 RUN/SELFTEST/RUN 交替:三条必须全落且各自文件内顺序不乱 */
@@ -1594,7 +1594,7 @@ static void tc_extra_branches(void)
&& (s_q_cnt == 0u);
}
CHECK(ok && (g_ff_obs.calls[FF_FAKE_OP_OPEN] == 3),
"TC-SYSLOG-097 队列侧换文件回投:三条全落、各文件内顺序不乱(回投不是丢弃)");
"TC-SYSLOG-097 queue-side file change requeues: all three land, order inside each file kept (requeue is not a drop)");
/* 098【C 项已修 2026-10-24】原来的 "if (dl >= desc_len) dl = desc_len - 1"
* 是永不可达的死分支(守卫已挡掉 desc_len <= SYSLOG_DESC_MAX,而 dl 恒
* <= SYSLOG_DESC_MAX),已从生产码删除。本条改为正向钉住"读侧不再截断":
@@ -1617,7 +1617,7 @@ static void tc_extra_branches(void)
&& (syslog_get_record(SYSLOG_RUN, 0u, ts, sizeof(ts), desc, sizeof(desc)) == 0)
&& (sys_log_evidence(NULL) == -1);
CHECK(ok && (s_lock_seq_err == 0),
"TC-SYSLOG-099 p_rec / p_desc 空指针守卫(守卫顺序在取锁之前,不放锁)");
"TC-SYSLOG-099 p_rec / p_desc NULL guards (guards run before taking the lock, so nothing is released)");
/* 100 last_epoch:有记录但读失败 -> -1 且把 *p_epoch 清 0
* (调用方 syslog_mcu_mounted 直接拿这个值判上电/重启,留旧值就会误判) */
@@ -1629,7 +1629,7 @@ static void tc_extra_branches(void)
epoch = 0xA5A5A5A5u;
ff_fake_inject_rc(P_RUN, FF_FAKE_OP_OPEN, FR_DISK_ERR, 1);
ok = (syslog_last_epoch(SYSLOG_RUN, &epoch) == -1) && (epoch == 0u);
CHECK(ok, "TC-SYSLOG-100 last_epoch 读失败 -> -1 且 *p_epoch 清零(不留调用方旧值)");
CHECK(ok, "TC-SYSLOG-100 last_epoch read failure -> -1 and *p_epoch cleared (never leave the caller's old value)");
(void)i;
}