extends SceneTree ## Editor-Test (headless): GUI-Smoke — Karte t_d3b93793. ## Ausführen: godot --headless --path . --script res://tests/test_gui_smoke.gd ## Exit 0 = alles grün. ## ## ANDERS als die übrigen Tests instanziert dieser Test die ECHTE Main-UI ## (scenes/main.tscn → src/ui/main.gd) und deckt damit Runtime-UI-Pfade ab, ## die die logik-only-Suite nie sieht (GUI-Start-Befund 15.10.: Terrain-Preset- ## Crash beim Panel-Bau + `command_pressed`-Spam bei jeder Taste — beides ## headless unsichtbar, weil das UI nie instanziert wurde). ## ## Was hier geprüft wird: ## 1. Panel-Bau überlebt _ready (kein abgebrochener _build_right_panel). ## 2. Terrain-Größen-Presets sind initial korrekt belegt (Mittel = 12 m) ## und klickbar (Klick stellt Radius-Slider + Label um). ## 3. Keyboard-Shortcut-Pfad (_unhandled_key_input) läuft ohne ## Property-Fehler und setzt Strg+Z wirklich in Undo um. var failures := 0 var checks := 0 var main: Control func _initialize() -> void: _run_all.call_deferred() func _run_all() -> void: var scene: PackedScene = load("res://scenes/main.tscn") _check(scene != null, "scenes/main.tscn laedt") if scene == null: _finish() return main = scene.instantiate() root.add_child(main) # Zwei Frames: _ready + Layout laufen lassen (auch deferred UI-Arbeit). await process_frame await process_frame _test_ui_built() _test_terrain_presets() _test_shortcut_undo() _finish() func _finish() -> void: if failures == 0: print("ALL OK: %d checks" % checks) quit(0) else: print("FAILED: %d/%d checks" % [failures, checks]) quit(1) func _check(cond: bool, label: String) -> void: checks += 1 if cond: print(" ok: %s" % label) else: failures += 1 print(" FAIL: %s" % label) ## Abnahme 1: Der komplette UI-Bau (_ready → _build_ui → _build_right_panel) ## läuft durch — genau dort crashte der Terrain-Preset-Handler (main.gd:659). func _test_ui_built() -> void: print("Testgruppe: UI-Bau überlebt _ready") _check(main != null, "Main-Instanz existiert") _check(main.terrain_size_btn_small != null, "Preset-Button Klein gebaut") _check(main.terrain_size_btn_medium != null, "Preset-Button Mittel gebaut") _check(main.terrain_size_btn_large != null, "Preset-Button Groß gebaut") _check(main.terrain_radius_slider != null, "Radius-Slider gebaut") _check(main.undo_btn != null and main.redo_btn != null, "Undo/Redo-Buttons gebaut (Panel-Bau lief komplett durch)") ## Abnahme 2a: Initialzustand ohne Nebeneffekt-Callback (set_pressed_no_signal): ## Mittel aktiv, Slider passend 12 m. func _test_terrain_presets() -> void: print("Testgruppe: Terrain-Größen-Presets") _check(main.terrain_size_btn_medium.button_pressed, "Mittel ist initial aktiv") _check(is_equal_approx(float(main.terrain_radius_slider.value), 12.0), "Slider startet bei 12 m (passend zum aktiven Preset)") # Klick auf Groß: button_pressed=true feuert toggled → Handler muss # jetzt (mit existierendem Slider) Radius + Label setzen. main.terrain_size_btn_large.button_pressed = true _check(is_equal_approx(float(main.terrain_radius_slider.value), 32.0), "Klick auf Groß setzt Slider auf 32 m") _check(str(main.terrain_radius_label.text).contains("32"), "Pinsel-Label zeigt 32 m") _check(main.terrain_size_btn_medium.button_pressed == false, "ButtonGroup: Mittel beim Klick auf Groß deaktiviert") # Klick auf Klein (Position-Klick simuliert echten User-Klick). main.terrain_size_btn_small.button_pressed = true _check(is_equal_approx(float(main.terrain_radius_slider.value), 4.0), "Klick auf Klein setzt Slider auf 4 m") func _press_key(keycode: Key, ctrl: bool) -> InputEventKey: var ev := InputEventKey.new() ev.keycode = keycode ev.physical_keycode = keycode ev.pressed = true ev.ctrl_pressed = ctrl return ev ## Abnahme 2b + 3: Der Shortcut-Pfad muss ohne Property-Fehler durchlaufen ## (vorher crashte `event.command_pressed` bei JEDER Taste) und Strg+Z ## tatsächlich in ein Undo übersetzen. func _test_shortcut_undo() -> void: print("Testgruppe: Keyboard-Shortcuts (Strg+Z)") # Echte History-Aktion in die laufende Editor-History legen. var before: Dictionary = main.history.snapshot(["objects"]) (main.doc["objects"] as Array).append( {"id": "test_objekt", "pos": [10.0, 0.0, 10.0], "scale": 1.0, "rot_y_deg": 0.0}) main.history.commit("Test: Objekt platzieren", before, main.history.snapshot(["objects"])) _check((main.doc["objects"] as Array).size() == 1, "Test-Objekt platziert") # Vorher-Zustand für die unbehandelte Taste merken. var status_vorher := str(main.status_label.text) main._unhandled_key_input(_press_key(KEY_F, false)) _check(str(main.status_label.text) == status_vorher, "unbehandelte Taste (F) ändert nichts, läuft aber sauber durch") main._unhandled_key_input(_press_key(KEY_Z, true)) _check((main.doc["objects"] as Array).is_empty(), "Strg+Z hat das Objekt entfernt (Undo wirkt)") _check(str(main.status_label.text).contains("Rückgängig gemacht"), "Statusleiste meldet das Undo") main._unhandled_key_input(_press_key(KEY_Y, true)) _check((main.doc["objects"] as Array).size() == 1, "Strg+Y stellt wieder her (Redo wirkt)") # Leere History + Strg+Z: freundliche Meldung statt Crash. # Erst das Redo-Ergebnis wieder weg-undoen, DANN ist die History leer. main._unhandled_key_input(_press_key(KEY_Z, true)) _check((main.doc["objects"] as Array).is_empty(), "Strg+Z nach Redo: History leer") main._unhandled_key_input(_press_key(KEY_Z, true)) _check(str(main.status_label.text).contains("Nichts zum Rückgängigmachen"), "Strg+Z bei leerer History: Statusmeldung, kein Absturz")