Files
gplan-2/game/tests/unit/presentation/forge_workbench_test.gd
T
DKChan 98470adc4d 卡④T3(迭代47·营地场景图批): 四柜台拆解四子界面独立可开+CampRefreshBus单口+CampOverlay退役——五句柄落子容器/场景点选改挂/生涯改挂笔记本/关层收闭
- 四view新件(自CampOverlay承载面迁移,界面逻辑复用零重设计契约4): forge_view(钥匙门+两区六路线行板)/treasure_view(12件行板+同调装配段+Y升级行+钥匙门)/tree_view(脉分组行板+Fork双态)/codex_view(占位挂起壳,锁文随形态订正『柜台』称谓L2)——各带返回钮发closed(关层归presenter);公共壳CampSubViewBase(实底dim+铭牌+钥石徽+返回钮)
- CampRefreshBus新件: 各写口尾→现开界面刷新+场景根HUD一闸(卡⑤HUD同口挂接;非autoload非信号广播——组合根单点推送);presenter八写口尾refresh_camp→bus.refresh(F9:七口+on_camp_buy双尾)
- 承载形态(§9-2拍板): 单一内页切换=场景根留底——模态栈open只隐上方登记层(modal_stack.gd:27实测),四子界面登记于场景根之上且实底遮挡,双开互斥靠遮挡天然成立;V2断言按留底派生(T5落)
- ui_registry: LAYER_CONTRACT camp_overlay槽→camp_scene(shell camp_screen)+forge/treasure/tree/codex_view四槽;node()改经modals.camp.X二层(卡⑥契约2);ui_camp_modals五枚成员(overlay枚随退役删除——卡⑥契约4)
- camp_screen: 持camp_scene取代CampOverlay成员;main_ui_build: 场景装配(布局表ConfigDB注入)+四view实例化+信号接线(意图→presenter/closed bind携视图/object_pressed→组合根路由)
- presenter承接面: 五目标改线(ctx.views束——成员预算12≤15)+open_camp_forge/treasure/tree/codex四开层口+on_camp_sub_closed+on_camp_closed关层收闭(营地层与选档层同收+开始层恢复);main_overlay_flow._on_camp_object_pressed五物件路由(gate/campfire归T4)+生涯营地语境关层分支(笔记本改挂——CareerOverlay本体零改);main.gd薄委托零新增成员
- 退役: camp_overlay_view.gd删除(吸收即死);旧形态断言同批摘除(test-conventions §5.5):theme_projection等高源码断言+最近冒险行投影段(卡面削弱申报授权:注销,条带Q4=甲撤下)
- 同批迁移: forge_workbench_test承载类camp_overlay_view→forge_view+_forge._X扁平化(断言零改12项绿);system_test三处机械随迁(V2实例化/:108同一性链/:121候选清单——camp_scene句柄更名)
- 验证: 冒烟boot PASS(15项0失败——装配全链通)+全流程孤检绿(12项:五句柄/铺层/点选路由四子界面/返回/生涯改挂/营地语境分支/关层收闭——临时件不入库);S9/S10/S13归基线(codex头注日期清偿/_build_shell超局部变量按顶栏底栏拆)
2026-11-01 18:06:45 +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/forge_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.meta_state.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"))