P1-5/P2-7 组合根可测化+模态协议内聚(场景拆分后重估结论=抽取面收敛为模态编排域): - modal_flow.gd 新纯逻辑类: 依赖仅 ModalStack+查询 Callable(审计处方)——开合编排 (挂起兜底/排播排空/遮挡记账/开合同步)/棋盘输入锁谓词(三例外注入)/双形制角标谓词; V6 modal_flow_test 19 断言直接 new() 进 run_all(26→27 套)——测试抓出并修正 挂起兜底 divergent return 一处(原 main 语义=先结挂起后继续开本层不短路) - ModalStack 互斥域随层登记: register(m, tags) + TAG_NON_LOCKING/TAG_SCREEN_STATE 封闭词表 + has_open_excluding_tags 组查询;原 has_open_excluding/_any 调用点拼装退役 (main 五处判据迁移);main._modals=flow.stack(ui_struct _list 登记序断言缝保留) - P1-5 控制器构造收拢 context: curio 16 参→CurioFlowContext/camp 13 参→CampFlowContext (字段逐一同名迁移,控制器可独立实例化) 验收: 对拍三变体全同;冒烟 1079/0+run_all 27 套+probe click+render golden 全绿
76 lines
5.9 KiB
GDScript
76 lines
5.9 KiB
GDScript
# tests/run_all.gd — 单元测试统一入口(ADR-0004 双载体的逻辑测试调用点,套件 manifest 协议 D2 AC-2b)
|
||
# 用法:godot --headless --path game --script res://tests/run_all.gd (CI 侧包装外部超时:timeout 120s …)
|
||
# 协议:套件清单逐条"套件 → 期望退出码";致命类独立进程(expect=1)。
|
||
# 执行形态(单元测试与契约层批 2026-09-28):逐套件起独立 Godot 子进程实跑
|
||
#(OS.get_executable_path() 解析本引擎二进制——--script 模式无 autoload/全局标识符,
|
||
# 每个测试文件自带显式实例化夹具,见 tests/README 协议要点)。
|
||
# 场景探针(.tscn 载体)由 CI/轻闸单独步骤调用,不经本入口。
|
||
extends SceneTree
|
||
|
||
|
||
func _init() -> void:
|
||
print("[run_all] unit/contract suite entry — %d suites" % _suites().size())
|
||
if DisplayServer.get_name() != "headless":
|
||
push_warning("[run_all] 建议以 --headless 运行(D2 冒烟协议)")
|
||
var failures := 0
|
||
for suite in _suites():
|
||
failures += _run_suite(suite)
|
||
if failures > 0:
|
||
push_error("[run_all] %d 个套件失败" % failures)
|
||
quit(1)
|
||
return
|
||
print("[run_all] all green (%d suites)" % _suites().size())
|
||
quit(0)
|
||
|
||
|
||
# 套件清单:{ "path": String, "expect": int };致命类(期望非 0)独立进程断言退出码。
|
||
func _suites() -> Array:
|
||
return [
|
||
{"path": "res://tests/unit/example_test.gd", "expect": 0},
|
||
{"path": "res://tests/unit/data_config/config_db_test.gd", "expect": 0},
|
||
{"path": "res://tests/unit/data_config/forge_table_test.gd", "expect": 0}, # 迭代 23 锻造工坊批 T1——六路线 schema 正反(V1)+特效留空(V11)+几何价格梯(V2 半边)
|
||
{"path": "res://tests/unit/data_config/config_db_fatal_oob_test.gd", "expect": 1},
|
||
{"path": "res://tests/unit/data_config/treasure_target_violation_test.gd", "expect": 1}, # 迭代 7 T1——真视窄域护栏
|
||
{"path": "res://tests/unit/data_config/reward_dangling_treasure_test.gd", "expect": 1}, # 迭代 7 T1——秘宝双表校验
|
||
{"path": "res://tests/unit/data_config/rng_service_test.gd", "expect": 0},
|
||
{"path": "res://tests/unit/core/treasure_items_test.gd", "expect": 0}, # 迭代 7 T7——秘宝结构冻结断言面
|
||
{"path": "res://tests/unit/core/breakpoint_resume_test.gd", "expect": 0}, # 迭代 8 卡①/T9——断点往返/续玩确定性/幂等/退出清断点
|
||
{"path": "res://tests/unit/core/curio_refresh_paid_test.gd", "expect": 0}, # 2026-10-06——三选一刷新免费双源+GP 付费档(对齐商店 MC-1:价曲线/优先序/停点清零/钱包单口)
|
||
{"path": "res://tests/unit/presentation/pacing_queue_test.gd", "expect": 0}, # 迭代 8 卡⑦ AC⑤/T9——排空零分叉/零丢行/延迟双态
|
||
{"path": "res://tests/unit/presentation/reward_overlay_test.gd", "expect": 0}, # 迭代 7 hotfix——奖励节点 UI 直验(盲区补漏)
|
||
{"path": "res://tests/unit/presentation/forge_workbench_test.gd", "expect": 0}, # 迭代 23 锻造工坊批 T6——工作间两区六路线 UI 直验(V13 自动化前置面)
|
||
{"path": "res://tests/unit/battle_settlement/damage_math_test.gd", "expect": 0},
|
||
{"path": "res://tests/unit/battle_settlement/damage_controller_test.gd", "expect": 0},
|
||
{"path": "res://tests/unit/battle_settlement/skill_unlock_test.gd", "expect": 0}, # 迭代14④ T6——Boss 半血解锁技·容器机制(门谓词/闩不可逆/双面过滤/保底不逼锁定/零扰动)
|
||
{"path": "res://tests/unit/contracts/system_contracts_test.gd", "expect": 0},
|
||
{"path": "res://tests/unit/presentation/ui_font_asset_test.gd", "expect": 0},
|
||
{"path": "res://tests/unit/presentation/terrain_tile_sets_test.gd", "expect": 0},
|
||
# fog_lantern_wiring_test 随提灯载体行退役摘除(迭代 22 T1——V13 旧验证约束同生死;呈现桥换代断言归 T4 阔视野带参数面)
|
||
{"path": "res://tests/unit/core/effect_words_t1_test.gd", "expect": 0},
|
||
{"path": "res://tests/unit/core/treasure_effects_test.gd", "expect": 0}, # 迭代 22 秘宝批 T3——新目录 12 件逐件行为(V7 附属表正常/边界/反例)
|
||
{"path": "res://tests/unit/core/tree_rules_v11_test.gd", "expect": 0}, # 迭代 21 天赋树批 V11——六键合成行闭集校验 # 迭代 20 T1——词表扩签封闭性(V1:新词在册/出域四路被拒/adventure 计数器往返/mod_eq 预评估口径)
|
||
{"path": "res://tests/unit/core/tree_requires_level_test.gd", "expect": 0}, # R1 机制位批 2026-10-13——requires_level 等级阈值前置(schema 四拒一过+判定三态+投影两态)
|
||
{"path": "res://tests/unit/core/pool_case_d_test.gd", "expect": 0}, # 迭代 20 T2——池结构案D 行为(V6 令牌三态/V7 曝光槽 2+1 回退/V8 概率上限解耦提前退役)
|
||
{"path": "res://tests/unit/core/feat_vouchers_test.gd", "expect": 0}, # 迭代 20 T4——凭证五件+留任二件(V9 路由逐件/F-1 存量账/V10 留任路由+AP 属性轴)
|
||
{"path": "res://tests/unit/core/settle_segments_test.gd", "expect": 0}, # 迭代 27 T2——结算五段 Segment(V4:直接 new/编排器接线/真实一轮走段序)
|
||
{"path": "res://tests/unit/presentation/modal_flow_test.gd", "expect": 0}, # 迭代 27 T4——模态编排纯逻辑(V6:直接 new/互斥域谓词/三例外锁/演播后排窗)
|
||
]
|
||
|
||
|
||
func _run_suite(suite: Dictionary) -> int:
|
||
var path: String = suite.get("path", "")
|
||
var expect: int = int(suite.get("expect", 0))
|
||
if path.is_empty():
|
||
push_error("[run_all] suite missing path")
|
||
return 1
|
||
var args := PackedStringArray(["--headless", "--path", ProjectSettings.globalize_path("res://"), "--script", path])
|
||
var out := PackedStringArray()
|
||
var code: int = OS.execute(OS.get_executable_path(), args, out, true, false)
|
||
var text := "\n".join(out)
|
||
print(text)
|
||
if code != expect:
|
||
push_error("[run_all] FAIL %s — 退出码 %d ≠ 期望 %d" % [path, code, expect])
|
||
return 1
|
||
print("[run_all] PASS %s (exit=%d)" % [path, code])
|
||
return 0
|