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