scopedvr-map-editor/tests/test_scene_tree.gd
slyphax 491a47d3f1 Editor-Bibliothek auf das Military-Desert-Pack umgestellt
- 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>
2026-10-25 16:31:28 +01:00

199 lines
No EOL
7.3 KiB
GDScript

extends SceneTree
## test_scene_tree (Karte t_e3c0310a, U2 Szenen-Baum links): prüft den
## hierarchischen Map-Inhalt-Baum mit Zwei-Wege-Auswahl.
##
## Geprüft wird:
## T1 Baum füllt sich aus dem Dokument (Objekte mit Kategorie-Ebene,
## Index-Meta, Auge-Präfix, Kopf „Objekte (N)“).
## T2 Klick im Baum setzt die Auswahl in 3D (Index stimmt).
## T3 Auswahl in 3D setzt die Baum-Markierung (beide Richtungen).
## T4 Mehrfachauswahl gespiegelt (2 Indizes → 2 markierte Zeilen).
## T5 Gruppen-Ebene: doc-Gruppe erscheint als Knoten mit Mitgliedern.
## T6 Leeres Dokument = Klartext-Hinweis (nicht klickbar).
## T7 Skalierung folgt ui_scale.gd (UIScale.px/v2 — eine Skalierungsquelle).
var _fails := 0
var _oks := 0
var main
var tree_mod
func _check(cond: bool, what: String) -> void:
if cond:
_oks += 1
print(" ok: ", what)
else:
_fails += 1
print(" FAIL: ", what)
func _init() -> void:
print("Testgruppe: Szenen-Baum links (U2 Zwei-Wege-Auswahl)")
var scene: PackedScene = load("res://scenes/main.tscn")
main = scene.instantiate()
root.add_child(main)
await process_frame
await process_frame
await process_frame
tree_mod = main.get("tree_mod")
_check(tree_mod != null, "tree_mod aus der Registry geladen")
_check(tree_mod.get("content_tree") != null, "content_tree im Modul vorhanden")
# Drei Objekte ins Doc: 2x props (barrel/crate), 1x sonstiges (fremde ID).
(main.doc["objects"] as Array).append({
"id": "barrel_001", "pos": [4.0, 0.0, 4.0], "scale": 1.0, "rot_y_deg": 0.0})
(main.doc["objects"] as Array).append({
"id": "box_001", "pos": [-6.0, 0.0, 2.0], "scale": 2.0, "rot_y_deg": 10.0})
(main.doc["objects"] as Array).append({
"id": "fremd_objekt_xyz", "pos": [0.0, 0.0, 8.0], "scale": 1.0, "rot_y_deg": 0.0})
main.call("_after_structure_change")
await process_frame
await _t1_baum_fuellt_sich()
await _t2_klick_setzt_auswahl()
await _t3_auswahl_3d_markiert_baum()
await _t4_mehrfach_gespiegelt()
await _t5_gruppen_ebene()
await _t6_leerer_zustand()
await _t7_skalierung()
_finish()
func _obj_items_under(item: TreeItem) -> Array:
## Alle Kind-Zeilen mit obj_index-Meta (nur DIREKTE Kinder).
var out: Array = []
for child in item.get_children():
if child.has_meta("obj_index"):
out.append(child)
return out
func _find_child(item: TreeItem, prefix: String) -> TreeItem:
for child in item.get_children():
if str(child.get_text(0)).begins_with(prefix):
return child
return null
func _t1_baum_fuellt_sich() -> void:
var tree: Tree = tree_mod.get("content_tree")
var root: TreeItem = tree.get_root()
var obj_head := _find_child(root, "Objekte (3)")
_check(obj_head != null, "T1 Kopf „Objekte (3)“ aus dem Dokument")
if obj_head == null:
return
# Kategorie-Ebene (Karte t_e3c0310a): Objekte hängen unter Kategorie-Knoten.
var kat_nodes: int = obj_head.get_child_count()
_check(kat_nodes >= 1, "T1 Kategorie-Ebene vorhanden (%d Knoten)" % kat_nodes)
var found_idx: Dictionary = {}
var all_ok := true
for kat in obj_head.get_children():
for oi in _obj_items_under(kat):
var idx := int(oi.get_meta("obj_index"))
if found_idx.has(idx):
all_ok = false
found_idx[idx] = true
all_ok = all_ok and str(oi.get_text(0)).begins_with("👁 ")
_check(found_idx.size() == 3, "T1 alle 3 Objekt-Indizes genau einmal im Baum")
_check(all_ok, "T1 Auge-Präfix (nur Anzeige) je Objekt-Zeile")
_check(found_idx.has(0) and found_idx.has(1) and found_idx.has(2), "T1 Indizes 0/1/2 stimmen")
func _t2_klick_setzt_auswahl() -> void:
var tree: Tree = tree_mod.get("content_tree")
var root: TreeItem = tree.get_root()
var obj_head := _find_child(root, "Objekte (3)")
var item1: TreeItem = null
for kat in obj_head.get_children():
for oi in _obj_items_under(kat):
if int(oi.get_meta("obj_index")) == 1:
item1 = oi
_check(item1 != null, "T2 Zeile für Objekt-Index 1 gefunden")
if item1 == null:
return
item1.select(0)
tree.item_selected.emit() # simuliert den Klick-Pfad (item_selected → _on_tree_selected)
await process_frame
var sel: Variant = main.interaction.get("selected_index")
_check(int(sel) == 1, "T2 Klick im Baum setzt Auswahl in 3D (Index 1 — hat %s)" % str(sel))
func _t3_auswahl_3d_markiert_baum() -> void:
var tree: Tree = tree_mod.get("content_tree")
var imap: Dictionary = tree_mod.get("_obj_index_map")
_check(imap.has(0) and imap.has(2), "T3 Index-Karte deckt 0 und 2 ab")
main.call("_mark_tree_selection", 0)
await process_frame
var item0: TreeItem = imap[0]
var item1: TreeItem = imap[1]
_check(item0.is_selected(0), "T3 Auswahl in 3D (0) markiert die Baum-Zeile")
_check(not item1.is_selected(0), "T3 alte Markierung (1) beim Einzel-Klick abgewählt")
# Scroll-zu-Auswahl (Karte t_e3c0310a): im selben Pfad ruft mark_tree_selection_multi
# Tree.scroll_to_item auf der Primär-Zeile auf — hier durch die Markierung mitgeprüft.
func _t4_mehrfach_gespiegelt() -> void:
var imap: Dictionary = tree_mod.get("_obj_index_map")
main.call("_mark_tree_selection_multi", [0, 2])
await process_frame
_check(imap[0].is_selected(0), "T4 Mehrfachauswahl: Zeile 0 markiert")
_check(imap[2].is_selected(0), "T4 Mehrfachauswahl: Zeile 2 markiert")
_check(not imap[1].is_selected(0), "T4 Zeile 1 bleibt abgewählt")
func _t5_gruppen_ebene() -> void:
var gid: int = GroupOps.group(main.doc, [0, 2])
_check(gid >= 0, "T5 Gruppe im Doc angelegt (id %d)" % gid)
main.call("_after_structure_change")
await process_frame
var tree: Tree = tree_mod.get("content_tree")
var root: TreeItem = tree.get_root()
var grp_head := _find_child(root, "Gruppen (1)")
_check(grp_head != null, "T5 Gruppen-Ebene im Baum")
if grp_head == null:
return
var g_node: TreeItem = grp_head.get_first_child()
_check(g_node != null and g_node.has_meta("group_id"), "T5 Gruppen-Knoten trägt group_id")
var members := _obj_items_under(g_node)
_check(members.size() == 2, "T5 Gruppe zeigt 2 Mitglieder im Baum")
# Klick auf den Gruppen-Knoten wählt ALLE Mitglieder in 3D (Zwei-Wege).
g_node.select(0)
tree.item_selected.emit()
await process_frame
var sel_idx: int = int(main.interaction.get("selected_index"))
var sel_many: Array = main.interaction.get("selected_indices")
var many_ok: bool = 0 in sel_many and 2 in sel_many
_check(many_ok and (sel_idx == 0 or sel_idx == 2),
"T5 Gruppen-Klick spiegelt beide Mitglieder in 3D (Anker %d)" % sel_idx)
func _t6_leerer_zustand() -> void:
(main.doc["objects"] as Array).clear()
main.doc["spawn_zones"] = {}
main.call("_after_structure_change")
await process_frame
var tree: Tree = tree_mod.get("content_tree")
var root: TreeItem = tree.get_root()
var hint := _find_child(root, "Noch keine Objekte")
_check(hint != null, "T6 leeres Dokument zeigt Klartext-Hinweis")
if hint != null:
_check(not hint.is_selectable(0), "T6 Hinweis-Zeile ist nicht anwählbar")
func _t7_skalierung() -> void:
var tree: Tree = tree_mod.get("content_tree")
var want: Vector2 = UIScale.v2(0, 160)
_check(tree.custom_minimum_size == want,
"T7 Baum-Mindestgröße folgt UIScale.v2 (%s)" % str(want))
_check(int(tree.custom_minimum_size.y) == UIScale.px(160),
"T7 Höhe = UIScale.px(160) — eine Skalierungsquelle")
func _finish() -> void:
print("CHECKS: %d FAILURES: %d" % [_oks + _fails, _fails])
if _fails > 0:
print("SCENE_TREE_TEST_FAIL")
quit(1)
else:
print("ALL OK: %d checks" % (_oks + _fails))
quit(0)