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
+28 -28
View File
@@ -365,7 +365,7 @@ static void tc_post_side(void)
uint32_t i;
int ok;
printf("-- TC-SOESTORE-001..007 post 侧(零 I/O 契约)--\n");
printf("-- TC-SOESTORE-001..007 post side (zero-IO contract) --\n");
/* 001:post 3 条只写环,绝不碰盘、绝不碰卷锁、绝不打日志 */
reset_all();
@@ -379,7 +379,7 @@ static void tc_post_side(void)
}
}
CHECK(ok && (s_lock_waits == 0) && (g_soe_err_count == 0) && (g_soe_info_count == 0),
"TC-SOESTORE-001 post 零 FatFs / 零卷锁 / 零日志(protectTask 栈预算)");
"TC-SOESTORE-001 post does zero FatFs / zero volume lock / zero logging (protectTask stack budget)");
/* 002:墙钟未建立 -> IV + epoch 字段 0(不造假时标) */
reset_all();
@@ -389,7 +389,7 @@ static void tc_post_side(void)
ok = read_rec(0u, &out);
CHECK(ok && (out.flags & SOE_FLG_IV) != 0u && (out.epoch_s == 0u)
&& (out.cp56[2] & 0x80u) != 0u && (out.value == 0xF0u),
"TC-SOESTORE-002 无墙钟 -> flags.IV + epoch=0 + CP56 IV 位(B9 口径)");
"TC-SOESTORE-002 no wall clock -> flags.IV + epoch=0 + CP56 IV bit (B9 rule)");
/* 003:seq 单调;丢弃的那条也占号(真机丢号 = 主机看到的号不连续是**如实**) */
reset_all();
@@ -397,7 +397,7 @@ static void tc_post_side(void)
soe_store_post((uint8_t)SOE_T_ELM_ASSERT, (uint8_t)i, i);
}
ok = (s_seq == 9u) && (s_drop_cnt == 1u);
CHECK(ok, "TC-SOESTORE-003 seq 单调递增,丢弃也占号(号不跳才是假象)");
CHECK(ok, "TC-SOESTORE-003 seq increases monotonically, dropped entries still consume a number");
/* 004:环满丢弃不阻塞、不崩、**不打日志**(留痕归 drain 侧) */
reset_all();
@@ -406,7 +406,7 @@ static void tc_post_side(void)
}
CHECK((s_ring_head == 8u) && (s_drop_cnt == 1u)
&& (g_soe_err_count == 0) && (g_soe_info_count == 0),
"TC-SOESTORE-004 环满丢弃:只计数,post 侧零 DBG(栈尾链 +320B 教训)");
"TC-SOESTORE-004 ring-full drop: count only, zero DBG on post side (lesson: +320B tail chain)");
/* 005:内核运行 + 队列已建 -> 走队列,环不再写 */
reset_all();
@@ -417,7 +417,7 @@ static void tc_post_side(void)
s_ring_tail = 0u;
soe_store_post((uint8_t)SOE_T_ELM_RETURN, 1u, 2u);
CHECK((s_ring_head == 0u) && (s_q_cnt == 1u) && (s_q_msgsz == SOE_REC_SIZE),
"TC-SOESTORE-005 队列已建 + 内核运行 -> 条目进队列、环不再写");
"TC-SOESTORE-005 queue created + kernel running -> entries go to the queue, ring not written");
/* 006:队列满 -> 丢弃计数(与环满同一条可观测出口) */
reset_all();
@@ -429,14 +429,14 @@ static void tc_post_side(void)
soe_store_post((uint8_t)SOE_T_ELM_ASSERT, (uint8_t)i, i);
}
CHECK((s_q_cnt == SOE_QUEUE_MAX) && (s_drop_cnt == 2u),
"TC-SOESTORE-006 队列满 -> 丢弃并计数(soe_store_dropped 同一出口)");
"TC-SOESTORE-006 queue full -> drop and count through the same soe_store_dropped exit");
/* 007:计数饱和不回绕 */
reset_all();
s_drop_cnt = UINT32_MAX;
soe_store_post((uint8_t)SOE_T_ELM_ASSERT, 1u, 1u);
CHECK((s_drop_cnt == UINT32_MAX) && (soe_store_dropped() == UINT32_MAX),
"TC-SOESTORE-007 丢弃计数饱和:UINT32_MAX 不回绕");
"TC-SOESTORE-007 drop counter saturates at UINT32_MAX, never wraps");
}
/* ===================== TC-SOESTORE-010..021:drain 落盘与故障注入 ===================== */
@@ -449,7 +449,7 @@ static void tc_drain_paths(void)
int opens_before;
int writes_before;
printf("-- TC-SOESTORE-010..021 drain 落盘 / 故障注入 --\n");
printf("-- TC-SOESTORE-010..021 drain to disk / fault injection --\n");
/* 010:首次 drain 惰性建队列 + 1 条 64B 落盘且能解析回来 */
reset_all();
@@ -459,7 +459,7 @@ static void tc_drain_paths(void)
&& (ff_fake_size(SOE_PATH) == SOE_REC_SIZE);
CHECK(ok && read_rec(0u, &out) && (out.type == (uint8_t)SOE_T_ELM_ASSERT)
&& (out.elm_id == 3u) && (out.value == 0xABCDu) && (out.seq == 0u),
"TC-SOESTORE-010 惰性建队列 + 64B 定长落盘 + 记录可解回");
"TC-SOESTORE-010 lazy queue creation + fixed 64B record on disk + record decodes back");
/* 011:打开模式必须带 FA_WRITE —— 陷阱一 */
reset_all();
@@ -478,7 +478,7 @@ static void tc_drain_paths(void)
{
FRESULT fr3 = f_write(&probe, payload, SOE_REC_SIZE, &bw);
CHECK(ok && (fr2 == FR_OK) && (fr3 == FR_DENIED) && (bw == 0u),
"TC-SOESTORE-011 模式必为 FA_WRITE|FA_OPEN_APPEND;缺写位 f_write 恒 FR_DENIED");
"TC-SOESTORE-011 mode must be FA_WRITE|FA_OPEN_APPEND; without the write bit f_write is FR_DENIED");
}
(void)f_close(&probe);
}
@@ -499,14 +499,14 @@ static void tc_drain_paths(void)
}
}
}
CHECK(ok, "TC-SOESTORE-012 逐条 open/write/close(无批量合并)+ FIFO 顺序正确");
CHECK(ok, "TC-SOESTORE-012 per-entry open/write/close (no batch merge) + correct FIFO order");
/* 013:open/close 严格配对 */
reset_all();
soe_store_post((uint8_t)SOE_T_SAMPLE_RESUME, SOE_ELM_NONE, 0u);
soe_store_drain();
CHECK(g_ff_obs.calls[FF_FAKE_OP_CLOSE] == g_ff_obs.calls[FF_FAKE_OP_OPEN],
"TC-SOESTORE-013 open/close 配对(脏句柄不跨调用残留)");
"TC-SOESTORE-013 open/close stay paired (no stale handle left across calls)");
/* 014:短写判失败 -> unlink 重建 -> 重试成功 -> 恰好 64 字节 */
reset_all();
@@ -517,7 +517,7 @@ static void tc_drain_paths(void)
&& (g_ff_obs.calls[FF_FAKE_OP_UNLINK] >= 1)
&& (g_ff_obs.last_write_bw == SOE_REC_SIZE)
&& (g_soe_err_count == 0),
"TC-SOESTORE-014 FR_OK+短写被当失败处理(不校验字节数就会静默收下 63B)");
"TC-SOESTORE-014 FR_OK plus short write counts as failure (63B would pass silently without check)");
/* 015:连续**两轮** drain 都失败 -> 留痕只许 1 次(一轮 = 首写 + 自愈重试
* = 2 次 f_write,所以注入 4 次零字节短写才够撑两轮) */
@@ -528,7 +528,7 @@ static void tc_drain_paths(void)
ok = (g_soe_err_count == 1) && (s_ring_tail == 0u) && (s_fault_reported == 1u);
soe_store_drain(); /* 第 2 轮仍失败:不得再留痕 */
CHECK(ok && (g_soe_err_count == 1) && (s_ring_tail == 0u),
"TC-SOESTORE-015 写故障留痕去重(防串口与 selftest 被同一条故障刷屏)");
"TC-SOESTORE-015 write-fault trace is de-duplicated (one fault must not flood UART and selftest)");
/* 015b:成功一次复位去重位,之后再失败才会重新留痕 */
/* 015b:失败(留痕1) -> 恢复(去重位复位) -> 再失败(必须留痕2)。
@@ -543,7 +543,7 @@ static void tc_drain_paths(void)
soe_store_post((uint8_t)SOE_T_ELM_ASSERT, 2u, 2u);
soe_store_drain(); /* 又失败 -> 留痕 2 */
CHECK(ok && (g_soe_err_count == 2) && (s_fault_reported == 1u),
"TC-SOESTORE-015b 恢复后再失败必须重新留痕(漏复位 = 永久静默)");
"TC-SOESTORE-015b a failure after recovery must trace again (missing reset = permanent silence)");
/* 016:卷忙 -> -2:不碰 FatFs、不 release、环不推进 */
reset_all();
@@ -554,7 +554,7 @@ static void tc_drain_paths(void)
CHECK(ok && (g_ff_obs.calls[FF_FAKE_OP_OPEN] == 0)
&& (g_ff_obs.calls[FF_FAKE_OP_WRITE] == 0)
&& (s_ring_tail == 0u) && (g_soe_err_count == 0),
"TC-SOESTORE-016 卷忙 = 顺延:零 FatFs、零 release、不计故障(喂狗点纪律)");
"TC-SOESTORE-016 volume busy means defer: zero FatFs, zero release, no fault counted (feed duty)");
/* 017:写失败时环不推进 tail -> 下轮重试、既不丢也不重复 */
reset_all();
@@ -566,7 +566,7 @@ static void tc_drain_paths(void)
soe_store_drain(); /* 下轮成功 */
CHECK(ok && (s_ring_tail == 1u) && (ff_fake_size(SOE_PATH) == SOE_REC_SIZE)
&& read_rec(0u, &out) && (out.elm_id == 5u),
"TC-SOESTORE-017 环条目写失败不推进 tail:不丢、下轮也不重复落");
"TC-SOESTORE-017 ring write failure does not advance tail: nothing lost, no duplicate next round");
/* 018:队列条目已出队 -> 卷忙只丢当前一条,剩余留在队列(现状不对称) */
reset_all();
@@ -584,18 +584,18 @@ static void tc_drain_paths(void)
&& (g_ff_obs.calls[FF_FAKE_OP_OPEN] == opens_before)
&& (g_ff_obs.calls[FF_FAKE_OP_WRITE] == writes_before)
&& (s_lock_waits >= 1) && (s_lock_seq_err == 0) && (s_q_get_calls >= 2),
"TC-SOESTORE-018 队列路径卷忙:只丢已出队那一条、本轮零 FatFs(与环路径不对称)");
"TC-SOESTORE-018 queue path with busy volume: only the dequeued entry is lost, zero FatFs now");
/* 019:容量满 -> unlink 重建 + INFO 留痕,新文件恰好 64 字节 */
reset_all();
CHECK(ff_fake_mkfile_size(SOE_PATH, (uint32_t)SOE_STORE_MAX * SOE_REC_SIZE) == 0,
"TC-SOESTORE-019 前置:铺 1024 条(64KB)假记录");
"TC-SOESTORE-019 setup: lay down 1024 fake records (64KB)");
soe_store_post((uint8_t)SOE_T_ELM_ASSERT, 9u, 0x99u);
soe_store_drain();
CHECK((g_ff_obs.calls[FF_FAKE_OP_UNLINK] == 1)
&& (ff_fake_size(SOE_PATH) == SOE_REC_SIZE)
&& (g_soe_info_count == 1) && read_rec(0u, &out) && (out.elm_id == 9u),
"TC-SOESTORE-019 满则删除重建:新文件只剩本次这一条");
"TC-SOESTORE-019 full file is deleted and recreated: the new file holds only this entry");
/* 020:丢弃留痕按差值上报一次,不刷屏 */
reset_all();
@@ -605,7 +605,7 @@ static void tc_drain_paths(void)
soe_store_drain(); /* 差值上报 1 条 */
soe_store_drain(); /* 无新丢弃 -> 不再报 */
CHECK((s_drop_cnt == 3u) && (s_drop_logged == 3u) && (g_soe_err_count == 1),
"TC-SOESTORE-020 丢弃留痕按差值上报一次(defaultTask 侧才是日志安全区)");
"TC-SOESTORE-020 drop trace reports the delta once (only the defaultTask side is log-safe)");
/* 021:队列创建失败 -> 条目滞留环、下轮再试、不崩 */
/* 021:osMessageQueueNew 返回 NULL —— 生产代码里环在队列**之前**排空,
@@ -620,12 +620,12 @@ static void tc_drain_paths(void)
&& (s_ring_tail == 1u) && (ff_fake_size(SOE_PATH) == SOE_REC_SIZE);
soe_store_post((uint8_t)SOE_T_ELM_ASSERT, 5u, 5u); /* 队列没建成 -> 仍进环 */
CHECK(ok && (s_q_cnt == 0u) && (s_ring_head == 2u),
"TC-SOESTORE-021 队列创建失败:环路径照常落盘不丢条目 + 留痕一次");
"TC-SOESTORE-021 queue creation failure: ring path still writes to disk, loses nothing + one trace");
s_q_new_fail = 0;
soe_store_drain();
CHECK((s_queue != NULL) && (s_ring_tail == 2u)
&& (ff_fake_size(SOE_PATH) == 2u * SOE_REC_SIZE) && (g_soe_err_count == 1),
"TC-SOESTORE-021b 堆恢复后队列补建、滞留条目全部落盘");
"TC-SOESTORE-021b once the heap recovers the queue is created and all pending entries reach disk");
}
/* ===================== TC-SOESTORE-022..024:陷阱二 —— 名字/参数类错误码 ===================== */
@@ -635,7 +635,7 @@ static void tc_name_error_not_volume(void)
uint32_t i;
int ok;
printf("-- TC-SOESTORE-022..024 名字/参数类错误码严禁升级成卷操作 --\n");
printf("-- TC-SOESTORE-022..024 name/parameter errors must never escalate into volume operations --\n");
/* 022【D 项已修 2026-10-24:正向断言】f_open 失败(名字/参数类码)
* -> 只留痕返回 -1:**绝不 unlink**、不动 /log 目录、已有记录一条不少。
@@ -692,7 +692,7 @@ static void tc_name_error_not_volume(void)
&& (s_ring_tail == 0u);
ff_fake_inject_write_short(SOE_PATH, 0u, 0); /* 清掉不再需要的注入 */
(void)ok;
CHECK(ok, "TC-SOESTORE-023 长跑反复失败:unlink 有界(<=1/轮),绝不升级为整卷动作");
CHECK(ok, "TC-SOESTORE-023 repeated failures: unlink stays bounded (<=1 per round), never a volume action");
/* 024:假卷严格 8.3 校验的保真自检 —— 生产路径必过、点开头必被拒 */
reset_all();
@@ -715,7 +715,7 @@ static void tc_name_error_not_volume(void)
CHECK((fr_ok == FR_OK)
&& ((fr_dot == FR_INVALID_NAME) || (fr_dot == FR_INVALID_DRIVE))
&& (fr_colon == FR_INVALID_DRIVE),
"TC-SOESTORE-024 假件保真:/log/soe.log 过 8.3,.fschk 与坏盘符被拒");
"TC-SOESTORE-024 fake fidelity: /log/soe.log passes 8.3, .fschk and a bad drive prefix are rejected");
}
/* 生产路径本身合规的正向断言:改名成非 8.3 会让上面那条保真自检变红 */
reset_all();
@@ -723,7 +723,7 @@ static void tc_name_error_not_volume(void)
soe_store_drain();
CHECK((strcmp(g_ff_obs.last_open_path, "/LOG/SOE.LOG") == 0)
&& (g_ff_obs.last_open_rc == (int)FR_OK),
"TC-SOESTORE-024b SOE_PATH 在严格 8.3 卷上确实打得开(改名=静默写失败的防线)");
"TC-SOESTORE-024b SOE_PATH really opens on a strict 8.3 volume (guard against silent write failure)");
}
/* ===================== 入口 ===================== */