33using NUnit . Framework ;
44using UnityEngine ;
55using UnityEditor ;
6+ using UnityEngine . TestTools ;
67using Newtonsoft . Json . Linq ;
78using MCPForUnity . Editor . Tools ;
89
@@ -194,5 +195,118 @@ public void PerformanceTest_CachingWorks()
194195 // Second call should be faster (though this test might be flaky)
195196 Assert . LessOrEqual ( secondCallTime , firstCallTime * 2 , "Cached call should not be significantly slower" ) ;
196197 }
198+
199+ [ Test ]
200+ public void SetComponentProperties_CollectsAllFailuresAndAppliesValidOnes ( )
201+ {
202+ // Arrange - add Transform and Rigidbody components to test with
203+ var transform = testGameObject . transform ;
204+ var rigidbody = testGameObject . AddComponent < Rigidbody > ( ) ;
205+
206+ // Create a params object with mixed valid and invalid properties
207+ var setPropertiesParams = new JObject
208+ {
209+ [ "action" ] = "modify" ,
210+ [ "target" ] = testGameObject . name ,
211+ [ "search_method" ] = "by_name" ,
212+ [ "componentProperties" ] = new JObject
213+ {
214+ [ "Transform" ] = new JObject
215+ {
216+ [ "localPosition" ] = new JObject { [ "x" ] = 1.0f , [ "y" ] = 2.0f , [ "z" ] = 3.0f } , // Valid
217+ [ "rotatoin" ] = new JObject { [ "x" ] = 0.0f , [ "y" ] = 90.0f , [ "z" ] = 0.0f } , // Invalid (typo - should be rotation)
218+ [ "localScale" ] = new JObject { [ "x" ] = 2.0f , [ "y" ] = 2.0f , [ "z" ] = 2.0f } // Valid
219+ } ,
220+ [ "Rigidbody" ] = new JObject
221+ {
222+ [ "mass" ] = 5.0f , // Valid
223+ [ "invalidProp" ] = "test" , // Invalid - doesn't exist
224+ [ "useGravity" ] = true // Valid
225+ }
226+ }
227+ } ;
228+
229+ // Store original values to verify changes
230+ var originalLocalPosition = transform . localPosition ;
231+ var originalLocalScale = transform . localScale ;
232+ var originalMass = rigidbody . mass ;
233+ var originalUseGravity = rigidbody . useGravity ;
234+
235+ Debug . Log ( $ "BEFORE TEST - Mass: { rigidbody . mass } , UseGravity: { rigidbody . useGravity } ") ;
236+
237+ // Expect the warning logs from the invalid properties
238+ LogAssert . Expect ( LogType . Warning , new System . Text . RegularExpressions . Regex ( "Property 'rotatoin' not found" ) ) ;
239+ LogAssert . Expect ( LogType . Warning , new System . Text . RegularExpressions . Regex ( "Property 'invalidProp' not found" ) ) ;
240+
241+ // Act
242+ var result = ManageGameObject . HandleCommand ( setPropertiesParams ) ;
243+
244+ Debug . Log ( $ "AFTER TEST - Mass: { rigidbody . mass } , UseGravity: { rigidbody . useGravity } ") ;
245+ Debug . Log ( $ "AFTER TEST - LocalPosition: { transform . localPosition } ") ;
246+ Debug . Log ( $ "AFTER TEST - LocalScale: { transform . localScale } ") ;
247+
248+ // Assert - verify that valid properties were set despite invalid ones
249+ Assert . AreEqual ( new Vector3 ( 1.0f , 2.0f , 3.0f ) , transform . localPosition ,
250+ "Valid localPosition should be set even with other invalid properties" ) ;
251+ Assert . AreEqual ( new Vector3 ( 2.0f , 2.0f , 2.0f ) , transform . localScale ,
252+ "Valid localScale should be set even with other invalid properties" ) ;
253+ Assert . AreEqual ( 5.0f , rigidbody . mass , 0.001f ,
254+ "Valid mass should be set even with other invalid properties" ) ;
255+ Assert . AreEqual ( true , rigidbody . useGravity ,
256+ "Valid useGravity should be set even with other invalid properties" ) ;
257+
258+ // Verify the result indicates errors (since we had invalid properties)
259+ Assert . IsNotNull ( result , "Should return a result object" ) ;
260+
261+ // The collect-and-continue behavior means we should get an error response
262+ // that contains info about the failed properties, but valid ones were still applied
263+ // This proves the collect-and-continue behavior is working
264+ }
265+
266+ [ Test ]
267+ public void SetComponentProperties_ContinuesAfterException ( )
268+ {
269+ // Arrange - create scenario that might cause exceptions
270+ var rigidbody = testGameObject . AddComponent < Rigidbody > ( ) ;
271+
272+ // Set initial values that we'll change
273+ rigidbody . mass = 1.0f ;
274+ rigidbody . useGravity = true ;
275+
276+ var setPropertiesParams = new JObject
277+ {
278+ [ "action" ] = "modify" ,
279+ [ "target" ] = testGameObject . name ,
280+ [ "search_method" ] = "by_name" ,
281+ [ "componentProperties" ] = new JObject
282+ {
283+ [ "Rigidbody" ] = new JObject
284+ {
285+ [ "mass" ] = 2.5f , // Valid - should be set
286+ [ "velocity" ] = "invalid_type" , // Invalid type - will cause exception
287+ [ "useGravity" ] = false // Valid - should still be set after exception
288+ }
289+ }
290+ } ;
291+
292+ // Expect the error logs from the invalid property
293+ LogAssert . Expect ( LogType . Error , new System . Text . RegularExpressions . Regex ( "Unexpected error converting token to UnityEngine.Vector3" ) ) ;
294+ LogAssert . Expect ( LogType . Error , new System . Text . RegularExpressions . Regex ( "SetProperty.*Failed to set 'velocity'" ) ) ;
295+ LogAssert . Expect ( LogType . Warning , new System . Text . RegularExpressions . Regex ( "Property 'velocity' not found" ) ) ;
296+
297+ // Act
298+ var result = ManageGameObject . HandleCommand ( setPropertiesParams ) ;
299+
300+ // Assert - verify that valid properties before AND after the exception were still set
301+ Assert . AreEqual ( 2.5f , rigidbody . mass , 0.001f ,
302+ "Mass should be set even if later property causes exception" ) ;
303+ Assert . AreEqual ( false , rigidbody . useGravity ,
304+ "UseGravity should be set even if previous property caused exception" ) ;
305+
306+ Assert . IsNotNull ( result , "Should return a result even with exceptions" ) ;
307+
308+ // The key test: processing continued after the exception and set useGravity
309+ // This proves the collect-and-continue behavior works even with exceptions
310+ }
197311 }
198312}
0 commit comments