scopedvr-map-editor/tests/test_library_browser_ui.gd

233 lines
No EOL
8.4 KiB
GDScript

extends SceneTree
## Editor-Test (headless): Bibliotheks-Browser-UI — Karte t_59fc0f21.
## Ausführen: godot --headless --path . --script res://tests/test_library_browser_ui.gd
## Exit 0 = alles grün.
##
## Instanziert die ECHTE Main-UI (Muster tests/test_gui_smoke.gd) und prüft:
## 1. Kacheln: Thumbnail-TextureRect ≥ 64 px (Vorgabe 96), 2-Spalten-Grid,
## deutscher Name (name_de) unter dem Bild.
## 2. Gruppen: Standard eingeklappt (nur erste Gruppe offen), Header fett/18 px
## mit Name + Anzahl, Manifest-Deckung (alle Objekte als Button).
## 3. Klapp-Zustand wird in user://scopedvr_editor.cfg gemerkt und nach
## Neustart (Neu-Instanz) wiederhergestellt.
## 4. Suche: „pilz" filtert live (nur Pilze-Gruppe sichtbar), Leeren stellt
## den gemerkten Klapp-Zustand wieder her.
## 5. „Alle auf" / „Alle zu" klappen alles um.
var failures := 0
var checks := 0
var main: Control
func _initialize() -> void:
_run_all.call_deferred()
func _run_all() -> void:
_clear_library_cfg_section()
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)
await process_frame
await process_frame
_test_built()
_test_default_collapsed()
_test_tiles()
_test_search()
await _test_persistence()
_test_all_buttons()
_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)
func _clear_library_cfg_section() -> void:
# Nur UNSEREN Abschnitt leeren — [test]/[update] der anderen Features bleiben.
var cfg := ConfigFile.new()
cfg.load("user://scopedvr_editor.cfg")
if cfg.has_section("library"):
cfg.erase_section("library")
cfg.save("user://scopedvr_editor.cfg")
func _group_row(g_key: String) -> Dictionary:
for row in main._library_group_rows:
if str(row["key"]) == g_key:
return row
return {}
func _test_built() -> void:
print("Testgruppe: UI-Bau (Suchfeld, Alle auf/zu, Gruppen)")
_check(main.library_search != null, "Suchfeld gebaut")
_check(main.library_open_all_btn != null and main.library_close_all_btn != null,
"Alle auf/Alle zu gebaut")
_check(main._library_group_rows.size() >= 8,
"Gruppen gebaut (%d)" % main._library_group_rows.size())
var lib: Dictionary = main.manifest.get("objects", {})
_check(main.library_buttons.size() == lib.size(),
"Manifest-Deckung: %d/%d Objekte als Button" % [main.library_buttons.size(), lib.size()])
func _test_default_collapsed() -> void:
print("Testgruppe: Standard eingeklappt (nur erste Gruppe offen)")
var open_count := 0
var first_key := ""
for row in main._library_group_rows:
var box := row["box"] as VBoxContainer
if box.visible:
open_count += 1
if first_key.is_empty():
first_key = str(row["key"])
_check(open_count == 1, "genau 1 Gruppe offen (ist %d)" % open_count)
_check(not first_key.is_empty(), "eine Gruppe ist offen (%s)" % first_key)
# Header: 18 px Font, Text enthält Name + Anzahl.
var row0: Dictionary = main._library_group_rows[0]
var header := row0["header"] as Button
_check(header.get_theme_font_size("font_size") >= 18, "Header-Schrift ≥ 18 px")
_check(header.text.contains("(%d)" % int(row0["count"])), "Header zeigt Anzahl (%s)" % header.text)
# Alle Boxen außer der ersten sind zu — trotz 347 Objekten klein.
var hidden_ok := true
for row in main._library_group_rows:
if str(row["key"]) != first_key and not (row["box"] as VBoxContainer).visible:
continue
elif str(row["key"]) == first_key and (row["box"] as VBoxContainer).visible:
continue
hidden_ok = false
_check(hidden_ok, "übrige Gruppen zugeklappt")
func _test_tiles() -> void:
print("Testgruppe: Kacheln (96-px-Vorschaubild + Name)")
var tex := LibraryBrowser.load_thumb("crate_wood")
_check(tex != null and tex.get_width() >= 96, "load_thumb liefert ≥ 96 px (ist %s)"
% (str(tex.get_width()) if tex != null else "null"))
var tile_btn := main.library_buttons.get("watchtower_wood") as Button
_check(tile_btn != null, "Kachel-Button existiert")
if tile_btn != null:
var tr: TextureRect = null
var lbl: Label = null
for child in tile_btn.get_children():
for sub in (child as Control).get_children():
if sub is TextureRect:
tr = sub
elif sub is Label:
lbl = sub
_check(tr != null, "TextureRect in Kachel")
_check(lbl != null, "Name-Label in Kachel")
if tr != null:
_check(tr.custom_minimum_size.x >= 64, "Thumbnail-Zielgröße ≥ 64 px (ist %d)"
% int(tr.custom_minimum_size.x))
_check(tr.size.x >= 64, "Thumbnail rendert ≥ 64 px breit (ist %.0f)" % tr.size.x)
_check(tr.texture != null and tr.texture.get_width() == 128,
"Textur auf 128 px skaliert")
if lbl != null:
_check(lbl.text == "Wachturm", "deutscher Name unter dem Bild (%s)" % lbl.text)
_check(tile_btn.size.y >= 100, "Kachel hoch genug (%.0f px)" % tile_btn.size.y)
func _test_search() -> void:
print("Testgruppe: Suche filtert live")
# „pilz" → nur die Pilze-Gruppe (6 Objekte) sichtbar.
main.library_search.text = "pilz"
main._apply_library_filter("pilz")
var visible_headers := 0
var pilze_row := _group_row("pilze")
for row in main._library_group_rows:
if (row["header"] as Button).visible:
visible_headers += 1
_check(visible_headers == 1, "nur 1 Gruppen-Header sichtbar (ist %d)" % visible_headers)
var visible_tiles := 0
for oid in pilze_row["ids"]:
if (main.library_buttons.get(str(oid)) as Button).visible:
visible_tiles += 1
_check(visible_tiles == 6, "6 Pilz-Kacheln sichtbar (ist %d)" % visible_tiles)
_check((pilze_row["box"] as VBoxContainer).visible, "Treffer-Gruppe offen")
# ID-Suche funktioniert auch: „watchtower" (ID) → Treffer in bauwerke.
main._apply_library_filter("watchtower")
var wt := main.library_buttons.get("watchtower_wood") as Button
_check(wt != null and wt.visible, "ID-Suche „watchtower“ findet Wachturm")
# Leeren → gemerkter Zustand wiederhergestellt (nur erste Gruppe offen).
main.library_search.text = ""
main._apply_library_filter("")
var open_count := 0
for row in main._library_group_rows:
if (row["box"] as VBoxContainer).visible:
open_count += 1
_check(open_count == 1, "nach Leeren wieder 1 Gruppe offen (ist %d)" % open_count)
func _test_persistence() -> void:
print("Testgruppe: Klapp-Zustand überlebt Neustart (cfg)")
# Fahrzeuge-Gruppe aufklappen → cfg speichert.
var row := _group_row("fahrzeuge")
_check(not row.is_empty(), "Gruppe fahrzeuge existiert")
if row.is_empty():
return
var header := row["header"] as Button
header.button_pressed = true
await process_frame
var cfg := ConfigFile.new()
cfg.load("user://scopedvr_editor.cfg")
_check(cfg.get_value("library", "fahrzeuge", null) == true,
"cfg [library] fahrzeuge=true nach Aufklappen")
# „Neustart": Instanz wegwerfen, neu bauen — Zustand muss zurückkommen.
# (queue_free + Frames: free() während laufender Frame-Arbeit ist gesperrt.)
main.queue_free()
await process_frame
await process_frame
main = (load("res://scenes/main.tscn") as PackedScene).instantiate()
root.add_child(main)
await process_frame
await process_frame
var row2 := _group_row("fahrzeuge")
_check(not row2.is_empty() and (row2["box"] as VBoxContainer).visible,
"nach Neu-Instanz ist fahrzeuge wieder offen")
# Und wieder zu machen — Zustand bleibt gemerkt (false).
(_group_row("fahrzeuge")["header"] as Button).button_pressed = false
await process_frame
var cfg2 := ConfigFile.new()
cfg2.load("user://scopedvr_editor.cfg")
_check(cfg2.get_value("library", "fahrzeuge", null) == false,
"cfg [library] fahrzeuge=false nach Zuklappen")
func _test_all_buttons() -> void:
print("Testgruppe: Alle auf / Alle zu")
main._on_library_collapse_all()
var open_count := 0
for row in main._library_group_rows:
if (row["box"] as VBoxContainer).visible:
open_count += 1
_check(open_count == 0, "Alle zu: 0 Gruppen offen (ist %d)" % open_count)
main._on_library_expand_all()
open_count = 0
for row in main._library_group_rows:
if (row["box"] as VBoxContainer).visible:
open_count += 1
_check(open_count == main._library_group_rows.size(),
"Alle auf: alle %d Gruppen offen (ist %d)" % [main._library_group_rows.size(), open_count])
# Aufräumen für die nächsten Läufe: wieder zu.
main._on_library_collapse_all()