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://core/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://core/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()