141 lines
7.5 KiB
GDScript
141 lines
7.5 KiB
GDScript
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||
# 模态编排纯逻辑类单测(ModalFlow 直接 new() 进 run_all;
|
||
# 互斥域谓词/三例外输入锁/演播后排窗挂起/演播完边沿派发/遮挡记账)。
|
||
# 载体零场景零树——纯 RefCounted + 哑 Control。
|
||
# 运行:godot --headless --path game --script res://tests/unit/presentation/modal_flow_test.gd(expect 0)
|
||
extends SceneTree
|
||
|
||
const Kit := preload("res://tests/unit/test_kit.gd")
|
||
const ModalFlowScript := preload("res://presentation/modal_flow.gd") # 探针载体禁全局类名裸引用惯例同源
|
||
const ModalStackScript := preload("res://presentation/modal_stack.gd")
|
||
|
||
|
||
func _init() -> void:
|
||
# oracle: design/engineering/code-conventions.md:54 (模态编排纯逻辑——层级与输入锁组)
|
||
# 哑层与桩 Callable(纯逻辑类零场景前提的证明面)
|
||
var start := Control.new()
|
||
var inter := Control.new()
|
||
var settlement_holder := {"s": null} # lambda 对局部按值捕获——容器装载
|
||
var rows := {"empty": true}
|
||
var calls := {"flush": 0, "open_sync": 0, "close_sync": 0, "replay": 0}
|
||
var flow = ModalFlowScript.new()
|
||
Kit.check_quiet(flow != null and flow.stack != null, "V6 ModalFlow 直接 new()(stack 内建)〔迭代27 T4〕")
|
||
flow.start_visible_get = func() -> bool: return start.visible
|
||
flow.inter_visible_get = func() -> bool: return inter.visible
|
||
flow.settlement_get = func() -> Variant: return settlement_holder["s"]
|
||
flow.rows_empty_get = func() -> bool: return rows["empty"]
|
||
flow.flush_rows = func() -> void: calls["flush"] += 1
|
||
flow.on_open_sync = func() -> void: calls["open_sync"] += 1
|
||
flow.on_close_sync = func() -> void: calls["close_sync"] += 1
|
||
flow.replay_click = func() -> void: calls["replay"] += 1
|
||
|
||
# V6-1 互斥域登记+遮挡记账
|
||
var a := Control.new() # 普通层
|
||
var dbg := Control.new() # 调试浮窗(non_locking)
|
||
var map := Control.new() # 关卡地图屏(screen_state)
|
||
flow.register(a)
|
||
flow.register(dbg, [ModalStackScript.TAG_NON_LOCKING])
|
||
flow.register(map, [ModalStackScript.TAG_SCREEN_STATE])
|
||
var tag_dump := "tags a=%s dbg=%s map=%s const=%s" % [str(flow.stack._tags.get(a, "MISSING")), str(flow.stack._tags.get(dbg, "MISSING")), str(flow.stack._tags.get(map, "MISSING")), ModalStackScript.TAG_NON_LOCKING]
|
||
print("[DBG] ", tag_dump)
|
||
flow.open(a)
|
||
Kit.check_quiet(a.visible and calls["open_sync"] == 1 and calls["flush"] == 1, "V6 开侧编排(flush→open→sync 单口序)〔迭代27 T4〕")
|
||
# 遮挡记账(登记序=z 序:开低层隐其上方可见层、关闭恢复——低层开启期高层照会不可见的呈现保真)
|
||
flow.open(map)
|
||
Kit.check_quiet(map.visible, "V6 开最高层(上方无可隐)〔迭代27 T4〕")
|
||
flow.open(a)
|
||
Kit.check_quiet(a.visible and not map.visible, "V6 遮挡记账(开低层隐其上方可见层)〔迭代27 T4〕")
|
||
flow.close(a)
|
||
Kit.check_quiet(map.visible and calls["close_sync"] == 1, "V6 关闭恢复(关低层显其上方被隐层+关侧同步)〔迭代27 T4〕")
|
||
|
||
# V6-2 输入锁谓词:互斥域随层登记(non_locking 不计)+ 三例外
|
||
start.visible = false
|
||
inter.visible = false
|
||
settlement_holder["s"] = Object.new()
|
||
flow.open(dbg)
|
||
Kit.check_quiet(not flow.locks_input(), "V6 输入锁:调试浮窗 non_locking 不计(T2 防线)〔迭代27 T4〕")
|
||
flow.close(dbg)
|
||
flow.open(a)
|
||
Kit.check_quiet(flow.locks_input(), "V6 输入锁:普通层开态计锁〔迭代27 T4〕")
|
||
flow.close(a)
|
||
flow.close(map) # 登记册全关(close(a) 经遮挡恢复 map——须一并关账才是「全关」态)
|
||
settlement_holder["s"] = null
|
||
Kit.check_quiet(flow.locks_input(), "V6 输入锁例外三:战斗缺位即锁〔迭代27 T4〕")
|
||
settlement_holder["s"] = Object.new()
|
||
Kit.check_quiet(not flow.locks_input(), "V6 输入锁:战斗在座+登记册全关=不锁〔迭代27 T4〕")
|
||
start.visible = true
|
||
Kit.check_quiet(flow.locks_input(), "V6 输入锁例外一:开始层可见即锁〔迭代27 T4〕")
|
||
start.visible = false
|
||
inter.visible = true
|
||
Kit.check_quiet(flow.locks_input(), "V6 输入锁例外二:过场层可见即锁〔迭代27 T4〕")
|
||
inter.visible = false
|
||
Kit.check_quiet(not flow.locks_input(), "V6 输入锁:全例外解除+登记册全关=不锁〔迭代27 T4〕")
|
||
|
||
# V6-3 角标谓词(状态/调试两屏同款守卫——与旧排除式逐位同值)
|
||
flow.open(dbg)
|
||
Kit.check_quiet(not flow.badge_greyed_battle() and not flow.badge_greyed_map(),
|
||
"V6 角标谓词:浮窗开态两形制均不置灰〔迭代27 T4〕")
|
||
flow.close(dbg)
|
||
flow.open(map)
|
||
Kit.check_quiet(not flow.badge_greyed_map() and flow.badge_greyed_battle(),
|
||
"V6 角标谓词:地图屏 screen_state 地图形制不计/战斗形制计(旧排除式 [debug] 与 [level,debug] 同值面)〔迭代27 T4〕")
|
||
flow.close(map)
|
||
flow.open(a)
|
||
Kit.check_quiet(flow.badge_greyed_battle() and flow.badge_greyed_map(),
|
||
"V6 角标谓词:普通层开态两形制均置灰〔迭代27 T4〕")
|
||
flow.close(a)
|
||
|
||
# V6-4 演播后排窗挂起+边沿派发(T17 语义)
|
||
var end_ov := Control.new()
|
||
end_ov.visible = false
|
||
flow.register(end_ov) # d9 fail-fast 后:未登记层不可进入编排(夹具按 register 先行契约登记)
|
||
rows["empty"] = false
|
||
var sync_before1: int = calls["open_sync"]
|
||
flow.open_after_playback(end_ov)
|
||
Kit.check_quiet(flow._deferred == end_ov and not end_ov.visible and calls["open_sync"] == sync_before1,
|
||
"V6 演播后排窗:在播挂起含视觉(不照会上屏——零开侧同步)〔迭代27 T4〕")
|
||
rows["empty"] = true
|
||
var sync_before2: int = calls["open_sync"]
|
||
flow.pump_ended()
|
||
Kit.check_quiet(flow._deferred == null and end_ov.visible and calls["open_sync"] == sync_before2 + 1,
|
||
"V6 演播完边沿:挂起 modal 先开(队列空判定由 rows_empty_get 承载)〔迭代27 T4〕")
|
||
flow.close(end_ov)
|
||
flow.pump_ended()
|
||
Kit.check_quiet(calls["replay"] == 1, "V6 演播完边沿:无挂起→锁期点击重放派发〔迭代27 T4〕")
|
||
# 挂起兜底(他路径开新层先结挂起防永不兑现)
|
||
rows["empty"] = false
|
||
flow.open_after_playback(end_ov)
|
||
rows["empty"] = true
|
||
var other := Control.new()
|
||
flow.register(other)
|
||
var sync_before: int = calls["open_sync"]
|
||
flow.open(other)
|
||
Kit.check_quiet(end_ov.visible and flow._deferred == null and calls["open_sync"] == sync_before + 2,
|
||
"V6 挂起兜底:开新层先结挂起(T17 防永不兑现——挂起层先开+新层后开两拍)〔迭代27 T4〕")
|
||
|
||
# V6-5 遮挡失败快+遮挡账合而非覆盖(d9)
|
||
var ms = ModalStackScript.new()
|
||
var ma := Control.new()
|
||
var mb := Control.new()
|
||
var stranger := Control.new()
|
||
stranger.visible = false # Control 默认 visible=true——先隐,才能断言 fail-fast 未把它照上屏
|
||
ms.register(ma)
|
||
ms.register(mb)
|
||
ms.open(ma)
|
||
ms.open(stranger) # 未登记层:push_error + 早退(零副作用)
|
||
Kit.check_quiet(not stranger.visible and ma.visible,
|
||
"V6 未登记层 open fail-fast(该层不可见、已开层不变)〔wd9〕")
|
||
ms.close(stranger)
|
||
Kit.check_quiet(not stranger.visible and ma.visible,
|
||
"V6 未登记层 close fail-fast(已开层不受影响)〔wd9〕")
|
||
ms.open(mb)
|
||
ms.open(ma) # 开低层隐其上方可见层
|
||
Kit.check_quiet(not mb.visible, "V6 开低层隐其上方层(重复 open 前态)〔wd9〕")
|
||
ms.open(ma) # 同层重复 open:上方已隐,hidden 空表——旧账须保留
|
||
Kit.check_quiet(not mb.visible, "V6 重复 open 保持遮挡(V6 在役语义不变)〔wd9〕")
|
||
ms.close(ma)
|
||
Kit.check_quiet(mb.visible, "V6 重复 open 不吞遮挡账(close 低层恢复 mb——合并非覆盖)〔wd9〕")
|
||
ms.close(mb)
|
||
|
||
quit(Kit.finish("modal_flow"))
|