1+ using System ;
2+ using System . IO ;
3+ using Newtonsoft . Json . Linq ;
4+ using NUnit . Framework ;
5+ using UnityEditor ;
6+ using UnityEngine ;
7+ using MCPForUnity . Editor . Tools ;
8+
9+ namespace MCPForUnityTests . Editor . Tools
10+ {
11+ public class MaterialParameterToolTests
12+ {
13+ private const string TempRoot = "Assets/Temp/MaterialParameterToolTests" ;
14+ private string _matPath ; // unique per test run
15+ private GameObject _sphere ;
16+
17+ [ SetUp ]
18+ public void SetUp ( )
19+ {
20+ _matPath = $ "{ TempRoot } /BlueURP_{ Guid . NewGuid ( ) . ToString ( "N" ) } .mat";
21+ if ( ! AssetDatabase . IsValidFolder ( "Assets/Temp" ) )
22+ {
23+ AssetDatabase . CreateFolder ( "Assets" , "Temp" ) ;
24+ }
25+ if ( ! AssetDatabase . IsValidFolder ( TempRoot ) )
26+ {
27+ AssetDatabase . CreateFolder ( "Assets/Temp" , "MaterialParameterToolTests" ) ;
28+ }
29+ // Ensure any leftover material from previous runs is removed
30+ if ( AssetDatabase . LoadAssetAtPath < UnityEngine . Object > ( _matPath ) != null )
31+ {
32+ AssetDatabase . DeleteAsset ( _matPath ) ;
33+ AssetDatabase . Refresh ( ) ;
34+ }
35+ // Hard-delete any stray files on disk (in case GUID lookup fails)
36+ var abs = Path . Combine ( Directory . GetCurrentDirectory ( ) , _matPath ) ;
37+ try
38+ {
39+ if ( File . Exists ( abs ) ) File . Delete ( abs ) ;
40+ if ( File . Exists ( abs + ".meta" ) ) File . Delete ( abs + ".meta" ) ;
41+ }
42+ catch { /* best-effort cleanup */ }
43+ AssetDatabase . Refresh ( ) ;
44+ }
45+
46+ [ TearDown ]
47+ public void TearDown ( )
48+ {
49+ if ( _sphere != null )
50+ {
51+ UnityEngine . Object . DestroyImmediate ( _sphere ) ;
52+ _sphere = null ;
53+ }
54+ if ( AssetDatabase . LoadAssetAtPath < Material > ( _matPath ) != null )
55+ {
56+ AssetDatabase . DeleteAsset ( _matPath ) ;
57+ }
58+ AssetDatabase . Refresh ( ) ;
59+ }
60+
61+ private static JObject ToJObject ( object result )
62+ {
63+ return result as JObject ?? JObject . FromObject ( result ) ;
64+ }
65+
66+ [ Test ]
67+ public void CreateMaterial_WithObjectProperties_SucceedsAndSetsColor ( )
68+ {
69+ // Ensure a clean state if a previous run left the asset behind (uses _matPath now)
70+ if ( AssetDatabase . LoadAssetAtPath < UnityEngine . Object > ( _matPath ) != null )
71+ {
72+ AssetDatabase . DeleteAsset ( _matPath ) ;
73+ AssetDatabase . Refresh ( ) ;
74+ }
75+ var createParams = new JObject
76+ {
77+ [ "action" ] = "create" ,
78+ [ "path" ] = _matPath ,
79+ [ "assetType" ] = "Material" ,
80+ [ "properties" ] = new JObject
81+ {
82+ [ "shader" ] = "Universal Render Pipeline/Lit" ,
83+ [ "color" ] = new JArray ( 0f , 0f , 1f , 1f )
84+ }
85+ } ;
86+
87+ var result = ToJObject ( ManageAsset . HandleCommand ( createParams ) ) ;
88+ Assert . IsTrue ( result . Value < bool > ( "success" ) , result . Value < string > ( "error" ) ) ;
89+
90+ var mat = AssetDatabase . LoadAssetAtPath < Material > ( _matPath ) ;
91+ Assert . IsNotNull ( mat , "Material should exist at path." ) ;
92+ // Verify color if shader exposes _Color
93+ if ( mat . HasProperty ( "_Color" ) )
94+ {
95+ Assert . AreEqual ( Color . blue , mat . GetColor ( "_Color" ) ) ;
96+ }
97+ }
98+
99+ [ Test ]
100+ public void AssignMaterial_ToSphere_UsingComponentPropertiesObject_Succeeds ( )
101+ {
102+ // Ensure material exists first
103+ CreateMaterial_WithObjectProperties_SucceedsAndSetsColor ( ) ;
104+
105+ // Create a sphere via handler
106+ var createGo = new JObject
107+ {
108+ [ "action" ] = "create" ,
109+ [ "name" ] = "ToolTestSphere" ,
110+ [ "primitiveType" ] = "Sphere"
111+ } ;
112+ var createGoResult = ToJObject ( ManageGameObject . HandleCommand ( createGo ) ) ;
113+ Assert . IsTrue ( createGoResult . Value < bool > ( "success" ) , createGoResult . Value < string > ( "error" ) ) ;
114+
115+ _sphere = GameObject . Find ( "ToolTestSphere" ) ;
116+ Assert . IsNotNull ( _sphere , "Sphere should be created." ) ;
117+
118+ // Assign material via object-typed componentProperties
119+ var modifyParams = new JObject
120+ {
121+ [ "action" ] = "modify" ,
122+ [ "target" ] = "ToolTestSphere" ,
123+ [ "searchMethod" ] = "by_name" ,
124+ [ "componentProperties" ] = new JObject
125+ {
126+ [ "MeshRenderer" ] = new JObject
127+ {
128+ [ "sharedMaterial" ] = _matPath
129+ }
130+ }
131+ } ;
132+
133+ var modifyResult = ToJObject ( ManageGameObject . HandleCommand ( modifyParams ) ) ;
134+ Assert . IsTrue ( modifyResult . Value < bool > ( "success" ) , modifyResult . Value < string > ( "error" ) ) ;
135+
136+ var renderer = _sphere . GetComponent < MeshRenderer > ( ) ;
137+ Assert . IsNotNull ( renderer , "Sphere should have MeshRenderer." ) ;
138+ Assert . IsNotNull ( renderer . sharedMaterial , "sharedMaterial should be assigned." ) ;
139+ StringAssert . StartsWith ( "BlueURP_" , renderer . sharedMaterial . name ) ;
140+ }
141+
142+ [ Test ]
143+ public void ReadRendererData_DoesNotInstantiateMaterial_AndIncludesSharedMaterial ( )
144+ {
145+ // Prepare object and assignment
146+ AssignMaterial_ToSphere_UsingComponentPropertiesObject_Succeeds ( ) ;
147+
148+ var renderer = _sphere . GetComponent < MeshRenderer > ( ) ;
149+ int beforeId = renderer . sharedMaterial != null ? renderer . sharedMaterial . GetInstanceID ( ) : 0 ;
150+
151+ var data = MCPForUnity . Editor . Helpers . GameObjectSerializer . GetComponentData ( renderer ) as System . Collections . Generic . Dictionary < string , object > ;
152+ Assert . IsNotNull ( data , "Serializer should return data." ) ;
153+
154+ int afterId = renderer . sharedMaterial != null ? renderer . sharedMaterial . GetInstanceID ( ) : 0 ;
155+ Assert . AreEqual ( beforeId , afterId , "sharedMaterial instance must not change (no instantiation in EditMode)." ) ;
156+
157+ if ( data . TryGetValue ( "properties" , out var propsObj ) && propsObj is System . Collections . Generic . Dictionary < string , object > props )
158+ {
159+ Assert . IsTrue (
160+ props . ContainsKey ( "sharedMaterial" ) || props . ContainsKey ( "material" ) || props . ContainsKey ( "sharedMaterials" ) || props . ContainsKey ( "materials" ) ,
161+ "Serialized data should include material info." ) ;
162+ }
163+ }
164+ }
165+ }
0 commit comments