bda7ab2b50
批 2(用户授权改名 + 「新名要一眼看懂」裁定)
- 16 个有歧义模块码单词化,共 1,146 处随 scripts/rename_ids.py 改写:
AI→ADCIN、AH→ADCHEALTH、PS→PROTSET、PE→PROTELEM、PH→PHASOR、
TS→TIMESYNC、VL→VOLLOCK、NP→NANDPORT、CFG→CONFIG、CLK→SYSCLK、
WD→WATCHDOG、STO→STORAGE、SH→SHA256、FA→FTPAUTH、FR→FREQ、104→IEC104
- 不动 NET/GD5F/RTC/SOE/UI/ADC/LOG/RS485/TOOL(已是单词、芯片名或业界通用词,
改了纯属 churn)
- 别名按全局登记:这批字面量已完全限定(TC-<码>-<nnn>),不存在裸形多义
- 映射表存档 scripts/rename_maps/batch2.json 作审计轨迹;§6 模块码表同步
连带修门禁(关键教训)
- 模块码涨到 9 位(ADCHEALTH/WATCHDOG)后,候选正则与族正则的 {0,4} 上界
会让改名后的号**整批从门禁眼里消失**:实测编号字面量从 8271 掉到 7315、
悬空假降 490 处。已放宽到 {0,9} 并写进 §6 注记
- 结论:改名批次必须连带复核识别面,只改数据不改判据 = 静默放行;
这次是靠「可判定比例跌破基线即失败」那条线拦下来的
现状与遗留
- 校验 1 未登记前缀 0 处;可判定比例 82.71%(基线 82.6%,只涨不跌成立)
- 遗留:7 个模块的「单元测试说明.md」仍缺(PROTSET 116、NANDPORT 109、
PROTELEM 65、FREQ 48、FTPAUTH 45、SHA256 25、SOE 14 处悬空)——改名不解决
缺文档,处置方式待议
- 遗留:T-2/T-3/T-4/T-6 历史任务号悬空(别名表未收全,属本工具批次漏项)
- 未改任何 C/H 可编译语义(仅注释与宏名内的编号),故不需 @build
342 lines
17 KiB
C
342 lines
17 KiB
C
/*
|
||
* 模块名称:保护定值模型(P1)主机侧单元测试
|
||
* 模块功能:在 PC 上对 App/algo/prot_set.c 做离线验证。
|
||
*
|
||
* 被测对象:真实源文件(#include 原样纳入)。纯逻辑,无需桩。
|
||
*
|
||
* 覆盖点(docs/算法/继电保护功能复现规划.md §5.2 / §3.4 L5-1):
|
||
* TC-PROTSET-001 init:默认值装载、越界位图 0、selfcheck 通过、未闭锁
|
||
* TC-PROTSET-002 set:范围内写入生效;越界拒写且原值不动
|
||
* TC-PROTSET-003 校验和封存语义:set 后未 seal → selfcheck 失败并闭锁;
|
||
* seal → 通过并解锁(L5-1 核心闭环)
|
||
* TC-PROTSET-004 load_raw:合法整表装载并封存;含越界项 → 整表不装载 +
|
||
* bad_mask 指认越界项(定值一致性:宁可全旧不可半新)
|
||
* TC-PROTSET-005 Q10 往返精度(±1 LSB)
|
||
* TC-PROTSET-006 元数据表自检:min<=max、投退项 0..1、非零通讯地址不重复
|
||
* TC-PROTSET-007 越界编号守卫(get/set)
|
||
* TC-PROTSET-008 全局软压板 PS_GLOBAL_EN(B7):默认投入、set_sealed 原子写
|
||
* 不破坏 selfcheck、脏标志三件套(peek/take/mark)
|
||
* TC-PROTSET-009 持久化 blob 往返:serialize → init 清场 → parse 恢复
|
||
* (位精确 + 封存自洽 + parse 不置脏)
|
||
* TC-PROTSET-010 损坏 blob 整表拒绝(all-or-nothing):值区位翻转/坏 magic/
|
||
* 截断/超长/坏版本/伪造自洽越界 → 全部拒绝且活跃值区一字不动
|
||
* TC-PROTSET-011 OF/UF 定值行(B8):40 项 / blob 版本 2 / 本地项地址 0 /
|
||
* 默认值与范围 / 返回系数独立性 / 64 位 bad_mask(bit 39)/
|
||
* B7 旧档(32 项)换代拒绝
|
||
*
|
||
* 通过:全部 TC PASS(main 返回 0)。
|
||
* 创建日期:2026-10-11;2026-10-12 扩 OF/UF(B8)
|
||
*/
|
||
#include <stdint.h>
|
||
#include <stdio.h>
|
||
|
||
static int s_total = 0, s_passed = 0, s_failed = 0;
|
||
|
||
#define CHECK(cond, name) do { \
|
||
s_total++; \
|
||
if (cond) { s_passed++; printf(" [PASS] %s\n", name); } \
|
||
else { s_failed++; printf(" [FAIL] %s (line %d)\n", name, __LINE__); } \
|
||
} while (0)
|
||
|
||
#include "prot_set.c"
|
||
|
||
/* TC-PROTSET-001 */
|
||
static void tc_init(void) {
|
||
prot_set_init();
|
||
CHECK(prot_set_bad_mask() == 0u, "TC-PROTSET-001 init: no bad items");
|
||
CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-001 init: selfcheck pass");
|
||
CHECK(prot_set_locked() == 0u, "TC-PROTSET-001 init: not locked");
|
||
CHECK(prot_set_get_f(PS_OC1_CUR) > 9.99f && prot_set_get_f(PS_OC1_CUR) < 10.01f,
|
||
"TC-PROTSET-001 default OC1 current = 10.0 A");
|
||
CHECK(prot_set_get_ctl(PS_OC3_TRIP) == 0u,
|
||
"TC-PROTSET-001 default OC3 = alarm (trip off)");
|
||
}
|
||
|
||
/* TC-PROTSET-002 */
|
||
static void tc_set_range(void) {
|
||
prot_set_init();
|
||
CHECK(prot_set_set(PS_OC2_CUR, PROT_SET_Q10(7.5)) == 0,
|
||
"TC-PROTSET-002 in-range set accepted");
|
||
CHECK(prot_set_get_f(PS_OC2_CUR) > 7.49f && prot_set_get_f(PS_OC2_CUR) < 7.51f,
|
||
"TC-PROTSET-002 value readable after set");
|
||
CHECK(prot_set_set(PS_OC2_CUR, PROT_SET_Q10(101.0)) == -1,
|
||
"TC-PROTSET-002 over-max set rejected");
|
||
CHECK(prot_set_get_f(PS_OC2_CUR) > 7.49f && prot_set_get_f(PS_OC2_CUR) < 7.51f,
|
||
"TC-PROTSET-002 rejected set leaves value unchanged");
|
||
CHECK(prot_set_set(PS_OC1_EN, PROT_SET_Q10(2)) == -1,
|
||
"TC-PROTSET-002 ctl item rejects value 2");
|
||
}
|
||
|
||
/* TC-PROTSET-003 */
|
||
static void tc_seal_selfcheck(void) {
|
||
prot_set_init();
|
||
CHECK(prot_set_set(PS_OC1_CUR, PROT_SET_Q10(8.0)) == 0, "TC-PROTSET-003 set ok");
|
||
CHECK(prot_set_selfcheck() == -1,
|
||
"TC-PROTSET-003 set-without-seal => selfcheck FAIL (tamper detect)");
|
||
CHECK(prot_set_locked() == 1u, "TC-PROTSET-003 selfcheck failure latches lock");
|
||
prot_set_seal();
|
||
CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-003 seal => selfcheck pass");
|
||
CHECK(prot_set_locked() == 0u, "TC-PROTSET-003 seal clears lock");
|
||
}
|
||
|
||
/* TC-PROTSET-004 */
|
||
static void tc_load_raw(void) {
|
||
int32_t tbl[PS_ID_COUNT];
|
||
uint32_t i;
|
||
|
||
prot_set_init();
|
||
for (i = 0u; i < (uint32_t)PS_ID_COUNT; i++) {
|
||
tbl[i] = prot_set_get((prot_set_id_t)i);
|
||
}
|
||
tbl[PS_OL_CUR] = PROT_SET_Q10(1.5);
|
||
CHECK(prot_set_load_raw(tbl) == 0, "TC-PROTSET-004 valid table loads");
|
||
CHECK(prot_set_get_f(PS_OL_CUR) > 1.49f && prot_set_get_f(PS_OL_CUR) < 1.51f,
|
||
"TC-PROTSET-004 loaded value visible");
|
||
CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-004 load_raw auto-seals");
|
||
|
||
tbl[PS_OC3_DLY] = PROT_SET_Q10(60001.0); /* 越上限 */
|
||
tbl[PS_OL_CUR] = PROT_SET_Q10(2.5); /* 合法改动 */
|
||
CHECK(prot_set_load_raw(tbl) == -1, "TC-PROTSET-004 bad table rejected");
|
||
CHECK(prot_set_bad_mask() == (1uLL << PS_OC3_DLY),
|
||
"TC-PROTSET-004 bad_mask points at the offending item");
|
||
CHECK(prot_set_get_f(PS_OL_CUR) > 1.49f && prot_set_get_f(PS_OL_CUR) < 1.51f,
|
||
"TC-PROTSET-004 rejected load keeps OLD table (all-or-nothing)");
|
||
CHECK(prot_set_load_raw(0) == -1, "TC-PROTSET-004 NULL table rejected");
|
||
}
|
||
|
||
/* TC-PROTSET-005 */
|
||
static void tc_q10_roundtrip(void) {
|
||
float v = 12.345f;
|
||
int32_t q;
|
||
|
||
prot_set_init();
|
||
q = PROT_SET_Q10(v);
|
||
CHECK(prot_set_set(PS_OC1_CUR, q) == 0, "TC-PROTSET-005 set ok");
|
||
{
|
||
float back = prot_set_get_f(PS_OC1_CUR);
|
||
float err = back - v;
|
||
if (err < 0.0f) { err = -err; }
|
||
CHECK(err < 0.001f, "TC-PROTSET-005 Q10 roundtrip error < 1 LSB");
|
||
}
|
||
}
|
||
|
||
/* TC-PROTSET-006 */
|
||
static void tc_meta_sanity(void) {
|
||
uint32_t i, j;
|
||
int ok_range = 1, ok_ctl = 1, ok_addr = 1;
|
||
|
||
for (i = 0u; i < (uint32_t)PS_ID_COUNT; i++) {
|
||
const prot_set_meta_t *m = &g_prot_set_meta[i];
|
||
if (m->min > m->max) { ok_range = 0; }
|
||
if ((m->def < m->min) || (m->def > m->max)) { ok_range = 0; }
|
||
if ((m->is_ctl != 0u) &&
|
||
((m->min != 0) || (m->max != PROT_SET_Q10(1)))) { ok_ctl = 0; }
|
||
if (m->comm_addr == 0u) { continue; }
|
||
for (j = i + 1u; j < (uint32_t)PS_ID_COUNT; j++) {
|
||
if (g_prot_set_meta[j].comm_addr == m->comm_addr) { ok_addr = 0; }
|
||
}
|
||
}
|
||
CHECK(ok_range, "TC-PROTSET-006 meta: min<=def<=max for all items");
|
||
CHECK(ok_ctl, "TC-PROTSET-006 meta: ctl items are 0..1");
|
||
CHECK(ok_addr, "TC-PROTSET-006 meta: comm addresses unique");
|
||
CHECK((uint32_t)PS_ID_COUNT <= 64u, "TC-PROTSET-006 item count fits 64-bit bad_mask (B8: 40)");
|
||
}
|
||
|
||
/* TC-PROTSET-007 */
|
||
static void tc_id_guard(void) {
|
||
prot_set_init();
|
||
CHECK(prot_set_get(PS_ID_COUNT) == 0, "TC-PROTSET-007 get out-of-range id -> 0");
|
||
CHECK(prot_set_set(PS_ID_COUNT, 0) == -1, "TC-PROTSET-007 set out-of-range id -> -1");
|
||
CHECK(prot_set_set_sealed(PS_ID_COUNT, 0) == -1, "TC-PROTSET-007 set_sealed id guard");
|
||
}
|
||
|
||
/* TC-PROTSET-008(B7:全局软压板 + 原子写 + 脏标志) */
|
||
static void tc_global_plate_dirty(void) {
|
||
prot_set_init();
|
||
CHECK(prot_set_dirty_peek() == 0u, "TC-PROTSET-008 init not dirty");
|
||
CHECK(prot_set_get_ctl(PS_GLOBAL_EN) == 1u, "TC-PROTSET-008 global plate default IN");
|
||
CHECK(prot_set_set(PS_GLOBAL_EN, PROT_SET_Q10(2)) == -1, "TC-PROTSET-008 plate rejects 2");
|
||
CHECK(prot_set_set_sealed(PS_GLOBAL_EN, 0) == 0, "TC-PROTSET-008 plate OUT via set_sealed");
|
||
CHECK(prot_set_get_ctl(PS_GLOBAL_EN) == 0u, "TC-PROTSET-008 plate OUT readable");
|
||
CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-008 set_sealed leaves selfcheck PASS (no unsealed window)");
|
||
CHECK(prot_set_locked() == 0u, "TC-PROTSET-008 set_sealed no lock");
|
||
CHECK(prot_set_dirty_peek() == 1u, "TC-PROTSET-008 set_sealed marks dirty");
|
||
CHECK(prot_set_dirty_take() == 1u, "TC-PROTSET-008 dirty take consumes");
|
||
CHECK(prot_set_dirty_peek() == 0u, "TC-PROTSET-008 dirty cleared after take");
|
||
prot_set_dirty_mark();
|
||
CHECK(prot_set_dirty_peek() == 1u, "TC-PROTSET-008 dirty mark re-arms (write-fail retry)");
|
||
CHECK(prot_set_set_sealed(PS_GLOBAL_EN, PROT_SET_Q10(2)) == -1, "TC-PROTSET-008 set_sealed range check");
|
||
CHECK(prot_set_get_ctl(PS_GLOBAL_EN) == 0u, "TC-PROTSET-008 rejected set_sealed keeps value");
|
||
}
|
||
|
||
/* TC-PROTSET-009(B7:blob 往返) */
|
||
static void tc_store_roundtrip(void) {
|
||
uint8_t blob[PROT_SET_BLOB_SZ];
|
||
uint32_t len = 0u;
|
||
int32_t cur;
|
||
|
||
prot_set_init();
|
||
(void)prot_set_set_sealed(PS_OC1_CUR, PROT_SET_Q10(12.5));
|
||
(void)prot_set_set_sealed(PS_GLOBAL_EN, 0);
|
||
(void)prot_set_dirty_take();
|
||
cur = prot_set_get(PS_OC1_CUR);
|
||
CHECK(prot_set_store_serialize(blob, sizeof(blob), &len) == 0, "TC-PROTSET-009 serialize ok");
|
||
CHECK(len == (uint32_t)PROT_SET_BLOB_SZ, "TC-PROTSET-009 blob exact size");
|
||
prot_set_init();
|
||
CHECK(prot_set_get(PS_OC1_CUR) != cur, "TC-PROTSET-009 init wiped to defaults");
|
||
CHECK(prot_set_store_parse(blob, len) == 0, "TC-PROTSET-009 parse ok");
|
||
CHECK(prot_set_get(PS_OC1_CUR) == cur, "TC-PROTSET-009 value round-trip bit-exact");
|
||
CHECK(prot_set_get_ctl(PS_GLOBAL_EN) == 0u, "TC-PROTSET-009 plate state round-trip");
|
||
CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-009 parsed table sealed");
|
||
CHECK(prot_set_dirty_peek() == 0u, "TC-PROTSET-009 parse does not mark dirty");
|
||
}
|
||
|
||
/* 伪造辅助:按 blob 值区重算尾部 sum/sumn(构造"自洽但越界"的对抗样本) */
|
||
static void s_forge_tail(uint8_t *b, uint32_t len) {
|
||
uint32_t sum = 0u;
|
||
uint32_t inv;
|
||
uint32_t i;
|
||
|
||
for (i = 0u; i < (uint32_t)PS_ID_COUNT; i++) {
|
||
sum += s_get32(b + PROT_SET_BLOB_HDR_SZ + 4u * i);
|
||
}
|
||
inv = ~sum;
|
||
s_put32(b + len - 8u, sum);
|
||
s_put32(b + len - 4u, inv);
|
||
}
|
||
|
||
/* TC-PROTSET-010(B7:损坏 blob 整表拒绝,all-or-nothing) */
|
||
static void tc_store_corrupt(void) {
|
||
uint8_t blob[PROT_SET_BLOB_SZ];
|
||
uint32_t len = 0u;
|
||
int32_t keep;
|
||
|
||
prot_set_init();
|
||
(void)prot_set_set_sealed(PS_OC2_CUR, PROT_SET_Q10(6.0));
|
||
keep = prot_set_get(PS_OC2_CUR);
|
||
CHECK(prot_set_store_serialize(blob, sizeof(blob), &len) == 0, "TC-PROTSET-010 serialize ok");
|
||
|
||
blob[PROT_SET_BLOB_HDR_SZ] ^= 0x01u; /* 值区一位翻转:sum 对不符 */
|
||
CHECK(prot_set_store_parse(blob, len) == -1, "TC-PROTSET-010 flipped value byte rejected (sum pair)");
|
||
CHECK(prot_set_get(PS_OC2_CUR) == keep, "TC-PROTSET-010 reject leaves values untouched");
|
||
|
||
(void)prot_set_store_serialize(blob, sizeof(blob), &len);
|
||
blob[0] ^= 0xFFu; /* magic 破坏 */
|
||
CHECK(prot_set_store_parse(blob, len) == -1, "TC-PROTSET-010 bad magic rejected");
|
||
|
||
(void)prot_set_store_serialize(blob, sizeof(blob), &len);
|
||
CHECK(prot_set_store_parse(blob, len - 4u) == -1, "TC-PROTSET-010 truncated blob rejected");
|
||
CHECK(prot_set_store_parse(blob, len + 4u) == -1, "TC-PROTSET-010 oversized blob rejected");
|
||
|
||
(void)prot_set_store_serialize(blob, sizeof(blob), &len);
|
||
blob[5] ^= 0x02u; /* version 高字节:1 -> 0x200 */
|
||
CHECK(prot_set_store_parse(blob, len) == -1, "TC-PROTSET-010 version mismatch rejected");
|
||
|
||
/* 对抗样本:越限定值 + 重算 sum 对(校验全过、范围必拦) */
|
||
(void)prot_set_store_serialize(blob, sizeof(blob), &len);
|
||
s_put32(blob + PROT_SET_BLOB_HDR_SZ + 4u * (uint32_t)PS_OC1_CUR,
|
||
(uint32_t)(g_prot_set_meta[PS_OC1_CUR].max + 1));
|
||
s_forge_tail(blob, len);
|
||
CHECK(prot_set_store_parse(blob, len) == -1, "TC-PROTSET-010 forged consistent out-of-range rejected");
|
||
CHECK(prot_set_bad_mask() == (1uLL << PS_OC1_CUR), "TC-PROTSET-010 bad_mask points at item");
|
||
CHECK(prot_set_get(PS_OC1_CUR) == PROT_SET_Q10(10.0), "TC-PROTSET-010 defaults still intact");
|
||
CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-010 active table still self-consistent after all rejects");
|
||
}
|
||
|
||
/* TC-PROTSET-011(B8:OF/UF 定值行 + 40 项 + 64 位 bad_mask + 换代拒绝) */
|
||
static void tc_of_uf_meta(void) {
|
||
uint8_t blob[PROT_SET_BLOB_SZ];
|
||
uint32_t len = 0u;
|
||
|
||
prot_set_init();
|
||
|
||
/* 结构:40 项、blob 版本 2、尺寸随项数自适应 */
|
||
CHECK((uint32_t)PS_ID_COUNT == 40u, "TC-PROTSET-011 PS_ID_COUNT == 40 (32 + 8 OF/UF)");
|
||
CHECK(PROT_SET_BLOB_VER == 2u, "TC-PROTSET-011 blob version bumped to 2 (B8)");
|
||
CHECK((uint32_t)PROT_SET_BLOB_SZ == (PROT_SET_BLOB_HDR_SZ + 4u * 40u + 8u),
|
||
"TC-PROTSET-011 blob size = hdr + 4*40 + tail");
|
||
|
||
/* 地址:参考逐项地址不在本仓库 -> 8 项全部本地项(comm_addr=0,104 不可寻址) */
|
||
CHECK((g_prot_set_meta[PS_OF_EN].comm_addr == 0u)
|
||
&& (g_prot_set_meta[PS_OF_HZ].comm_addr == 0u)
|
||
&& (g_prot_set_meta[PS_OF_DLY].comm_addr == 0u)
|
||
&& (g_prot_set_meta[PS_UF_EN].comm_addr == 0u)
|
||
&& (g_prot_set_meta[PS_UF_HZ].comm_addr == 0u)
|
||
&& (g_prot_set_meta[PS_UF_DLY].comm_addr == 0u)
|
||
&& (g_prot_set_meta[PS_RET_OF].comm_addr == 0u)
|
||
&& (g_prot_set_meta[PS_RET_UF].comm_addr == 0u),
|
||
"TC-PROTSET-011 OF/UF items all local (comm_addr=0, pending reference table)");
|
||
|
||
/* 投退 = ctl 项(0/1),其余 = 模拟量 Q10 */
|
||
CHECK((g_prot_set_meta[PS_OF_EN].is_ctl == 1u) && (g_prot_set_meta[PS_UF_EN].is_ctl == 1u)
|
||
&& (g_prot_set_meta[PS_OF_HZ].is_ctl == 0u) && (g_prot_set_meta[PS_RET_UF].is_ctl == 0u),
|
||
"TC-PROTSET-011 EN items are ctl, HZ/DLY/RET are Q10 analog");
|
||
|
||
/* 出厂默认(拟定值)与范围 */
|
||
CHECK(prot_set_get(PS_OF_EN) == PROT_SET_Q10(1.0), "TC-PROTSET-011 OF EN default 1");
|
||
CHECK(prot_set_get(PS_UF_EN) == PROT_SET_Q10(1.0), "TC-PROTSET-011 UF EN default 1");
|
||
CHECK(prot_set_get(PS_OF_HZ) == PROT_SET_Q10(51.0), "TC-PROTSET-011 OF default 51.0 Hz");
|
||
CHECK(prot_set_get(PS_UF_HZ) == PROT_SET_Q10(49.0), "TC-PROTSET-011 UF default 49.0 Hz");
|
||
CHECK(prot_set_get(PS_OF_DLY) == PROT_SET_Q10(1000.0), "TC-PROTSET-011 OF default 1000 ms");
|
||
CHECK(prot_set_get(PS_UF_DLY) == PROT_SET_Q10(1000.0), "TC-PROTSET-011 UF default 1000 ms");
|
||
CHECK(prot_set_get(PS_RET_OF) == PROT_SET_Q10(0.99), "TC-PROTSET-011 RET_OF default 0.99");
|
||
CHECK(prot_set_get(PS_RET_UF) == PROT_SET_Q10(1.01), "TC-PROTSET-011 RET_UF default 1.01");
|
||
CHECK((g_prot_set_meta[PS_OF_HZ].min == PROT_SET_Q10(50.0))
|
||
&& (g_prot_set_meta[PS_OF_HZ].max == PROT_SET_Q10(55.0)),
|
||
"TC-PROTSET-011 OF range 50.0~55.0 Hz");
|
||
CHECK((g_prot_set_meta[PS_UF_HZ].min == PROT_SET_Q10(45.0))
|
||
&& (g_prot_set_meta[PS_UF_HZ].max == PROT_SET_Q10(50.0)),
|
||
"TC-PROTSET-011 UF range 45.0~50.0 Hz");
|
||
|
||
/* 频率返回系数与电气量系数独立:返回**门槛** = 定值×系数(Q10 乘积
|
||
* /1024)——OF 门槛 < 动作门槛、UF 门槛 > 动作门槛(方向相反) */
|
||
CHECK(((int64_t)prot_set_get(PS_OF_HZ) * (int64_t)prot_set_get(PS_RET_OF)) / 1024
|
||
< (int64_t)prot_set_get(PS_OF_HZ),
|
||
"TC-PROTSET-011 OF return threshold (set x 0.99) below pickup");
|
||
CHECK(((int64_t)prot_set_get(PS_UF_HZ) * (int64_t)prot_set_get(PS_RET_UF)) / 1024
|
||
> (int64_t)prot_set_get(PS_UF_HZ),
|
||
"TC-PROTSET-011 UF return threshold (set x 1.01) above pickup");
|
||
|
||
/* 投退可经 set_sealed 投/退(YK 口径同 GLOBAL_EN;Q10(2)=2048 越界拒) */
|
||
CHECK(prot_set_set_sealed(PS_OF_EN, 0) == 0, "TC-PROTSET-011 OF EN set_sealed OK");
|
||
CHECK(prot_set_get_ctl(PS_OF_EN) == 0u, "TC-PROTSET-011 OF EN readable after seal");
|
||
CHECK(prot_set_set_sealed(PS_OF_EN, PROT_SET_Q10(2)) == -1, "TC-PROTSET-011 OF EN rejects Q10(2)");
|
||
CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-011 no lock after OF/UF seal ops");
|
||
|
||
/* 64 位 bad_mask:末项(bit 39 > 31)越界可指认 */
|
||
(void)prot_set_set_sealed(PS_OC1_CUR, PROT_SET_Q10(11.0));
|
||
(void)prot_set_dirty_take();
|
||
CHECK(prot_set_store_serialize(blob, sizeof(blob), &len) == 0, "TC-PROTSET-011 serialize ok");
|
||
s_put32(blob + PROT_SET_BLOB_HDR_SZ + 4u * (uint32_t)PS_RET_UF,
|
||
(uint32_t)(g_prot_set_meta[PS_RET_UF].max + 1));
|
||
s_forge_tail(blob, len);
|
||
CHECK(prot_set_store_parse(blob, len) == -1, "TC-PROTSET-011 out-of-range RET_UF rejected");
|
||
CHECK(prot_set_bad_mask() == (1uLL << PS_RET_UF),
|
||
"TC-PROTSET-011 bad_mask bit 39 addressable (64-bit mask, B8)");
|
||
CHECK(prot_set_get(PS_RET_UF) == PROT_SET_Q10(1.01), "TC-PROTSET-011 default RET_UF intact");
|
||
|
||
/* 换代语义:B7 旧档(ver=1 / 32 项 = 144 B)在新固件必被拒 -> 出厂默认 */
|
||
CHECK(prot_set_store_parse(blob, 8u + 4u * 32u + 8u) == -1,
|
||
"TC-PROTSET-011 legacy 32-item blob length rejected");
|
||
CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-011 active table intact after legacy reject");
|
||
}
|
||
|
||
int main(void) {
|
||
printf("=== Prot Set Tests ===\n");
|
||
tc_init();
|
||
tc_set_range();
|
||
tc_seal_selfcheck();
|
||
tc_load_raw();
|
||
tc_q10_roundtrip();
|
||
tc_meta_sanity();
|
||
tc_id_guard();
|
||
tc_global_plate_dirty();
|
||
tc_store_roundtrip();
|
||
tc_store_corrupt();
|
||
tc_of_uf_meta();
|
||
|
||
printf("\n=== Prot Set Tests: %d/%d PASSED (failed=%d) ===\n",
|
||
s_passed, s_total, s_failed);
|
||
return (s_failed == 0) ? 0 : 1;
|
||
}
|