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