scopedvr-map-editor/tests/test_resize_dialog.gd

254 lines
No EOL
10 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extends SceneTree
## Editor-Test (headless): R3 Resize-Dialog — Karte t_c863b93b.
## Ausführen: godot --headless --path . --script res://tests/test_resize_dialog.gd
## Exit 0 = alles grün.
##
## Deckt ab:
## 1. Dialog-Aufbau (Stil wie new_map_dialog): Presets, Clamp 256–4096,
## Info-Zeile mit aktueller Größe/Auflösung.
## 2. Preview-Texte (R2 resize_preview): Verlust-Liste beim Verkleinern,
## „nichts verloren“-Fall, Spawn-Speicher-Warnung (< 4 Punkte/Team, V11),
## Warnband beim Vergrößern über ~1024 m (Dichte-Leiter-Deckel).
## 3. Verdrahtung in main.gd: Menü-ID 6 öffnet Dialog, Bestätigen = resize_apply
## als EINE Undo-Einheit, Undo-Roundtrip speichert die alte Map
## BYTE-IDENTISCH, Redo stellt den Resize wieder her.
var failures := 0
var checks := 0
var main: Control
func _initialize() -> void:
_run_all.call_deferred()
func _run_all() -> void:
_test_dialog_basics()
_test_preview_texts()
await _test_main_wiring()
_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)
# --------------------------------------------------------------- Dialog -----
func _make_dialog() -> ConfirmationDialog:
var dlg: ConfirmationDialog = preload("res://src/ui/resize_map_dialog.gd").new()
return dlg
func _test_dialog_basics() -> void:
print("Testgruppe: Dialog-Aufbau + Clamp")
var dlg := _make_dialog()
var doc := SvmapDocument.create_new("Test", 1024.0, "mittag")
dlg.setup(doc)
_check(dlg.info_label.text.contains("1024"), "Info-Zeile zeigt aktuelle Groesse (1024 m)")
_check(dlg.info_label.text.contains("129"), "Info-Zeile zeigt Aufloesung (129 Punkte)")
_check(is_equal_approx(dlg.get_new_size_x(), 1024.0), "Freifeld startet bei aktueller Groesse")
# Preset-Button 256: beide Achsen wandern mit (Button sitzt in der Preset-HBox).
var preset_btn: Button = null
for child in dlg.get_child(0).get_children():
if child is HBoxContainer:
for b in (child as HBoxContainer).get_children():
if b is Button and b.text == "256 m":
preset_btn = b
_check(preset_btn != null, "Preset-Button 256 m vorhanden")
if preset_btn != null:
preset_btn.emit_signal("pressed")
_check(is_equal_approx(dlg.get_new_size_x(), 256.0)
and is_equal_approx(dlg.get_new_size_z(), 256.0),
"Preset 256 setzt beide Achsen")
# Clamp: SpinBox deckelt auf 256–4096.
dlg.size_x_edit.value = 99999.0
_check(is_equal_approx(dlg.get_new_size_x(), 4096.0), "Clamp oben: 4096 m")
dlg.size_x_edit.value = 1.0
_check(is_equal_approx(dlg.get_new_size_x(), 256.0), "Clamp unten: 256 m")
dlg.free()
# -------------------------------------------------------------- Preview -----
## Map mit Objekt + Bauteil + Spawn-Punkt draußen (X = ±5000 m) bauen.
func _doc_with_outsiders(size: float) -> Dictionary:
var doc := SvmapDocument.create_new("Preview", size, "mittag")
doc["objects"] = [
{"id": "drinnen", "pos": [10.0, 0.0, 10.0], "rot": 0.0, "scale": 1.0},
{"id": "draussen", "pos": [5000.0, 0.0, 0.0], "rot": 0.0, "scale": 1.0},
]
doc["gebaeude"] = [
{"pos": [-30.0, 0.0, -30.0], "rot": 0.0,
"punkte": [[-2.0, 0.0, -2.0], [2.0, 0.0, 2.0]]},
{"pos": [-5000.0, 0.0, 0.0], "rot": 0.0,
"punkte": [[-2.0, 0.0, -2.0], [2.0, 0.0, 2.0]]},
]
var zone0: Dictionary = doc["spawn_zones"]["0"]
var pts: Array = zone0["points"]
for i in pts.size():
pts[i]["pos"][0] = 5000.0 + float(i) # Team Blau komplett draußen
zone0["points"] = pts
return doc
func _test_preview_texts() -> void:
print("Testgruppe: Preview-Texte (Verlust-Liste, Spawn-Warnung, Warnband)")
var dlg := _make_dialog()
# 1) Verkleinern mit Verlust: Liste + Entfernen-Hinweis + Spawn-Warnung.
var doc := _doc_with_outsiders(1024.0)
dlg.setup(doc)
dlg.size_x_edit.value = 256.0
dlg.size_z_edit.value = 256.0
dlg._update_preview() # auerhalb des Baums feuert value_changed nicht (in-tree: live)
var text: String = dlg.preview_label.text
_check(text.contains("draußen") and text.contains("1 Objekt"), "Verlust-Liste nennt 1 Objekt draußen")
_check(text.contains("1 Bauteil"), "Verlust-Liste nennt 1 Bauteil draußen")
# 4 verschobene (Team Blau) + 4 Default-Punkte (Team Rot bei ±0,8 × 512 m) = 8 draußen.
_check(text.contains("8 Spawn-Punkt"), "Verlust-Liste nennt 8 Spawn-Punkte draußen")
_check(text.contains("ENTFERNT"), "Hinweis: draußen wird entfernt (Checkbox an)")
_check(text.contains("Team") and text.contains("4 pro Team"), "Spawn-Speicher-Warnung: Team unter 4 Punkte")
_check(dlg.get_drop_outside(), "Checkbox Entfernen ist Default-an")
# 2) Entfernen aus: draußen bleibt, Map ist dann nicht speicherbar (V9).
dlg.drop_check.button_pressed = false
dlg._update_preview()
text = dlg.preview_label.text
_check(text.contains("bleiben") and text.contains("Rand"), "Ohne Entfernen: draußen bleibt in der Map")
_check(text.contains("NICHT speicherbar"), "Ohne Entfernen: Warnung vor V9 (Speichern blockiert)")
_check(not text.contains("ENTFERNT"), "Kein Entfernen-Hinweis bei Checkbox aus")
dlg.drop_check.button_pressed = true
# 3) Verkleinern ohne Verlust: alles innen → Klartext „nichts verloren“.
var doc_leer := SvmapDocument.create_new("Leer", 512.0, "mittag")
var z0: Dictionary = doc_leer["spawn_zones"]["0"]
var z1: Dictionary = doc_leer["spawn_zones"]["1"]
for zone in [z0, z1]:
var pts2: Array = zone["points"]
for i in pts2.size():
pts2[i]["pos"][0] = 5.0 * float(i) # alle nah am Zentrum
pts2[i]["pos"][2] = 0.0 # Z ebenfalls rein (Default-Z wäre ±153 m)
zone["points"] = pts2
dlg.setup(doc_leer)
dlg.size_x_edit.value = 256.0
dlg.size_z_edit.value = 256.0
dlg._update_preview()
text = dlg.preview_label.text
_check(text.contains("nichts verloren"), "Verkleinern ohne Verlust: Klartext-Meldung")
# 4) Vergrößern > 1024 m: Warnband (Dichte grobt, Quest-Perf).
dlg.setup(SvmapDocument.create_new("Grow", 512.0, "mittag"))
dlg.size_x_edit.value = 2048.0
dlg.size_z_edit.value = 2048.0
dlg._update_preview()
text = dlg.preview_label.text
_check(text.contains("grober") and text.contains("Quest"), "Warnband bei Grow > 1024 m (Dichte + Quest-Perf)")
_check(text.contains("flaches Gras") or text.contains("Randzone"), "Grow-Hinweis: neue Randzone wird Gras")
dlg.free()
# -------------------------------------------------------- main.gd-Drähte ----
func _test_main_wiring() -> void:
print("Testgruppe: main.gd-Verdrahtung + Undo-Roundtrip")
var scene: PackedScene = load("res://scenes/main.tscn")
_check(scene != null, "scenes/main.tscn laedt")
if scene == null:
return
main = scene.instantiate()
root.add_child(main)
await process_frame
await process_frame
_check(main.resize_dialog != null, "Resize-Dialog in der Main-UI gebaut")
main._start_with_new_map()
var doc: Dictionary = main.doc
_check(is_equal_approx(float(doc["terrain"]["size_x_m"]), 1024.0), "Start-Map 1024 m")
# Team Blau komplett draußen schieben (Verkleinern 1024 → 256).
var zone0: Dictionary = doc["spawn_zones"]["0"]
var pts: Array = zone0["points"]
for i in pts.size():
pts[i]["pos"][0] = 500.0 + float(i) # drin (±512), aber draußen bei 256
zone0["points"] = pts
# Referenz-Sicherheit: history hält doc als Objekt (keine Kopie).
_check(is_same(main.history.doc, main.doc), "History haelt doc per Referenz")
# Vorher-Zustand speichern → später Byte-Identität prüfen.
var path_a := "/tmp/r3_vorher.svmap"
var path_b := "/tmp/r3_nach_undo.svmap"
var save_a := SvmapIO.save_to_file(path_a, doc)
_check(bool(save_a["ok"]), "Vorher-Zustand speicherbar")
# Dialog öffnen (Menü-Pfad): Info-Zeile + Preview gefüllt.
main._open_resize_dialog()
_check(main.resize_dialog.visible, "Menue-Eintrag oeffnet den Dialog")
_check(main.resize_dialog.info_label.text.contains("1024"), "Dialog zeigt aktuelle Groesse")
main.resize_dialog.size_x_edit.value = 256.0
main.resize_dialog.size_z_edit.value = 256.0
_check(main.resize_dialog.preview_label.text.contains("draußen"),
"Live-Preview listet Verlust beim Verkleinern")
# Bestätigen: resize_apply + EINE Undo-Einheit.
main._on_resize_confirmed()
var t: Dictionary = main.doc["terrain"]
_check(is_equal_approx(float(t["size_x_m"]), 256.0), "Terrain auf 256 m verkleinert")
_check((main.doc["spawn_zones"]["0"]["points"] as Array).is_empty(),
"Draußen liegende Spawn-Punkte entfernt (Drop an)")
_check(bool(main.dirty), "Dirty-Flag gesetzt")
_check(main.history.can_undo() and main.history.undo_desc().contains("256"),
"EINE Undo-Einheit: Karte auf 256 m")
_check(is_same(main.history.doc, main.doc), "doc-Identitaet bleibt beim Resize erhalten")
# Strg+Z: kompletter Vorher-Zustand, Map speichert BYTE-IDENTISCH.
main._do_undo()
var t2: Dictionary = main.doc["terrain"]
_check(is_equal_approx(float(t2["size_x_m"]), 1024.0), "Undo: Terrain wieder 1024 m")
_check((main.doc["spawn_zones"]["0"]["points"] as Array).size() == 4,
"Undo: entfernte Spawn-Punkte komplett zurueck")
var save_b := SvmapIO.save_to_file(path_b, main.doc)
_check(bool(save_b["ok"]), "Nach-Undo-Zustand speicherbar")
var bytes_a := FileAccess.get_file_as_bytes(path_a)
var bytes_b := FileAccess.get_file_as_bytes(path_b)
_check(bytes_a == bytes_b, "Undo-Roundtrip: alte Map BYTE-IDENTISCH")
# Strg+Y: Resize wieder hergestellt.
main._do_redo()
_check(is_equal_approx(float(main.doc["terrain"]["size_x_m"]), 256.0),
"Redo: Resize wiederhergestellt")
_check((main.doc["spawn_zones"]["0"]["points"] as Array).is_empty(),
"Redo: Spawn-Punkte wieder entfernt")
# Drop aus: draußen bleibt in der Map (Dialog-Checkbox aus) — dokumentiertes
# Verhalten: Map bleibt, ist ABER nicht speicherbar (V9: Spawn außerhalb der
# Match-Grenzen); der Dialog warnt davor.
main.resize_dialog.drop_check.button_pressed = false
main.resize_dialog.size_x_edit.value = 256.0
main.resize_dialog.size_z_edit.value = 256.0
# Erst Undo (zurück auf 1024 mit Punkten), dann Resize ohne Drop.
main._do_undo()
var before_count := (main.doc["spawn_zones"]["0"]["points"] as Array).size()
main._on_resize_confirmed()
_check((main.doc["spawn_zones"]["0"]["points"] as Array).size() == before_count,
"Drop aus: draußen liegende Spawn-Punkte bleiben in der Map")
_check(not bool(SvmapIO.save_to_file("/tmp/r3_drop_aus.svmap", main.doc)["ok"]),
"Drop aus + Punkte draußen: Speichern blockiert (V9), wie im Dialog gewarnt")