test(断言三件): 未开格类型微光机检面(迭代 30 卡① T2-①②③)——①冒烟 smoke_all.gd 新增 _smoke_type_glow 八相 24 项(相0 作用集恒等+默认开+已开/r0 零微光/相1 八邻派八型五组逐格映射/相2 清单外"keystone"显式登记+零微光/相3 封锁格零微光零登记/相4 解封复位/相5 off/on 两态+关前快照逐位复现+零玩法写入三面/相6 换图 rebuild 重算/相7 契约 1 同板同序列 on/off 双实例结算逐位一致 12 步 digest 对照);夹具 = seed 4242 L1 板+novice 驱动(初始展开覆盖 8 邻故必驱动)+八邻派型+哈希兜底九型全集;冒烟 1127→1151 项。②单测 type_glow_test.gd 五段 51 检查(归组封闭含清单外 6 负样本+两带并存锚定/冻结色相面 HSV 稽核 ΔH≤0.2°·ΔS≤0.01+群伤 V=0.65 专项/呈现参数锚定 α170·band 0.125·组号域 0-5/伽马合成空间阶梯单调+相邻组模型 CR≥1.20/probe API 形状),登记 run_all.gd(33→34 套件);extends SceneTree+Kit/UiKitScript preload(--script 模式禁 class_name 裸引用)。③ui_input_probe case⑰ 活板面走查(生产身份面:作用集==diggable 键集/真实点击挖开即灭/移动复亮出圈灭/相位门控两态/开关两态零扰动),十八断言全绿。批末变异验证五组反例实证:M1 归组错映(单测+冒烟红)/M2 清单外静默(冒烟红)/M3 相位切换不重算(冒烟+探针红)/M4 α=0 不绘(渲染闸红)/M5 派生路径误触玩法 API(冒烟相7 分叉红)——红输出与还原结论实录见 reports/iter30-实现报告-2026-10-17.md §四。
This commit is contained in:
1 parent
bd44e658e8
commit
80ac80ef1a
5 files changed
+544
-1
No files matched your search
@@ -0,0 +1,173 @@
|
||||
# tests/unit/presentation/type_glow_test.gd — 未开格类型微光数据面直验(迭代 30 卡① T2-②)
|
||||
# 断言面 = 纯函数/常量域(无渲染):① 九 cell_type → 五组封闭判定(含清单外显式失败、
|
||||
# 禁子串匹配、与卡顶带 tg_band 的归组差异锚定——Q3 甲案两带并存);② 五组色值冻结面
|
||||
# (HSV 对照 art-bible §4.2 冻结值只准动明度档——2026-10-17 群伤组一案停机呈报后用户裁
|
||||
# #A61D37,本测试即该裁定的守门件);③ 呈现参数锚定(α170/带宽 cell÷8);④ 合成空间
|
||||
# 阶梯单调 + 相邻组模型 CR ≥1.20(色弱灰度互辨的数据面预判,终审在渲染取证探针实测);
|
||||
# ⑤ probe API 形状(默认开/空态键集)。
|
||||
# 运行:godot --headless --path game --script res://tests/unit/presentation/type_glow_test.gd
|
||||
extends SceneTree
|
||||
|
||||
const Kit := preload("res://tests/unit/test_kit.gd")
|
||||
# --script 模式无全局标识符(class_name 不可用)——使用方 preload
|
||||
const UiKitScript := preload("res://presentation/views/ui_kit.gd")
|
||||
const BoardViewScript := preload("res://presentation/views/board_view.gd")
|
||||
|
||||
# art-bible §4.2 样张 v2 冻结五组(F3 抄录表——本测试的冻结面基准)
|
||||
const FROZEN := {
|
||||
"BUFF": Color8(0xD6, 0xC1, 0x3A), "HEAL": Color8(0x5C, 0xB8, 0x3A),
|
||||
"PIERCE": Color8(0x2E, 0x9E, 0x9E), "MAGIC": Color8(0x7B, 0x5B, 0xD6),
|
||||
"AOE": Color8(0xFF, 0x2D, 0x55),
|
||||
}
|
||||
# 九 cell_type 全值域 → 期望组号(art-bible §4.2 成员集合逐字照抄)
|
||||
const TYPE_EXPECT := {
|
||||
"attack": UiKitScript.GLOW_BUFF, "defense": UiKitScript.GLOW_BUFF,
|
||||
"weaken": UiKitScript.GLOW_BUFF, "action": UiKitScript.GLOW_BUFF,
|
||||
"gp": UiKitScript.GLOW_BUFF, "heal": UiKitScript.GLOW_HEAL,
|
||||
"pierce": UiKitScript.GLOW_PIERCE, "blast": UiKitScript.GLOW_AOE,
|
||||
"magic": UiKitScript.GLOW_MAGIC,
|
||||
}
|
||||
# provisional 明度档终值(2026-10-17 用户裁后)——逐位锚定,谁改色值这里红
|
||||
const IMPL := {
|
||||
"BUFF": Color8(247, 223, 67), "HEAL": Color8(104, 208, 66),
|
||||
"PIERCE": Color8(48, 166, 166), "MAGIC": Color8(123, 91, 214),
|
||||
"AOE": Color8(166, 29, 55),
|
||||
}
|
||||
# 实现常量直引(禁 class get() 动态取——parse 层就不许)
|
||||
const IMPL_CONSTS := {
|
||||
"BUFF": UiKitScript.TG_GLOW_BUFF, "HEAL": UiKitScript.TG_GLOW_HEAL,
|
||||
"PIERCE": UiKitScript.TG_GLOW_PIERCE, "MAGIC": UiKitScript.TG_GLOW_MAGIC,
|
||||
"AOE": UiKitScript.TG_GLOW_AOE,
|
||||
}
|
||||
const CONST_NAME := {
|
||||
"BUFF": "TG_GLOW_BUFF", "HEAL": "TG_GLOW_HEAL", "PIERCE": "TG_GLOW_PIERCE",
|
||||
"MAGIC": "TG_GLOW_MAGIC", "AOE": "TG_GLOW_AOE",
|
||||
}
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
_test_grouping_closed()
|
||||
_test_frozen_hue_face()
|
||||
_test_render_params()
|
||||
_test_gamma_ladder()
|
||||
_test_probe_api_shape()
|
||||
quit(Kit.finish("type_glow_test"))
|
||||
|
||||
|
||||
# ① 归组封闭:九值全域映射+清单外显式失败+禁子串+两带差异锚定
|
||||
func _test_grouping_closed() -> void:
|
||||
for t in TYPE_EXPECT:
|
||||
var got: int = UiKitScript.glow_group_for_cell_type(t)
|
||||
Kit.check("九型封闭:%s → 组%d(期望组%d)" % [t, got, int(TYPE_EXPECT[t])], got == int(TYPE_EXPECT[t]))
|
||||
# 清单外值 = GLOW_NONE(调用方显式登记,禁静默空光;大宝箱未来第十型落数据时必须同步加归组,
|
||||
# 否则本通道报红——这是该纪律的机检防线)
|
||||
for bad in ["keystone", "", "ATTACK", "aoe", "blast_mine", " heal"]:
|
||||
Kit.check("清单外值「%s」→ GLOW_NONE(禁静默空光)" % bad,
|
||||
UiKitScript.glow_group_for_cell_type(bad) == UiKitScript.GLOW_NONE)
|
||||
# 与卡顶带 tg_band 的归组差异锚定(Q3 甲案两带并存、禁互引):blast 在格面带归群伤、
|
||||
# 在卡顶带归魔法(E5 回滚既存行为)——若将来误把两带统一,本断言红
|
||||
var band_blast: Color = UiKitScript.tg_band("blast_charge")
|
||||
Kit.check("两带并存锚定:卡顶带 blast→TG_MAGIC(E5 回滚既存行为未动)", band_blast == UiKitScript.TG_MAGIC)
|
||||
Kit.check("两带并存锚定:格面微光 blast→群伤组(与卡顶带刻意不同)",
|
||||
UiKitScript.glow_group_for_cell_type("blast") == UiKitScript.GLOW_AOE)
|
||||
# 色值出口:五组各取本组常量;无组/越界组号 → 全透明(不画)
|
||||
Kit.check("glow_color_for_group 群伤组 = TG_GLOW_AOE",
|
||||
UiKitScript.glow_color_for_group(UiKitScript.GLOW_AOE) == UiKitScript.TG_GLOW_AOE)
|
||||
Kit.check("glow_color_for_group 无组(GLOW_NONE)→ 全透明",
|
||||
UiKitScript.glow_color_for_group(UiKitScript.GLOW_NONE) == Color(0, 0, 0, 0))
|
||||
Kit.check("glow_color_for_group 越界组号 → 全透明",
|
||||
UiKitScript.glow_color_for_group(99) == Color(0, 0, 0, 0))
|
||||
|
||||
|
||||
# ② 冻结色相面:逐组 HSV 对照 art-bible §4.2 冻结值——只准动明度(ΔH≤0.2°/ΔS≤0.01)
|
||||
func _test_frozen_hue_face() -> void:
|
||||
for g in FROZEN:
|
||||
var f: Color = FROZEN[g]
|
||||
var m: Color = IMPL[g]
|
||||
var impl_const: Color = IMPL_CONSTS[g]
|
||||
Kit.check("实现值锚定:%s = #%02X%02X%02X(色值单点 ui_kit,逐位钉死)" % [CONST_NAME[g],
|
||||
int(m.r8), int(m.g8), int(m.b8)], impl_const == m)
|
||||
var dh: float = absf(m.h - f.h)
|
||||
dh = minf(dh, 1.0 - dh) # 色相环回绕
|
||||
var ds: float = absf(m.s - f.s)
|
||||
Kit.check("冻结色相保持:%s ΔH=%.3f° ≤0.2° 且 ΔS=%.4f ≤0.01(只动明度档)" % [g, dh * 360.0, ds],
|
||||
dh <= 0.2 / 360.0 and ds <= 0.01)
|
||||
# 群伤组专锚(2026-10-17 停机呈报→用户裁 #A61D37):H/S 与冻结逐位一致、V=0.65 档
|
||||
var aoe_f: Color = FROZEN["AOE"]
|
||||
var aoe_m: Color = UiKitScript.TG_GLOW_AOE
|
||||
Kit.check("群伤组专项:H 与冻结 #FF2D55 差 %.4f°(零移动)" % (absf(aoe_m.h - aoe_f.h) * 360.0),
|
||||
absf(aoe_m.h - aoe_f.h) < 0.001)
|
||||
Kit.check("群伤组专项:S 与冻结差 %.4f ≤0.01(8bit 量化噪声级)" % absf(aoe_m.s - aoe_f.s),
|
||||
absf(aoe_m.s - aoe_f.s) <= 0.01)
|
||||
Kit.check("群伤组专项:V=0.65 明度档( provisional 域内)", absf(aoe_m.v - 166.0 / 255.0) < 0.002)
|
||||
|
||||
|
||||
# ③ 呈现参数锚定(art-bible §4.2 v2 冻结参数)
|
||||
func _test_render_params() -> void:
|
||||
Kit.check("泛光强度 α = 170/255(v2 呈现参数冻结)",
|
||||
is_equal_approx(UiKitScript.TYPE_GLOW_ALPHA, 170.0 / 255.0))
|
||||
Kit.check("带宽 = cell÷8(TYPE_GLOW_BAND_FRAC=0.125)",
|
||||
is_equal_approx(UiKitScript.TYPE_GLOW_BAND_FRAC, 0.125))
|
||||
Kit.check("组号常量域连续(GLOW_NONE=0…GLOW_MAGIC=5)",
|
||||
UiKitScript.GLOW_NONE == 0 and UiKitScript.GLOW_BUFF == 1 and UiKitScript.GLOW_HEAL == 2
|
||||
and UiKitScript.GLOW_PIERCE == 3 and UiKitScript.GLOW_AOE == 4 and UiKitScript.GLOW_MAGIC == 5)
|
||||
|
||||
|
||||
# ④ 合成空间阶梯:模型域单调 + 相邻组 CR ≥1.20(色弱互辨数据面预判;终审=探针实测)
|
||||
func _test_gamma_ladder() -> void:
|
||||
# 合成模型(ui_kit 头注登记口径):带内均值 ≈ 0.49×色值 + 0.51×瓦片(BRICK 未开掩尘地砖)
|
||||
var k := 0.49
|
||||
var tile: Color = UiKitScript.BRICK
|
||||
var comp := func(c: Color) -> Color:
|
||||
return Color(k * c.r + (1.0 - k) * tile.r, k * c.g + (1.0 - k) * tile.g, k * c.b + (1.0 - k) * tile.b)
|
||||
var order := ["BUFF", "HEAL", "PIERCE", "MAGIC", "AOE"]
|
||||
var prev_lum := 2.0
|
||||
for g in order:
|
||||
var cc: Color = comp.call(IMPL[g])
|
||||
var lum: float = _rel_lum709(cc)
|
||||
Kit.check("阶梯单调:%s 合成亮度 %.4f < 上一档 %.4f(伽马合成空间)" % [g, lum, prev_lum], lum < prev_lum)
|
||||
prev_lum = lum
|
||||
for i in range(order.size() - 1):
|
||||
var a: Color = comp.call(IMPL[order[i]])
|
||||
var b: Color = comp.call(IMPL[order[i + 1]])
|
||||
var cr: float = _wcag_cr(a, b)
|
||||
Kit.check("相邻组模型 CR:%s/%s = %.3f ≥1.20(色弱互辨预判)" % [order[i], order[i + 1], cr], cr >= 1.20)
|
||||
# 首版排反的那一对专项:群伤线性亮度必须低于魔法(线性域序 = WCAG 判据域)
|
||||
var aoe_lin: float = _rel_lum_lin(comp.call(IMPL["AOE"]))
|
||||
var magic_lin: float = _rel_lum_lin(comp.call(IMPL["MAGIC"]))
|
||||
Kit.check("群伤/魔法线性亮度序:群伤 %.4f < 魔法 %.4f(首版 CIE L* 排反事故的守门)" % [aoe_lin, magic_lin],
|
||||
aoe_lin < magic_lin)
|
||||
|
||||
|
||||
# ⑤ probe API 形状:默认开+空态键集(无板直取——不依赖棋盘装配)
|
||||
func _test_probe_api_shape() -> void:
|
||||
var view = BoardViewScript.new()
|
||||
var snap: Dictionary = view.type_glow_probe()
|
||||
Kit.check("probe 键集 = {enabled, cells, errors}",
|
||||
snap.has("enabled") and snap.has("cells") and snap.has("errors") and snap.size() == 3)
|
||||
Kit.check("probe 默认态:enabled=true(Q4 丙案生产默认开)", bool(snap.get("enabled", false)))
|
||||
Kit.check("probe 默认态:作用集空(无板未派生)", (snap.get("cells", {}) as Dictionary).is_empty())
|
||||
Kit.check("probe 默认态:清单外登记空", (snap.get("errors", []) as Array).is_empty())
|
||||
view.set_type_glow_enabled(false)
|
||||
Kit.check("set_type_glow_enabled(false) → probe enabled=false(无板不崩)",
|
||||
not bool(view.type_glow_probe().get("enabled", true)))
|
||||
view.free()
|
||||
|
||||
|
||||
# Rec.709 相对亮度(sRGB 值域——灰度互辨通道读数,与 shot_checker 同口径)
|
||||
static func _rel_lum709(c: Color) -> float:
|
||||
return 0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b
|
||||
|
||||
|
||||
# WCAG 线性域相对亮度(反伽马)
|
||||
static func _rel_lum_lin(c: Color) -> float:
|
||||
var lin := func(ch: float) -> float:
|
||||
return ch / 12.92 if ch <= 0.04045 else pow((ch + 0.055) / 1.055, 2.4)
|
||||
return 0.2126 * lin.call(c.r) + 0.7152 * lin.call(c.g) + 0.0722 * lin.call(c.b)
|
||||
|
||||
|
||||
# WCAG 对比对(线性域 +0.05 偏移)
|
||||
static func _wcag_cr(a: Color, b: Color) -> float:
|
||||
var la: float = _rel_lum_lin(a)
|
||||
var lb: float = _rel_lum_lin(b)
|
||||
return (maxf(la, lb) + 0.05) / (minf(la, lb) + 0.05)
|
||||
@@ -0,0 +1 @@
|
||||
uid://bykt02pgt6mbf
|
||||
Reference in new issue
Block a user