# tests/smoke_boot.gd — 冒烟测试:极小启动场景(这版活着吗——零逻辑判定) # 以项目运行目标拉起=真实开机路径:autoload 四件注册在位、配置表全载(fail-fast 通道)、 # 全局字体与主题可加载、主屏场景实例化、启动态菜单可见。 # 断言只查存在性与可见性,不做任何玩法逻辑判定;断言完打印摘要并以退出码收口, # 判定三闸(退出码+摘要失败数+脚本错误扫描)由外部运行器 tools/run_smoke.py 承担。 # 运行:python tools/run_smoke.py(本地闸 00 冒烟测试) extends Node const MAIN_SCENE_PATH: String = "res://presentation/main.tscn" const FONT_PATH: String = "res://assets/fonts/ui_font_fusion_pixel_zh_hans.ttf" const THEME_PATH: String = "res://assets/theme/main_theme.tres" const BOOT_FRAMES: int = 4 # 主屏装配是逐帧推进的挂树过程,等满再断言(探针族同惯例) var _failures: int = 0 var _checks: int = 0 func check(cond: bool, label: String) -> void: _checks += 1 if cond: print(" [PASS] " + label) else: _failures += 1 print(" [FAIL] " + label) func _ready() -> void: _check_autoloads() var main: Node = await _boot_main_scene() _check_main_scene(main) print("[smoke] 摘要:%d 项检查,%d 项失败" % [_checks, _failures]) get_tree().quit(1 if _failures > 0 else 0) # 开机前置面:autoload 注册与资源可加载(挂主屏之前先查,失败时主屏断言整段跳过) func _check_autoloads() -> void: for autoload_name in ["ConfigDB", "RngService", "SaveManager", "MetaProgression"]: var node: Node = get_node_or_null(NodePath("/root/" + autoload_name)) check(node != null, "autoload %s 在位" % autoload_name) var db: Node = get_node_or_null(NodePath("/root/ConfigDB")) check(db != null and bool(db.get("is_ready")) and db.get("hero") != null, "ConfigDB 就绪且配置表全载(is_ready+hero 表在座,校验失败会致命中止)") check(load(MAIN_SCENE_PATH) != null, "主屏场景资源可加载(%s)" % MAIN_SCENE_PATH) check(load(FONT_PATH) != null, "全局字体资源可加载(%s)" % FONT_PATH) check(load(THEME_PATH) != null, "全局主题资源可加载(%s)" % THEME_PATH) # 以项目运行目标同款方式实例化主屏(真实开机路径——区别于 --script 模式的无 autoload 裸跑) func _boot_main_scene() -> Node: await get_tree().process_frame var packed: PackedScene = load(MAIN_SCENE_PATH) as PackedScene if packed == null: return null var main: Node = packed.instantiate() if main == null: return null add_child(main) for i in range(BOOT_FRAMES): await get_tree().process_frame return main # 主屏存活面:组合根装配句柄在位(main.X 一级句柄契约,探针挂载假设的启动侧证明) func _check_main_scene(main: Node) -> void: check(main != null and main.is_inside_tree(), "主屏场景已实例化并在树") if main == null: return var run_scope: Node = main.get("run_scope") check(run_scope != null, "闲时会话 run_scope 非空(永非 null 契约)") check(run_scope != null and run_scope.is_inside_tree(), "闲时会话 run_scope 在树") var start_overlay: Control = main.get("_start_overlay") check(start_overlay != null, "开始菜单层已装配(_start_overlay)") check(start_overlay != null and start_overlay.visible, "启动态菜单可见(boot 后玩家见菜单)") check(main.get("settings_store") != null, "系统设置存储已装配(settings_store)") check(main.get("debug_badge") != null, "调试入口角标已装配(debug_badge)") check(main.get("legend_overlay") != null, "图例覆盖层已装配(legend_overlay)") check(main.get("status_panel") != null, "局内状态面板已装配(status_panel)")