794906cdc8
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,台账回填留待主树合并后。
380 lines
12 KiB
C
380 lines
12 KiB
C
/*
|
||
* 模块名称:NET 层兄弟模块桩(net_socket 主机侧单测专用)
|
||
* 模块功能:net_socket.c 依赖的三个兄弟模块(net_listener / net_pending / net_events)
|
||
* 在这里**按边界契约打桩**,让本套单测只测 net_socket.c 自己那部分决策。
|
||
*
|
||
* ⚠ 仅供 test/host/net_socket/ 使用,不参与 MCU 构建。
|
||
*
|
||
* 为什么打桩而不是 #include 真实源(而不是"越真越好"):
|
||
* 1. 那三个模块**已各有自己的主机单测**(net_listener 34 条、net_events 34 条、
|
||
* net_pending 43 条),本套再跑一遍不增加任何对 net_socket.c 的判别力,
|
||
* 只会把"谁的红"变成糊账;
|
||
* 2. 本套真正要钉的是**边界契约**——net_socket.c 在什么条件下把什么 reason 登记给
|
||
* 监听层、什么条件下把挂起请求登记给 pending 层、以及"登记了就不能再自己发回执"。
|
||
* 桩把这些变成可断言的记录,比让真实 tick 在背后默默跑更有判别力;
|
||
* 3. 原型一律取**真实头**(net_listener.h / net_pending.h / net_events.h),
|
||
* 兄弟模块改签名 → 本套编译期就红。
|
||
*
|
||
* 桩的取值纪律(不自己发明语义,全部按真实头的函数说明):
|
||
* - net_pending_register / net_send_pending_register 返回 NET_PENDING_REGISTERED,
|
||
* 与真实实现一致(登记成功=哨兵,供分派跳过即时通知);可注入 -1 测登记被拒;
|
||
* - net_pending_tick 支持"下一轮把脚本里的结果当作数据到达,通知登记时的 caller",
|
||
* 复刻真实 tick 的"数据到达即通知"契约;
|
||
* - 其余全为纯记录(次数 + 最近一次入参),供"不该登记/必须登记"的断言。
|
||
*
|
||
* 创建日期:2026-10-24
|
||
*/
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
#include "net_listener.h"
|
||
#include "net_pending.h"
|
||
#include "net_events.h"
|
||
#include "net_socket.h"
|
||
#include "ns_peers.h"
|
||
#include "ns_rtos.h"
|
||
|
||
ns_peers_obs_t g_peers;
|
||
|
||
/* 桩内部"完成/取消"要发通知:转给假内核,这样测试能断言通知次数与通知值 */
|
||
void ns_peers_note_notify(TaskHandle_t to, uint32_t v)
|
||
{
|
||
ns_rtos_post_notify(to, v);
|
||
}
|
||
|
||
/* 挂起登记簿(只记一条,够本套断言用) */
|
||
static int s_pend_active[NET_MAX_SOCKETS];
|
||
static void *s_pend_buf[NET_MAX_SOCKETS];
|
||
static int s_pend_len[NET_MAX_SOCKETS];
|
||
static TaskHandle_t s_pend_caller[NET_MAX_SOCKETS];
|
||
static int s_snd_active[NET_MAX_SOCKETS];
|
||
static TaskHandle_t s_snd_caller[NET_MAX_SOCKETS];
|
||
|
||
/* tick 完成脚本:fd -> 结果值(一次生效) */
|
||
static int s_pend_done_armed[NET_MAX_SOCKETS];
|
||
static int s_pend_done_val[NET_MAX_SOCKETS];
|
||
static int s_snd_done_armed[NET_MAX_SOCKETS];
|
||
static int s_snd_done_val[NET_MAX_SOCKETS];
|
||
|
||
void ns_peers_reset(void)
|
||
{
|
||
(void)memset(&g_peers, 0, sizeof(g_peers));
|
||
(void)memset(s_pend_active, 0, sizeof(s_pend_active));
|
||
(void)memset(s_pend_buf, 0, sizeof(s_pend_buf));
|
||
(void)memset(s_pend_len, 0, sizeof(s_pend_len));
|
||
(void)memset(s_pend_caller, 0, sizeof(s_pend_caller));
|
||
(void)memset(s_snd_active, 0, sizeof(s_snd_active));
|
||
(void)memset(s_snd_caller, 0, sizeof(s_snd_caller));
|
||
(void)memset(s_pend_done_armed, 0, sizeof(s_pend_done_armed));
|
||
(void)memset(s_pend_done_val, 0, sizeof(s_pend_done_val));
|
||
(void)memset(s_snd_done_armed, 0, sizeof(s_snd_done_armed));
|
||
(void)memset(s_snd_done_val, 0, sizeof(s_snd_done_val));
|
||
g_peers.pend_register_rc = NET_PENDING_REGISTERED;
|
||
g_peers.send_register_rc = NET_PENDING_REGISTERED;
|
||
}
|
||
|
||
void ns_peers_arm_pending_done(int sockfd, int result)
|
||
{
|
||
if ((sockfd >= 0) && (sockfd < NET_MAX_SOCKETS)) {
|
||
s_pend_done_armed[sockfd] = 1;
|
||
s_pend_done_val[sockfd] = result;
|
||
}
|
||
}
|
||
|
||
void ns_peers_arm_send_pending_done(int sockfd, int result)
|
||
{
|
||
if ((sockfd >= 0) && (sockfd < NET_MAX_SOCKETS)) {
|
||
s_snd_done_armed[sockfd] = 1;
|
||
s_snd_done_val[sockfd] = result;
|
||
}
|
||
}
|
||
|
||
/* ================= net_listener.h ================= */
|
||
|
||
void net_listener_request(int sockfd, net_listener_req_t reason)
|
||
{
|
||
g_peers.listener_req_calls++;
|
||
g_peers.last_req_fd = sockfd;
|
||
g_peers.last_req_reason = (int)reason;
|
||
if ((sockfd >= 0) && (sockfd < NET_MAX_SOCKETS)) {
|
||
g_peers.req_armed[sockfd] = 1;
|
||
g_peers.req_reason[sockfd] = (int)reason;
|
||
}
|
||
}
|
||
|
||
void net_listener_clear(int sockfd)
|
||
{
|
||
g_peers.listener_clear_calls++;
|
||
g_peers.last_clear_fd = sockfd;
|
||
if ((sockfd >= 0) && (sockfd < NET_MAX_SOCKETS)) {
|
||
g_peers.req_armed[sockfd] = 0;
|
||
}
|
||
}
|
||
|
||
void net_listener_tick(void)
|
||
{
|
||
g_peers.listener_tick_calls++;
|
||
}
|
||
|
||
void net_listener_settle(int sockfd, net_listener_settle_t level)
|
||
{
|
||
g_peers.listener_settle_calls++;
|
||
g_peers.last_settle_fd = sockfd;
|
||
g_peers.last_settle_level = (int)level;
|
||
}
|
||
|
||
/* ================= net_pending.h(recv 侧) ================= */
|
||
|
||
void net_pending_capture_owner(void)
|
||
{
|
||
g_peers.pending_capture_calls++;
|
||
}
|
||
|
||
int net_pending_register(int sockfd, void *buf, int len, uint32_t to_ms,
|
||
TaskHandle_t caller)
|
||
{
|
||
g_peers.pending_reg_calls++;
|
||
g_peers.last_pend_fd = sockfd;
|
||
g_peers.last_pend_to = to_ms;
|
||
g_peers.last_pend_caller = caller;
|
||
if (g_peers.pend_register_rc != NET_PENDING_REGISTERED) {
|
||
return g_peers.pend_register_rc; /* 测"登记被拒"分支 */
|
||
}
|
||
if ((sockfd >= 0) && (sockfd < NET_MAX_SOCKETS)) {
|
||
s_pend_active[sockfd] = 1;
|
||
s_pend_buf[sockfd] = buf;
|
||
s_pend_len[sockfd] = len;
|
||
s_pend_caller[sockfd] = caller;
|
||
g_peers.pend_active_now[sockfd] = 1;
|
||
}
|
||
return NET_PENDING_REGISTERED;
|
||
}
|
||
|
||
void net_pending_tick(net_sock_t *p_socks)
|
||
{
|
||
int i;
|
||
|
||
g_peers.pending_tick_calls++;
|
||
(void)p_socks;
|
||
/* 复刻真实 tick 的主用例:数据到达 → 按登记时的 caller 通知 → 清槽 */
|
||
for (i = 0; i < NET_MAX_SOCKETS; i++) {
|
||
if ((s_pend_active[i] != 0) && (s_pend_done_armed[i] != 0)) {
|
||
s_pend_done_armed[i] = 0;
|
||
s_pend_active[i] = 0;
|
||
g_peers.pend_active_now[i] = 0;
|
||
g_peers.pending_notified++;
|
||
ns_peers_note_notify(s_pend_caller[i], (uint32_t)s_pend_done_val[i]);
|
||
}
|
||
}
|
||
}
|
||
|
||
void net_pending_clear(int sockfd)
|
||
{
|
||
g_peers.pending_clear_calls++;
|
||
g_peers.last_pend_clear_fd = sockfd;
|
||
if ((sockfd >= 0) && (sockfd < NET_MAX_SOCKETS)) {
|
||
s_pend_active[sockfd] = 0;
|
||
g_peers.pend_active_now[sockfd] = 0;
|
||
}
|
||
}
|
||
|
||
void net_pending_cancel(int sockfd, int err)
|
||
{
|
||
g_peers.pending_cancel_calls++;
|
||
g_peers.last_pend_cancel_err = err;
|
||
if ((sockfd >= 0) && (sockfd < NET_MAX_SOCKETS)) {
|
||
s_pend_active[sockfd] = 0;
|
||
g_peers.pend_active_now[sockfd] = 0;
|
||
}
|
||
}
|
||
|
||
void net_pending_cancel_all(int err)
|
||
{
|
||
int i;
|
||
|
||
g_peers.pending_cancel_all_calls++;
|
||
g_peers.last_pend_cancel_err = err;
|
||
for (i = 0; i < NET_MAX_SOCKETS; i++) {
|
||
if (s_pend_active[i] != 0) {
|
||
g_peers.pending_notified++;
|
||
ns_peers_note_notify(s_pend_caller[i], (uint32_t)err);
|
||
}
|
||
s_pend_active[i] = 0;
|
||
g_peers.pend_active_now[i] = 0;
|
||
}
|
||
}
|
||
|
||
void net_pending_settle_close(int sockfd, net_sock_t *p_sock)
|
||
{
|
||
g_peers.pending_settle_calls++;
|
||
g_peers.last_pend_fd = sockfd;
|
||
(void)p_sock;
|
||
if ((sockfd >= 0) && (sockfd < NET_MAX_SOCKETS) && (s_pend_active[sockfd] != 0)) {
|
||
/* 真实实现:有数据先送达,无数据按 CONNRESET 取消——两者都**必通知** */
|
||
s_pend_active[sockfd] = 0;
|
||
g_peers.pend_active_now[sockfd] = 0;
|
||
g_peers.pending_notified++;
|
||
ns_peers_note_notify(s_pend_caller[sockfd], (uint32_t)NET_ERR_CONNRESET);
|
||
}
|
||
}
|
||
|
||
int net_pending_active(int sockfd)
|
||
{
|
||
if ((sockfd < 0) || (sockfd >= NET_MAX_SOCKETS)) {
|
||
return 0;
|
||
}
|
||
return s_pend_active[sockfd];
|
||
}
|
||
|
||
/* ================= net_pending.h(send 侧) ================= */
|
||
|
||
int net_send_pending_register(int sockfd, const void *buf, int len, int sent,
|
||
TaskHandle_t caller)
|
||
{
|
||
g_peers.send_reg_calls++;
|
||
g_peers.last_snd_fd = sockfd;
|
||
g_peers.last_snd_sent = sent;
|
||
g_peers.last_snd_len = len;
|
||
(void)buf;
|
||
if (g_peers.send_register_rc != NET_PENDING_REGISTERED) {
|
||
return g_peers.send_register_rc;
|
||
}
|
||
/* 真实实现的硬前置:sent >= len 视为参数非法拒收(末块边界) */
|
||
if (sent >= len) {
|
||
return -1;
|
||
}
|
||
if ((sockfd >= 0) && (sockfd < NET_MAX_SOCKETS)) {
|
||
s_snd_active[sockfd] = 1;
|
||
s_snd_caller[sockfd] = caller;
|
||
}
|
||
return NET_PENDING_REGISTERED;
|
||
}
|
||
|
||
void net_send_pending_tick(net_sock_t *p_socks)
|
||
{
|
||
int i;
|
||
|
||
g_peers.send_tick_calls++;
|
||
(void)p_socks;
|
||
for (i = 0; i < NET_MAX_SOCKETS; i++) {
|
||
if ((s_snd_active[i] != 0) && (s_snd_done_armed[i] != 0)) {
|
||
s_snd_done_armed[i] = 0;
|
||
s_snd_active[i] = 0;
|
||
g_peers.send_notified++;
|
||
ns_peers_note_notify(s_snd_caller[i], (uint32_t)s_snd_done_val[i]);
|
||
}
|
||
}
|
||
}
|
||
|
||
void net_send_pending_clear(int sockfd)
|
||
{
|
||
g_peers.send_clear_calls++;
|
||
if ((sockfd >= 0) && (sockfd < NET_MAX_SOCKETS)) {
|
||
s_snd_active[sockfd] = 0;
|
||
}
|
||
}
|
||
|
||
void net_send_pending_cancel(int sockfd, int err)
|
||
{
|
||
g_peers.send_cancel_calls++;
|
||
g_peers.last_snd_cancel_err = err;
|
||
if ((sockfd >= 0) && (sockfd < NET_MAX_SOCKETS) && (s_snd_active[sockfd] != 0)) {
|
||
s_snd_active[sockfd] = 0;
|
||
g_peers.send_notified++;
|
||
ns_peers_note_notify(s_snd_caller[sockfd], (uint32_t)err);
|
||
}
|
||
}
|
||
|
||
void net_send_pending_cancel_all(int err)
|
||
{
|
||
int i;
|
||
|
||
g_peers.send_cancel_all_calls++;
|
||
g_peers.last_snd_cancel_err = err;
|
||
for (i = 0; i < NET_MAX_SOCKETS; i++) {
|
||
if (s_snd_active[i] != 0) {
|
||
g_peers.send_notified++;
|
||
ns_peers_note_notify(s_snd_caller[i], (uint32_t)err);
|
||
}
|
||
s_snd_active[i] = 0;
|
||
}
|
||
}
|
||
|
||
int net_send_pending_active(int sockfd)
|
||
{
|
||
if ((sockfd < 0) || (sockfd >= NET_MAX_SOCKETS)) {
|
||
return 0;
|
||
}
|
||
return s_snd_active[sockfd];
|
||
}
|
||
|
||
/* ================= net_events.h(事件面与对账) ================= */
|
||
|
||
/* 事件处理桩:按真实头注释的效果改控制块(CONNECT→ESTABLISHED + 记对端等),
|
||
* 让 net_poll 的"中断 → 状态机"分派可断言;同时计数。 */
|
||
void handle_connect_event(net_sock_t *p_sock)
|
||
{
|
||
g_peers.evt_connect_calls++;
|
||
if (p_sock != NULL) {
|
||
p_sock->state = NET_SOCK_STATE_ESTABLISHED;
|
||
p_sock->readable = 0U;
|
||
p_sock->released_abnormal = 0U;
|
||
p_sock->session_dead = 0U;
|
||
}
|
||
}
|
||
|
||
void handle_disconnect_event(net_sock_t *p_sock)
|
||
{
|
||
g_peers.evt_disconnect_calls++;
|
||
if (p_sock != NULL) {
|
||
p_sock->last_peer_port = p_sock->remote_port;
|
||
p_sock->state = NET_SOCK_STATE_CLOSED;
|
||
p_sock->session_dead = 1U;
|
||
}
|
||
}
|
||
|
||
void handle_recv_event(net_sock_t *p_sock)
|
||
{
|
||
g_peers.evt_recv_calls++;
|
||
if (p_sock != NULL) {
|
||
p_sock->readable = 1U;
|
||
}
|
||
}
|
||
|
||
void handle_send_event(net_sock_t *p_sock)
|
||
{
|
||
g_peers.evt_send_calls++;
|
||
if (p_sock != NULL) {
|
||
p_sock->send_ready = 1U;
|
||
}
|
||
}
|
||
|
||
void handle_timeout_event(net_sock_t *p_sock)
|
||
{
|
||
g_peers.evt_timeout_calls++;
|
||
if (p_sock != NULL) {
|
||
p_sock->last_peer_port = p_sock->remote_port;
|
||
p_sock->state = NET_SOCK_STATE_CLOSED;
|
||
p_sock->released_abnormal = 1U;
|
||
p_sock->session_dead = 1U;
|
||
}
|
||
}
|
||
|
||
void net_reconcile_tick(void)
|
||
{
|
||
g_peers.reconcile_calls++;
|
||
}
|
||
|
||
void net_lost_connect_probe(net_sock_t *p_sock)
|
||
{
|
||
g_peers.lost_probe_calls++;
|
||
g_peers.last_probe_state = (p_sock != NULL) ? (int)p_sock->state : -1;
|
||
if ((p_sock != NULL) && (g_peers.lost_probe_hit != 0)) {
|
||
/* 脚本:探针命中 → 直接转 ESTABLISHED(复刻补 accept 的净效果) */
|
||
p_sock->state = NET_SOCK_STATE_ESTABLISHED;
|
||
p_sock->lost_conn_seen = 0U;
|
||
}
|
||
}
|