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