238 lines
No EOL
8.7 KiB
GDScript
238 lines
No EOL
8.7 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://core/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 _t2b_echter_klick()
|
|
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))
|
|
|
|
|
|
## FIX 25.10.: Im Modus SELECT_MULTI feuert Godot nie item_selected — der Test
|
|
## oben simulierte einen Weg, den es in der Praxis nicht gab. Hier ein ECHTER
|
|
## Mausklick (Eingabe-Ereignis) auf eine Zeile.
|
|
func _t2b_echter_klick() -> void:
|
|
var tree: Tree = tree_mod.get("content_tree")
|
|
main.interaction.clear_selection()
|
|
root.size = Vector2i(1600, 900)
|
|
await process_frame
|
|
await process_frame
|
|
var item0: TreeItem = null
|
|
for kat in _find_child(tree.get_root(), "Objekte (3)").get_children():
|
|
for oi in _obj_items_under(kat):
|
|
if int(oi.get_meta("obj_index")) == 2:
|
|
item0 = oi
|
|
_check(item0 != null, "T2b Zeile für Objekt-Index 2 gefunden")
|
|
if item0 == null:
|
|
return
|
|
tree.scroll_to_item(item0)
|
|
await process_frame
|
|
var r := tree.get_item_area_rect(item0, 0)
|
|
var pos := tree.get_global_position() + r.position + Vector2(r.size.x * 0.5, r.size.y * 0.5)
|
|
_check(tree.get_global_rect().has_point(pos), "T2b Zeile liegt im sichtbaren Baum-Rechteck")
|
|
var ev := InputEventMouseButton.new()
|
|
ev.button_index = MOUSE_BUTTON_LEFT
|
|
ev.position = pos
|
|
ev.global_position = pos
|
|
ev.pressed = true
|
|
root.push_input(ev)
|
|
await process_frame
|
|
var up := ev.duplicate()
|
|
up.pressed = false
|
|
root.push_input(up)
|
|
await process_frame
|
|
await process_frame
|
|
_check(int(main.interaction.get("selected_index")) == 2,
|
|
"T2b ECHTER Klick auf die Listenzeile wählt das Objekt in der Szene (Index 2 — hat %s)" % str(main.interaction.get("selected_index")))
|
|
|
|
|
|
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) |