2003-05-12 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / corlib / Test / System.Reflection.Emit / MethodBuilderTest.cs
1 //\r
2 // MethodBuilderTest.cs - NUnit Test Cases for the MethodBuilder class\r
3 //\r
4 // Zoltan Varga (vargaz@freemail.hu)\r
5 //\r
6 // (C) Ximian, Inc.  http://www.ximian.com\r
7 \r
8 // TODO:\r
9 //  - implement 'Signature' (what the hell it does???) and test it\r
10 //  - implement Equals and test it\r
11 //  - AddDeclarativeSecurity\r
12 \r
13 using System;\r
14 using System.Threading;\r
15 using System.Reflection;\r
16 using System.Reflection.Emit;\r
17 using System.Runtime.CompilerServices;\r
18 \r
19 using NUnit.Framework;\r
20 \r
21 namespace MonoTests.System.Reflection.Emit\r
22 {\r
23 \r
24 [TestFixture]\r
25 public class MethodBuilderTest : Assertion\r
26 {       \r
27     private TypeBuilder genClass;\r
28 \r
29         private ModuleBuilder module;\r
30 \r
31         [SetUp]\r
32         protected void SetUp () {\r
33                 AssemblyName assemblyName = new AssemblyName();\r
34                 assemblyName.Name = "MonoTests.System.Reflection.Emit.MethodBuilderTest";\r
35 \r
36                 AssemblyBuilder assembly \r
37                         = Thread.GetDomain().DefineDynamicAssembly(\r
38                                 assemblyName, AssemblyBuilderAccess.Run);\r
39 \r
40                 module = assembly.DefineDynamicModule("module1");\r
41                 \r
42                 genClass = module.DefineType("class1", \r
43                                                                          TypeAttributes.Public);\r
44         }\r
45 \r
46         static int methodIndexer = 0;\r
47 \r
48         // Return a unique method name\r
49         private string genMethodName () {\r
50                 return "m" + (methodIndexer ++);\r
51         }\r
52 \r
53         public void TestAttributes () {\r
54                 MethodBuilder mb = genClass.DefineMethod (\r
55                         genMethodName (), MethodAttributes.Public, typeof (void), new Type [0]);\r
56 \r
57                 AssertEquals ("Attributes works", \r
58                                           mb.Attributes, MethodAttributes.Public);\r
59         }\r
60 \r
61         public void TestCallingConvention () {\r
62                 MethodBuilder mb = genClass.DefineMethod (\r
63                         genMethodName (), 0, typeof (void), new Type[0]);\r
64                 AssertEquals ("CallingConvetion defaults to Standard+HasThis",\r
65                                           mb.CallingConvention, \r
66                                           CallingConventions.Standard | CallingConventions.HasThis);\r
67 \r
68                 MethodBuilder mb3 = genClass.DefineMethod (\r
69                         genMethodName (), 0, CallingConventions.VarArgs, typeof (void), new Type[0]);\r
70                 AssertEquals ("CallingConvetion works",\r
71                                           mb3.CallingConvention, \r
72                                           CallingConventions.VarArgs | CallingConventions.HasThis);\r
73 \r
74                 MethodBuilder mb4 = genClass.DefineMethod (\r
75                         genMethodName (), MethodAttributes.Static, CallingConventions.Standard,\r
76                         typeof (void), new Type [0]);\r
77                 AssertEquals ("Static implies !HasThis",\r
78                                           mb4.CallingConvention,\r
79                                           CallingConventions.Standard);\r
80         }\r
81 \r
82         public void TestDeclaringType () {\r
83                 MethodBuilder mb = genClass.DefineMethod (\r
84                         genMethodName (), 0, typeof (void), new Type[0]);\r
85 \r
86                 AssertEquals ("DeclaringType works",\r
87                                           mb.DeclaringType, genClass);\r
88         }\r
89 \r
90         public void TestInitLocals () {\r
91                 MethodBuilder mb = genClass.DefineMethod (\r
92                         genMethodName (), 0, typeof (void), new Type[0]);\r
93 \r
94                 AssertEquals ("InitLocals defaults to true", mb.InitLocals, true);\r
95                 mb.InitLocals = false;\r
96                 AssertEquals ("InitLocals is settable", mb.InitLocals, false);\r
97         }\r
98 \r
99         public void TestMethodHandle () {\r
100                 MethodBuilder mb = genClass.DefineMethod (\r
101                         genMethodName (), 0, typeof (void), new Type [0]);\r
102 \r
103                 try {\r
104                         RuntimeMethodHandle handle = mb.MethodHandle;\r
105                         Fail ();\r
106                 } catch (NotSupportedException) {\r
107                 }\r
108         }\r
109 \r
110         public void TestName () {\r
111                 string name = genMethodName ();\r
112                 MethodBuilder mb = genClass.DefineMethod (\r
113                         name, 0, typeof (void), new Type [0]);\r
114 \r
115                 AssertEquals ("Name works", mb.Name, name);\r
116         }\r
117 \r
118         public void TestReflectedType () {\r
119                 MethodBuilder mb = genClass.DefineMethod (\r
120                         genMethodName (), 0, typeof (void), new Type [0]);\r
121 \r
122                 AssertEquals ("ReflectedType works", \r
123                                           genClass, mb.ReflectedType);\r
124         }\r
125 \r
126         public void TestReturnType () {\r
127                 MethodBuilder mb = genClass.DefineMethod (\r
128                         genMethodName (), 0, typeof (Console), new Type [0]);\r
129 \r
130                 AssertEquals ("ReturnType works", \r
131                                           mb.ReturnType, typeof (Console));\r
132 \r
133                 \r
134                 MethodBuilder mb2 = genClass.DefineMethod (\r
135                         genMethodName (), 0, null, new Type [0]);\r
136 \r
137                 AssertEquals ("ReturnType is null",\r
138                                           mb2.ReturnType, null);\r
139         }\r
140 \r
141         public void TestReturnTypeCustomAttributes () {\r
142                 MethodBuilder mb = genClass.DefineMethod (\r
143                         genMethodName (), 0, typeof (Console), new Type [0]);\r
144 \r
145                 AssertEquals ("ReturnTypeCustomAttributes must be null",\r
146                                           mb.ReturnTypeCustomAttributes, null);\r
147         }\r
148 \r
149         /*\r
150         public void TestSignature () {\r
151                 MethodBuilder mb = genClass.DefineMethod (\r
152                         "m91", 0, typeof (Console), new Type [1] { typeof (Console) });\r
153 \r
154                 Console.WriteLine (mb.Signature);\r
155         }\r
156         */\r
157 \r
158         public void TestCreateMethodBody () {\r
159                 MethodBuilder mb = genClass.DefineMethod (\r
160                         genMethodName (), 0, typeof (void), new Type [0]);\r
161 \r
162                 // Clear body\r
163                 mb.CreateMethodBody (null, 999);\r
164 \r
165                 // Check arguments 1.\r
166                 try {\r
167                         mb.CreateMethodBody (new byte[1], -1);\r
168                         Fail ();\r
169                 } catch (ArgumentException) {\r
170                 }\r
171 \r
172                 // Check arguments 2.\r
173                 try {\r
174                         mb.CreateMethodBody (new byte[1], 2);\r
175                         Fail ();\r
176                 } catch (ArgumentException) {\r
177                 }\r
178 \r
179                 mb.CreateMethodBody (new byte[2], 1);\r
180 \r
181                 // Could only be called once\r
182                 try {\r
183                         mb.CreateMethodBody (new byte[2], 1);\r
184                         Fail ();\r
185                 } catch (InvalidOperationException) {\r
186                 }\r
187 \r
188                 // Can not be called on a created type\r
189                 TypeBuilder tb = module.DefineType ("class6", TypeAttributes.Public);\r
190                 MethodBuilder mb2 = tb.DefineMethod (\r
191                         genMethodName (), 0, typeof (void), new Type [0]);\r
192                 ILGenerator ilgen = mb2.GetILGenerator ();\r
193                 ilgen.Emit (OpCodes.Ret);\r
194                 tb.CreateType ();\r
195 \r
196                 try {\r
197                         mb2.CreateMethodBody (new byte[2], 1);\r
198                         Fail ();\r
199                 } catch (InvalidOperationException) {\r
200                 }\r
201         }\r
202 \r
203         public void TestDefineParameter () {\r
204                 TypeBuilder tb = module.DefineType ("class7", TypeAttributes.Public);\r
205                 MethodBuilder mb = tb.DefineMethod (\r
206                         genMethodName (), 0, typeof (void), \r
207                         new Type [2] { typeof(int), typeof(int) });\r
208 \r
209                 // index out of range\r
210 \r
211                 // This fails on mono because the mono version accepts a 0 index\r
212                 /*\r
213                 try {\r
214                         mb.DefineParameter (0, 0, "param1");\r
215                         Fail ();\r
216                 } catch (ArgumentOutOfRangeException) {\r
217                 }\r
218                 */\r
219 \r
220                 try {\r
221                         mb.DefineParameter (3, 0, "param1");\r
222                         Fail ();\r
223                 } catch (ArgumentOutOfRangeException) {\r
224                 }\r
225 \r
226                 // Normal usage\r
227                 mb.DefineParameter (1, 0, "param1");\r
228                 mb.DefineParameter (1, 0, "param1");\r
229                 mb.DefineParameter (2, 0, null);\r
230 \r
231                 // Can not be called on a created type\r
232                 mb.CreateMethodBody (new byte[2], 0);\r
233                 tb.CreateType ();\r
234                 try {\r
235                         mb.DefineParameter (1, 0, "param1");\r
236                         Fail ();\r
237                 }\r
238                 catch (InvalidOperationException) {\r
239                 }\r
240         }\r
241 \r
242         public void TestGetBaseDefinition () {\r
243                 MethodBuilder mb = genClass.DefineMethod (\r
244                         genMethodName (), 0, typeof (void), new Type [0]);\r
245 \r
246                 AssertEquals ("GetBaseDefinition works",\r
247                                           mb.GetBaseDefinition (), mb);\r
248         }\r
249 \r
250         public void TestGetILGenerator () {\r
251                 MethodBuilder mb = genClass.DefineMethod (\r
252                         genMethodName (), 0, typeof (void), new Type [0]);\r
253 \r
254                 // The same instance is returned on the second call\r
255                 ILGenerator ilgen1 = mb.GetILGenerator ();\r
256                 ILGenerator ilgen2 = mb.GetILGenerator ();\r
257 \r
258                 AssertEquals ("The same ilgen is returned on the second call",\r
259                                           ilgen1, ilgen2);\r
260 \r
261                 // Does not work on unmanaged code\r
262                 MethodBuilder mb2 = genClass.DefineMethod (\r
263                         genMethodName (), 0, typeof (void), new Type [0]);              \r
264                 try {\r
265                         mb2.SetImplementationFlags (MethodImplAttributes.Unmanaged);\r
266                         mb2.GetILGenerator ();\r
267                         Fail ();\r
268                 } catch (InvalidOperationException) {\r
269                 }\r
270                 try {\r
271                         mb2.SetImplementationFlags (MethodImplAttributes.Native);\r
272                         mb2.GetILGenerator ();\r
273                         Fail ();\r
274                 } catch (InvalidOperationException) {\r
275                 }\r
276         }\r
277 \r
278         public void TestMethodImplementationFlags () {\r
279                 TypeBuilder tb = module.DefineType ("class14", TypeAttributes.Public);\r
280                 MethodBuilder mb = tb.DefineMethod (\r
281                         genMethodName (), 0, typeof (void), new Type [0]);\r
282 \r
283                 AssertEquals ("MethodImplementationFlags defaults to Managed+IL",\r
284                                           mb.GetMethodImplementationFlags (),\r
285                                           MethodImplAttributes.Managed | MethodImplAttributes.IL);\r
286 \r
287                 mb.SetImplementationFlags (MethodImplAttributes.OPTIL);\r
288 \r
289                 AssertEquals ("SetImplementationFlags works",\r
290                                           mb.GetMethodImplementationFlags (),\r
291                                           MethodImplAttributes.OPTIL);\r
292 \r
293                 // Can not be called on a created type\r
294                 mb.CreateMethodBody (new byte[2], 0);\r
295                 mb.SetImplementationFlags (MethodImplAttributes.Managed);\r
296                 tb.CreateType ();\r
297                 try {\r
298                         mb.SetImplementationFlags (MethodImplAttributes.OPTIL);\r
299                         Fail ();\r
300                 }\r
301                 catch (InvalidOperationException) {\r
302                 }\r
303         }\r
304 \r
305         public void TestGetModule () {\r
306                 MethodBuilder mb = genClass.DefineMethod (\r
307                         genMethodName (), 0, typeof (void), new Type [0]);\r
308 \r
309                 AssertEquals ("GetMethod works",\r
310                                           mb.GetModule (), module);\r
311         }\r
312 \r
313         public void TestGetParameters () {\r
314                 TypeBuilder tb = module.DefineType ("class16", TypeAttributes.Public);\r
315                 MethodBuilder mb = tb.DefineMethod (\r
316                         genMethodName (), 0, typeof (void), new Type [1] {typeof(void)});\r
317 \r
318                 /*\r
319                  * According to the MSDN docs, this method should fail with a\r
320                  * NotSupportedException. In reality, it throws an \r
321                  * InvalidOperationException under MS .NET, and returns the \r
322                  * requested data under mono.\r
323                  */\r
324                 /*\r
325                 try {\r
326                         mb.GetParameters ();\r
327                         Fail ("#161");\r
328                 } catch (InvalidOperationException ex) {\r
329                         Console.WriteLine (ex);\r
330                 }\r
331                 */\r
332         }\r
333 \r
334         public void TestGetToken () {\r
335                 TypeBuilder tb = module.DefineType ("class17", TypeAttributes.Public);\r
336                 MethodBuilder mb = tb.DefineMethod (\r
337                         genMethodName (), 0, typeof (void), new Type [1] {typeof(void)});\r
338 \r
339                 mb.GetToken ();\r
340         }\r
341 \r
342         public void TestInvoke () {\r
343                 MethodBuilder mb = genClass.DefineMethod (\r
344                         genMethodName (), 0, typeof (void), \r
345                         new Type [1] {typeof(int)});\r
346 \r
347                 try {\r
348                         mb.Invoke (null, new object [1] { 42 });\r
349                         Fail ();\r
350                 } catch (NotSupportedException) {\r
351                 }\r
352 \r
353                 try {\r
354                         mb.Invoke (null, 0, null, new object [1] { 42 }, null);\r
355                         Fail ();\r
356                 } catch (NotSupportedException) {\r
357                 }\r
358         }\r
359 \r
360         public void TestIsDefined () {\r
361                 MethodBuilder mb = genClass.DefineMethod (\r
362                         genMethodName (), 0, typeof (void), \r
363                         new Type [1] {typeof(int)});\r
364 \r
365                 try {\r
366                         mb.IsDefined (null, true);\r
367                         Fail ();\r
368                 } catch (NotSupportedException) {\r
369                 }\r
370         }\r
371 \r
372         public void TestGetCustomAttributes () {\r
373                 MethodBuilder mb = genClass.DefineMethod (\r
374                         genMethodName (), 0, typeof (void), \r
375                         new Type [1] {typeof(int)});\r
376 \r
377                 try {\r
378                         mb.GetCustomAttributes (true);\r
379                         Fail ();\r
380                 } catch (NotSupportedException) {\r
381                 }\r
382 \r
383                 try {\r
384                         mb.GetCustomAttributes (null, true);\r
385                         Fail ();\r
386                 } catch (NotSupportedException) {\r
387                 }\r
388         }\r
389 \r
390         public void TestSetCustomAttribute () {\r
391                 TypeBuilder tb = module.DefineType ("class21", TypeAttributes.Public);\r
392                 string name = genMethodName ();\r
393                 MethodBuilder mb = tb.DefineMethod (\r
394                         name, MethodAttributes.Public, typeof (void), \r
395                         new Type [1] {typeof(int)});\r
396 \r
397                 // Null argument\r
398                 try {\r
399                         mb.SetCustomAttribute (null);\r
400                         Fail ();\r
401                 } catch (ArgumentNullException) {\r
402                 }\r
403 \r
404                 byte[] custAttrData = { 1, 0, 0, 0, 0};\r
405                 Type attrType = Type.GetType\r
406                         ("System.Reflection.AssemblyKeyNameAttribute");\r
407                 Type[] paramTypes = new Type[1];\r
408                 paramTypes[0] = typeof(String);\r
409                 ConstructorInfo ctorInfo =\r
410                         attrType.GetConstructor(paramTypes);\r
411 \r
412                 mb.SetCustomAttribute (ctorInfo, custAttrData);\r
413 \r
414                 // Test MethodImplAttribute\r
415                 mb.SetCustomAttribute (new CustomAttributeBuilder (typeof (MethodImplAttribute).GetConstructor (new Type[1] { typeof (short) }), new object[1] {(short)MethodImplAttributes.Synchronized}));\r
416                 mb.GetILGenerator ().Emit (OpCodes.Ret);\r
417 \r
418                 Type t = tb.CreateType ();\r
419 \r
420                 AssertEquals ("Setting MethodImplAttributes works",\r
421                                           MethodImplAttributes.Synchronized,\r
422                                           t.GetMethod (name).GetMethodImplementationFlags ());\r
423 \r
424                 // Null arguments again\r
425                 try {\r
426                         mb.SetCustomAttribute (null, new byte[2]);\r
427                         Fail ();\r
428                 } catch (ArgumentNullException) {\r
429                 }\r
430 \r
431                 try {\r
432                         mb.SetCustomAttribute (ctorInfo, null);\r
433                         Fail ();\r
434                 } catch (ArgumentNullException) {\r
435                 }\r
436         }\r
437 }\r
438 }\r