extends SceneTree ## Editor-Tests (headless): Karte t_b84af40f — „▶ Karte testen" Verkabelung. ## Ausführen: godot --headless --path . --script res://tests/test_testrun.gd ## Exit 0 = alles grün. Läuft OHNE UI (TestRun/SvmapIO/SvmapDocument): ## Temp-Export (auch ungespeicherte Maps), Client-Suche, Godot-Binär-Findung, ## Argument-Aufbau — der eigentliche Prozess-Start ist Desktop-Sache ## (run_testmap_e2e.sh im CLIENT deckt die other-Seite ab). var failures := 0 var checks := 0 const TEST_DIR := "user://test_testrun" func _init() -> void: _cleanup() _run_tests() _cleanup() 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 _cleanup() -> void: _cleanup_dir(ProjectSettings.globalize_path(TEST_DIR)) # Kompletten Temp-Ordner purgen statt nur einer Datei: eine Stale-Export- # datei fremden Owners (root-Testlauf vs. slyphax-Lauf teilen sich user://) # ließ den Schreibvorgang still scheitern ("Datei nicht schreibbar") und # faerbte "Temp-Datei existiert auf Disk" faelschlich gruen. Der Ordner- # Owner darf unlinken, auch wenn die Datei selbst root gehoert. _cleanup_dir(ProjectSettings.globalize_path(TestRun.TESTRUN_DIR)) func _cleanup_dir(base: String) -> void: if not DirAccess.dir_exists_absolute(base): return var d := DirAccess.open(base) if d == null: return for file in d.get_files(): DirAccess.remove_absolute(base.path_join(file)) for sub in d.get_directories(): _cleanup_dir(base.path_join(sub)) DirAccess.remove_absolute(base) func _run_tests() -> void: print("== Temp-Map-Pfad ==") var path := TestRun.temp_map_path({"info": {"name": "Offenes Gelände 2!"}}) _check(str(path).begins_with("user://testrun/"), "Temp-Pfad liegt unter user://testrun/") _check(str(path).ends_with("Offenes_Gel_nde_2.svmap"), "Map-Name bereinigt (Sonderzeichen → _, kein trailing _)") path = TestRun.temp_map_path({}) _check(str(path).ends_with("karte.svmap"), "fehlender Name → Fallback „karte.svmap“") print("== Temp-Export (ungespeicherte Map) ==") var doc := SvmapDocument.create_new("Testkarte", 256.0, "mittag") var exported := TestRun.export_temp_map(doc) if not bool(exported["ok"]): print(" (save_to_file-Fehler: %s)" % str(exported.get("errors", []))) _check(bool(exported["ok"]), "neue Map exportiert (ohne je gespeichert zu haben)") var global_path := str(exported["path"]) _check(FileAccess.file_exists(global_path), "Temp-Datei existiert auf Disk") var back := SvmapIO.load_from_file(global_path) _check(bool(back["ok"]), "Temp-Datei lädt wieder (Prüfsumme gültig — voller Roundtrip)") _check(str(back["data"]["info"]["name"]) == "Testkarte", "Inhalt identisch") print("== Temp-Export (ungültige Map → Klartext-Block) ==") var broken: Dictionary = doc.duplicate(true) broken["spawn_zones"] = {"0": {"points": []}, "1": {"points": []}} var failed := TestRun.export_temp_map(broken) _check(not bool(failed["ok"]), "ungültige Map wird NICHT exportiert") _check((failed["errors"] as Array).size() > 0, "Fehlerliste fürs Dialog-Fenster vorhanden") print("== Client-Suche ==") var base := ProjectSettings.globalize_path(TEST_DIR) DirAccess.make_dir_recursive_absolute(base.path_join("mein-editor-projekt")) DirAccess.make_dir_recursive_absolute(base.path_join("scopedvr-client")) var f := FileAccess.open(base.path_join("scopedvr-client/project.godot"), FileAccess.WRITE) f.store_string("[application]\n") # 2) Nachbar-Klon wird gefunden: var found := TestRun.find_client(base.path_join("mein-editor-projekt"), ConfigFile.new()) _check(found == base.path_join("scopedvr-client"), "Nachbar-Klon ../scopedvr-client gefunden") # 1) Konfiguration gewinnt (Ordner existiert, ohne project.godot-Check): var cfg := ConfigFile.new() cfg.set_value("test", "client_dir", base.path_join("irgendwo")) DirAccess.make_dir_recursive_absolute(base.path_join("irgendwo")) var found2 := TestRun.find_client(base.path_join("mein-editor-projekt"), cfg) _check(found2 == base.path_join("irgendwo"), "Konfig-Pfad hat Vorrang (Ordner existiert)") # 3) Gar nichts da: DirAccess.remove_absolute(base.path_join("scopedvr-client/project.godot")) var found3 := TestRun.find_client(base.path_join("mein-editor-projekt"), ConfigFile.new()) _check(found3 == "", "kein Client → leerer String (Fehler-Dialog greift)") print("== Godot-Binär-Findung ==") var exe := TestRun.find_godot(ConfigFile.new()) _check(not exe.is_empty() and exe.get_file().to_lower().contains("godot"), "Editor läuft über Godot → dasselbe Binary zum Starten") print("== Argument-Aufbau ==") var args := TestRun.launch_args("/pfad/client", "/tmp/x.svmap") var want := ["--path", "/pfad/client", "--", "--testmap", "/tmp/x.svmap", "--mock-master"] var ok := args.size() == want.size() if ok: for i in want.size(): if str(args[i]) != want[i]: ok = false _check(ok, "launch_args exakt: --path … -- --testmap … --mock-master") var hp := TestRun.hand_pose_args("/pfad/client") _check(Array(hp) == ["--xr-mode", "off", "--path", "/pfad/client", "res://tools/hand_pose_tool/hand_pose_tool.tscn"], "hand_pose_args exakt: ohne VR, Szene aus dem Client")