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;
18 using NUnit.Framework;
20 namespace MonoTests.System.Reflection.Emit
23 public class DynamicMethodTest
25 private delegate int HelloInvoker (string msg);
28 public void Constructor1_Name_Null ()
31 new DynamicMethod (null,
33 new Type[] { typeof (string) },
34 typeof (DynamicMethodTest).Module);
36 } catch (ArgumentNullException ex) {
37 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
38 Assert.AreEqual ("name", ex.ParamName, "#3");
39 Assert.IsNull (ex.InnerException, "#4");
44 public void Constructor2_Name_Null ()
47 new DynamicMethod (null,
49 new Type[] { typeof (string) },
50 typeof (DynamicMethodTest));
52 } catch (ArgumentNullException ex) {
53 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
54 Assert.AreEqual ("name", ex.ParamName, "#3");
55 Assert.IsNull (ex.InnerException, "#4");
60 public void Constructor3_Name_Null ()
63 new DynamicMethod (null,
65 new Type[] { typeof (string) },
66 typeof (DynamicMethodTest).Module, true);
68 } catch (ArgumentNullException ex) {
69 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
70 Assert.AreEqual ("name", ex.ParamName, "#3");
71 Assert.IsNull (ex.InnerException, "#4");
76 public void Constructor4_Name_Null ()
79 new DynamicMethod (null,
81 new Type[] { typeof (string) },
82 typeof (DynamicMethodTest), true);
84 } catch (ArgumentNullException ex) {
85 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
86 Assert.AreEqual ("name", ex.ParamName, "#3");
87 Assert.IsNull (ex.InnerException, "#4");
92 public void Constructor5_Name_Null ()
95 new DynamicMethod (null,
96 MethodAttributes.Public | MethodAttributes.Static,
97 CallingConventions.Standard,
99 new Type[] { typeof (string) },
100 typeof (DynamicMethodTest).Module, true);
102 } catch (ArgumentNullException ex) {
103 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
104 Assert.AreEqual ("name", ex.ParamName, "#3");
105 Assert.IsNull (ex.InnerException, "#4");
110 public void Constructor6_Name_Null ()
113 new DynamicMethod (null,
114 MethodAttributes.Public | MethodAttributes.Static,
115 CallingConventions.Standard,
117 new Type[] { typeof (string) },
118 typeof (DynamicMethodTest), true);
120 } catch (ArgumentNullException ex) {
121 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
122 Assert.AreEqual ("name", ex.ParamName, "#3");
123 Assert.IsNull (ex.InnerException, "#4");
128 public void OwnerCantBeArray ()
130 TestOwner (typeof (int[]));
134 public void OwnerCantBeInterface ()
136 TestOwner (typeof (global::System.Collections.IEnumerable));
139 private void TestOwner (Type owner)
142 new DynamicMethod ("Name", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard,
143 typeof(void), new Type[] { }, owner, true);
144 Assert.Fail (string.Format ("Created dynamic method with owner being {0}.", owner));
145 } catch (ArgumentException) {
150 public void DynamicMethodReference ()
152 DynamicMethod hello = new DynamicMethod ("Hello",
154 new Type[] { typeof (string) },
155 typeof (DynamicMethodTest).Module);
156 Assert.IsNull (hello.DeclaringType, "#1");
158 DynamicMethod write = new DynamicMethod ("Write",
160 new Type[] { typeof (string) },
161 typeof (DynamicMethodTest));
162 Assert.IsNull (hello.DeclaringType, "#2");
164 MethodInfo invokeWrite = write.GetBaseDefinition ();
166 ILGenerator helloIL = hello.GetILGenerator ();
167 helloIL.Emit (OpCodes.Ldarg_0);
168 helloIL.EmitCall (OpCodes.Call, invokeWrite, null);
169 helloIL.Emit (OpCodes.Ret);
171 ILGenerator writeIL = write.GetILGenerator ();
172 writeIL.Emit (OpCodes.Ldc_I4_2);
173 writeIL.Emit (OpCodes.Ret);
176 (HelloInvoker) hello.CreateDelegate (typeof (HelloInvoker));
177 int ret = hi ("Hello, World!");
178 Assert.AreEqual (2, ret, "#3");
180 object[] invokeArgs = { "Hello, World!" };
181 object objRet = hello.Invoke (null, invokeArgs);
182 Assert.AreEqual (2, objRet, "#4");
186 public void EmptyMethodBody ()
188 DynamicMethod hello = new DynamicMethod ("Hello",
190 new Type[] { typeof (string) },
191 typeof (DynamicMethodTest).Module);
192 object[] invokeArgs = { "Hello, World!" };
196 hello.Invoke (null, invokeArgs);
198 } catch (InvalidOperationException) {
202 hello.GetILGenerator ();
204 hello.Invoke (null, invokeArgs);
206 } catch (InvalidOperationException) {
210 private delegate string ReturnString (string msg);
211 private delegate void DoNothing (string msg);
213 private static string private_method (string s) {
218 public void SkipVisibility ()
220 DynamicMethod hello = new DynamicMethod ("Hello",
222 new Type[] { typeof (string) },
223 typeof (DynamicMethodTest).Module, true);
225 ILGenerator helloIL = hello.GetILGenerator ();
226 helloIL.Emit (OpCodes.Ldarg_0);
227 helloIL.EmitCall (OpCodes.Call, typeof (DynamicMethodTest).GetMethod ("private_method", BindingFlags.Static|BindingFlags.NonPublic), null);
228 helloIL.Emit (OpCodes.Ret);
231 (ReturnString) hello.CreateDelegate (typeof (ReturnString));
232 Assert.AreEqual ("ABCD", del ("ABCD"));
236 public void ReturnType_Null ()
238 DynamicMethod hello = new DynamicMethod ("Hello",
240 new Type[] { typeof (string) },
241 typeof (DynamicMethodTest).Module, true);
242 Assert.AreEqual (typeof (void), hello.ReturnType, "#1");
244 ILGenerator helloIL = hello.GetILGenerator ();
245 helloIL.Emit (OpCodes.Ret);
247 DoNothing dn = (DoNothing) hello.CreateDelegate (typeof (DoNothing));
250 object[] invokeArgs = { "Hello, World!" };
251 object objRet = hello.Invoke (null, invokeArgs);
252 Assert.IsNull (objRet, "#2");
256 public void Name_Empty ()
258 DynamicMethod hello = new DynamicMethod (string.Empty,
260 new Type[] { typeof (string) },
261 typeof (DynamicMethodTest).Module);
262 Assert.AreEqual (string.Empty, hello.Name, "#1");
264 DynamicMethod write = new DynamicMethod ("Write",
266 new Type[] { typeof (string) },
267 typeof (DynamicMethodTest));
269 MethodInfo invokeWrite = write.GetBaseDefinition ();
271 ILGenerator helloIL = hello.GetILGenerator ();
272 helloIL.Emit (OpCodes.Ldarg_0);
273 helloIL.EmitCall (OpCodes.Call, invokeWrite, null);
274 helloIL.Emit (OpCodes.Ret);
276 ILGenerator writeIL = write.GetILGenerator ();
277 writeIL.Emit (OpCodes.Ldc_I4_2);
278 writeIL.Emit (OpCodes.Ret);
281 (HelloInvoker) hello.CreateDelegate (typeof (HelloInvoker));
282 int ret = hi ("Hello, World!");
283 Assert.AreEqual (2, ret, "#2");
285 object[] invokeArgs = { "Hello, World!" };
286 object objRet = hello.Invoke (null, invokeArgs);
287 Assert.AreEqual (2, objRet, "#3");
291 public void Circular_Refs () {
292 DynamicMethod m1 = new DynamicMethod("f1", typeof(int), new Type[] { typeof (int) },
294 DynamicMethod m2 = new DynamicMethod("f2", typeof(int), new Type[] { typeof (int) },
297 ILGenerator il1 = m1.GetILGenerator();
298 ILGenerator il2 = m2.GetILGenerator();
300 Label l = il1.DefineLabel ();
301 //il1.EmitWriteLine ("f1");
302 il1.Emit (OpCodes.Ldarg_0);
303 il1.Emit (OpCodes.Ldc_I4_0);
304 il1.Emit (OpCodes.Bne_Un, l);
305 il1.Emit (OpCodes.Ldarg_0);
306 il1.Emit (OpCodes.Ret);
308 il1.Emit (OpCodes.Ldarg_0);
309 il1.Emit (OpCodes.Ldc_I4_1);
310 il1.Emit (OpCodes.Sub);
311 il1.Emit (OpCodes.Call, m2);
312 il1.Emit (OpCodes.Ret);
314 //il2.EmitWriteLine("f2");
315 il2.Emit(OpCodes.Ldarg_0);
316 il2.Emit(OpCodes.Call, m1);
317 il2.Emit(OpCodes.Ret);
319 m1.Invoke(null, new object[] { 5 });
322 // Disabl known warning, the Field is never used directly from C#
323 #pragma warning disable 414
325 static string Field = "foo";
327 #pragma warning restore 414
329 [Category ("NotDotNet")] // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=297416
330 public void TestOwnerMemberAccess ()
332 DynamicMethod method = new DynamicMethod ("GetField",
333 typeof (string), new Type [0], typeof (Host));
335 ILGenerator il = method.GetILGenerator ();
336 il.Emit (OpCodes.Ldsfld, typeof (Host).GetField (
337 "Field", BindingFlags.Static | BindingFlags.NonPublic));
338 il.Emit (OpCodes.Ret);
340 string ret = (string) method.Invoke (null, new object [] {});
341 Assert.AreEqual ("foo", ret, "#1");
345 public void AnonHosted ()
347 DynamicMethod hello = new DynamicMethod ("Hello",
349 new Type[] { typeof (string) });
350 ILGenerator helloIL = hello.GetILGenerator ();
351 helloIL.Emit (OpCodes.Ldc_I4_2);
352 helloIL.Emit (OpCodes.Ret);
355 (HelloInvoker) hello.CreateDelegate (typeof (HelloInvoker));
356 int ret = hi ("Hello, World!");
357 Assert.AreEqual (2, ret);
359 object[] invokeArgs = { "Hello, World!" };
360 object objRet = hello.Invoke (null, invokeArgs);
361 Assert.AreEqual (2, objRet);
364 public delegate int IntInvoker();
366 public class Foo<T> {
367 public virtual int Test () { return 99; }
371 public void ConstrainedPrexixDoesntCrash () //bug #529238
373 Type foo = typeof (Foo<int>);
375 DynamicMethod dm = new DynamicMethod ("Hello", typeof (int), null);
376 ILGenerator ilgen = dm.GetILGenerator ();
377 ilgen.DeclareLocal (foo);
378 ilgen.Emit (OpCodes.Newobj, foo.GetConstructor (new Type [0]));
379 ilgen.Emit (OpCodes.Stloc_0);
380 ilgen.Emit (OpCodes.Ldloca_S, 0);
381 ilgen.Emit (OpCodes.Constrained, foo);
382 ilgen.Emit (OpCodes.Callvirt, foo.GetMethod ("Test"));
383 ilgen.Emit (OpCodes.Ret);
385 IntInvoker hi = (IntInvoker) dm.CreateDelegate (typeof (IntInvoker));
386 Assert.AreEqual (99, hi (), "#1");
391 public void Module_GetMethod () {
392 AssemblyName assemblyName = new AssemblyName ();
393 assemblyName.Name = "foo";
395 AssemblyBuilder assembly =
396 AppDomain.CurrentDomain.DefineDynamicAssembly (
397 assemblyName, AssemblyBuilderAccess.RunAndSave);
399 ModuleBuilder module = assembly.DefineDynamicModule ("foo.dll");
401 var d = new DynamicMethod ("foo", typeof (int), new Type [] { typeof (int[,]) }, module);
402 var ig = d.GetILGenerator ();
403 ig.Emit (OpCodes.Ldarg_0);
404 ig.Emit (OpCodes.Ldc_I4, 1);
405 ig.Emit (OpCodes.Ldc_I4, 1);
406 ig.Emit (OpCodes.Call, module.GetArrayMethod (typeof (int[,]), "Get", CallingConventions.Standard, typeof (int), new Type [] { typeof (int), typeof (int) }));
407 ig.Emit (OpCodes.Ret);
409 var del = (Func<int[,], int>)d.CreateDelegate (typeof (Func<int[,], int>));
410 int[,] arr = new int [10, 10];
412 Assert.AreEqual (5, del (arr));
416 [Category ("NotWorking")]
417 public void InvalidUnicodeName ()
419 var name = new StringBuilder ().Append ('\udf45').Append ('\ud808');
420 var method = new DynamicMethod (name.ToString (), typeof (bool), new Type [0]);
421 var il = method.GetILGenerator ();
422 il.Emit (OpCodes.Ldc_I4_1);
423 il.Emit (OpCodes.Ret);
425 var function = (Func<bool>) method.CreateDelegate (typeof (Func<bool>));
427 Assert.IsTrue (function ());
431 [ExpectedException (typeof (InvalidOperationException))]
432 public void GetMethodBody ()
434 var method = new DynamicMethod ("method", typeof (object), new Type [] { typeof (object) });
436 var il = method.GetILGenerator ();
437 il.Emit (OpCodes.Ldarg_0);
438 il.Emit (OpCodes.Ret);
440 var f = (Func<object, object>) method.CreateDelegate (typeof (Func<object, object>));
441 f.Method.GetMethodBody ();
444 public delegate object RetObj();
446 public void GetCurrentMethodWorksWithDynamicMethods ()
448 DynamicMethod dm = new DynamicMethod("Foo", typeof(object), null);
449 ILGenerator ilgen = dm.GetILGenerator();
450 ilgen.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("GetCurrentMethod"));
451 ilgen.Emit(OpCodes.Ret);
452 RetObj del = (RetObj)dm.CreateDelegate(typeof(RetObj));
453 MethodInfo res = (MethodInfo)del();
454 Assert.AreEqual (dm.Name, res.Name, "#1");
458 [StructLayout (LayoutKind.Explicit)]
459 struct SizeOfTarget {
460 [FieldOffset (0)] public int X;
461 [FieldOffset (4)] public int Y;
465 public void SizeOf ()
467 var method = new DynamicMethod ("", typeof (int), Type.EmptyTypes);
468 var il = method.GetILGenerator ();
469 il.Emit (OpCodes.Sizeof, typeof (SizeOfTarget));
470 il.Emit (OpCodes.Ret);
472 var func = (Func<int>) method.CreateDelegate (typeof (Func<int>));
473 var point_size = func ();
475 Assert.AreEqual (8, point_size);
478 class TypedRefTarget {
482 class ExceptionHandling_Test_Support
484 public static Exception Caught;
485 public static string CaughtStackTrace;
487 public static void ThrowMe ()
490 CaughtStackTrace = null;
491 throw new Exception("test");
494 public static void Handler (Exception e)
497 CaughtStackTrace = e.StackTrace.ToString ();
502 public void ExceptionHandling ()
504 var method = new DynamicMethod ("", typeof(void), new[] { typeof(int) }, typeof (DynamicMethodTest));
505 var ig = method.GetILGenerator ();
507 ig.BeginExceptionBlock();
508 ig.Emit(OpCodes.Call, typeof(ExceptionHandling_Test_Support).GetMethod("ThrowMe"));
510 ig.BeginCatchBlock(typeof(Exception));
511 ig.Emit(OpCodes.Call, typeof(ExceptionHandling_Test_Support).GetMethod("Handler"));
512 ig.EndExceptionBlock();
514 ig.Emit(OpCodes.Ret);
516 var invoke = (Action<int>) method.CreateDelegate (typeof(Action<int>));
519 Assert.IsNotNull (ExceptionHandling_Test_Support.Caught, "#1");
520 Assert.AreEqual (2, ExceptionHandling_Test_Support.CaughtStackTrace.Split (new[] { Environment.NewLine }, StringSplitOptions.None).Length, "#2");
522 var st = new StackTrace (ExceptionHandling_Test_Support.Caught, 0, true);
524 // Caught stack trace when dynamic method is gone
525 Assert.AreEqual (ExceptionHandling_Test_Support.CaughtStackTrace, st.ToString (), "#3");
527 // Catch handler stack trace inside dynamic method match
528 Assert.AreEqual (ExceptionHandling_Test_Support.Caught.StackTrace, st.ToString (), "#4");
531 class ExceptionHandlingWithExceptionDispatchInfo_Test_Support
533 public static Exception Caught;
534 public static string CaughtStackTrace;
536 public static void ThrowMe ()
539 CaughtStackTrace = null;
543 throw new Exception("test");
544 } catch (Exception e2) {
548 var edi = ExceptionDispatchInfo.Capture(e);
553 public static void Handler (Exception e)
555 var split = e.StackTrace.Split (new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
556 Assert.AreEqual (5, split.Length, "#1");
557 Assert.IsTrue (split [1].Contains ("---"), "#2");
562 public void ExceptionHandlingWithExceptionDispatchInfo ()
564 var method = new DynamicMethod ("", typeof(void), new[] { typeof(int) }, typeof (DynamicMethodTest));
565 var ig = method.GetILGenerator ();
567 ig.BeginExceptionBlock();
568 ig.Emit(OpCodes.Call, typeof(ExceptionHandlingWithExceptionDispatchInfo_Test_Support).GetMethod("ThrowMe"));
570 ig.BeginCatchBlock(typeof(Exception));
571 ig.Emit(OpCodes.Call, typeof(ExceptionHandlingWithExceptionDispatchInfo_Test_Support).GetMethod("Handler"));
572 ig.EndExceptionBlock();
574 ig.Emit(OpCodes.Ret);
576 var invoke = (Action<int>) method.CreateDelegate (typeof(Action<int>));
583 public void TypedRef ()
585 var method = new DynamicMethod ("", typeof (TypedRefTarget), new [] {typeof (TypedRefTarget)}, true);
586 var il = method.GetILGenerator ();
587 var tr = il.DeclareLocal (typeof (TypedReference));
589 il.Emit (OpCodes.Ldarga, 0);
590 il.Emit (OpCodes.Mkrefany, typeof (TypedRefTarget));
591 il.Emit (OpCodes.Stloc, tr);
593 il.Emit (OpCodes.Ldloc, tr);
594 il.Emit (OpCodes.Call, GetType ().GetMethod ("AssertTypedRef", BindingFlags.NonPublic | BindingFlags.Static));
596 il.Emit (OpCodes.Ldloc, tr);
597 il.Emit (OpCodes.Refanyval, typeof (TypedRefTarget));
598 il.Emit (OpCodes.Ldobj, typeof (TypedRefTarget));
599 il.Emit (OpCodes.Ret);
601 var f = (Func<TypedRefTarget, TypedRefTarget>) method.CreateDelegate (typeof (Func<TypedRefTarget, TypedRefTarget>));
603 var target = new TypedRefTarget { Name = "Foo" };
606 Assert.AreEqual (target, rt);
609 private static void AssertTypedRef (TypedReference tr)
611 Assert.AreEqual (typeof (TypedRefTarget), TypedReference.GetTargetType (tr));