[eglib] Prefer <langinfo.h> to <localcharset.h>
[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
10 using System;
11 using System.Reflection;
12 using System.Reflection.Emit;
13 using System.Runtime.InteropServices;
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                 // Disabl known warning, the Field is never used directly from C#
321                 #pragma warning disable 414
322                 class Host {
323                         static string Field = "foo";
324                 }
325                 #pragma warning restore 414
326                 [Test]
327                 [Category ("NotDotNet")] // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=297416
328                 public void TestOwnerMemberAccess ()
329                 {
330                         DynamicMethod method = new DynamicMethod ("GetField",
331                                 typeof (string), new Type [0], typeof (Host));
332
333                         ILGenerator il = method.GetILGenerator ();
334                         il.Emit (OpCodes.Ldsfld, typeof (Host).GetField (
335                                 "Field", BindingFlags.Static | BindingFlags.NonPublic));
336                         il.Emit (OpCodes.Ret);
337
338                         string ret = (string) method.Invoke (null, new object [] {});
339                         Assert.AreEqual ("foo", ret, "#1");
340                 }
341
342                 [Test]
343                 public void AnonHosted ()
344                 {
345                         DynamicMethod hello = new DynamicMethod ("Hello",
346                                                                                                          typeof (int),
347                                                                                                          new Type[] { typeof (string) });
348                         ILGenerator helloIL = hello.GetILGenerator ();
349                         helloIL.Emit (OpCodes.Ldc_I4_2);
350                         helloIL.Emit (OpCodes.Ret);
351
352                         HelloInvoker hi =
353                                 (HelloInvoker) hello.CreateDelegate (typeof (HelloInvoker));
354                         int ret = hi ("Hello, World!");
355                         Assert.AreEqual (2, ret);
356
357                         object[] invokeArgs = { "Hello, World!" };
358                         object objRet = hello.Invoke (null, invokeArgs);
359                         Assert.AreEqual (2, objRet);
360                 }
361
362                 public delegate int IntInvoker();
363
364                 public class Foo<T> {
365                         public virtual int Test () { return 99; }
366                 } 
367
368                 [Test]
369                 public void ConstrainedPrexixDoesntCrash () //bug #529238
370                 {
371                         Type foo = typeof (Foo<int>);
372
373                         DynamicMethod dm = new DynamicMethod ("Hello", typeof (int), null);
374                         ILGenerator ilgen = dm.GetILGenerator ();
375                         ilgen.DeclareLocal (foo);
376                         ilgen.Emit (OpCodes.Newobj, foo.GetConstructor (new Type [0]));
377                         ilgen.Emit (OpCodes.Stloc_0);
378                         ilgen.Emit (OpCodes.Ldloca_S, 0);
379                         ilgen.Emit (OpCodes.Constrained, foo);
380                         ilgen.Emit (OpCodes.Callvirt, foo.GetMethod ("Test"));
381                         ilgen.Emit (OpCodes.Ret);
382
383                         IntInvoker hi = (IntInvoker) dm.CreateDelegate (typeof (IntInvoker));
384                         Assert.AreEqual (99, hi (), "#1");      
385                 }
386
387                 // #575955
388                 [Test]
389                 public void Module_GetMethod () {
390                         AssemblyName assemblyName = new AssemblyName ();
391                         assemblyName.Name = "foo";
392
393                         AssemblyBuilder assembly =
394                                 AppDomain.CurrentDomain.DefineDynamicAssembly (
395                                                                                                                            assemblyName, AssemblyBuilderAccess.RunAndSave);
396
397                         ModuleBuilder module = assembly.DefineDynamicModule ("foo.dll");
398
399                         var d = new DynamicMethod ("foo", typeof (int), new Type [] { typeof (int[,]) }, module);
400                         var ig = d.GetILGenerator ();
401                         ig.Emit (OpCodes.Ldarg_0);
402                         ig.Emit (OpCodes.Ldc_I4, 1);
403                         ig.Emit (OpCodes.Ldc_I4, 1);
404                         ig.Emit (OpCodes.Call, module.GetArrayMethod (typeof (int[,]), "Get", CallingConventions.Standard, typeof (int), new Type [] { typeof (int), typeof (int) }));
405                         ig.Emit (OpCodes.Ret);
406                 
407                         var del = (Func<int[,], int>)d.CreateDelegate (typeof (Func<int[,], int>));
408                         int[,] arr = new int [10, 10];
409                         arr [1, 1] = 5;
410                         Assert.AreEqual (5, del (arr));
411                 }
412
413                 [Test]
414                 [Category ("NotWorking")]
415                 public void InvalidUnicodeName ()
416                 {
417                         var name = new StringBuilder ().Append ('\udf45').Append ('\ud808');
418                         var method = new DynamicMethod (name.ToString (), typeof (bool), new Type [0]);
419                         var il = method.GetILGenerator ();
420                         il.Emit (OpCodes.Ldc_I4_1);
421                         il.Emit (OpCodes.Ret);
422
423                         var function = (Func<bool>) method.CreateDelegate (typeof (Func<bool>));
424
425                         Assert.IsTrue (function ());
426                 }
427
428                 [Test]
429                 [ExpectedException (typeof (InvalidOperationException))]
430                 public void GetMethodBody ()
431                 {
432                         var method = new DynamicMethod ("method", typeof (object), new Type [] { typeof (object) });
433
434                         var il = method.GetILGenerator ();
435                         il.Emit (OpCodes.Ldarg_0);
436                         il.Emit (OpCodes.Ret);
437
438                         var f = (Func<object, object>) method.CreateDelegate (typeof (Func<object, object>));
439                         f.Method.GetMethodBody ();
440                 }
441
442         public delegate object RetObj();
443                 [Test] //#640702
444                 public void GetCurrentMethodWorksWithDynamicMethods ()
445                 {
446                 DynamicMethod dm = new DynamicMethod("Foo", typeof(object), null);
447                 ILGenerator ilgen = dm.GetILGenerator();
448                 ilgen.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("GetCurrentMethod"));
449                 ilgen.Emit(OpCodes.Ret);
450                 RetObj del = (RetObj)dm.CreateDelegate(typeof(RetObj));
451                     MethodInfo res = (MethodInfo)del();
452                         Assert.AreEqual (dm.Name, res.Name, "#1");
453
454                 }
455
456                 [StructLayout (LayoutKind.Explicit)]
457                 struct SizeOfTarget {
458                         [FieldOffset (0)] public int X;
459                         [FieldOffset (4)] public int Y;
460                 }
461
462                 [Test]
463                 public void SizeOf ()
464                 {
465                         var method = new DynamicMethod ("", typeof (int), Type.EmptyTypes);
466                         var il = method.GetILGenerator ();
467                         il.Emit (OpCodes.Sizeof, typeof (SizeOfTarget));
468                         il.Emit (OpCodes.Ret);
469
470                         var func = (Func<int>) method.CreateDelegate (typeof (Func<int>));
471                         var point_size = func ();
472
473                         Assert.AreEqual (8, point_size);
474                 }
475
476                 class TypedRefTarget {
477                         public string Name;
478                 }
479
480                 [Test]
481                 public void TypedRef ()
482                 {
483                         var method = new DynamicMethod ("", typeof (TypedRefTarget), new [] {typeof (TypedRefTarget)}, true);
484                         var il = method.GetILGenerator ();
485                         var tr = il.DeclareLocal (typeof (TypedReference));
486
487                         il.Emit (OpCodes.Ldarga, 0);
488                         il.Emit (OpCodes.Mkrefany, typeof (TypedRefTarget));
489                         il.Emit (OpCodes.Stloc, tr);
490
491                         il.Emit (OpCodes.Ldloc, tr);
492                         il.Emit (OpCodes.Call, GetType ().GetMethod ("AssertTypedRef", BindingFlags.NonPublic | BindingFlags.Static));
493
494                         il.Emit (OpCodes.Ldloc, tr);
495                         il.Emit (OpCodes.Refanyval, typeof (TypedRefTarget));
496                         il.Emit (OpCodes.Ldobj, typeof (TypedRefTarget));
497                         il.Emit (OpCodes.Ret);
498
499                         var f = (Func<TypedRefTarget, TypedRefTarget>) method.CreateDelegate (typeof (Func<TypedRefTarget, TypedRefTarget>));
500
501                         var target = new TypedRefTarget { Name = "Foo" };
502                         var rt = f (target);
503
504                         Assert.AreEqual (target, rt);
505                 }
506
507                 private static void AssertTypedRef (TypedReference tr)
508                 {
509                         Assert.AreEqual (typeof (TypedRefTarget), TypedReference.GetTargetType (tr));
510                 }
511         }
512 }
513