extends SceneTree ## Headless smoke test for ModBison Studio application shell, menu dispatch, ## docking layout, and project serialization (Task b67bc0dfd35c). var _failures: int = 0 var _checks: int = 0 const StudioMainClass = preload("res://scripts/studio/studio_main.gd") const MBWorldProjectIOClass = preload("res://scripts/studio/mbworld_project_io.gd") const TransformGizmo3DClass = preload("res://scripts/studio/gizmos/transform_gizmo_3d.gd") const StudioViewportCameraClass = preload("res://scripts/studio/studio_viewport_camera.gd") func _init() -> void: print("--- Running Smoke Test: ModBison Studio Application Shell ---") test_studio_shell_initialization() test_menu_and_toolbar_actions() test_template_and_project_io() test_gizmo_and_camera_controls() if _failures == 0: print("--- PASS: All %d studio shell checks passed! ---" % _checks) quit(0) else: printerr("--- FAIL: %d failures out of %d checks ---" % [_failures, _checks]) quit(1) func _check(desc: String, cond: bool) -> void: _checks += 1 if cond: print(" ✓ %s" % desc) else: _failures += 1 printerr(" ✗ FAIL: %s" % desc) func test_studio_shell_initialization() -> void: print("Testing Studio shell instantiation and docking layout...") var studio := StudioMainClass.new() root.add_child(studio) _check("Studio shell instantiated", studio != null) _check("EditorCore initialized", studio.core != null) _check("Top MenuBar exists", studio._menu_bar != null) _check("Toolbar exists", studio._toolbar != null) _check("3D SubViewport exists", studio._sub_viewport != null) _check("Studio Camera exists", studio._camera_3d != null) _check("3D Transform Gizmo exists", studio._gizmo_3d != null) _check("Scene Hierarchy Dock exists", studio._hierarchy_dock != null) _check("Property Inspector Dock exists", studio._inspector_dock != null) _check("Collections Dock exists", studio._collections_dock != null) studio.queue_free() func test_menu_and_toolbar_actions() -> void: print("Testing Menu Bar registration and tool switching...") var studio := StudioMainClass.new() root.add_child(studio) # Verify menu bar menus var menu_names: Array[String] = [] for child in studio._menu_bar.get_children(): menu_names.append(child.name) _check("MenuBar has 'File' menu", menu_names.has("File")) _check("MenuBar has 'Edit' menu", menu_names.has("Edit")) _check("MenuBar has 'View' menu", menu_names.has("View")) _check("MenuBar has 'Model' menu", menu_names.has("Model")) _check("MenuBar has 'Test' menu", menu_names.has("Test")) _check("MenuBar has 'Publish' menu", menu_names.has("Publish")) # Test gizmo mode toggles studio._set_gizmo_mode(TransformGizmo3DClass.Mode.TRANSLATE) _check("Gizmo set to TRANSLATE mode", studio._gizmo_3d.current_mode == TransformGizmo3DClass.Mode.TRANSLATE) studio._set_gizmo_mode(TransformGizmo3DClass.Mode.ROTATE) _check("Gizmo set to ROTATE mode", studio._gizmo_3d.current_mode == TransformGizmo3DClass.Mode.ROTATE) studio._set_gizmo_mode(TransformGizmo3DClass.Mode.SCALE) _check("Gizmo set to SCALE mode", studio._gizmo_3d.current_mode == TransformGizmo3DClass.Mode.SCALE) studio.queue_free() func test_template_and_project_io() -> void: print("Testing Starter Templates and .mbworld Project Serialization...") # 1. Baseplate template var baseplate_data := MBWorldProjectIOClass.create_template("baseplate") _check("Baseplate template has spawn pad object", baseplate_data["objects"].size() >= 1) # 2. Obby template var obby_data := MBWorldProjectIOClass.create_template("obby") _check("Obby template has multiple platforms", obby_data["objects"].size() >= 3) # 3. Save to disk and reload var test_path := "user://smoke_test_project.mbworld" var save_ok := MBWorldProjectIOClass.save_project(test_path, obby_data) _check("Successfully saved .mbworld project file", save_ok) _check("Project file exists on disk", FileAccess.file_exists(test_path)) var loaded_data := MBWorldProjectIOClass.load_project(test_path) _check("Loaded project contains matching title", loaded_data.get("title") == obby_data.get("title")) _check("Loaded project contains same object count", loaded_data.get("objects", []).size() == obby_data.get("objects", []).size()) # Clean up file DirAccess.remove_absolute(test_path) func test_gizmo_and_camera_controls() -> void: print("Testing Camera presets and Gizmo snapping...") var studio := StudioMainClass.new() root.add_child(studio) # Test camera presets studio._camera_3d.set_view_preset(StudioViewportCameraClass.ViewPreset.TOP) _check("Camera switched to Top orthographic view", studio._camera_3d.projection == Camera3D.PROJECTION_ORTHOGONAL) studio._camera_3d.set_view_preset(StudioViewportCameraClass.ViewPreset.PERSPECTIVE) _check("Camera returned to Perspective projection", studio._camera_3d.projection == Camera3D.PROJECTION_PERSPECTIVE) # Test gizmo snapping studio._gizmo_3d.set_snap(true, 2.0, 45.0) _check("Gizmo translate snap set to 2.0", is_equal_approx(studio._gizmo_3d.snap_translate, 2.0)) _check("Gizmo rotate snap set to 45 degrees", is_equal_approx(studio._gizmo_3d.snap_rotate_deg, 45.0)) studio.queue_free()