- 423 Objekte in 19 deutschen Kategorien (Panzer, Radfahrzeuge, Flugzeuge, Gebaeude, Zelte, Tuerme, Mauern, Sperren, Kisten, Technik, Felsen, Boden, Decals ...); Gruppen "Bauwerke" und "Kisten & Barrieren" samt Test-Asset-Namenslisten entfernt - LibraryBrowser: Gruppen/Namen aus dem Manifest (kategorie, name_de), unbekannte Kategorien bekommen automatisch eine eigene Gruppe - Thumbs neu, library/ synchronisiert (inkl. neuer Kollision) - Neue Identitaetsprobe: Kollision ALLER Objekte Editor = Client = Server - Tests auf Pack-Objekte umgestellt Co-Authored-By: Claude <noreply@anthropic.com>
233 lines
No EOL
8.6 KiB
GDScript
233 lines
No EOL
8.6 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("box_001")
|
|
_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("water_tower_004") 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 == str(main.manifest["objects"]["water_tower_004"]["name_de"]), "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")
|
|
# „zelt" → nur die Zelte-Gruppe (14 Objekte) sichtbar.
|
|
main.library_search.text = "zelt"
|
|
main._apply_library_filter("zelt")
|
|
var visible_headers := 0
|
|
var pilze_row := _group_row("zelte")
|
|
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 == (pilze_row["ids"] as Array).size() and visible_tiles >= 10, "alle %d Zelt-Kacheln sichtbar (ist %d)" % [(pilze_row["ids"] as Array).size(), visible_tiles])
|
|
_check((pilze_row["box"] as VBoxContainer).visible, "Treffer-Gruppe offen")
|
|
# ID-Suche funktioniert auch: „water_tower_004" (ID) → Treffer in tuerme.
|
|
main._apply_library_filter("water_tower_004")
|
|
var wt := main.library_buttons.get("water_tower_004") as Button
|
|
_check(wt != null and wt.visible, "ID-Suche „water_tower_004“ findet den Wasserturm")
|
|
# 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)")
|
|
# Luftfahrzeuge-Gruppe aufklappen → cfg speichert.
|
|
var row := _group_row("luftfahrzeuge")
|
|
_check(not row.is_empty(), "Gruppe luftfahrzeuge 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", "luftfahrzeuge", null) == true,
|
|
"cfg [library] luftfahrzeuge=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("luftfahrzeuge")
|
|
_check(not row2.is_empty() and (row2["box"] as VBoxContainer).visible,
|
|
"nach Neu-Instanz ist luftfahrzeuge wieder offen")
|
|
# Und wieder zu machen — Zustand bleibt gemerkt (false).
|
|
(_group_row("luftfahrzeuge")["header"] as Button).button_pressed = false
|
|
await process_frame
|
|
var cfg2 := ConfigFile.new()
|
|
cfg2.load("user://scopedvr_editor.cfg")
|
|
_check(cfg2.get_value("library", "luftfahrzeuge", null) == false,
|
|
"cfg [library] luftfahrzeuge=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() |