Files
gplan-2/game/tests/unit/presentation/forge_workbench_test.gd
T
DKChan fd6cf968dc 工程(存量断言精简·C档批): 六组手写断言族改表驱动循环——33 静态站点并为 7,清单 1587→1561,运行期条数不变
- C1 level_gen_params 逐类负向 11→1(消息带期望/实际与违例明细);C2 rng_stream_boot 黄金向量 8→1;C3 player_copy 禁词族 3→1、2→1;C4 standee_fx 蓄力判据 4→1;C5 ui_font 字形集 3→1(缺字明细进消息);C6 forge_workbench 持有行 2→1(两行取谓词并集,轻甲行补两子句,只增不减)
- 个案标签字面量全部保留在表内,失败定位不降级;冻结清单不动(对账基准 1587),extract_checks --diff=消失 33/新增 7,逐条对应删并申报表
- 用户裁决 2026-10-28:六组全批
2026-10-28 23:51:01 +08:00

108 lines
6.2 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends SceneTree
# 锻造工坊工作间 UI 直验套件(V13 人闸的自动化前置面:两区结构/钮态/意图信号/锁定态纪律)
# 覆盖:锁定态零行板零购买路径(占位纪律延续)· 两区各三路线 · 初始持有行购买钮(几何价 20)·
# 待解锁行解锁钮(200)+无购买钮 · 选中钮当前态禁用 · 余额不足禁用态 · 满级无购买钮 ·
# 三意图信号外发(UI 只发意图——契约 9,写口归 MetaProgression 由冒烟侧覆盖)。
# 运行:godot --headless --path game --script res://tests/unit/presentation/forge_workbench_test.gd(expect 0)
const Kit := preload("res://tests/unit/test_kit.gd")
const _TEST_SAVE := "user://test_forge_workbench.json"
func _initialize() -> void:
call_deferred("_run")
func _row_by_id(ov) -> Dictionary:
var out := {}
for r in ov._forge_rows:
out[String(r.route_id)] = r
return out
func _run() -> void:
var db = load("res://core/config_db.gd").new()
var load_ok: bool = db.load_tables("res://data/tables", true)
if not load_ok:
Kit.check("ConfigDb 加载(工作间测试夹具前提)", false)
quit(Kit.finish("forge_workbench_test"))
return
var sv = load("res://core/save_manager.gd").new(_TEST_SAVE)
sv.load_from_disk()
var mp = load("res://core/meta_progression.gd").new(db, sv)
var ov = load("res://presentation/views/camp_overlay_view.gd").new()
root.add_child(ov)
var buys := []
var unlocks := []
var selects := []
ov.forge_buy_requested.connect(func(rid): buys.append(rid))
ov.forge_unlock_requested.connect(func(rid): unlocks.append(rid))
ov.forge_select_requested.connect(func(rid): selects.append(rid))
# ① 锁定态:树钥匙未点亮 → 工作间不可见、两区零行板(无任何可交互购买路径)
ov.open_camp({"balance": 999, "forge": mp.forge_shop_status(), "tree": []})
Kit.check("锁定态:工作间不可见(forge_workshop 钥匙未点亮)〔锻造工坊批 V13〕",
not ov._forge_workbench.visible and ov._forge_lock_l.visible)
Kit.check("锁定态:两区零行板(占位纪律——零购买路径)〔锻造工坊批 V13〕",
ov._forge_zone_weapon.get_child_count() == 0 and ov._forge_zone_armor.get_child_count() == 0)
# ② 解锁态:钥匙点亮 → 两区各三路线
ov.open_camp({"balance": 500, "forge": mp.forge_shop_status(),
"tree": [{"node_id": "forge_workshop", "level": 1}]})
Kit.check("解锁态:工作间可见(钥匙点亮展开)〔锻造工坊批 V13〕", ov._forge_workbench.visible)
Kit.check("两区各三路线(武器锻造区 3 + 护甲锻造区 3)〔锻造工坊批 V13〕",
ov._forge_zone_weapon.get_child_count() == 3 and ov._forge_zone_armor.get_child_count() == 3)
var rows: Dictionary = _row_by_id(ov)
Kit.check("六路线行册恰全(sword/spear/staff/light/heavy/ward)〔锻造工坊批 V13〕",
rows.has("sword") and rows.has("spear") and rows.has("staff")
and rows.has("light") and rows.has("heavy") and rows.has("ward"))
# ③ 初始持有行(长剑/轻甲):购买钮现形带几何价、选中钮=当前禁用
# 两行同取谓词并集(轻甲行补 select_btn 非空 + buy_btn 可用两子句——原件少写,只增不减)
for pair in [["sword", "长剑"], ["light", "轻甲"]]:
var r: Dictionary = rows.get(pair[0], {})
Kit.check("%s行:购买钮「锻造 20」(0 级位几何价)+选中钮「当前」禁用〔锻造工坊批 V13〕" % pair[1],
r.get("buy_btn") != null and String(r.buy_btn.text) == "锻造 20" and not r.buy_btn.disabled
and r.get("select_btn") != null and String(r.select_btn.text) == "当前" and r.select_btn.disabled)
# ④ 待解锁行(长枪/法杖/重甲/魔法护甲):解锁钮 200、无购买钮、无选中钮、状态含双通道文案
var rsp = rows.get("spear", {})
var rwa = rows.get("ward", {})
Kit.check("长枪行:解锁钮「解锁 200」+无购买钮+无选中钮〔锻造工坊批 V13〕",
rsp.get("unlock_btn") != null and String(rsp.unlock_btn.text) == "解锁 200" and not rsp.unlock_btn.disabled
and rsp.get("buy_btn") == null and rsp.get("select_btn") == null)
Kit.check("魔法护甲行:解锁钮「解锁 200」+状态含并联双通道文案(练满轻甲锻造 或 200 钥石直购)〔锻造工坊批 V13〕",
rwa.get("unlock_btn") != null and String(rwa.status_l.text).contains("练满轻甲锻造")
and String(rwa.status_l.text).contains("200"))
# ⑤ 余额不足禁用态(常态防线)
ov.refresh_camp({"balance": 0, "forge": mp.forge_shop_status(),
"tree": [{"node_id": "forge_workshop", "level": 1}]})
rows = _row_by_id(ov)
Kit.check("余额 0:长剑购买钮禁用+长枪解锁钮禁用(余额联动常态防线)〔锻造工坊批 V13〕",
rows.sword.buy_btn.disabled and rows.spear.unlock_btn.disabled)
# ⑥ 满级行:无购买钮、状态=已满级(直置存档域构造——两分法调试口径)
sv.set_forge_route_level("sword", 5)
ov.refresh_camp({"balance": 500, "forge": mp.forge_shop_status(),
"tree": [{"node_id": "forge_workshop", "level": 1}]})
rows = _row_by_id(ov)
Kit.check("长剑满级:无购买钮+状态「已满级」+长枪派生解锁出解锁钮消失(练满通道)〔锻造工坊批 V13〕",
rows.sword.get("buy_btn") == null and String(rows.sword.status_l.text) == "已满级"
and rows.spear.get("unlock_btn") == null and rows.spear.get("buy_btn") != null)
# ⑦ 三意图信号外发(UI 只发意图——按真实按钮路径;选中钮直发信号面)
buys.clear(); unlocks.clear(); selects.clear()
rows.spear.buy_btn.pressed.emit() # 长枪已派生解锁——真实按钮路径
rows.heavy.unlock_btn.pressed.emit() # 重甲待解锁——真实按钮路径
ov.forge_select_requested.emit("spear") # 选中意图(当前行选中钮禁用态——信号面直发)
Kit.check("三意图信号外发(buy=spear/unlock=heavy/select=spear——UI 只发意图)〔锻造工坊批 V13〕",
buys == ["spear"] and unlocks == ["heavy"] and selects == ["spear"])
# 尾清(测试文件绝不残留)
ov.queue_free()
for suffix in ["", ".tmp", ".corrupt.bak"]:
if FileAccess.file_exists(_TEST_SAVE + suffix):
DirAccess.remove_absolute(_TEST_SAVE + suffix)
quit(Kit.finish("forge_workbench_test"))