#!/usr/bin/env python3 # -*- coding: utf-8 -*- """dhara NAND 移植层(nand_ftl)的主机侧纯逻辑单元测试运行器(纯标准库)。 做什么: 用本机 MSVC 编译 test/host/nand_port/nand_port_test.c(它以 #include 纳入 **生产源文件** Drivers/BSP/GD5F2GQ5UE/nand_ftl.c),在 PC 上离线跑 dhara NAND HAL 六个入口(is_bad / mark_bad / erase / prog / is_free / read / copy)的 几何守卫与整页判空,失败即非 0 退出。零硬件、零烧录、毫秒级。 工具链探测 / INCLUDE-LIB 拼接 / 编译运行 / 退出码判定全部委托给通用 harness `test/host/common/unit_test_harness.py`(本文件只做声明)。 为什么要主机侧单测(而不是只用板端套件): 移植层是**纯地址算术 + 边界判定**,芯片侧只经 11 个 SPI 原语打交道——把它换成 一块 RAM 假芯片,整层就完全可在 PC 上跑。而它要防的两类缺陷恰恰是真机极难复现的: - is_free 只看页首 64 B → "页首 0xFF、后段有数据"的页被误判空闲 → dhara 往已编程页再编程 = 静默数据丢失(真机要恰好撞上那种页形态才发作); - 越界页/块号(含 DHARA_PAGE_NONE 哨兵)被地址位截断成真实页 → 静默读写/搬走无辜数据(真机上没有任何路径会主动喂进越界号)。 假芯片把"双编程"做成可数事件、并记录全部访问次数,于是"越界不产生任何芯片 访问""越界标坏块次数为 0"这类判据可机械断言——这是板端永远拿不到的观测面。 用法(仓库根目录): python test/host/nand_port/run_unit_test.py 或统一用 .venv: & '.venv\\Scripts\\python.exe' test/host/nand_port/run_unit_test.py 退出码:0=PASS / 1=测试失败 / 2=环境错误(找不到编译器 / 编译失败 / 无汇总行)。 设计依据:dhara 移植层两条硬约束(原评审报告 2026-10-25 已删除;其建议的 `test/host/dhara/` 移植层单测,落位为 test/host/nand_port/); 创建日期:2026-10-15 """ import os import sys HERE = os.path.dirname(os.path.abspath(__file__)) ROOT = os.path.dirname(os.path.dirname(os.path.dirname(HERE))) # harness 位于 test/host/common/ sys.path.insert(0, os.path.join(ROOT, "test", "host", "common")) from unit_test_harness import TestBuild, run_host_unit_test # noqa: E402 # 顺序敏感:stub 目录必须**先于**生产目录,才能覆盖 gd5f2gq5ue.h(真实头会拖入 # main.h + 整套 ST HAL/CMSIS,PC 上不可编译)与 dbg_log.h(真实头依赖 sys_clock)。 # nand.h / journal.h / map.h / error.h(Lib/dhara)与 ff.h / diskio.h / ffconf.h # (Lib/FatFs)用**真实头**——接口契约原汁,桩与真实 API 一旦漂移编译期即报错。 BUILD = TestBuild( name="NAND Port Tests", src=os.path.join(HERE, "nand_port_test.c"), include_dirs=[ os.path.join(HERE, "stub"), os.path.join(ROOT, "Drivers", "BSP"), # bsp_err.h(nand_ftl.c 依赖,2026-10-23) os.path.join(ROOT, "Drivers", "BSP", "GD5F2GQ5UE"), os.path.join(ROOT, "Lib", "dhara"), os.path.join(ROOT, "Lib", "FatFs"), HERE, ], summary_marker="=== NAND Port Tests:", ) if __name__ == "__main__": sys.exit(run_host_unit_test(BUILD))