unity-mcp/TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ManageGameObjectTests.cs

560 lines
26 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
Payload-safe paging for hierarchy/components + safer asset search + docs (#490) * Fix test teardown to avoid dropping MCP bridge CodexConfigHelperTests was calling MCPServiceLocator.Reset() in TearDown, which disposes the active bridge/transport during MCP-driven test runs. Replace with restoring only the mutated service (IPlatformService). * Avoid leaking PlatformService in CodexConfigHelperTests Capture the original IPlatformService before this fixture runs and restore it in TearDown. This preserves the MCP connection safety fix (no MCPServiceLocator.Reset()) while avoiding global state leakage to subsequent tests. * Fix SO MCP tooling: validate folder roots, normalize paths, expand tests; remove vestigial SO tools * Remove UnityMCPTests stress artifacts and ignore Assets/Temp * Ignore UnityMCPTests Assets/Temp only * Clarify array_resize fallback logic comments * Refactor: simplify action set and reuse slash sanitization * Enhance: preserve GUID on overwrite & support Vector/Color types in ScriptableObject tools * Fix: ensure asset name matches filename to suppress Unity warnings * Fix: resolve Unity warnings by ensuring asset name match and removing redundant import * Refactor: Validate assetName, strict object parsing for vectors, remove broken SO logic from ManageAsset * Hardening: reject Windows drive paths; clarify supported asset types * Delete FixscriptableobjecPlan.md * Paginate get_hierarchy and get_components to prevent large payload crashes * dev: add uvx dev-mode refresh + safer HTTP stop; fix server typing eval * Payload-safe paging defaults + docs; harden asset search; stabilize Codex tests * chore: align uvx args + coercion helpers; tighten safety guidance * chore: minor cleanup + stabilize EditMode SO tests
2025-12-29 12:57:57 +08:00
using System.Linq;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Newtonsoft.Json.Linq;
using MCPForUnity.Editor.Tools;
namespace MCPForUnityTests.Editor.Tools
{
public class ManageGameObjectTests
{
private GameObject testGameObject;
2025-10-01 04:25:33 +08:00
[SetUp]
public void SetUp()
{
// Create a test GameObject for each test
testGameObject = new GameObject("TestObject");
}
2025-10-01 04:25:33 +08:00
[TearDown]
public void TearDown()
{
// Clean up test GameObject
if (testGameObject != null)
{
UnityEngine.Object.DestroyImmediate(testGameObject);
}
}
[Test]
public void HandleCommand_ReturnsError_ForNullParams()
{
var result = ManageGameObject.HandleCommand(null);
2025-10-01 04:25:33 +08:00
Assert.IsNotNull(result, "Should return a result object");
// Note: Actual error checking would need access to Response structure
}
2025-10-01 04:25:33 +08:00
[Test]
public void HandleCommand_ReturnsError_ForEmptyParams()
{
var emptyParams = new JObject();
var result = ManageGameObject.HandleCommand(emptyParams);
2025-10-01 04:25:33 +08:00
Assert.IsNotNull(result, "Should return a result object for empty params");
}
[Test]
public void HandleCommand_ProcessesValidCreateAction()
{
var createParams = new JObject
{
["action"] = "create",
["name"] = "TestCreateObject"
};
2025-10-01 04:25:33 +08:00
var result = ManageGameObject.HandleCommand(createParams);
2025-10-01 04:25:33 +08:00
Assert.IsNotNull(result, "Should return a result for valid create action");
2025-10-01 04:25:33 +08:00
// Clean up - find and destroy the created object
var createdObject = GameObject.Find("TestCreateObject");
if (createdObject != null)
{
UnityEngine.Object.DestroyImmediate(createdObject);
}
}
[Test]
public void ComponentResolver_Integration_WorksWithRealComponents()
{
// Test that our ComponentResolver works with actual Unity components
var transformResult = ComponentResolver.TryResolve("Transform", out Type transformType, out string error);
2025-10-01 04:25:33 +08:00
Assert.IsTrue(transformResult, "Should resolve Transform component");
Assert.AreEqual(typeof(Transform), transformType, "Should return correct Transform type");
Assert.IsEmpty(error, "Should have no error for valid component");
}
[Test]
public void ComponentResolver_Integration_WorksWithBuiltInComponents()
{
var components = new[]
{
("Rigidbody", typeof(Rigidbody)),
2025-10-01 04:25:33 +08:00
("Collider", typeof(Collider)),
("Renderer", typeof(Renderer)),
("Camera", typeof(Camera)),
("Light", typeof(Light))
};
foreach (var (componentName, expectedType) in components)
{
var result = ComponentResolver.TryResolve(componentName, out Type actualType, out string error);
2025-10-01 04:25:33 +08:00
// Some components might not resolve (abstract classes), but the method should handle gracefully
if (result)
{
2025-10-01 04:25:33 +08:00
Assert.IsTrue(expectedType.IsAssignableFrom(actualType),
$"{componentName} should resolve to assignable type");
}
else
{
Assert.IsNotEmpty(error, $"Should have error message for {componentName}");
}
}
}
[Test]
public void PropertyMatching_Integration_WorksWithRealGameObject()
{
// Add a Rigidbody to test real property matching
var rigidbody = testGameObject.AddComponent<Rigidbody>();
2025-10-01 04:25:33 +08:00
var properties = ComponentResolver.GetAllComponentProperties(typeof(Rigidbody));
2025-10-01 04:25:33 +08:00
Assert.IsNotEmpty(properties, "Rigidbody should have properties");
Assert.Contains("mass", properties, "Rigidbody should have mass property");
Assert.Contains("useGravity", properties, "Rigidbody should have useGravity property");
2025-10-01 04:25:33 +08:00
// Test AI suggestions
var suggestions = ComponentResolver.GetAIPropertySuggestions("Use Gravity", properties);
Assert.Contains("useGravity", suggestions, "Should suggest useGravity for 'Use Gravity'");
}
[Test]
public void PropertyMatching_HandlesMonoBehaviourProperties()
{
var properties = ComponentResolver.GetAllComponentProperties(typeof(MonoBehaviour));
2025-10-01 04:25:33 +08:00
Assert.IsNotEmpty(properties, "MonoBehaviour should have properties");
Assert.Contains("enabled", properties, "MonoBehaviour should have enabled property");
Assert.Contains("name", properties, "MonoBehaviour should have name property");
Assert.Contains("tag", properties, "MonoBehaviour should have tag property");
}
2025-10-01 04:25:33 +08:00
[Test]
public void PropertyMatching_HandlesCaseVariations()
{
var testProperties = new List<string> { "maxReachDistance", "playerHealth", "movementSpeed" };
2025-10-01 04:25:33 +08:00
var testCases = new[]
{
("max reach distance", "maxReachDistance"),
("Max Reach Distance", "maxReachDistance"),
("MAX_REACH_DISTANCE", "maxReachDistance"),
("player health", "playerHealth"),
("movement speed", "movementSpeed")
};
foreach (var (input, expected) in testCases)
{
var suggestions = ComponentResolver.GetAIPropertySuggestions(input, testProperties);
Assert.Contains(expected, suggestions, $"Should suggest {expected} for input '{input}'");
}
}
[Test]
public void ErrorHandling_ReturnsHelpfulMessages()
{
// This test verifies that error messages are helpful and contain suggestions
var testProperties = new List<string> { "mass", "velocity", "drag", "useGravity" };
var suggestions = ComponentResolver.GetAIPropertySuggestions("weight", testProperties);
2025-10-01 04:25:33 +08:00
// Even if no perfect match, should return valid list
Assert.IsNotNull(suggestions, "Should return valid suggestions list");
2025-10-01 04:25:33 +08:00
// Test with completely invalid input
var badSuggestions = ComponentResolver.GetAIPropertySuggestions("xyz123invalid", testProperties);
Assert.IsNotNull(badSuggestions, "Should handle invalid input gracefully");
}
[Test]
public void PerformanceTest_CachingWorks()
{
var properties = ComponentResolver.GetAllComponentProperties(typeof(Transform));
var input = "Test Property Name";
2025-10-01 04:25:33 +08:00
// First call - populate cache
var startTime = System.DateTime.UtcNow;
var suggestions1 = ComponentResolver.GetAIPropertySuggestions(input, properties);
var firstCallTime = (System.DateTime.UtcNow - startTime).TotalMilliseconds;
2025-10-01 04:25:33 +08:00
// Second call - should use cache
startTime = System.DateTime.UtcNow;
var suggestions2 = ComponentResolver.GetAIPropertySuggestions(input, properties);
var secondCallTime = (System.DateTime.UtcNow - startTime).TotalMilliseconds;
2025-10-01 04:25:33 +08:00
Assert.AreEqual(suggestions1.Count, suggestions2.Count, "Cached results should be identical");
CollectionAssert.AreEqual(suggestions1, suggestions2, "Cached results should match exactly");
2025-10-01 04:25:33 +08:00
// Second call should be faster (though this test might be flaky)
Assert.LessOrEqual(secondCallTime, firstCallTime * 2, "Cached call should not be significantly slower");
}
[Test]
public void SetComponentProperties_CollectsAllFailuresAndAppliesValidOnes()
{
// Arrange - add Transform and Rigidbody components to test with
var transform = testGameObject.transform;
var rigidbody = testGameObject.AddComponent<Rigidbody>();
2025-10-01 04:25:33 +08:00
// Create a params object with mixed valid and invalid properties
var setPropertiesParams = new JObject
{
["action"] = "modify",
["target"] = testGameObject.name,
2025-10-01 04:25:33 +08:00
["search_method"] = "by_name",
["componentProperties"] = new JObject
{
["Transform"] = new JObject
{
["localPosition"] = new JObject { ["x"] = 1.0f, ["y"] = 2.0f, ["z"] = 3.0f }, // Valid
["rotatoin"] = new JObject { ["x"] = 0.0f, ["y"] = 90.0f, ["z"] = 0.0f }, // Invalid (typo - should be rotation)
["localScale"] = new JObject { ["x"] = 2.0f, ["y"] = 2.0f, ["z"] = 2.0f } // Valid
},
2025-10-01 04:25:33 +08:00
["Rigidbody"] = new JObject
{
["mass"] = 5.0f, // Valid
["invalidProp"] = "test", // Invalid - doesn't exist
["useGravity"] = true // Valid
}
}
};
// Store original values to verify changes
var originalLocalPosition = transform.localPosition;
var originalLocalScale = transform.localScale;
var originalMass = rigidbody.mass;
var originalUseGravity = rigidbody.useGravity;
2025-10-01 04:25:33 +08:00
Debug.Log($"BEFORE TEST - Mass: {rigidbody.mass}, UseGravity: {rigidbody.useGravity}");
// Expect the warning logs from the invalid properties
LogAssert.Expect(LogType.Warning, new System.Text.RegularExpressions.Regex("Property 'rotatoin' not found"));
LogAssert.Expect(LogType.Warning, new System.Text.RegularExpressions.Regex("Property 'invalidProp' not found"));
// Act
var result = ManageGameObject.HandleCommand(setPropertiesParams);
2025-10-01 04:25:33 +08:00
Debug.Log($"AFTER TEST - Mass: {rigidbody.mass}, UseGravity: {rigidbody.useGravity}");
Debug.Log($"AFTER TEST - LocalPosition: {transform.localPosition}");
Debug.Log($"AFTER TEST - LocalScale: {transform.localScale}");
// Assert - verify that valid properties were set despite invalid ones
2025-10-01 04:25:33 +08:00
Assert.AreEqual(new Vector3(1.0f, 2.0f, 3.0f), transform.localPosition,
"Valid localPosition should be set even with other invalid properties");
Assert.AreEqual(new Vector3(2.0f, 2.0f, 2.0f), transform.localScale,
"Valid localScale should be set even with other invalid properties");
Assert.AreEqual(5.0f, rigidbody.mass, 0.001f,
"Valid mass should be set even with other invalid properties");
Assert.AreEqual(true, rigidbody.useGravity,
"Valid useGravity should be set even with other invalid properties");
// Verify the result indicates errors (since we had invalid properties)
Assert.IsNotNull(result, "Should return a result object");
2025-10-01 04:25:33 +08:00
// The collect-and-continue behavior means we should get an error response
// that contains info about the failed properties, but valid ones were still applied
// This proves the collect-and-continue behavior is working
// Harden: verify structured error response with failures list contains both invalid fields
var successProp = result.GetType().GetProperty("success");
Assert.IsNotNull(successProp, "Result should expose 'success' property");
Assert.IsFalse((bool)successProp.GetValue(result), "Result.success should be false for partial failure");
var dataProp = result.GetType().GetProperty("data");
Assert.IsNotNull(dataProp, "Result should include 'data' with errors");
var dataVal = dataProp.GetValue(result);
Assert.IsNotNull(dataVal, "Result.data should not be null");
var errorsProp = dataVal.GetType().GetProperty("errors");
Assert.IsNotNull(errorsProp, "Result.data should include 'errors' list");
var errorsEnum = errorsProp.GetValue(dataVal) as System.Collections.IEnumerable;
Assert.IsNotNull(errorsEnum, "errors should be enumerable");
bool foundRotatoin = false;
bool foundInvalidProp = false;
foreach (var err in errorsEnum)
{
string s = err?.ToString() ?? string.Empty;
if (s.Contains("rotatoin")) foundRotatoin = true;
if (s.Contains("invalidProp")) foundInvalidProp = true;
}
Assert.IsTrue(foundRotatoin, "errors should mention the misspelled 'rotatoin' property");
Assert.IsTrue(foundInvalidProp, "errors should mention the 'invalidProp' property");
}
2025-10-01 04:25:33 +08:00
[Test]
public void SetComponentProperties_ContinuesAfterException()
{
// Arrange - create scenario that might cause exceptions
var rigidbody = testGameObject.AddComponent<Rigidbody>();
2025-10-01 04:25:33 +08:00
// Set initial values that we'll change
rigidbody.mass = 1.0f;
rigidbody.useGravity = true;
2025-10-01 04:25:33 +08:00
var setPropertiesParams = new JObject
{
["action"] = "modify",
["target"] = testGameObject.name,
["search_method"] = "by_name",
["componentProperties"] = new JObject
{
["Rigidbody"] = new JObject
{
["mass"] = 2.5f, // Valid - should be set
["velocity"] = "invalid_type", // Invalid type - will cause exception
["useGravity"] = false // Valid - should still be set after exception
}
}
};
// Expect the error logs from the invalid property
LogAssert.Expect(LogType.Error, new System.Text.RegularExpressions.Regex("Unexpected error converting token to UnityEngine.Vector3"));
LogAssert.Expect(LogType.Error, new System.Text.RegularExpressions.Regex("SetProperty.*Failed to set 'velocity'"));
LogAssert.Expect(LogType.Warning, new System.Text.RegularExpressions.Regex("Property 'velocity' not found"));
// Act
var result = ManageGameObject.HandleCommand(setPropertiesParams);
// Assert - verify that valid properties before AND after the exception were still set
Assert.AreEqual(2.5f, rigidbody.mass, 0.001f,
"Mass should be set even if later property causes exception");
Assert.AreEqual(false, rigidbody.useGravity,
"UseGravity should be set even if previous property caused exception");
Assert.IsNotNull(result, "Should return a result even with exceptions");
2025-10-01 04:25:33 +08:00
// The key test: processing continued after the exception and set useGravity
// This proves the collect-and-continue behavior works even with exceptions
// Harden: verify structured error response contains velocity failure
var successProp2 = result.GetType().GetProperty("success");
Assert.IsNotNull(successProp2, "Result should expose 'success' property");
Assert.IsFalse((bool)successProp2.GetValue(result), "Result.success should be false when an exception occurs for a property");
var dataProp2 = result.GetType().GetProperty("data");
Assert.IsNotNull(dataProp2, "Result should include 'data' with errors");
var dataVal2 = dataProp2.GetValue(result);
Assert.IsNotNull(dataVal2, "Result.data should not be null");
var errorsProp2 = dataVal2.GetType().GetProperty("errors");
Assert.IsNotNull(errorsProp2, "Result.data should include 'errors' list");
var errorsEnum2 = errorsProp2.GetValue(dataVal2) as System.Collections.IEnumerable;
Assert.IsNotNull(errorsEnum2, "errors should be enumerable");
bool foundVelocityError = false;
foreach (var err in errorsEnum2)
{
string s = err?.ToString() ?? string.Empty;
if (s.Contains("velocity")) { foundVelocityError = true; break; }
}
Assert.IsTrue(foundVelocityError, "errors should include a message referencing 'velocity'");
}
Fix material mesh instantiation warnings (#331) * Editor: prevent material/mesh instantiation in edit mode - GameObjectSerializer: in edit mode, normalize material/mesh access - material -> sharedMaterial - materials -> sharedMaterials - mesh -> sharedMesh - also guard materials/sharedMaterial/sharedMaterials property names - Tests: add strong instanceID equality checks for Renderer/MeshFilter - prove no instantiation by shared instanceID before/after - cover multi-material, null cases; prune brittle presence/console tests - Clean up and relax ManageGameObject tests to avoid false negatives * Address review: simplify edit-mode guard; include protected/internal [SerializeField]; fix tests to destroy temp primitives and use dictionary access; strengthen instanceID assertions * Fix resource leaks in test files - ManageGameObjectTests.cs: Destroy temporary primitive GameObject after extracting sharedMesh - MaterialMeshInstantiationTests.cs: Destroy instantiated uniqueMesh after test completion These fixes prevent resource leaks in Unity test files by properly cleaning up temporary objects created during tests. * Fix reflection bug in GetComponentData tests - Replace incorrect reflection-based field access with proper dictionary key access - GetComponentData() returns Dictionary<string, object> where 'properties' is a key, not a field - Tests now properly access the properties dictionary and run assertions - Fixes ineffective tests that were silently failing due to reflection returning null
2025-10-21 09:34:33 +08:00
[Test]
public void GetComponentData_DoesNotInstantiateMaterialsInEditMode()
{
// Arrange - Create a GameObject with MeshRenderer and MeshFilter components
var testObject = new GameObject("MaterialMeshTestObject");
var meshRenderer = testObject.AddComponent<MeshRenderer>();
var meshFilter = testObject.AddComponent<MeshFilter>();
// Create a simple material and mesh for testing
var testMaterial = new Material(Shader.Find("Standard"));
var tempCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
var testMesh = tempCube.GetComponent<MeshFilter>().sharedMesh;
UnityEngine.Object.DestroyImmediate(tempCube);
// Set the shared material and mesh (these should be used in edit mode)
meshRenderer.sharedMaterial = testMaterial;
meshFilter.sharedMesh = testMesh;
// Act - Get component data which should trigger material/mesh property access
var prevIgnore = LogAssert.ignoreFailingMessages;
LogAssert.ignoreFailingMessages = true; // Avoid failing due to incidental editor logs during reflection
object result;
try
{
result = MCPForUnity.Editor.Helpers.GameObjectSerializer.GetComponentData(meshRenderer);
}
finally
{
LogAssert.ignoreFailingMessages = prevIgnore;
}
// Assert - Basic success and shape tolerance
Assert.IsNotNull(result, "GetComponentData should return a result");
if (result is Dictionary<string, object> dict &&
dict.TryGetValue("properties", out var propsObj) &&
propsObj is Dictionary<string, object> properties)
{
Assert.IsTrue(properties.ContainsKey("material") || properties.ContainsKey("sharedMaterial") || properties.ContainsKey("materials") || properties.ContainsKey("sharedMaterials"),
"Serialized data should include a material-related key when present.");
}
// Clean up
UnityEngine.Object.DestroyImmediate(testMaterial);
UnityEngine.Object.DestroyImmediate(testObject);
}
[Test]
public void GetComponentData_DoesNotInstantiateMeshesInEditMode()
{
// Arrange - Create a GameObject with MeshFilter component
var testObject = new GameObject("MeshTestObject");
var meshFilter = testObject.AddComponent<MeshFilter>();
// Create a simple mesh for testing
var tempSphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
var testMesh = tempSphere.GetComponent<MeshFilter>().sharedMesh;
UnityEngine.Object.DestroyImmediate(tempSphere);
meshFilter.sharedMesh = testMesh;
// Act - Get component data which should trigger mesh property access
var prevIgnore2 = LogAssert.ignoreFailingMessages;
LogAssert.ignoreFailingMessages = true;
object result;
try
{
result = MCPForUnity.Editor.Helpers.GameObjectSerializer.GetComponentData(meshFilter);
}
finally
{
LogAssert.ignoreFailingMessages = prevIgnore2;
}
// Assert - Basic success and shape tolerance
Assert.IsNotNull(result, "GetComponentData should return a result");
if (result is Dictionary<string, object> dict2 &&
dict2.TryGetValue("properties", out var propsObj2) &&
propsObj2 is Dictionary<string, object> properties2)
{
Assert.IsTrue(properties2.ContainsKey("mesh") || properties2.ContainsKey("sharedMesh"),
"Serialized data should include a mesh-related key when present.");
}
// Clean up
UnityEngine.Object.DestroyImmediate(testObject);
}
[Test]
public void GetComponentData_UsesSharedMaterialInEditMode()
{
// Arrange - Create a GameObject with MeshRenderer
var testObject = new GameObject("SharedMaterialTestObject");
var meshRenderer = testObject.AddComponent<MeshRenderer>();
// Create a test material
var testMaterial = new Material(Shader.Find("Standard"));
testMaterial.name = "TestMaterial";
meshRenderer.sharedMaterial = testMaterial;
// Act - Get component data in edit mode
var result = MCPForUnity.Editor.Helpers.GameObjectSerializer.GetComponentData(meshRenderer);
// Assert - Verify that the material property was accessed without instantiation
Assert.IsNotNull(result, "GetComponentData should return a result");
// Check that result is a dictionary with properties key
if (result is Dictionary<string, object> resultDict &&
resultDict.TryGetValue("properties", out var propertiesObj) &&
propertiesObj is Dictionary<string, object> properties)
{
Assert.IsTrue(properties.ContainsKey("material") || properties.ContainsKey("sharedMaterial"),
"Serialized data should include 'material' or 'sharedMaterial' when present.");
}
// Clean up
UnityEngine.Object.DestroyImmediate(testMaterial);
UnityEngine.Object.DestroyImmediate(testObject);
}
[Test]
public void GetComponentData_UsesSharedMeshInEditMode()
{
// Arrange - Create a GameObject with MeshFilter
var testObject = new GameObject("SharedMeshTestObject");
var meshFilter = testObject.AddComponent<MeshFilter>();
// Create a test mesh
var tempCylinder = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
var testMesh = tempCylinder.GetComponent<MeshFilter>().sharedMesh;
UnityEngine.Object.DestroyImmediate(tempCylinder);
testMesh.name = "TestMesh";
meshFilter.sharedMesh = testMesh;
// Act - Get component data in edit mode
var result = MCPForUnity.Editor.Helpers.GameObjectSerializer.GetComponentData(meshFilter);
// Assert - Verify that the mesh property was accessed without instantiation
Assert.IsNotNull(result, "GetComponentData should return a result");
// Check that result is a dictionary with properties key
if (result is Dictionary<string, object> resultDict &&
resultDict.TryGetValue("properties", out var propertiesObj) &&
propertiesObj is Dictionary<string, object> properties)
{
Assert.IsTrue(properties.ContainsKey("mesh") || properties.ContainsKey("sharedMesh"),
"Serialized data should include 'mesh' or 'sharedMesh' when present.");
}
// Clean up
UnityEngine.Object.DestroyImmediate(testObject);
}
[Test]
public void GetComponentData_HandlesNullMaterialsAndMeshes()
{
// Arrange - Create a GameObject with MeshRenderer and MeshFilter but no materials/meshes
var testObject = new GameObject("NullMaterialMeshTestObject");
var meshRenderer = testObject.AddComponent<MeshRenderer>();
var meshFilter = testObject.AddComponent<MeshFilter>();
// Don't set any materials or meshes - they should be null
// Act - Get component data
var rendererResult = MCPForUnity.Editor.Helpers.GameObjectSerializer.GetComponentData(meshRenderer);
var meshFilterResult = MCPForUnity.Editor.Helpers.GameObjectSerializer.GetComponentData(meshFilter);
// Assert - Verify that the operations succeeded even with null materials/meshes
Assert.IsNotNull(rendererResult, "GetComponentData should handle null materials");
Assert.IsNotNull(meshFilterResult, "GetComponentData should handle null meshes");
// Clean up
UnityEngine.Object.DestroyImmediate(testObject);
}
[Test]
public void GetComponentData_WorksWithMultipleMaterials()
{
// Arrange - Create a GameObject with MeshRenderer that has multiple materials
var testObject = new GameObject("MultiMaterialTestObject");
var meshRenderer = testObject.AddComponent<MeshRenderer>();
// Create multiple test materials
var material1 = new Material(Shader.Find("Standard"));
material1.name = "TestMaterial1";
var material2 = new Material(Shader.Find("Standard"));
material2.name = "TestMaterial2";
meshRenderer.sharedMaterials = new Material[] { material1, material2 };
// Act - Get component data
var result = MCPForUnity.Editor.Helpers.GameObjectSerializer.GetComponentData(meshRenderer);
// Assert - Verify that the operation succeeded with multiple materials
Assert.IsNotNull(result, "GetComponentData should handle multiple materials");
// Clean up
UnityEngine.Object.DestroyImmediate(material1);
UnityEngine.Object.DestroyImmediate(material2);
UnityEngine.Object.DestroyImmediate(testObject);
}
}
2025-10-01 04:25:33 +08:00
}