test(host): P2 覆盖率批次,5 套主机单测与共享假 FatFs

P2 五个文件全部进分母(三名队友并行,写范围互斥、零越界):
  net_socket 420 条 / 881-883=99.8%、52-52 函数(S1~S6 分片)
  sys_log_mcu 75 条 / 310-313=99.0%、12-12
  console_log 104 条 / 188-189=99.5%、15-15
  cfg_file_store_mcu 34 条 / 97-97=100%、10-10
  soe_store 26 条 / 78-79=98.7%、4-4
合计 659 条断言,P2 本体 1554-1561=99.6%、93-93 函数。

账:套件 28→33 全绿;files_tested 32→37;未触及 112→107(.c 34→29,
恒等式 29 = 0(P1剩) + 0(P2) + 29(P3) 咬合,§9 终点判据达成);分母
4684→6245 插桩行;line 85.8%→89.3%;func 90.1%→92.2%(这批 5 个文件
全都以 ≥98.7% 进分母,故未摊薄)。--update-baseline 前后逐文件比对:
下降 0 个文件。

基建:新建 test/host/common/fatfs_fake.{h,c}(以真实 ff.h 为声明源、只
定义三文件实际调用的 9 个 f_*,缺哪个链接期响;卷忙/短写/FR_DENIED
可注入;短名违规分档);扩展 ch395f_fake 为纯新增(g_fx/g_fxchip 另开
一份世界 + ext_reset 挂进既有复位,既有三套面一字不动),并按真头修正
两个错值常量(SOCKET_OPEN 0x01→0x05、TCP_ESTABLISHED 0x05→0x04),
另在 net_socket runner 加真头/假件同名常量文本核对闸(负例验证过)。
存量回归:net_listener 34、net_events 34、net_pending 43、net_select 22、
nand_port 149、lftpd_io 33、vol_lock 33、soe 32、cfg_file 151 全绿。

编号:补 TC-HOST-{NETSOCK,SYSLOG,CFGFST,SOESTORE,CONLOG} 五族(22→27,
先补族再引号);net_socket 模块码由自取的两字母 NS 正名为 NETSOCK;
id-check 增量拦截无台账外新账,可判定比例 83.27%(基线 82.6%)。

文档:覆盖率口径 §9 新增「P2 落地」(含两套分母口径差、10 条现状表、
12 条可复用手法与并发红线),§8 第 1 条改「清单已吃穿」,补变更记录。
本提交未改任何生产代码(App/Drivers/Src/Lib/MDK-ARM 零触碰)。

10 条现状已逐条登记在 §9(含 sys_log_mcu.c:509~537 卷忙整批丢日志、
net_socket.c 同文件两套 IP 字节序、UDP 两 API 绕过 netTask),已获指示
全部修复,另开一轮(含测试字面量统一纯 ASCII)。

gate: pre-commit run --all-files → 39 hooks, 38 Passed; only mem-numbers
Failed(本工作树从未 @build,无 .map 事实源,属分支期已知陷阱);
mem-budget Passed;test-coverage 与 id-check Passed。RAM/Flash 增量 = 0
(纯测试批次)。按仓内分支约定走 --no-verify,台账回填留待主树合并后。
This commit is contained in:
2026-10-24 17:54:02 +08:00
parent 4ac869058d
commit 794906cdc8
46 changed files with 10821 additions and 39 deletions
+200 -3
View File
@@ -44,10 +44,10 @@
#define CH395F_ERR_SUCCESS 0x00U
#define CH395F_PROTO_TYPE_TCP 0x03U
#define CH395F_SOCKET_CLOSED 0x00U
#define CH395F_SOCKET_OPEN 0x01U
#define CH395F_SOCKET_OPEN 0x05U /* 真头 ch395f.h:220 = 0x05U(05H SOCKET_OPEN,docs/芯片手册/CH395F.md:527)*/
#define CH395F_TCP_CLOSED 0x00U
#define CH395F_TCP_LISTEN 0x01U
#define CH395F_TCP_ESTABLISHED 0x05U
#define CH395F_TCP_ESTABLISHED 0x04U /* 真头 ch395f.h:229 = 0x04U(04H TCP_ESTABLISHED,docs/芯片手册/CH395F.md:539)*/
/* 发送/接收缓冲尺寸宏链:**与真实 ch395f.h 同构转抄**(2026-10-23 逐条核对)。
* net_pending.h 里的 NET_SEND_CHUNK_MAX 由这两个宏推导,是"一次最多往芯片写多少"
@@ -66,6 +66,68 @@
#define CH395F_FAKE_SOCK_MAX 8 /* 与 NET_MAX_SOCKETS 同量级,测试自用 */
#define CH395F_FAKE_QUEUE_LEN 24
#define CH395F_FAKE_LOG_LEN 96
#define CH395F_FAKE_GLOB_QUEUE 24
/* ===== 扩展区(2026-10-24,net_socket 主机单测批次;**纯新增**,上面既有宏/字段/函数
* 一字未动,net_listener / net_events / net_pending 三套的语义不受影响)=====
*
* 追加的是 net_socket.c 这一层会调、而前三个模块不调的芯片原语(初始化下发类 +
* 全局中断 + sock_reset 复位机 + cmd_done 判据)。签名/常量同样**逐字抄自真实头**
* Drivers/BSP/CH395F/ch395f.h,改真头即编译期/断言期暴露漂移。
*
* 必须复刻的第三条芯片怪癖(前两套测不到、net_socket.c 却是主路):
* 3. GET_GLOB_INT_STATUS_ALL(0x19,2 字节)**整体读即清**,且它是全局寄存器
* (含全部 Socket 事件位)。AGENTS 模块约定 B3:唯一读者只能是 net_poll。
* 假件按调用序号返回预置值,并单独计数,让"别处偷偷读全局"成为可断言的事。
* 4. sock_reset 复位机(E4 定案四步:读空 RX → CLOSE → 排空事件(quiescent) →
* 等 byte0=00H,含 LISTEN 态二段 CLOSE 补发)。这里做**契约等价**实现:
* 阶段推进与最短等待(GRACEFUL 100ms / QUARANTINE 400ms)照抄驱动,
* 但不复制驱动的超时数值细节(那属于驱动自己的单测面)。
*/
#define CH395F_ERR_BUSY 0x10U /* 真头 ch395f.h:170 */
#define CH395F_ERR_MEM 0x11U /* 真头 ch395f.h:171 */
#define CH395F_ERR_TIMEOUT 0x13U /* 真头 ch395f.h:173 */
#define CH395F_ERR_VAL 0x19U /* 真头 ch395f.h:179 */
#define CH395F_ERR_USE 0x1BU /* 真头 ch395f.h:181(open 已被占用)*/
#define CH395F_PROTO_TYPE_UDP 0x02U /* 真头 ch395f.h:213 */
#define CH395F_FUN_PARA_SOCKET_CLOSE (1UL << 3) /* 真头 ch395f.h:205 */
#define CH395F_TCP_MSS 1024U /* 真头 ch395f.h:124 */
#define CH395F_PHY_DISCONN 0x01U /* 真头 ch395f.h:191 */
#define CH395F_GINT_STAT_PHY_CHANGE 0x04U /* 真头 ch395f.h:245 */
#define CH395F_SOCK_STATE_NONE 0xFFU /* 真头 ch395f.h:762 */
#define CH395F_SINT_STAT_SENBUF_FREE 0x01U /* 真头 ch395f.h:263 */
#define CH395F_SINT_STAT_SEND_OK 0x02U /* 真头 ch395f.h:264 */
#define CH395F_SINT_STAT_RECV_OK 0x04U /* 真头 ch395f.h:265 */
#define CH395F_SINT_STAT_CONNECT 0x08U /* 真头 ch395f.h:266 */
#define CH395F_SINT_STAT_DISCONNECT 0x10U /* 真头 ch395f.h:267 */
#define CH395F_SINT_STAT_SOCK_TIMEOUT 0x40U /* 真头 ch395f.h:269 */
typedef enum {
CH395F_STATUS_OK = 0, /* 真头 ch395f.h:275 */
CH395F_STATUS_ERROR = -1,
CH395F_STATUS_TIMEOUT = -2,
CH395F_STATUS_NOT_DETECTED = -3
} ch395f_status_t;
typedef enum {
CH395F_RESET_GRACEFUL = 0, /* 真头 :803:最短等待 100ms */
CH395F_RESET_QUARANTINE /* 真头 :804:最短等待 400ms */
} ch395f_reset_mode_t;
typedef enum {
CH395F_DONE_OPEN = 0, /* 真头 :826:byte0 变 05H */
CH395F_DONE_LISTEN, /* 真头 :827:byte0=05H 且 TCP=01H */
CH395F_DONE_CLOSE /* 真头 :828:byte0=00H */
} ch395f_done_what_t;
/* 复位机阶段(与驱动同名状态的**契约等价**简化,不代表驱动内部实现) */
#define CH395F_FAKE_RST_IDLE 0
#define CH395F_FAKE_RST_DRAINED 1 /* 已读空 RX 并发过 CLOSE */
#define CH395F_FAKE_RST_MINWAIT 2 /* 等最短沉降窗(100/400ms) */
#define CH395F_FAKE_RST_QUIET 3 /* 排空本 Socket 事件(连续 2 轮无位) */
#define CH395F_FAKE_RST_WAITCLS 4 /* 等 byte0=00H(含二段 CLOSE 补发) */
#define CH395F_FAKE_RST_QUIESCENT 2U
typedef struct {
uint8_t open;
@@ -111,7 +173,13 @@ typedef struct {
/* 调用顺序日志(短名首字母):
* 'c'=close 'i'=int_status(读即清) 's'=get_socket_status 'r'=read_recv_buf
* 'R'=get_recv_len 'o'=open_socket 'l'=tcp_listen 'p'=set_sour_port
* 'P'=set_proto_type */
* 'P'=set_proto_type 'w'=write_send_buf
* 扩展区新增(net_socket 批次):'G'=读全局中断 'v'=sock_events(读即清)
* 'X'=sock_reset_begin 'x'=sock_reset_poll 'z'=cmd_done 'T'=tcp_connect
* 'I'=set_ip_addr 'N'=set_gwip 'K'=set_mask 'M'=set_mac 'D'=set_dhcp
* 'F'=set_fun_para 'Q'=set_tcp_mss 'b'=set_send_buf 'u'=set_recv_buf
* 'e'=set_des_ip 'q'=set_des_port 'g'=get_phy_status 'E'=check_exist
* 'Z'=reset 'n'=init */
char log[CH395F_FAKE_LOG_LEN];
int log_n;
} ch395f_fake_obs_t;
@@ -143,4 +211,133 @@ void ch395f_set_keepalive_enable(uint8_t sock, uint8_t enable);
uint8_t ch395f_link_up_cached(void);
uint16_t ch395f_link_change_count(void);
/* ===== 扩展区第二部分:新增状态世界 + 新增假芯片原型 =====
* ⚠ 刻意**不往既有 ch395f_fake_world_t / ch395f_fake_obs_t 里加字段**,而是另开一份
* ch395f_fake_ext_t / ch395f_fake_ext_obs_t:既有三套单测的复位与断言面一字不动,
* 新增状态由 ch395f_fake_reset() 调 ch395f_fake_ext_reset() 一并清零(场景间不残留)。
*/
typedef struct {
/* —— 初始化/参数下发面(net_init 主路)—— */
int exist_rc; /* ch395f_check_exist 返回(ch395f_status_t)*/
int reset_rc; /* ch395f_reset 返回 */
int init_rc; /* ch395f_init 返回 */
uint8_t version; /* ch395f_get_version(版本门控 0x46 的用点位)*/
uint8_t dhcp_enable; /* ch395f_set_dhcp */
uint8_t ping_enable; /* ch395f_ping_enable */
uint8_t ip[4]; /* ch395f_set_ip_addr */
uint8_t gw[4]; /* ch395f_set_gwip_addr */
uint8_t mask[4]; /* ch395f_set_mask_addr */
uint8_t mac[6]; /* ch395f_set_mac_addr */
uint32_t fun_para; /* ch395f_set_fun_para 最近一次实发值 */
uint16_t mss; /* ch395f_set_tcp_mss */
uint8_t retrans_cnt;
uint16_t retrans_period;
uint32_t ka_idle;
uint32_t ka_intvl;
uint8_t ka_cnt;
uint8_t send_blk_start[CH395F_FAKE_SOCK_MAX]; /* ch395f_set_send_buf */
uint8_t send_blk_cnt[CH395F_FAKE_SOCK_MAX];
uint8_t recv_blk_start[CH395F_FAKE_SOCK_MAX]; /* ch395f_set_recv_buf */
uint8_t recv_blk_cnt[CH395F_FAKE_SOCK_MAX];
uint8_t des_ip[CH395F_FAKE_SOCK_MAX][4]; /* ch395f_set_des_ip */
uint16_t des_port[CH395F_FAKE_SOCK_MAX]; /* ch395f_set_des_port */
uint8_t connect_rc[CH395F_FAKE_SOCK_MAX]; /* ch395f_tcp_connect 返回 */
/* —— 全局中断(0x19,整体读即清;唯一读者应为 net_poll)—— */
uint16_t glob_q[CH395F_FAKE_GLOB_QUEUE];
int glob_n;
int glob_i;
uint8_t phy_status; /* ch395f_get_phy_status(喂 glob_event_feed)*/
/* —— sock_reset 复位机(契约等价,见文件头注释 4)—— */
uint8_t rst_state[CH395F_FAKE_SOCK_MAX];
uint8_t rst_mode[CH395F_FAKE_SOCK_MAX];
uint32_t rst_t0[CH395F_FAKE_SOCK_MAX];
uint8_t rst_quiet[CH395F_FAKE_SOCK_MAX]; /* 连续无事件轮数 */
/* 1=复位机**不**替芯片把 cached_open 落回 CLOSED(造"永远关不掉"的芯片形态,
* 用来量上层的复位超时收口)。默认 0 → 与既有行为一致。 */
uint8_t rst_keep_open[CH395F_FAKE_SOCK_MAX];
/* SINT 的**电平型**来源(可脚本化):读即清之后立刻把这个掩码放回 int_status。
* 默认 0 → 与既有假件行为逐字相同(读一次就没了)。真实芯片的 RECV_OK /
* SENBUF_FREE 本就是"条件位":只要条件还在(RX 仍非空 / 发送缓冲仍空),下一轮
* 就还会再报一次。net_socket.c 的多块发送要的就是这个稳态,没有它就只能
* 造"写完一块就再也等不到空闲"的假死形态。 */
uint8_t sint_sticky[CH395F_FAKE_SOCK_MAX];
} ch395f_fake_ext_t;
typedef struct {
int exist_calls;
int reset_calls;
int init_calls;
int set_ip_calls;
int set_gw_calls;
int set_mask_calls;
int set_mac_calls;
int set_dhcp_calls;
int ping_calls;
int set_fun_para_calls;
int set_mss_calls;
int set_retrans_calls;
int set_ka_calls;
int set_send_buf_calls;
int set_recv_buf_calls;
int set_des_ip_calls;
int set_des_port_calls;
int connect_calls;
int glob_calls; /* 读全局中断次数(B3:除 net_poll 外应为 0)*/
int glob_bits; /* 最近一次读到的 16 位全局位图 */
int sock_events_calls; /* ch395f_sock_events(只碰本 Socket 的护栏原语)*/
int rst_begin_calls;
int rst_begin_reject; /* begin 被拒次数(复位机已在运行)*/
int rst_poll_calls;
int rst_done[CH395F_FAKE_SOCK_MAX]; /* 复位机完成计数 */
int rst_fail[CH395F_FAKE_SOCK_MAX]; /* 复位机失败计数 */
int cmd_done_calls;
uint8_t last_cmd_done_what;
int rst_close_calls; /* 复位机内部发出的 CLOSE 命令(含二段补发)*/
int rst_rx_discard_calls; /* 复位机 RX 排空事务次数 */
} ch395f_fake_ext_obs_t;
extern ch395f_fake_ext_t g_fx;
extern ch395f_fake_ext_obs_t g_fxchip;
/* 由 ch395f_fake_reset() 自动调用;单独暴露是为了让测试能只清扩展面 */
void ch395f_fake_ext_reset(void);
void ch395f_fake_push_glob(uint16_t v); /* 预置全局中断返回序列 */
void ch395f_fake_set_sint_sticky(uint8_t sock, uint8_t mask);
/* 顺序断言辅助:清空调用日志 / 找某个短名第一次出现的位置(-1=没调过)。
* 刻意提供"清零日志",否则一次长轮询(如 sock_reset 的几十轮 'x')会把 96 格
* 环形外的顺序信息挤掉,让后续场景的顺序断言失真。 */
void ch395f_fake_clear_log(void);
int ch395f_fake_log_find(char c);
/* —— 新增假芯片实现(签名与真实 ch395f.h 一字不改)—— */
ch395f_status_t ch395f_check_exist(void);
ch395f_status_t ch395f_reset(void);
ch395f_status_t ch395f_init(void);
uint8_t ch395f_get_version(void);
void ch395f_set_fun_para(uint32_t para);
void ch395f_set_tcp_mss(uint16_t mss);
void ch395f_set_retrans_count(uint8_t cnt);
void ch395f_set_retrans_period(uint16_t period);
void ch395f_set_keepalive_idle(uint32_t time);
void ch395f_set_keepalive_intvl(uint32_t time);
void ch395f_set_keepalive_cnt(uint8_t cnt);
void ch395f_set_dhcp(uint8_t enable);
void ch395f_ping_enable(uint8_t enable);
void ch395f_set_ip_addr(uint8_t *p_ip);
void ch395f_set_gwip_addr(uint8_t *p_gwip);
void ch395f_set_mask_addr(uint8_t *p_mask);
void ch395f_set_mac_addr(uint8_t *p_mac);
void ch395f_set_send_buf(uint8_t sock, uint8_t start_block, uint8_t block_count);
void ch395f_set_recv_buf(uint8_t sock, uint8_t start_block, uint8_t block_count);
void ch395f_set_des_ip(uint8_t sock, uint8_t *p_ip);
void ch395f_set_des_port(uint8_t sock, uint16_t port);
uint8_t ch395f_tcp_connect(uint8_t sock);
uint8_t ch395f_get_phy_status(void);
uint16_t ch395f_get_glob_int_status_all(void);
void ch395f_glob_event_feed(uint16_t glob_bits);
uint8_t ch395f_sock_events(uint8_t sn);
int ch395f_sock_reset_begin(uint8_t sn, ch395f_reset_mode_t mode);
int ch395f_sock_reset_poll(uint8_t sn);
int ch395f_cmd_done(uint8_t sn, ch395f_done_what_t what);
#endif /* CH395F_FAKE_H */