Skip to main content
Glama
ManagePrefabsTests.cs9.82 kB
using System.IO; using Newtonsoft.Json.Linq; using NUnit.Framework; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; using MCPForUnity.Editor.Tools.Prefabs; namespace MCPForUnityTests.Editor.Tools { public class ManagePrefabsTests { private const string TempDirectory = "Assets/Temp/ManagePrefabsTests"; [SetUp] public void SetUp() { StageUtility.GoToMainStage(); EnsureTempDirectoryExists(); } [TearDown] public void TearDown() { StageUtility.GoToMainStage(); // Clean up temp directory after each test if (AssetDatabase.IsValidFolder(TempDirectory)) { AssetDatabase.DeleteAsset(TempDirectory); } // Clean up parent Temp folder if it's empty if (AssetDatabase.IsValidFolder("Assets/Temp")) { var remainingDirs = Directory.GetDirectories("Assets/Temp"); var remainingFiles = Directory.GetFiles("Assets/Temp"); if (remainingDirs.Length == 0 && remainingFiles.Length == 0) { AssetDatabase.DeleteAsset("Assets/Temp"); } } } [Test] public void OpenStage_OpensPrefabInIsolation() { string prefabPath = CreateTestPrefab("OpenStageCube"); try { var openParams = new JObject { ["action"] = "open_stage", ["prefabPath"] = prefabPath }; var openResult = ToJObject(ManagePrefabs.HandleCommand(openParams)); Assert.IsTrue(openResult.Value<bool>("success"), "open_stage should succeed for a valid prefab."); UnityEditor.SceneManagement.PrefabStage stage = PrefabStageUtility.GetCurrentPrefabStage(); Assert.IsNotNull(stage, "Prefab stage should be open after open_stage."); Assert.AreEqual(prefabPath, stage.assetPath, "Opened stage should match prefab path."); var stageInfo = ToJObject(MCPForUnity.Editor.Resources.Editor.PrefabStage.HandleCommand(new JObject())); Assert.IsTrue(stageInfo.Value<bool>("success"), "get_prefab_stage should succeed when stage is open."); var data = stageInfo["data"] as JObject; Assert.IsNotNull(data, "Stage info should include data payload."); Assert.IsTrue(data.Value<bool>("isOpen")); Assert.AreEqual(prefabPath, data.Value<string>("assetPath")); } finally { StageUtility.GoToMainStage(); AssetDatabase.DeleteAsset(prefabPath); } } [Test] public void CloseStage_ReturnsSuccess_WhenNoStageOpen() { StageUtility.GoToMainStage(); var closeResult = ToJObject(ManagePrefabs.HandleCommand(new JObject { ["action"] = "close_stage" })); Assert.IsTrue(closeResult.Value<bool>("success"), "close_stage should succeed even if no stage is open."); } [Test] public void CloseStage_ClosesOpenPrefabStage() { string prefabPath = CreateTestPrefab("CloseStageCube"); try { ManagePrefabs.HandleCommand(new JObject { ["action"] = "open_stage", ["prefabPath"] = prefabPath }); var closeResult = ToJObject(ManagePrefabs.HandleCommand(new JObject { ["action"] = "close_stage" })); Assert.IsTrue(closeResult.Value<bool>("success"), "close_stage should succeed when stage is open."); Assert.IsNull(PrefabStageUtility.GetCurrentPrefabStage(), "Prefab stage should be closed after close_stage."); } finally { StageUtility.GoToMainStage(); AssetDatabase.DeleteAsset(prefabPath); } } [Test] public void SaveOpenStage_SavesDirtyChanges() { string prefabPath = CreateTestPrefab("SaveStageCube"); try { ManagePrefabs.HandleCommand(new JObject { ["action"] = "open_stage", ["prefabPath"] = prefabPath }); UnityEditor.SceneManagement.PrefabStage stage = PrefabStageUtility.GetCurrentPrefabStage(); Assert.IsNotNull(stage, "Stage should be open before modifying."); stage.prefabContentsRoot.transform.localScale = new Vector3(2f, 2f, 2f); var saveResult = ToJObject(ManagePrefabs.HandleCommand(new JObject { ["action"] = "save_open_stage" })); Assert.IsTrue(saveResult.Value<bool>("success"), "save_open_stage should succeed when stage is open."); Assert.IsFalse(stage.scene.isDirty, "Stage scene should not be dirty after saving."); GameObject reloaded = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath); Assert.AreEqual(new Vector3(2f, 2f, 2f), reloaded.transform.localScale, "Saved prefab asset should include changes from open stage."); } finally { StageUtility.GoToMainStage(); AssetDatabase.DeleteAsset(prefabPath); } } [Test] public void SaveOpenStage_ReturnsError_WhenNoStageOpen() { StageUtility.GoToMainStage(); var saveResult = ToJObject(ManagePrefabs.HandleCommand(new JObject { ["action"] = "save_open_stage" })); Assert.IsFalse(saveResult.Value<bool>("success"), "save_open_stage should fail when no stage is open."); } [Test] public void CreateFromGameObject_CreatesPrefabAndLinksInstance() { EnsureTempDirectoryExists(); StageUtility.GoToMainStage(); string prefabPath = Path.Combine(TempDirectory, "SceneObjectSaved.prefab").Replace('\\', '/'); GameObject sceneObject = new GameObject("ScenePrefabSource"); try { var result = ToJObject(ManagePrefabs.HandleCommand(new JObject { ["action"] = "create_from_gameobject", ["target"] = sceneObject.name, ["prefabPath"] = prefabPath })); Assert.IsTrue(result.Value<bool>("success"), "create_from_gameobject should succeed for a valid scene object."); var data = result["data"] as JObject; Assert.IsNotNull(data, "Response data should include prefab information."); string savedPath = data.Value<string>("prefabPath"); Assert.AreEqual(prefabPath, savedPath, "Returned prefab path should match the requested path."); GameObject prefabAsset = AssetDatabase.LoadAssetAtPath<GameObject>(savedPath); Assert.IsNotNull(prefabAsset, "Prefab asset should exist at the saved path."); int instanceId = data.Value<int>("instanceId"); var linkedInstance = EditorUtility.InstanceIDToObject(instanceId) as GameObject; Assert.IsNotNull(linkedInstance, "Linked instance should resolve from instanceId."); Assert.AreEqual(savedPath, PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(linkedInstance), "Instance should be connected to the new prefab."); sceneObject = linkedInstance; } finally { if (AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(prefabPath) != null) { AssetDatabase.DeleteAsset(prefabPath); } if (sceneObject != null) { if (PrefabUtility.IsPartOfPrefabInstance(sceneObject)) { PrefabUtility.UnpackPrefabInstance( sceneObject, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction ); } UnityEngine.Object.DestroyImmediate(sceneObject, true); } } } private static string CreateTestPrefab(string name) { EnsureTempDirectoryExists(); GameObject temp = GameObject.CreatePrimitive(PrimitiveType.Cube); temp.name = name; string path = Path.Combine(TempDirectory, name + ".prefab").Replace('\\', '/'); PrefabUtility.SaveAsPrefabAsset(temp, path, out bool success); UnityEngine.Object.DestroyImmediate(temp); Assert.IsTrue(success, "PrefabUtility.SaveAsPrefabAsset should succeed for test prefab."); return path; } private static void EnsureTempDirectoryExists() { if (!AssetDatabase.IsValidFolder("Assets/Temp")) { AssetDatabase.CreateFolder("Assets", "Temp"); } if (!AssetDatabase.IsValidFolder(TempDirectory)) { AssetDatabase.CreateFolder("Assets/Temp", "ManagePrefabsTests"); } } private static JObject ToJObject(object result) { return result as JObject ?? JObject.FromObject(result); } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/CoplayDev/unity-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server