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
+27 -27
View File
@@ -178,26 +178,26 @@ static void tc_sample_gate(void)
CHECK((s_prof[TASK_PROF_UI_PERIOD].count == 1u) &&
(s_prof[TASK_PROF_UI_PERIOD].last == 500u) &&
(s_prof[TASK_PROF_UI_PERIOD].max == 500u),
"TC-TASKPROF-001 有效样本记 count/last/max");
"TC-TASKPROF-001 valid sample records count/last/max");
task_prof_sample(TASK_PROF_UI_PERIOD, 300u);
CHECK((s_prof[TASK_PROF_UI_PERIOD].max == 500u) &&
(s_prof[TASK_PROF_UI_PERIOD].last == 300u) &&
(s_prof[TASK_PROF_UI_PERIOD].count == 2u),
"TC-TASKPROF-002 更小样本不改 max");
"TC-TASKPROF-002 smaller sample does not change max");
reset_all();
task_prof_sample(TASK_PROF_UI_PERIOD, 0u);
CHECK((s_prof[TASK_PROF_UI_PERIOD].glitch == 1u) &&
(s_prof[TASK_PROF_UI_PERIOD].count == 0u) &&
(s_prof[TASK_PROF_UI_PERIOD].max == 0u),
"TC-TASKPROF-003 cyc=0 只累加 glitch(DWT 复位防线)");
"TC-TASKPROF-003 cyc=0 only accumulates glitch (DWT reset defence)");
reset_all();
task_prof_sample(TASK_PROF_UI_PERIOD, SystemCoreClock * 10u);
CHECK((s_prof[TASK_PROF_UI_PERIOD].glitch == 1u) &&
(s_prof[TASK_PROF_UI_PERIOD].count == 0u),
"TC-TASKPROF-004 超上界样本只累加 glitch");
"TC-TASKPROF-004 over-upper-bound sample only accumulates glitch");
reset_all();
task_prof_sample((task_prof_id_t)TASK_PROF_ID_COUNT, 100u);
@@ -205,7 +205,7 @@ static void tc_sample_gate(void)
task_prof_enter((task_prof_id_t)TASK_PROF_ID_COUNT);
task_prof_exit((task_prof_id_t)TASK_PROF_ID_COUNT);
CHECK((s_prof[0].count == 0u) && (s_prof[TASK_PROF_ID_COUNT - 1].count == 0u),
"TC-TASKPROF-005 id 越界安全返回,不碰任何槽");
"TC-TASKPROF-005 out-of-range id returns safely, touches no slot");
}
/* ===================== 时基与 enter/exit 配对 ===================== */
@@ -219,27 +219,27 @@ static void tc_enter_exit(void)
CHECK(((g_coredebug.DEMCR & CoreDebug_DEMCR_TRCENA_Msk) != 0u) &&
((g_dwt.CTRL & DWT_CTRL_CYCCNTENA_Msk) != 0u) &&
(s_dwt_ok == 1u),
"TC-TASKPROF-006 首次取时基即惰性使能 DWT");
"TC-TASKPROF-006 first timebase read lazily enables DWT");
reset_all();
set_cyc(2000u);
task_prof_enter(TASK_PROF_UI_WORK);
CHECK((s_prof[TASK_PROF_UI_WORK].in_seg == 1u) &&
(s_prof[TASK_PROF_UI_WORK].t_start == 2000u),
"TC-TASKPROF-007 enter 置 in_seg 并记起点");
"TC-TASKPROF-007 enter sets in_seg and records the start point");
set_cyc(2640u);
task_prof_exit(TASK_PROF_UI_WORK);
CHECK((s_prof[TASK_PROF_UI_WORK].in_seg == 0u) &&
(s_prof[TASK_PROF_UI_WORK].last == 640u) &&
(s_prof[TASK_PROF_UI_WORK].count == 1u),
"TC-TASKPROF-008 exit 结算 Δ 并清 in_seg");
"TC-TASKPROF-008 exit settles the delta and clears in_seg");
reset_all();
task_prof_exit(TASK_PROF_ADC_BEAT);
CHECK((s_prof[TASK_PROF_ADC_BEAT].count == 0u) &&
(s_prof[TASK_PROF_ADC_BEAT].glitch == 0u),
"TC-TASKPROF-009 未 enter 直接 exit 不记账(防 0 起点假超大样本)");
"TC-TASKPROF-009 exit without enter records nothing (guards fake huge sample from 0 start)");
reset_all();
set_cyc(100u);
@@ -247,7 +247,7 @@ static void tc_enter_exit(void)
set_cyc(150u);
task_prof_exit(TASK_PROF_NET_POLL);
task_prof_exit(TASK_PROF_NET_POLL);
CHECK(s_prof[TASK_PROF_NET_POLL].count == 1u, "TC-TASKPROF-010 重复 exit 不重复记账");
CHECK(s_prof[TASK_PROF_NET_POLL].count == 1u, "TC-TASKPROF-010 repeated exit does not double count");
}
/* ===================== 上报节流与通道 ===================== */
@@ -258,26 +258,26 @@ static void tc_report_throttle(void)
reset_all();
g_tick = 4999u;
task_prof_report();
CHECK((g_line_calls == 0) && (g_raw_calls == 0), "TC-TASKPROF-011 首 5 s 前不发");
CHECK((g_line_calls == 0) && (g_raw_calls == 0), "TC-TASKPROF-011 nothing sent before the first 5 s");
g_tick = 5000u;
task_prof_report();
CHECK((g_line_calls == 2) && (g_raw_calls == 0),
"TC-TASKPROF-012 到点发两行走环形缓冲");
"TC-TASKPROF-012 on schedule: sends two lines via the ring buffer");
g_tick = 6999u;
task_prof_report();
CHECK(g_line_calls == 2, "TC-TASKPROF-013 不足 2 s 不发");
CHECK(g_line_calls == 2, "TC-TASKPROF-013 less than 2 s apart sends nothing");
g_tick = 7000u;
task_prof_report();
CHECK(g_line_calls == 4, "TC-TASKPROF-014 满 2 s 再发两行");
CHECK(g_line_calls == 4, "TC-TASKPROF-014 after a full 2 s sends two lines again");
g_line_calls = 0;
g_raw_calls = 0;
task_prof_report_raw();
CHECK((g_raw_calls == 2) && (g_line_calls == 0),
"TC-TASKPROF-015 report_raw 无视节流且走裸发通道");
"TC-TASKPROF-015 report_raw ignores throttling and uses the raw channel");
}
/* ===================== 行内容与换算 ===================== */
@@ -293,11 +293,11 @@ static void tc_line_format(void)
CHECK((g_line_calls == 2) &&
(strncmp(g_line[0], "[PROF] ", 7) == 0) &&
(strncmp(g_line[1], "[PROF2] ", 8) == 0),
"TC-TASKPROF-016 两行行首分别是 [PROF] / [PROF2]");
"TC-TASKPROF-016 the two lines start with [PROF] / [PROF2] respectively");
CHECK((strstr(g_line[0], "\r\n") != NULL) &&
(strstr(g_line[1], "\r\n") != NULL),
"TC-TASKPROF-016b 两行都以 CRLF 结尾");
CHECK(field_of(0, "uip=") == 0L, "TC-TASKPROF-016c 未采样的槽打印 0");
"TC-TASKPROF-016b both lines end with CRLF");
CHECK(field_of(0, "uip=") == 0L, "TC-TASKPROF-016c an unsampled slot prints 0");
/* 017:打印的是**微秒**,分母是 SystemCoreClock —— 断言落在打印字段上 */
reset_all();
@@ -306,14 +306,14 @@ static void tc_line_format(void)
g_tick = 5000u;
task_prof_report();
CHECK(field_of(0, "uip=") == 10L,
"TC-TASKPROF-017 168 MHz:1680 周期的 max 打印成 uip=10");
"TC-TASKPROF-017 168 MHz: max of 1680 cycles prints as uip=10");
CHECK(field_of(0, "adcm=") == 20L,
"TC-TASKPROF-017b 同频:3360 周期的 max 打印成 adcm=20");
"TC-TASKPROF-017b same clock: max of 3360 cycles prints as adcm=20");
SystemCoreClock = 84000000u; /* 改时钟树而忘了同步 → 整表偏移,这里必须显式跟着变 */
g_tick = 7000u;
task_prof_report();
CHECK(field_of(2, "uip=") == 20L,
"TC-TASKPROF-017c 84 MHz 下同一批周期数打印成 20");
"TC-TASKPROF-017c at 84 MHz the same cycle counts print as 20");
SystemCoreClock = 168000000u;
/* 018:gl= 是**所有槽**的 glitch 汇总,不是当前槽 */
@@ -323,7 +323,7 @@ static void tc_line_format(void)
task_prof_sample(TASK_PROF_NET_POLL, 0u);
g_tick = 5000u;
task_prof_report();
CHECK(field_of(0, "gl=") == 3L, "TC-TASKPROF-018 gl= 汇总所有槽的 glitch");
CHECK(field_of(0, "gl=") == 3L, "TC-TASKPROF-018 gl= sums the glitch of all slots");
/* 019:段未结算时,"此刻已在段内多久"要看得见(uipn / netn 两个字段) */
/* 字段口径 = 上报时刻的 CYCCNT 减去各自的进段时刻(**不是**样本值):
@@ -338,13 +338,13 @@ static void tc_line_format(void)
g_tick = 5000u;
task_prof_report();
CHECK(field_of(0, "uipn=") == 301L,
"TC-TASKPROF-019 UI_PERIOD 段内:uipn= 上报此刻已停留的 us");
"TC-TASKPROF-019 inside UI_PERIOD segment: uip= reports the us elapsed so far");
CHECK(field_of(1, "netn=") == 248L,
"TC-TASKPROF-019b NET_POLL 段内:[PROF2] 的 netn= 同步可见");
"TC-TASKPROF-019b inside NET_POLL segment: netn= of [PROF2] is visible too");
CHECK(field_of(0, "adcn=") == 0L,
"TC-TASKPROF-019c 未进段的 ADC_BEAT 打印 0(不串用别的槽)");
"TC-TASKPROF-019c ADC_BEAT not in segment prints 0 (no cross-slot leakage)");
CHECK(s_prof[TASK_PROF_UI_PERIOD].in_seg == 1u,
"TC-TASKPROF-019d 上报不消费段状态(只观测)");
"TC-TASKPROF-019d reporting does not consume segment state (observe only)");
/* 020:count 是累计量,两轮上报之间不能清零 */
reset_all();
@@ -355,7 +355,7 @@ static void tc_line_format(void)
task_prof_report();
CHECK((s_prof[TASK_PROF_UI_WORK].count == 1u) && (field_of(2, "uic=") == 0L) &&
(field_of(0, "uic=") == 0L),
"TC-TASKPROF-020 上报不清零(UI_WORK 不在 uic= 字段,仍为累计 1)");
"TC-TASKPROF-020 reporting does not clear counters (UI_WORK not in uic= field, still cumulative 1)");
}