2 // DynamicMethodTest.cs - NUnit Test Cases for the DynamicMethod class
4 // Gert Driesen (drieseng@users.sourceforge.net)
11 using System.Reflection;
12 using System.Reflection.Emit;
13 using System.Runtime.InteropServices;
15 using System.Diagnostics;
16 using System.Runtime.ExceptionServices;
19 using NUnit.Framework;
21 namespace MonoTests.System.Reflection.Emit
24 public class DynamicMethodTest
26 private delegate int HelloInvoker (string msg);
29 public void Constructor1_Name_Null ()
32 new DynamicMethod (null,
34 new Type[] { typeof (string) },
35 typeof (DynamicMethodTest).Module);
37 } catch (ArgumentNullException ex) {
38 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
39 Assert.AreEqual ("name", ex.ParamName, "#3");
40 Assert.IsNull (ex.InnerException, "#4");
45 public void Constructor2_Name_Null ()
48 new DynamicMethod (null,
50 new Type[] { typeof (string) },
51 typeof (DynamicMethodTest));
53 } catch (ArgumentNullException ex) {
54 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
55 Assert.AreEqual ("name", ex.ParamName, "#3");
56 Assert.IsNull (ex.InnerException, "#4");
61 public void Constructor3_Name_Null ()
64 new DynamicMethod (null,
66 new Type[] { typeof (string) },
67 typeof (DynamicMethodTest).Module, true);
69 } catch (ArgumentNullException ex) {
70 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
71 Assert.AreEqual ("name", ex.ParamName, "#3");
72 Assert.IsNull (ex.InnerException, "#4");
77 public void Constructor4_Name_Null ()
80 new DynamicMethod (null,
82 new Type[] { typeof (string) },
83 typeof (DynamicMethodTest), true);
85 } catch (ArgumentNullException ex) {
86 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
87 Assert.AreEqual ("name", ex.ParamName, "#3");
88 Assert.IsNull (ex.InnerException, "#4");
93 public void Constructor5_Name_Null ()
96 new DynamicMethod (null,
97 MethodAttributes.Public | MethodAttributes.Static,
98 CallingConventions.Standard,
100 new Type[] { typeof (string) },
101 typeof (DynamicMethodTest).Module, true);
103 } catch (ArgumentNullException ex) {
104 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
105 Assert.AreEqual ("name", ex.ParamName, "#3");
106 Assert.IsNull (ex.InnerException, "#4");
111 public void Constructor6_Name_Null ()
114 new DynamicMethod (null,
115 MethodAttributes.Public | MethodAttributes.Static,
116 CallingConventions.Standard,
118 new Type[] { typeof (string) },
119 typeof (DynamicMethodTest), true);
121 } catch (ArgumentNullException ex) {
122 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
123 Assert.AreEqual ("name", ex.ParamName, "#3");
124 Assert.IsNull (ex.InnerException, "#4");
129 public void OwnerCantBeArray ()
131 TestOwner (typeof (int[]));
135 public void OwnerCantBeInterface ()
137 TestOwner (typeof (global::System.Collections.IEnumerable));
140 private void TestOwner (Type owner)
143 new DynamicMethod ("Name", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard,
144 typeof(void), new Type[] { }, owner, true);
145 Assert.Fail (string.Format ("Created dynamic method with owner being {0}.", owner));
146 } catch (ArgumentException) {
151 public void DynamicMethodReference ()
153 DynamicMethod hello = new DynamicMethod ("Hello",
155 new Type[] { typeof (string) },
156 typeof (DynamicMethodTest).Module);
157 Assert.IsNull (hello.DeclaringType, "#1");
159 DynamicMethod write = new DynamicMethod ("Write",
161 new Type[] { typeof (string) },
162 typeof (DynamicMethodTest));
163 Assert.IsNull (hello.DeclaringType, "#2");
165 MethodInfo invokeWrite = write.GetBaseDefinition ();
167 ILGenerator helloIL = hello.GetILGenerator ();
168 helloIL.Emit (OpCodes.Ldarg_0);
169 helloIL.EmitCall (OpCodes.Call, invokeWrite, null);
170 helloIL.Emit (OpCodes.Ret);
172 ILGenerator writeIL = write.GetILGenerator ();
173 writeIL.Emit (OpCodes.Ldc_I4_2);
174 writeIL.Emit (OpCodes.Ret);
177 (HelloInvoker) hello.CreateDelegate (typeof (HelloInvoker));
178 int ret = hi ("Hello, World!");
179 Assert.AreEqual (2, ret, "#3");
181 object[] invokeArgs = { "Hello, World!" };
182 object objRet = hello.Invoke (null, invokeArgs);
183 Assert.AreEqual (2, objRet, "#4");
187 public void EmptyMethodBody ()
189 DynamicMethod hello = new DynamicMethod ("Hello",
191 new Type[] { typeof (string) },
192 typeof (DynamicMethodTest).Module);
193 object[] invokeArgs = { "Hello, World!" };
197 hello.Invoke (null, invokeArgs);
199 } catch (InvalidOperationException) {
203 hello.GetILGenerator ();
205 hello.Invoke (null, invokeArgs);
207 } catch (InvalidOperationException) {
211 private delegate string ReturnString (string msg);
212 private delegate void DoNothing (string msg);
214 private static string private_method (string s) {
219 public void SkipVisibility ()
221 DynamicMethod hello = new DynamicMethod ("Hello",
223 new Type[] { typeof (string) },
224 typeof (DynamicMethodTest).Module, true);
226 ILGenerator helloIL = hello.GetILGenerator ();
227 helloIL.Emit (OpCodes.Ldarg_0);
228 helloIL.EmitCall (OpCodes.Call, typeof (DynamicMethodTest).GetMethod ("private_method", BindingFlags.Static|BindingFlags.NonPublic), null);
229 helloIL.Emit (OpCodes.Ret);
232 (ReturnString) hello.CreateDelegate (typeof (ReturnString));
233 Assert.AreEqual ("ABCD", del ("ABCD"));
237 public void ReturnType_Null ()
239 DynamicMethod hello = new DynamicMethod ("Hello",
241 new Type[] { typeof (string) },
242 typeof (DynamicMethodTest).Module, true);
243 Assert.AreEqual (typeof (void), hello.ReturnType, "#1");
245 ILGenerator helloIL = hello.GetILGenerator ();
246 helloIL.Emit (OpCodes.Ret);
248 DoNothing dn = (DoNothing) hello.CreateDelegate (typeof (DoNothing));
251 object[] invokeArgs = { "Hello, World!" };
252 object objRet = hello.Invoke (null, invokeArgs);
253 Assert.IsNull (objRet, "#2");
257 public void Name_Empty ()
259 DynamicMethod hello = new DynamicMethod (string.Empty,
261 new Type[] { typeof (string) },
262 typeof (DynamicMethodTest).Module);
263 Assert.AreEqual (string.Empty, hello.Name, "#1");
265 DynamicMethod write = new DynamicMethod ("Write",
267 new Type[] { typeof (string) },
268 typeof (DynamicMethodTest));
270 MethodInfo invokeWrite = write.GetBaseDefinition ();
272 ILGenerator helloIL = hello.GetILGenerator ();
273 helloIL.Emit (OpCodes.Ldarg_0);
274 helloIL.EmitCall (OpCodes.Call, invokeWrite, null);
275 helloIL.Emit (OpCodes.Ret);
277 ILGenerator writeIL = write.GetILGenerator ();
278 writeIL.Emit (OpCodes.Ldc_I4_2);
279 writeIL.Emit (OpCodes.Ret);
282 (HelloInvoker) hello.CreateDelegate (typeof (HelloInvoker));
283 int ret = hi ("Hello, World!");
284 Assert.AreEqual (2, ret, "#2");
286 object[] invokeArgs = { "Hello, World!" };
287 object objRet = hello.Invoke (null, invokeArgs);
288 Assert.AreEqual (2, objRet, "#3");
292 public void Circular_Refs () {
293 DynamicMethod m1 = new DynamicMethod("f1", typeof(int), new Type[] { typeof (int) },
295 DynamicMethod m2 = new DynamicMethod("f2", typeof(int), new Type[] { typeof (int) },
298 ILGenerator il1 = m1.GetILGenerator();
299 ILGenerator il2 = m2.GetILGenerator();
301 Label l = il1.DefineLabel ();
302 //il1.EmitWriteLine ("f1");
303 il1.Emit (OpCodes.Ldarg_0);
304 il1.Emit (OpCodes.Ldc_I4_0);
305 il1.Emit (OpCodes.Bne_Un, l);
306 il1.Emit (OpCodes.Ldarg_0);
307 il1.Emit (OpCodes.Ret);
309 il1.Emit (OpCodes.Ldarg_0);
310 il1.Emit (OpCodes.Ldc_I4_1);
311 il1.Emit (OpCodes.Sub);
312 il1.Emit (OpCodes.Call, m2);
313 il1.Emit (OpCodes.Ret);
315 //il2.EmitWriteLine("f2");
316 il2.Emit(OpCodes.Ldarg_0);
317 il2.Emit(OpCodes.Call, m1);
318 il2.Emit(OpCodes.Ret);
320 m1.Invoke(null, new object[] { 5 });
323 // Disabl known warning, the Field is never used directly from C#
324 #pragma warning disable 414
326 static string Field = "foo";
328 #pragma warning restore 414
330 [Category ("NotDotNet")] // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=297416
331 public void TestOwnerMemberAccess ()
333 DynamicMethod method = new DynamicMethod ("GetField",
334 typeof (string), new Type [0], typeof (Host));
336 ILGenerator il = method.GetILGenerator ();
337 il.Emit (OpCodes.Ldsfld, typeof (Host).GetField (
338 "Field", BindingFlags.Static | BindingFlags.NonPublic));
339 il.Emit (OpCodes.Ret);
341 string ret = (string) method.Invoke (null, new object [] {});
342 Assert.AreEqual ("foo", ret, "#1");
346 public void AnonHosted ()
348 DynamicMethod hello = new DynamicMethod ("Hello",
350 new Type[] { typeof (string) });
351 ILGenerator helloIL = hello.GetILGenerator ();
352 helloIL.Emit (OpCodes.Ldc_I4_2);
353 helloIL.Emit (OpCodes.Ret);
356 (HelloInvoker) hello.CreateDelegate (typeof (HelloInvoker));
357 int ret = hi ("Hello, World!");
358 Assert.AreEqual (2, ret);
360 object[] invokeArgs = { "Hello, World!" };
361 object objRet = hello.Invoke (null, invokeArgs);
362 Assert.AreEqual (2, objRet);
365 public delegate int IntInvoker();
367 public class Foo<T> {
368 public virtual int Test () { return 99; }
372 public void ConstrainedPrexixDoesntCrash () //bug #529238
374 Type foo = typeof (Foo<int>);
376 DynamicMethod dm = new DynamicMethod ("Hello", typeof (int), null);
377 ILGenerator ilgen = dm.GetILGenerator ();
378 ilgen.DeclareLocal (foo);
379 ilgen.Emit (OpCodes.Newobj, foo.GetConstructor (new Type [0]));
380 ilgen.Emit (OpCodes.Stloc_0);
381 ilgen.Emit (OpCodes.Ldloca_S, 0);
382 ilgen.Emit (OpCodes.Constrained, foo);
383 ilgen.Emit (OpCodes.Callvirt, foo.GetMethod ("Test"));
384 ilgen.Emit (OpCodes.Ret);
386 IntInvoker hi = (IntInvoker) dm.CreateDelegate (typeof (IntInvoker));
387 Assert.AreEqual (99, hi (), "#1");
392 public void Module_GetMethod () {
393 AssemblyName assemblyName = new AssemblyName ();
394 assemblyName.Name = "foo";
396 AssemblyBuilder assembly =
397 AppDomain.CurrentDomain.DefineDynamicAssembly (
398 assemblyName, AssemblyBuilderAccess.RunAndSave);
400 ModuleBuilder module = assembly.DefineDynamicModule ("foo.dll");
402 var d = new DynamicMethod ("foo", typeof (int), new Type [] { typeof (int[,]) }, module);
403 var ig = d.GetILGenerator ();
404 ig.Emit (OpCodes.Ldarg_0);
405 ig.Emit (OpCodes.Ldc_I4, 1);
406 ig.Emit (OpCodes.Ldc_I4, 1);
407 ig.Emit (OpCodes.Call, module.GetArrayMethod (typeof (int[,]), "Get", CallingConventions.Standard, typeof (int), new Type [] { typeof (int), typeof (int) }));
408 ig.Emit (OpCodes.Ret);
410 var del = (Func<int[,], int>)d.CreateDelegate (typeof (Func<int[,], int>));
411 int[,] arr = new int [10, 10];
413 Assert.AreEqual (5, del (arr));
417 [Category ("NotWorking")]
418 public void InvalidUnicodeName ()
420 var name = new StringBuilder ().Append ('\udf45').Append ('\ud808');
421 var method = new DynamicMethod (name.ToString (), typeof (bool), new Type [0]);
422 var il = method.GetILGenerator ();
423 il.Emit (OpCodes.Ldc_I4_1);
424 il.Emit (OpCodes.Ret);
426 var function = (Func<bool>) method.CreateDelegate (typeof (Func<bool>));
428 Assert.IsTrue (function ());
432 [ExpectedException (typeof (InvalidOperationException))]
433 public void GetMethodBody ()
435 var method = new DynamicMethod ("method", typeof (object), new Type [] { typeof (object) });
437 var il = method.GetILGenerator ();
438 il.Emit (OpCodes.Ldarg_0);
439 il.Emit (OpCodes.Ret);
441 var f = (Func<object, object>) method.CreateDelegate (typeof (Func<object, object>));
442 f.Method.GetMethodBody ();
445 public delegate object RetObj();
447 public void GetCurrentMethodWorksWithDynamicMethods ()
449 DynamicMethod dm = new DynamicMethod("Foo", typeof(object), null);
450 ILGenerator ilgen = dm.GetILGenerator();
451 ilgen.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("GetCurrentMethod"));
452 ilgen.Emit(OpCodes.Ret);
453 RetObj del = (RetObj)dm.CreateDelegate(typeof(RetObj));
454 MethodInfo res = (MethodInfo)del();
455 Assert.AreEqual (dm.Name, res.Name, "#1");
459 [StructLayout (LayoutKind.Explicit)]
460 struct SizeOfTarget {
461 [FieldOffset (0)] public int X;
462 [FieldOffset (4)] public int Y;
466 public void SizeOf ()
468 var method = new DynamicMethod ("", typeof (int), Type.EmptyTypes);
469 var il = method.GetILGenerator ();
470 il.Emit (OpCodes.Sizeof, typeof (SizeOfTarget));
471 il.Emit (OpCodes.Ret);
473 var func = (Func<int>) method.CreateDelegate (typeof (Func<int>));
474 var point_size = func ();
476 Assert.AreEqual (8, point_size);
479 class TypedRefTarget {
483 class ExceptionHandling_Test_Support
485 public static Exception Caught;
486 public static string CaughtStackTrace;
488 public static void ThrowMe ()
491 CaughtStackTrace = null;
492 throw new Exception("test");
495 public static void Handler (Exception e)
498 CaughtStackTrace = e.StackTrace.ToString ();
503 public void ExceptionHandling ()
505 var method = new DynamicMethod ("", typeof(void), new[] { typeof(int) }, typeof (DynamicMethodTest));
506 var ig = method.GetILGenerator ();
508 ig.BeginExceptionBlock();
509 ig.Emit(OpCodes.Call, typeof(ExceptionHandling_Test_Support).GetMethod("ThrowMe"));
511 ig.BeginCatchBlock(typeof(Exception));
512 ig.Emit(OpCodes.Call, typeof(ExceptionHandling_Test_Support).GetMethod("Handler"));
513 ig.EndExceptionBlock();
515 ig.Emit(OpCodes.Ret);
517 var invoke = (Action<int>) method.CreateDelegate (typeof(Action<int>));
520 Assert.IsNotNull (ExceptionHandling_Test_Support.Caught, "#1");
522 var lines = ExceptionHandling_Test_Support.CaughtStackTrace.Split (new[] { Environment.NewLine }, StringSplitOptions.None);
523 lines = lines.Where (l => !l.StartsWith ("[")).ToArray ();
524 Assert.AreEqual (2, lines.Length, "#2");
526 var st = new StackTrace (ExceptionHandling_Test_Support.Caught, 0, true);
528 // Caught stack trace when dynamic method is gone
529 Assert.AreEqual (ExceptionHandling_Test_Support.CaughtStackTrace, st.ToString (), "#3");
531 // Catch handler stack trace inside dynamic method match
532 Assert.AreEqual (ExceptionHandling_Test_Support.Caught.StackTrace, st.ToString (), "#4");
535 class ExceptionHandlingWithExceptionDispatchInfo_Test_Support
537 public static Exception Caught;
538 public static string CaughtStackTrace;
540 public static void ThrowMe ()
543 CaughtStackTrace = null;
547 throw new Exception("test");
548 } catch (Exception e2) {
552 var edi = ExceptionDispatchInfo.Capture(e);
557 public static void Handler (Exception e)
559 var lines = e.StackTrace.Split (new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
561 lines = lines.Where (l => !l.StartsWith ("[")).ToArray ();
563 Assert.AreEqual (5, lines.Length, "#1");
564 Assert.IsTrue (lines [1].Contains ("---"), "#2");
569 public void ExceptionHandlingWithExceptionDispatchInfo ()
571 var method = new DynamicMethod ("", typeof(void), new[] { typeof(int) }, typeof (DynamicMethodTest));
572 var ig = method.GetILGenerator ();
574 ig.BeginExceptionBlock();
575 ig.Emit(OpCodes.Call, typeof(ExceptionHandlingWithExceptionDispatchInfo_Test_Support).GetMethod("ThrowMe"));
577 ig.BeginCatchBlock(typeof(Exception));
578 ig.Emit(OpCodes.Call, typeof(ExceptionHandlingWithExceptionDispatchInfo_Test_Support).GetMethod("Handler"));
579 ig.EndExceptionBlock();
581 ig.Emit(OpCodes.Ret);
583 var invoke = (Action<int>) method.CreateDelegate (typeof(Action<int>));
590 public void TypedRef ()
592 var method = new DynamicMethod ("", typeof (TypedRefTarget), new [] {typeof (TypedRefTarget)}, true);
593 var il = method.GetILGenerator ();
594 var tr = il.DeclareLocal (typeof (TypedReference));
596 il.Emit (OpCodes.Ldarga, 0);
597 il.Emit (OpCodes.Mkrefany, typeof (TypedRefTarget));
598 il.Emit (OpCodes.Stloc, tr);
600 il.Emit (OpCodes.Ldloc, tr);
601 il.Emit (OpCodes.Call, GetType ().GetMethod ("AssertTypedRef", BindingFlags.NonPublic | BindingFlags.Static));
603 il.Emit (OpCodes.Ldloc, tr);
604 il.Emit (OpCodes.Refanyval, typeof (TypedRefTarget));
605 il.Emit (OpCodes.Ldobj, typeof (TypedRefTarget));
606 il.Emit (OpCodes.Ret);
608 var f = (Func<TypedRefTarget, TypedRefTarget>) method.CreateDelegate (typeof (Func<TypedRefTarget, TypedRefTarget>));
610 var target = new TypedRefTarget { Name = "Foo" };
613 Assert.AreEqual (target, rt);
616 private static void AssertTypedRef (TypedReference tr)
618 Assert.AreEqual (typeof (TypedRefTarget), TypedReference.GetTargetType (tr));