Merge pull request #260 from pcc/topmost
[mono.git] / mcs / class / corlib / Test / System.Reflection.Emit / DynamicMethodTest.cs
1 //
2 // DynamicMethodTest.cs - NUnit Test Cases for the DynamicMethod class
3 //
4 // Gert Driesen (drieseng@users.sourceforge.net)
5 // Konrad Kruczynski
6 //
7 // (C) 2006 Novell
8
9 #if NET_2_0
10
11 using System;
12 using System.Reflection;
13 using System.Reflection.Emit;
14 using System.Text;
15
16 using NUnit.Framework;
17
18 namespace MonoTests.System.Reflection.Emit
19 {
20         [TestFixture]
21         public class DynamicMethodTest
22         {
23                 private delegate int HelloInvoker (string msg);
24
25                 [Test]
26                 public void Constructor1_Name_Null ()
27                 {
28                         try {
29                                 new DynamicMethod (null,
30                                         typeof (void),
31                                         new Type[] { typeof (string) },
32                                         typeof (DynamicMethodTest).Module);
33                                 Assert.Fail ("#1");
34                         } catch (ArgumentNullException ex) {
35                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
36                                 Assert.AreEqual ("name", ex.ParamName, "#3");
37                                 Assert.IsNull (ex.InnerException, "#4");
38                         }
39                 }
40
41                 [Test]
42                 public void Constructor2_Name_Null ()
43                 {
44                         try {
45                                 new DynamicMethod (null,
46                                         typeof (void),
47                                         new Type[] { typeof (string) },
48                                         typeof (DynamicMethodTest));
49                                 Assert.Fail ("#1");
50                         } catch (ArgumentNullException ex) {
51                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
52                                 Assert.AreEqual ("name", ex.ParamName, "#3");
53                                 Assert.IsNull (ex.InnerException, "#4");
54                         }
55                 }
56
57                 [Test]
58                 public void Constructor3_Name_Null ()
59                 {
60                         try {
61                                 new DynamicMethod (null,
62                                         typeof (void),
63                                         new Type[] { typeof (string) },
64                                         typeof (DynamicMethodTest).Module, true);
65                                 Assert.Fail ("#1");
66                         } catch (ArgumentNullException ex) {
67                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
68                                 Assert.AreEqual ("name", ex.ParamName, "#3");
69                                 Assert.IsNull (ex.InnerException, "#4");
70                         }
71                 }
72
73                 [Test]
74                 public void Constructor4_Name_Null ()
75                 {
76                         try {
77                                 new DynamicMethod (null,
78                                         typeof (void),
79                                         new Type[] { typeof (string) },
80                                         typeof (DynamicMethodTest), true);
81                                 Assert.Fail ("#1");
82                         } catch (ArgumentNullException ex) {
83                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
84                                 Assert.AreEqual ("name", ex.ParamName, "#3");
85                                 Assert.IsNull (ex.InnerException, "#4");
86                         }
87                 }
88
89                 [Test]
90                 public void Constructor5_Name_Null ()
91                 {
92                         try {
93                                 new DynamicMethod (null,
94                                         MethodAttributes.Public | MethodAttributes.Static,
95                                         CallingConventions.Standard,
96                                         typeof (void),
97                                         new Type[] { typeof (string) },
98                                         typeof (DynamicMethodTest).Module, true);
99                                 Assert.Fail ("#1");
100                         } catch (ArgumentNullException ex) {
101                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
102                                 Assert.AreEqual ("name", ex.ParamName, "#3");
103                                 Assert.IsNull (ex.InnerException, "#4");
104                         }
105                 }
106
107                 [Test]
108                 public void Constructor6_Name_Null ()
109                 {
110                         try {
111                                 new DynamicMethod (null,
112                                         MethodAttributes.Public | MethodAttributes.Static,
113                                         CallingConventions.Standard,
114                                         typeof (void),
115                                         new Type[] { typeof (string) },
116                                         typeof (DynamicMethodTest), true);
117                                 Assert.Fail ("#1");
118                         } catch (ArgumentNullException ex) {
119                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
120                                 Assert.AreEqual ("name", ex.ParamName, "#3");
121                                 Assert.IsNull (ex.InnerException, "#4");
122                         }
123                 }
124
125                 [Test]
126                 public void OwnerCantBeArray ()
127                 {
128                         TestOwner (typeof (int[]));
129                 }
130
131                 [Test]
132                 public void OwnerCantBeInterface ()
133                 {
134                         TestOwner (typeof (global::System.Collections.IEnumerable));
135                 }
136
137                 private void TestOwner (Type owner)
138                 {
139                         try {
140                                 new DynamicMethod ("Name", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard,
141                                                    typeof(void), new Type[] { }, owner, true);
142                                 Assert.Fail (string.Format ("Created dynamic method with owner being {0}.", owner));
143                         } catch (ArgumentException) {
144                         }
145                 }
146
147                 [Test] // bug #78253
148                 public void DynamicMethodReference ()
149                 {
150                         DynamicMethod hello = new DynamicMethod ("Hello",
151                                 typeof (int),
152                                 new Type[] { typeof (string) },
153                                 typeof (DynamicMethodTest).Module);
154                         Assert.IsNull (hello.DeclaringType, "#1");
155
156                         DynamicMethod write = new DynamicMethod ("Write",
157                                 typeof (int),
158                                 new Type[] { typeof (string) },
159                                 typeof (DynamicMethodTest));
160                         Assert.IsNull (hello.DeclaringType, "#2");
161
162                         MethodInfo invokeWrite = write.GetBaseDefinition ();
163
164                         ILGenerator helloIL = hello.GetILGenerator ();
165                         helloIL.Emit (OpCodes.Ldarg_0);
166                         helloIL.EmitCall (OpCodes.Call, invokeWrite, null);
167                         helloIL.Emit (OpCodes.Ret);
168
169                         ILGenerator writeIL = write.GetILGenerator ();
170                         writeIL.Emit (OpCodes.Ldc_I4_2);
171                         writeIL.Emit (OpCodes.Ret);
172
173                         HelloInvoker hi =
174                                 (HelloInvoker) hello.CreateDelegate (typeof (HelloInvoker));
175                         int ret = hi ("Hello, World!");
176                         Assert.AreEqual (2, ret, "#3");
177
178                         object[] invokeArgs = { "Hello, World!" };
179                         object objRet = hello.Invoke (null, invokeArgs);
180                         Assert.AreEqual (2, objRet, "#4");
181                 }
182
183                 [Test]
184                 public void EmptyMethodBody ()
185                 {
186                         DynamicMethod hello = new DynamicMethod ("Hello",
187                                 typeof (int),
188                                 new Type[] { typeof (string) },
189                                 typeof (DynamicMethodTest).Module);
190                         object[] invokeArgs = { "Hello, World!" };
191
192                         // no IL generator
193                         try {
194                                 hello.Invoke (null, invokeArgs);
195                                 Assert.Fail ("#1");
196                         } catch (InvalidOperationException) {
197                         }
198
199                         // empty method body
200                         hello.GetILGenerator ();
201                         try {
202                                 hello.Invoke (null, invokeArgs);
203                                 Assert.Fail ("#2");
204                         } catch (InvalidOperationException) {
205                         }
206                 }
207
208                 private delegate string ReturnString (string msg);
209                 private delegate void DoNothing (string msg);
210
211                 private static string private_method (string s) {
212                         return s;
213                 }
214
215                 [Test]
216                 public void SkipVisibility ()
217                 {
218                         DynamicMethod hello = new DynamicMethod ("Hello",
219                                 typeof (string),
220                                 new Type[] { typeof (string) },
221                                 typeof (DynamicMethodTest).Module, true);
222
223                         ILGenerator helloIL = hello.GetILGenerator ();
224                         helloIL.Emit (OpCodes.Ldarg_0);
225                         helloIL.EmitCall (OpCodes.Call, typeof (DynamicMethodTest).GetMethod ("private_method", BindingFlags.Static|BindingFlags.NonPublic), null);
226                         helloIL.Emit (OpCodes.Ret);
227
228                         ReturnString del =
229                                 (ReturnString) hello.CreateDelegate (typeof (ReturnString));
230                         Assert.AreEqual ("ABCD", del ("ABCD"));
231                 }
232
233                 [Test]
234                 public void ReturnType_Null ()
235                 {
236                         DynamicMethod hello = new DynamicMethod ("Hello",
237                                 null,
238                                 new Type[] { typeof (string) },
239                                 typeof (DynamicMethodTest).Module, true);
240                         Assert.AreEqual (typeof (void), hello.ReturnType, "#1");
241
242                         ILGenerator helloIL = hello.GetILGenerator ();
243                         helloIL.Emit (OpCodes.Ret);
244
245                         DoNothing dn = (DoNothing) hello.CreateDelegate (typeof (DoNothing));
246                         dn ("whatever");
247
248                         object[] invokeArgs = { "Hello, World!" };
249                         object objRet = hello.Invoke (null, invokeArgs);
250                         Assert.IsNull (objRet, "#2");
251                 }
252
253                 [Test]
254                 public void Name_Empty ()
255                 {
256                         DynamicMethod hello = new DynamicMethod (string.Empty,
257                                 typeof (int),
258                                 new Type[] { typeof (string) },
259                                 typeof (DynamicMethodTest).Module);
260                         Assert.AreEqual (string.Empty, hello.Name, "#1");
261
262                         DynamicMethod write = new DynamicMethod ("Write",
263                                 typeof (int),
264                                 new Type[] { typeof (string) },
265                                 typeof (DynamicMethodTest));
266
267                         MethodInfo invokeWrite = write.GetBaseDefinition ();
268
269                         ILGenerator helloIL = hello.GetILGenerator ();
270                         helloIL.Emit (OpCodes.Ldarg_0);
271                         helloIL.EmitCall (OpCodes.Call, invokeWrite, null);
272                         helloIL.Emit (OpCodes.Ret);
273
274                         ILGenerator writeIL = write.GetILGenerator ();
275                         writeIL.Emit (OpCodes.Ldc_I4_2);
276                         writeIL.Emit (OpCodes.Ret);
277
278                         HelloInvoker hi =
279                                 (HelloInvoker) hello.CreateDelegate (typeof (HelloInvoker));
280                         int ret = hi ("Hello, World!");
281                         Assert.AreEqual (2, ret, "#2");
282
283                         object[] invokeArgs = { "Hello, World!" };
284                         object objRet = hello.Invoke (null, invokeArgs);
285                         Assert.AreEqual (2, objRet, "#3");
286                 }
287
288                 [Test]
289                 public void Circular_Refs () {
290                         DynamicMethod m1 = new DynamicMethod("f1", typeof(int), new Type[] { typeof (int) },
291                                                                                                  typeof(object));
292                         DynamicMethod m2 = new DynamicMethod("f2", typeof(int), new Type[] { typeof (int) },
293                                                                                                  typeof(object));
294
295                         ILGenerator il1 = m1.GetILGenerator();
296                         ILGenerator il2 = m2.GetILGenerator();
297
298                         Label l = il1.DefineLabel ();
299                         //il1.EmitWriteLine ("f1");
300                         il1.Emit (OpCodes.Ldarg_0);
301                         il1.Emit (OpCodes.Ldc_I4_0);
302                         il1.Emit (OpCodes.Bne_Un, l);
303                         il1.Emit (OpCodes.Ldarg_0);
304                         il1.Emit (OpCodes.Ret);
305                         il1.MarkLabel (l);
306                         il1.Emit (OpCodes.Ldarg_0);
307                         il1.Emit (OpCodes.Ldc_I4_1);
308                         il1.Emit (OpCodes.Sub);
309                         il1.Emit (OpCodes.Call, m2);
310                         il1.Emit (OpCodes.Ret);
311
312                         //il2.EmitWriteLine("f2");
313                         il2.Emit(OpCodes.Ldarg_0);
314                         il2.Emit(OpCodes.Call, m1);
315                         il2.Emit(OpCodes.Ret);
316
317                         m1.Invoke(null, new object[] { 5 });
318                 }
319
320                 class Host {
321                         static string Field = "foo";
322                 }
323
324                 [Test]
325                 [Category ("NotDotNet")] // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=297416
326                 public void TestOwnerMemberAccess ()
327                 {
328                         DynamicMethod method = new DynamicMethod ("GetField",
329                                 typeof (string), new Type [0], typeof (Host));
330
331                         ILGenerator il = method.GetILGenerator ();
332                         il.Emit (OpCodes.Ldsfld, typeof (Host).GetField (
333                                 "Field", BindingFlags.Static | BindingFlags.NonPublic));
334                         il.Emit (OpCodes.Ret);
335
336                         string ret = (string) method.Invoke (null, new object [] {});
337                         Assert.AreEqual ("foo", ret, "#1");
338                 }
339
340                 [Test]
341                 public void AnonHosted ()
342                 {
343                         DynamicMethod hello = new DynamicMethod ("Hello",
344                                                                                                          typeof (int),
345                                                                                                          new Type[] { typeof (string) });
346                         ILGenerator helloIL = hello.GetILGenerator ();
347                         helloIL.Emit (OpCodes.Ldc_I4_2);
348                         helloIL.Emit (OpCodes.Ret);
349
350                         HelloInvoker hi =
351                                 (HelloInvoker) hello.CreateDelegate (typeof (HelloInvoker));
352                         int ret = hi ("Hello, World!");
353                         Assert.AreEqual (2, ret);
354
355                         object[] invokeArgs = { "Hello, World!" };
356                         object objRet = hello.Invoke (null, invokeArgs);
357                         Assert.AreEqual (2, objRet);
358                 }
359
360                 public delegate int IntInvoker();
361
362                 public class Foo<T> {
363                         public virtual int Test () { return 99; }
364                 } 
365
366                 [Test]
367                 public void ConstrainedPrexixDoesntCrash () //bug #529238
368                 {
369                         Type foo = typeof (Foo<int>);
370
371                         DynamicMethod dm = new DynamicMethod ("Hello", typeof (int), null);
372                         ILGenerator ilgen = dm.GetILGenerator ();
373                         ilgen.DeclareLocal (foo);
374                         ilgen.Emit (OpCodes.Newobj, foo.GetConstructor (new Type [0]));
375                         ilgen.Emit (OpCodes.Stloc_0);
376                         ilgen.Emit (OpCodes.Ldloca_S, 0);
377                         ilgen.Emit (OpCodes.Constrained, foo);
378                         ilgen.Emit (OpCodes.Callvirt, foo.GetMethod ("Test"));
379                         ilgen.Emit (OpCodes.Ret);
380
381                         IntInvoker hi = (IntInvoker) dm.CreateDelegate (typeof (IntInvoker));
382                         Assert.AreEqual (99, hi (), "#1");      
383                 }
384
385                 // #575955
386                 [Test]
387                 public void Module_GetMethod () {
388                         AssemblyName assemblyName = new AssemblyName ();
389                         assemblyName.Name = "foo";
390
391                         AssemblyBuilder assembly =
392                                 AppDomain.CurrentDomain.DefineDynamicAssembly (
393                                                                                                                            assemblyName, AssemblyBuilderAccess.RunAndSave);
394
395                         ModuleBuilder module = assembly.DefineDynamicModule ("foo.dll");
396
397                         var d = new DynamicMethod ("foo", typeof (int), new Type [] { typeof (int[,]) }, module);
398                         var ig = d.GetILGenerator ();
399                         ig.Emit (OpCodes.Ldarg_0);
400                         ig.Emit (OpCodes.Ldc_I4, 1);
401                         ig.Emit (OpCodes.Ldc_I4, 1);
402                         ig.Emit (OpCodes.Call, module.GetArrayMethod (typeof (int[,]), "Get", CallingConventions.Standard, typeof (int), new Type [] { typeof (int), typeof (int) }));
403                         ig.Emit (OpCodes.Ret);
404                 
405                         var del = (Func<int[,], int>)d.CreateDelegate (typeof (Func<int[,], int>));
406                         int[,] arr = new int [10, 10];
407                         arr [1, 1] = 5;
408                         Assert.AreEqual (5, del (arr));
409                 }
410
411                 [Test]
412                 [Category ("NotWorking")]
413                 public void InvalidUnicodeName ()
414                 {
415                         var name = new StringBuilder ().Append ('\udf45').Append ('\ud808');
416                         var method = new DynamicMethod (name.ToString (), typeof (bool), new Type [0]);
417                         var il = method.GetILGenerator ();
418                         il.Emit (OpCodes.Ldc_I4_1);
419                         il.Emit (OpCodes.Ret);
420
421                         var function = (Func<bool>) method.CreateDelegate (typeof (Func<bool>));
422
423                         Assert.IsTrue (function ());
424                 }
425
426                 [Test]
427                 [ExpectedException (typeof (InvalidOperationException))]
428                 public void GetMethodBody ()
429                 {
430                         var method = new DynamicMethod ("method", typeof (object), new Type [] { typeof (object) });
431
432                         var il = method.GetILGenerator ();
433                         il.Emit (OpCodes.Ldarg_0);
434                         il.Emit (OpCodes.Ret);
435
436                         var f = (Func<object, object>) method.CreateDelegate (typeof (Func<object, object>));
437                         f.Method.GetMethodBody ();
438                 }
439
440         public delegate object RetObj();
441                 [Test] //#640702
442                 public void GetCurrentMethodWorksWithDynamicMethods ()
443                 {
444                 DynamicMethod dm = new DynamicMethod("Foo", typeof(object), null);
445                 ILGenerator ilgen = dm.GetILGenerator();
446                 ilgen.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("GetCurrentMethod"));
447                 ilgen.Emit(OpCodes.Ret);
448                 RetObj del = (RetObj)dm.CreateDelegate(typeof(RetObj));
449                     MethodInfo res = (MethodInfo)del();
450                         Assert.AreEqual (dm.Name, res.Name, "#1");
451
452                 }
453         }
454 }
455
456 #endif