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
+29 -29
View File
@@ -221,7 +221,7 @@ void osDelay(uint32_t ticks)
(void)ticks;
g_n.delay_calls++;
if (g_n.delay_calls > 500) {
printf(" ABORT 跑飞(>500 轮 osDelay)\n");
printf(" ABORT runaway (>500 osDelay rounds)\n");
fflush(stdout);
exit(2);
}
@@ -278,22 +278,22 @@ static void tc_bind_listen(void)
(g_n.last_bind_family == NET_AF_INET) &&
(g_n.last_bind_port_net == net_htons(IEC104_SERV_PORT)) &&
(g_n.last_bind_addr == NET_INADDR_ANY),
"TC-I104SRV-001 建监听:2404 端口过 htons、绑任意地址、记下监听号");
"TC-I104SRV-001 build the listener: port 2404 through htons, bind to any address, remember the listen handle");
reset_all();
g_n.socket_rc = -1;
CHECK((s_bind_listen() == -1) && (g_n.bind_calls == 0) && (g_n.close_calls == 0),
"TC-I104SRV-002 建不出 socket 就返回,不去 bind 也不关不存在的口");
"TC-I104SRV-002 if no socket can be created return at once: no bind and no close of a handle that does not exist");
reset_all();
g_n.bind_rc = -1;
CHECK((s_bind_listen() == -1) && (g_n.close_calls == 1) && (g_n.listen_calls == 0),
"TC-I104SRV-003 bind 失败要把刚建的口关掉(否则每次重试漏一个 socket 号)");
"TC-I104SRV-003 a bind failure must close the socket just created (otherwise every retry leaks a handle)");
reset_all();
g_n.listen_rc = -1;
CHECK((s_bind_listen() == -1) && (g_n.close_calls == 1) && (s_listen == -1),
"TC-I104SRV-004 listen 失败同样关口且不留下半个监听");
"TC-I104SRV-004 a listen failure also closes it and leaves no half-built listener");
}
/* ===================== 发送与连续短写判死 ===================== */
@@ -307,25 +307,25 @@ static void tc_send(void)
s_client = -1;
s_send_apdu(NULL, apdu, 4u);
CHECK((g_n.send_rc == 0) && (g_n.close_calls == 0) && (g_i4_error_count == 0),
"TC-I104SRV-010 没连接时直接返回(不发 net_send、不报错)");
"TC-I104SRV-010 with no connection it returns directly (no net_send, no error)");
reset_all();
s_client = 7;
g_n.send_rc = 4;
s_send_apdu(NULL, apdu, 4u);
CHECK((s_send_fail_run == 0u) && (s_conn_dead == 0u),
"TC-I104SRV-011 完整发出把连败计数清零");
"TC-I104SRV-011 a fully sent frame clears the consecutive-failure counter");
reset_all();
s_client = 7;
g_n.send_rc = 2; /* 短写:只发了 2/4 */
s_send_apdu(NULL, apdu, 4u);
CHECK((s_send_fail_run == 1u) && (s_conn_dead == 0u) && (g_i4_error_count == 1),
"TC-I104SRV-012 第一次短写:留痕但不判死(拥塞很正常)");
"TC-I104SRV-012 the first short write is logged but does not declare death (congestion is normal)");
s_send_apdu(NULL, apdu, 4u);
s_send_apdu(NULL, apdu, 4u);
CHECK((s_send_fail_run == 3u) && (s_conn_dead == 1u),
"TC-I104SRV-012b 连到 3 次才判死(IEC104_SEND_FAIL_MAX)");
"TC-I104SRV-012b only the 3rd failure in a row declares death (IEC104_SEND_FAIL_MAX)");
reset_all();
s_client = 7;
@@ -338,7 +338,7 @@ static void tc_send(void)
s_send_apdu(NULL, apdu, 4u);
s_send_apdu(NULL, apdu, 4u);
CHECK((s_conn_dead == 0u) && (s_send_fail_run == 2u),
"TC-I104SRV-013 **成功即复位**:偶发拥塞不会被累计成误杀");
"TC-I104SRV-013 success resets the counter: occasional congestion never adds up into a false kill");
}
/* ===================== 时钟桥接边界 ===================== */
@@ -348,22 +348,22 @@ static void tc_clock(void)
printf("-- TC-I104SRV-020..023 clock bridge --\n");
reset_all();
CHECK(s_clock_sync(NULL, 0x100000000ULL * 1000ULL) == -1,
"TC-I104SRV-020 秒数超过 32 位一律拒绝(截断写进 RTC 就是 2106 年后的乱值)");
CHECK(g_clock_set_calls == 0, "TC-I104SRV-020b 拒绝时根本不该碰时钟");
"TC-I104SRV-020 any second count beyond 32 bits is rejected (truncating it into the RTC means garbage past 2106)");
CHECK(g_clock_set_calls == 0, "TC-I104SRV-020b when rejected the clock must not be touched at all");
reset_all();
(void)s_clock_sync(NULL, 1700000123000ULL);
CHECK((g_clock_set_calls == 1) && (g_clock_last_secs == 1700000123u),
"TC-I104SRV-021 毫秒按整除换秒后写时钟");
"TC-I104SRV-021 milliseconds become seconds by integer division before the clock is written");
reset_all();
g_clock_val = UINT32_MAX; /* 未对时的哨兵值 */
CHECK(s_epoch_ms(NULL) == UINT64_MAX,
"TC-I104SRV-022 未对时回 UINT64_MAX 哨兵(绝不能把 1970 当成设备时间)");
"TC-I104SRV-022 without time sync return the UINT64_MAX sentinel (1970 must never pass for device time)");
reset_all();
g_clock_val = 1700000123u;
CHECK(s_epoch_ms(NULL) == 1700000123000ULL, "TC-I104SRV-023 正常时对时给出毫秒");
CHECK(s_epoch_ms(NULL) == 1700000123000ULL, "TC-I104SRV-023 with a synced clock the answer is in milliseconds");
}
/* ===================== 代次重建与 accept 门控 ===================== */
@@ -379,13 +379,13 @@ static void tc_generation(void)
CHECK((g_n.close_calls == 2) && (g_n.last_closed_fd == 5) &&
(s_client == -1) && (s_liveness_ctr == 0u) && (s_conn_dead == 0u) &&
(g_lk_close == 1) && (s_gen == 101u) && (g_n.bind_calls == 1),
"TC-I104SRV-030 代次一变就拆掉旧连接与旧监听并重建(新 IP 上端口必须继续服务)");
"TC-I104SRV-030 a generation change tears down the old connection and listener and rebuilds them (the port must keep serving on the new IP)");
reset_all();
s_listen = -1;
s_serv_poll();
CHECK((g_n.bind_calls == 1) && (s_listen == 5) && (g_n.accept_calls == 0),
"TC-I104SRV-031 监听丢了就补建,这一轮不去 accept");
"TC-I104SRV-031 a lost listener is rebuilt and this round does not accept");
reset_all();
s_listen = 5;
@@ -393,7 +393,7 @@ static void tc_generation(void)
g_n.sock_exists = 1;
s_serv_poll();
CHECK((g_n.accept_calls == 0) && (s_listen == 5),
"TC-I104SRV-032 监听门未开时不 accept(否则对着未就绪的号空转)");
"TC-I104SRV-032 no accept while the listener gate is down (otherwise it spins on a handle that is not ready)");
reset_all();
s_listen = 5;
@@ -401,7 +401,7 @@ static void tc_generation(void)
g_n.sock_exists = 0; /* 表项已不存在 */
s_serv_poll();
CHECK((s_listen == -1) && (g_n.accept_calls == 0),
"TC-I104SRV-032b 表项已失效时把监听号丢掉,下一轮重建");
"TC-I104SRV-032b once the slot is invalid the listen handle is dropped and rebuilt next round");
reset_all();
s_listen = 5;
@@ -413,7 +413,7 @@ static void tc_generation(void)
CHECK((s_client == 9) && (g_lk_open == 1) && (g_lk_last_now == 5000u) &&
(s_send_fail_run == 0u) && (s_conn_dead == 0u) && (s_liveness_ctr == 0u) &&
(g_i4_info_count == 1),
"TC-I104SRV-033 新连接:打开链路、三个失败计数全部复位");
"TC-I104SRV-033 a new connection opens the link and resets all three failure counters");
}
/* ===================== 活性分频、对端 FIN、错误丢弃 ===================== */
@@ -428,7 +428,7 @@ static void tc_liveness(void)
s_liveness_ctr = 0u;
s_serv_poll();
CHECK((g_n.recv_calls == 0) && (g_lk_poll == 1) && (s_liveness_ctr == 1u),
"TC-I104SRV-034 无可读数据时按 32 分频探活,这一轮不收包(省 CPU 预算)");
"TC-I104SRV-034 with nothing readable the liveness probe runs on a divide-by-32 tick and this round receives nothing (saves CPU budget)");
reset_all();
s_listen = 5;
@@ -441,7 +441,7 @@ static void tc_liveness(void)
s_liveness_ctr = 31u; /* 下一轮正好到分频点 */
s_serv_poll();
CHECK((g_n.recv_calls == 1) && (g_lk_poll == 1) && (s_client == 9),
"TC-I104SRV-035 分频到点才去收一次(TESTFR 等活性帧靠它发出去)");
"TC-I104SRV-035 only when the divider fires does it receive once (liveness frames such as TESTFR depend on it going out)");
reset_all();
s_listen = 5;
@@ -451,7 +451,7 @@ static void tc_liveness(void)
s_serv_poll();
CHECK((g_n.last_closed_fd == 9) && (s_client == -1) && (g_lk_close == 1) &&
(g_n.close_calls == 1) && (s_listen == 5) && (g_n.bind_calls == 0),
"TC-I104SRV-036 对端正常断开:只关数据口、**监听必须留着**(单连接 socket 关错就是端口失联)");
"TC-I104SRV-036 a normal peer disconnect closes only the data socket: the listener must stay (on a single-socket chip closing the wrong one kills the port)");
reset_all();
s_listen = 5;
@@ -460,7 +460,7 @@ static void tc_liveness(void)
g_n.recv_rc = 0;
s_serv_poll();
CHECK((g_n.close_calls == 0) && (s_client == -1) && (g_lk_close == 1),
"TC-I104SRV-036b 数据号与监听号同号时**不许关**(否则把监听一起毁掉)");
"TC-I104SRV-036b when the data handle equals the listen handle it must NOT be closed (that would destroy the listener too)");
reset_all();
s_listen = 5;
@@ -470,7 +470,7 @@ static void tc_liveness(void)
g_n.errno_val = NET_ERR_WOULDBLOCK; /* 空转:没数据可读 */
s_serv_poll();
CHECK((s_client == 9) && (g_lk_close == 0) && (g_i4_error_count == 0),
"TC-I104SRV-037 WOULDBLOCK 是正常空转,不能当成错误丢连接");
"TC-I104SRV-037 WOULDBLOCK is normal idling and must not drop the connection as an error");
reset_all();
s_listen = 5;
@@ -481,7 +481,7 @@ static void tc_liveness(void)
s_serv_poll();
CHECK((s_client == -1) && (s_listen == 5) && (g_i4_error_count == 1) &&
(g_lk_close == 1) && (s_liveness_ctr == 0u),
"TC-I104SRV-038 真错误:丢连接并**当场重建监听**(不留空窗)");
"TC-I104SRV-038 a real error drops the connection and rebuilds the listener on the spot (no gap in service)");
reset_all();
s_listen = 5;
@@ -489,7 +489,7 @@ static void tc_liveness(void)
s_conn_dead = 1u;
s_service_link(1000u);
CHECK((s_client == -1) && (g_n.close_calls == 1) && (g_i4_error_count == 1),
"TC-I104SRV-039 判死后由 service_link 收口(发送失败线索单独成一条)");
"TC-I104SRV-039 after death is declared service_link does the teardown (the send-failure path is a separate case)");
reset_all();
s_listen = 5;
@@ -497,7 +497,7 @@ static void tc_liveness(void)
g_lk_state = IEC104_ST_IDLE; /* 链路层自己回到了未建立 */
s_service_link(1000u);
CHECK((s_client == -1) && (g_lk_close >= 1) && (s_listen == 5),
"TC-I104SRV-040 协议状态掉回 IDLE 也要丢并重生(否则服务挂着但永不服务)");
"TC-I104SRV-040 falling back to IDLE also drops and respawns the session (otherwise the service stays up but never serves)");
reset_all();
s_listen = 9;
@@ -508,7 +508,7 @@ static void tc_liveness(void)
g_n.recv_rc = 0;
s_serv_poll();
CHECK((s_client == -1) && (s_listen == -1) && (g_n.close_calls == 0),
"TC-I104SRV-041 表项没了又重建失败:丢掉假监听号,下一轮继续重试(数据号与监听同号时不许关)");
"TC-I104SRV-041 slot gone and the rebuild failed: drop the stale listen handle and retry next round (never close it while it equals the data handle)");
}
int main(void)