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