#nullable enable using System.Collections; using System.Collections.Generic; using System.Linq; using com.IvanMurzak.ReflectorNet; using com.IvanMurzak.ReflectorNet.Model; using com.IvanMurzak.Unity.MCP.Reflection.Converter; using com.IvanMurzak.Unity.MCP.TestFiles; using NUnit.Framework; using UnityEditor; using UnityEngine; using UnityEngine.TestTools; namespace com.IvanMurzak.Unity.MCP.Editor.Tests { public class SerializeTest : BaseTest { [UnityTest] public IEnumerator Serialize_GameObject_WithComponent_ListOfNullColliders() { var reflector = UnityMcpPluginEditor.Instance.Reflector ?? throw new System.InvalidOperationException("Reflector should not be null."); // Create a GameObject with the test component var go = new GameObject("TestGameObject_ColliderList"); var component = go.AddComponent(); // Set the list to contain two null objects component.colliderList.Add(null!); component.colliderList.Add(null!); EditorUtility.SetDirty(go); EditorUtility.SetDirty(component); // Wait 3 frames to ensure everything is initialized yield return null; yield return null; yield return null; var serializedComponent = reflector.Serialize( component, recursive: true, logger: _logger); var jsonComponent = serializedComponent.ToJson(reflector); Debug.Log($"[{nameof(SerializeTest)}] Serialized ColliderListTestScript:\n{jsonComponent}"); // Serialize the GameObject with recursive set to true var serialized = reflector.Serialize( go, recursive: true, logger: _logger); var json = serialized.ToJson(reflector); Debug.Log($"[{nameof(SerializeTest)}] Serialized GameObject with null collider list:\n{json}"); // Validate that the serialization completed without errors Assert.IsNotNull(serializedComponent, "Serialized component result should not be null."); Assert.IsNotNull(serializedComponent.fields, "Serialized component fields should not be null."); // Validate that the colliderList field exists in the component var colliderListField = serializedComponent.fields.FirstOrDefault(f => f.name == "colliderList"); Assert.IsNotNull(colliderListField, "colliderList field should be serialized."); var deserializedColliderList = reflector.Deserialize( colliderListField!, typeof(List), logger: _logger) as List; Assert.IsNotNull(deserializedColliderList, "Deserialized collider list should not be null."); var str = string.Join(", ", deserializedColliderList!.Select(c => c == null ? "null" : c.name)); Debug.Log($"[{nameof(SerializeTest)}] deserializedColliderList: {str}"); yield return null; } [UnityTest] public IEnumerator Serialize_GameObject_WithComponent_ListOfDestroyedColliders() { var reflector = UnityMcpPluginEditor.Instance.Reflector ?? throw new System.InvalidOperationException("Reflector should not be null."); // Create a GameObject with the test component var go = new GameObject("TestGameObject_ColliderList"); var component = go.AddComponent(); // Create two GameObjects with colliders var goCapsule = new GameObject("TestGameObject_CapsuleCollider"); var capsuleCollider = goCapsule.AddComponent(); var goBox = new GameObject("TestGameObject_BoxCollider"); var boxCollider = goBox.AddComponent(); // Add the colliders to the list component.colliderList.Add(capsuleCollider); component.colliderList.Add(boxCollider); EditorUtility.SetDirty(go); EditorUtility.SetDirty(component); // Destroy the collider components UnityEngine.Object.DestroyImmediate(capsuleCollider); UnityEngine.Object.DestroyImmediate(boxCollider); // Wait 3 frames to ensure everything is processed yield return null; yield return null; yield return null; var serializedComponent = reflector.Serialize( component, recursive: true, logger: _logger); var jsonComponent = serializedComponent.ToJson(reflector); Debug.Log($"[{nameof(SerializeTest)}] Serialized ColliderListTestScript with destroyed colliders:\n{jsonComponent}"); // Serialize the GameObject with recursive set to true var serialized = reflector.Serialize( go, recursive: true, logger: _logger); var json = serialized.ToJson(reflector); Debug.Log($"[{nameof(SerializeTest)}] Serialized GameObject with destroyed collider list:\n{json}"); // Validate that the serialization completed without errors Assert.IsNotNull(serializedComponent, "Serialized component result should not be null."); Assert.IsNotNull(serializedComponent.fields, "Serialized component fields should not be null."); // Validate that the colliderList field exists in the component var colliderListField = serializedComponent.fields.FirstOrDefault(f => f.name == "colliderList"); Assert.IsNotNull(colliderListField, "colliderList field should be serialized."); var deserializedColliderList = reflector.Deserialize( colliderListField!, typeof(List), logger: _logger) as List; Assert.IsNotNull(deserializedColliderList, "Deserialized collider list should not be null."); var str = string.Join(", ", deserializedColliderList!.Select(c => c == null ? "null" : c.name)); Debug.Log($"[{nameof(SerializeTest)}] deserializedColliderList: {str}"); // Cleanup the additional GameObjects UnityEngine.Object.DestroyImmediate(goCapsule); UnityEngine.Object.DestroyImmediate(goBox); yield return null; } [UnityTest] public IEnumerator Serialize_BoxCollider_ShouldNotContainMaterialField() { var reflector = UnityMcpPluginEditor.Instance.Reflector ?? throw new System.InvalidOperationException("Reflector should not be null."); // Create a GameObject and add BoxCollider component var go = new GameObject("TestGameObject_BoxCollider"); var boxCollider = go.AddComponent(); EditorUtility.SetDirty(go); EditorUtility.SetDirty(boxCollider); // Wait for initialization yield return null; yield return null; yield return null; // Serialize the BoxCollider component var serialized = reflector.Serialize( boxCollider, recursive: true, logger: _logger); var json = serialized.ToJson(reflector); Debug.Log($"[{nameof(SerializeTest)}] Serialized BoxCollider:\n{json}"); // Validate that the serialization completed without errors Assert.IsNotNull(serialized, "Serialized result should not be null."); Assert.IsNotNull(serialized.props, "Serialized properties should not be null."); // Check that no property with name "material" exists (should be ignored by custom reflection converter) var materialProperty = FindMemberByName(serialized.props, "material"); Assert.IsNull(materialProperty, "Property 'material' should not exist in serialized BoxCollider (should be ignored by custom reflection converter)."); // Cleanup UnityEngine.Object.DestroyImmediate(go); yield return null; } [UnityTest] public IEnumerator Converter_ColliderTypes_ShouldUseColliderReflectionConverter() { var reflector = UnityMcpPluginEditor.Instance.Reflector ?? throw new System.InvalidOperationException("Reflector should not be null."); yield return null; // Verify that the correct converter is used for BoxCollider var boxColliderConverter = reflector.Converters.GetConverter(typeof(BoxCollider)); Assert.IsNotNull(boxColliderConverter, "Converter for BoxCollider should not be null."); Assert.IsInstanceOf(boxColliderConverter, "BoxCollider should use UnityEngine_Collider_ReflectionConverter."); // Verify that the correct converter is used for SphereCollider var sphereColliderConverter = reflector.Converters.GetConverter(typeof(SphereCollider)); Assert.IsNotNull(sphereColliderConverter, "Converter for SphereCollider should not be null."); Assert.IsInstanceOf(sphereColliderConverter, "SphereCollider should use UnityEngine_Collider_ReflectionConverter."); // Verify that the correct converter is used for CapsuleCollider var capsuleColliderConverter = reflector.Converters.GetConverter(typeof(CapsuleCollider)); Assert.IsNotNull(capsuleColliderConverter, "Converter for CapsuleCollider should not be null."); Assert.IsInstanceOf(capsuleColliderConverter, "CapsuleCollider should use UnityEngine_Collider_ReflectionConverter."); // Verify that the correct converter is used for MeshCollider var meshColliderConverter = reflector.Converters.GetConverter(typeof(MeshCollider)); Assert.IsNotNull(meshColliderConverter, "Converter for MeshCollider should not be null."); Assert.IsInstanceOf(meshColliderConverter, "MeshCollider should use UnityEngine_Collider_ReflectionConverter."); } private SerializedMember? FindMemberByName(IEnumerable? members, string name) { return members?.FirstOrDefault(member => member.name == name); } } }