using NUnit.Framework; using UnityEngine; using UnityEngine.Events; using UnityEditor; using Newtonsoft.Json.Linq; using MCPForUnity.Editor.Helpers; using MCPForUnity.Editor.Tools; using TestNamespace; namespace MCPForUnityTests.Editor.Tools { public class ComponentOpsUnityEventTests { private GameObject testGo; [SetUp] public void SetUp() { testGo = new GameObject("UnityEventTestGO"); } [TearDown] public void TearDown() { if (testGo != null) Object.DestroyImmediate(testGo); } [Test] public void SetProperty_UnityEvent_SinglePersistentCall_PersistsViaSerialization() { var comp = testGo.AddComponent(); int targetId = testGo.GetInstanceID(); var value = JObject.Parse(@"{ ""m_PersistentCalls"": { ""m_Calls"": [ { ""m_Target"": { ""instanceID"": " + targetId + @" }, ""m_TargetAssemblyTypeName"": ""UnityEngine.GameObject, UnityEngine"", ""m_MethodName"": ""SetActive"", ""m_Mode"": 6, ""m_Arguments"": { ""m_BoolArgument"": true }, ""m_CallState"": 2 } ] } }"); bool ok = ComponentOps.SetProperty(comp, "onSimpleEvent", value, out string error); Assert.IsTrue(ok, $"SetProperty should succeed, got error: {error}"); // Verify via SerializedObject readback var so = new SerializedObject(comp); var callsProp = so.FindProperty("onSimpleEvent.m_PersistentCalls.m_Calls"); Assert.IsNotNull(callsProp, "m_Calls property should exist"); Assert.AreEqual(1, callsProp.arraySize, "Should have 1 persistent call"); var call0 = callsProp.GetArrayElementAtIndex(0); Assert.AreEqual("SetActive", call0.FindPropertyRelative("m_MethodName").stringValue); Assert.AreEqual(testGo, call0.FindPropertyRelative("m_Target").objectReferenceValue); Assert.AreEqual(6, call0.FindPropertyRelative("m_Mode").enumValueIndex); Assert.AreEqual(2, call0.FindPropertyRelative("m_CallState").enumValueIndex); } [Test] public void SetProperty_UnityEvent_MultiplePersistentCalls_AllPersist() { var comp = testGo.AddComponent(); int targetId = testGo.GetInstanceID(); var value = JObject.Parse(@"{ ""m_PersistentCalls"": { ""m_Calls"": [ { ""m_Target"": { ""instanceID"": " + targetId + @" }, ""m_TargetAssemblyTypeName"": ""UnityEngine.GameObject, UnityEngine"", ""m_MethodName"": ""SetActive"", ""m_Mode"": 6, ""m_Arguments"": { ""m_BoolArgument"": true }, ""m_CallState"": 2 }, { ""m_Target"": { ""instanceID"": " + targetId + @" }, ""m_TargetAssemblyTypeName"": ""UnityEngine.GameObject, UnityEngine"", ""m_MethodName"": ""SetActive"", ""m_Mode"": 6, ""m_Arguments"": { ""m_BoolArgument"": false }, ""m_CallState"": 2 } ] } }"); bool ok = ComponentOps.SetProperty(comp, "onSimpleEvent", value, out string error); Assert.IsTrue(ok, $"SetProperty should succeed, got error: {error}"); var so = new SerializedObject(comp); var callsProp = so.FindProperty("onSimpleEvent.m_PersistentCalls.m_Calls"); Assert.AreEqual(2, callsProp.arraySize, "Should have 2 persistent calls"); Assert.AreEqual("SetActive", callsProp.GetArrayElementAtIndex(0).FindPropertyRelative("m_MethodName").stringValue); Assert.AreEqual("SetActive", callsProp.GetArrayElementAtIndex(1).FindPropertyRelative("m_MethodName").stringValue); } [Test] public void SetProperty_UnityEvent_EmptyCalls_ClearsEvent() { var comp = testGo.AddComponent(); // First set a call int targetId = testGo.GetInstanceID(); var withCall = JObject.Parse(@"{ ""m_PersistentCalls"": { ""m_Calls"": [ { ""m_Target"": { ""instanceID"": " + targetId + @" }, ""m_TargetAssemblyTypeName"": ""UnityEngine.GameObject, UnityEngine"", ""m_MethodName"": ""SetActive"", ""m_Mode"": 6, ""m_Arguments"": { ""m_BoolArgument"": true }, ""m_CallState"": 2 } ] } }"); ComponentOps.SetProperty(comp, "onSimpleEvent", withCall, out _); // Now clear it var empty = JObject.Parse(@"{ ""m_PersistentCalls"": { ""m_Calls"": [] } }"); bool ok = ComponentOps.SetProperty(comp, "onSimpleEvent", empty, out string error); Assert.IsTrue(ok, $"SetProperty should succeed, got error: {error}"); var so = new SerializedObject(comp); var callsProp = so.FindProperty("onSimpleEvent.m_PersistentCalls.m_Calls"); Assert.AreEqual(0, callsProp.arraySize, "Should have 0 persistent calls after clearing"); } [Test] public void SetProperty_PrivateSerializedUnityEvent_RoutesViaSerialization() { var comp = testGo.AddComponent(); int targetId = testGo.GetInstanceID(); var value = JObject.Parse(@"{ ""m_PersistentCalls"": { ""m_Calls"": [ { ""m_Target"": { ""instanceID"": " + targetId + @" }, ""m_TargetAssemblyTypeName"": ""UnityEngine.GameObject, UnityEngine"", ""m_MethodName"": ""SetActive"", ""m_Mode"": 6, ""m_Arguments"": { ""m_BoolArgument"": true }, ""m_CallState"": 2 } ] } }"); bool ok = ComponentOps.SetProperty(comp, "_onPrivateEvent", value, out string error); Assert.IsTrue(ok, $"SetProperty on private [SerializeField] UnityEvent should succeed, got error: {error}"); var so = new SerializedObject(comp); var callsProp = so.FindProperty("_onPrivateEvent.m_PersistentCalls.m_Calls"); Assert.IsNotNull(callsProp, "Private event m_Calls should exist"); Assert.AreEqual(1, callsProp.arraySize, "Should have 1 persistent call"); } [Test] public void SetProperty_SimpleFloat_StillWorksViaReflection() { var audioSource = testGo.AddComponent(); bool ok = ComponentOps.SetProperty(audioSource, "volume", new JValue(0.5f), out string error); Assert.IsTrue(ok, $"SetProperty for float should succeed, got error: {error}"); Assert.AreEqual(0.5f, audioSource.volume, 0.001f); } [Test] public void HandleCommand_EndToEnd_UnityEventWiring() { testGo.AddComponent(); int targetId = testGo.GetInstanceID(); var p = new JObject { ["action"] = "set_property", ["target"] = testGo.name, ["search_method"] = "by_name", ["component_type"] = "UnityEventTestComponent", ["property"] = "onSimpleEvent", ["value"] = JObject.Parse(@"{ ""m_PersistentCalls"": { ""m_Calls"": [ { ""m_Target"": { ""instanceID"": " + targetId + @" }, ""m_TargetAssemblyTypeName"": ""UnityEngine.GameObject, UnityEngine"", ""m_MethodName"": ""SetActive"", ""m_Mode"": 6, ""m_Arguments"": { ""m_BoolArgument"": true }, ""m_CallState"": 2 } ] } }") }; var result = ManageComponents.HandleCommand(p); var resultObj = result as JObject ?? JObject.FromObject(result); Assert.IsTrue(resultObj.Value("success"), $"HandleCommand should succeed: {resultObj}"); // Verify via SerializedObject var comp = testGo.GetComponent(); var so = new SerializedObject(comp); var callsProp = so.FindProperty("onSimpleEvent.m_PersistentCalls.m_Calls"); Assert.AreEqual(1, callsProp.arraySize, "Should have 1 persistent call after end-to-end"); Assert.AreEqual("SetActive", callsProp.GetArrayElementAtIndex(0).FindPropertyRelative("m_MethodName").stringValue); } } }