2008-03-06 Jb Evain <jbevain@novell.com>
[mono.git] / mcs / class / corlib / Test / System.Reflection.Emit / ILGeneratorTest.cs
index c80a736f7f84e227c914fcb1be4f6f6de2540e8b..39ca7025c472894e9cd0b2a9a88ec74527b42715 100644 (file)
@@ -8,17 +8,26 @@
 using System;
 using System.Reflection;
 using System.Reflection.Emit;
+using System.Runtime.InteropServices;
 using System.Threading;
 
 using NUnit.Framework;
 
-namespace MonoTests.System.Reflection.Emit {
-
+namespace MonoTests.System.Reflection.Emit
+{
        [TestFixture]
-       public class ILGeneratorTest {
-
+       public class ILGeneratorTest
+       {
+               TypeBuilder tb;
                ILGenerator il_gen;
 
+               void DefineBasicMethod ()
+               {
+                       MethodBuilder mb = tb.DefineMethod("F",
+                               MethodAttributes.Public, typeof(string), null);
+                       il_gen = mb.GetILGenerator ();
+               }
+
                [SetUp]
                public void SetUp ()
                {
@@ -26,22 +35,371 @@ namespace MonoTests.System.Reflection.Emit {
                        assemblyName.Name = "MonoTests.System.Reflection.Emit.ILGeneratorTest";
 
                        AssemblyBuilder assembly = Thread.GetDomain ().DefineDynamicAssembly (
-                               assemblyName, AssemblyBuilderAccess.Run);
+                               assemblyName, AssemblyBuilderAccess.RunAndSave);
 
                        ModuleBuilder module = assembly.DefineDynamicModule ("module1");
-                       TypeBuilder _tb = module.DefineType ("GetType", TypeAttributes.Public);
+                       tb = module.DefineType ("T", TypeAttributes.Public);
+               }
+
+               [Test]
+               public void DeclareLocal_LocalType_Null ()
+               {
+                       DefineBasicMethod ();
+
+                       try {
+                               il_gen.DeclareLocal (null);
+                               Assert.Fail ("#A1");
+                       } catch (ArgumentNullException ex) {
+                               Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#A2");
+                               Assert.IsNull (ex.InnerException, "#A3");
+                               Assert.IsNotNull (ex.Message, "#A4");
+                               Assert.IsNotNull (ex.ParamName, "#A5");
+                               Assert.AreEqual ("localType", ex.ParamName, "#A");
+                       }
+
+#if NET_2_0
+                       try {
+                               il_gen.DeclareLocal (null, false);
+                               Assert.Fail ("#B1");
+                       } catch (ArgumentNullException ex) {
+                               Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#B2");
+                               Assert.IsNull (ex.InnerException, "#B3");
+                               Assert.IsNotNull (ex.Message, "#B4");
+                               Assert.IsNotNull (ex.ParamName, "#B5");
+                               Assert.AreEqual ("localType", ex.ParamName, "#B6");
+                       }
+#endif
+               }
+
+               [Test]
+               [ExpectedException (typeof (ArgumentException))]
+               public void DefineFilterBodyWithTypeNotNull ()
+               {
+                       DefineBasicMethod ();
+                       il_gen.BeginExceptionBlock ();
+                       il_gen.EmitWriteLine ("in try");
+                       il_gen.BeginExceptFilterBlock ();
+                       il_gen.EmitWriteLine ("in filter head");
+                       il_gen.BeginCatchBlock (typeof (Exception));
+                       il_gen.EmitWriteLine ("in filter body");
+                       il_gen.EndExceptionBlock ();
+               }
+
+               [Test] // bug #81431
+               public void FilterAndCatchBlock ()
+               {
+                       DefineBasicMethod ();
+                       ILGenerator il = il_gen;
+                       il.BeginExceptionBlock ();
+                       il.BeginExceptFilterBlock ();
+                       il.BeginCatchBlock (null);
+                       il.BeginCatchBlock (typeof (SystemException));
+               }
+               
+               [Test]
+               [ExpectedException (typeof (InvalidOperationException))]
+               public void InvalidFilterBlock1 ()
+               {
+                       DefineBasicMethod ();
+                       ILGenerator il = il_gen;
+                       il.BeginExceptionBlock ();
+                       il.BeginExceptFilterBlock ();
+                       il.EndExceptionBlock ();
+               }
+               
+               [Test]
+               public void ValidFilterBlock1 ()
+               {
+                       DefineBasicMethod ();
+                       ILGenerator il = il_gen;
+                       il.BeginExceptionBlock ();
+                       il.BeginExceptFilterBlock ();
+                       il.BeginFaultBlock ();
+                       il.EndExceptionBlock ();
+               }
+               
+               [Test]
+               public void ValidFilterBlock2 ()
+               {
+                       DefineBasicMethod ();
+                       ILGenerator il = il_gen;
+                       il.BeginExceptionBlock ();
+                       il.BeginExceptFilterBlock ();
+                       il.BeginFinallyBlock ();
+                       il.EndExceptionBlock ();
+               }
+               
+               /// <summary>
+               /// Try to emit something like that:
+               ///
+               /// .method public static bool TestFilter (bool execute_handler)
+               /// {
+               ///     .locals init(bool)
+               ///     try {
+               ///             newobj  instance void [mscorlib]System.Exception::.ctor()
+               ///             throw
+               ///     } filter {
+               ///             pop
+               ///             ldarg.0
+               ///             endfilter
+               ///     } {
+               ///             ldc.i4.1
+               ///             stloc.0
+               ///             leave quit
+               ///     }
+               ///     ldc.i4.0
+               ///     stloc.0
+               /// quit:
+               ///     ldloc.0
+               ///     ret
+               /// }
+               ///
+               /// It should return true if the handler has been executed
+               /// Otherwise, the exception should not be catched
+               /// </summary>
+               void DefineTestFilterMethod ()
+               {
+                       MethodBuilder mb = tb.DefineMethod("TestFilter",
+                               MethodAttributes.Public | MethodAttributes.Static, typeof(bool), new Type [] { typeof (bool) });
+
+                       ConstructorInfo exCtor = typeof (Exception).GetConstructor (new Type [0]);
+
+                       il_gen = mb.GetILGenerator ();
+                       il_gen.DeclareLocal (typeof (bool));
+                       Label quit = il_gen.DefineLabel ();
+                       il_gen.BeginExceptionBlock ();
+                       il_gen.Emit (OpCodes.Newobj, exCtor);
+                       il_gen.Emit (OpCodes.Throw);
+                       il_gen.BeginExceptFilterBlock ();
+                       il_gen.Emit (OpCodes.Pop);
+                       il_gen.Emit (OpCodes.Ldarg_0);
+                       il_gen.BeginCatchBlock (null);
+                       il_gen.Emit (OpCodes.Ldc_I4_1);
+                       il_gen.Emit (OpCodes.Stloc_0);
+                       il_gen.Emit (OpCodes.Leave, quit);
+                       il_gen.EndExceptionBlock ();
+                       il_gen.Emit (OpCodes.Ldc_I4_0);
+                       il_gen.Emit (OpCodes.Stloc_0);
+                       il_gen.MarkLabel (quit);
+                       il_gen.Emit (OpCodes.Ldloc_0);
+                       il_gen.Emit (OpCodes.Ret);
+               }
+
+               [Test] // Emit (OpCode, ConstructorInfo)
+#if NET_2_0
+               [Category ("NotDotNet")] // MS bug: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304610
+#endif
+               public void Emit3_Constructor_Null ()
+               {
+                       DefineBasicMethod ();
+                       try {
+                               il_gen.Emit (OpCodes.Newobj, (ConstructorInfo) null);
+                               Assert.Fail ("#1");
+                       } catch (ArgumentNullException ex) {
+                               Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
+                               Assert.IsNull (ex.InnerException, "#3");
+                               Assert.IsNotNull (ex.Message, "#4");
+                               Assert.IsNotNull (ex.ParamName, "#5");
+                       }
+               }
+
+#if NET_2_0
+               [Test] // Emit (OpCode, ConstructorInfo)
+               [Category ("NotWorking")] // MS bug: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304610
+               public void Emit3_Constructor_Null_MS ()
+               {
+                       DefineBasicMethod ();
+                       try {
+                               il_gen.Emit (OpCodes.Newobj, (ConstructorInfo) null);
+                               Assert.Fail ("#1");
+                       } catch (NullReferenceException) {
+                       }
+               }
+#endif
 
-                       MethodBuilder myMethod = _tb.DefineMethod("Function1",
-                               MethodAttributes.Public, typeof(String), null);
+               [Test] // Emit (OpCode, FieldInfo)
+               public void Emit5_Field_Null ()
+               {
+                       DefineBasicMethod ();
+                       try {
+                               il_gen.Emit (OpCodes.Ldsfld, (FieldInfo) null);
+                               Assert.Fail ("#1");
+                       } catch (ArgumentNullException ex) {
+                               Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
+                               Assert.IsNull (ex.InnerException, "#3");
+                               Assert.IsNotNull (ex.Message, "#4");
+                               Assert.IsNotNull (ex.ParamName, "#5");
+                       }
+               }
+
+               [Test] // Emit (OpCode, Label [])
+               [Category ("NotDotNet")] // MS bug: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304610
+               public void Emit10_Labels_Null ()
+               {
+                       DefineBasicMethod ();
+                       try {
+                               il_gen.Emit (OpCodes.Switch, (Label []) null);
+                               Assert.Fail ("#1");
+                       } catch (ArgumentNullException ex) {
+                               Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
+                               Assert.IsNull (ex.InnerException, "#3");
+                               Assert.IsNotNull (ex.Message, "#4");
+                               Assert.IsNotNull (ex.ParamName, "#5");
+                               Assert.AreEqual ("labels", ex.ParamName, "#6");
+                       }
+               }
+
+               [Test]
+               [Category ("NotWorking")] // MS bug: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304610
+               public void Emit10_Labels_Null_MS ()
+               {
+                       DefineBasicMethod ();
+                       try {
+                               il_gen.Emit (OpCodes.Switch, (Label []) null);
+                               Assert.Fail ("#1");
+                       } catch (NullReferenceException) {
+                       }
+               }
+
+               [Test] // Emit (OpCode, LocalBuilder)
+               public void Emit11_Local_Null ()
+               {
+                       DefineBasicMethod ();
+                       try {
+                               il_gen.Emit (OpCodes.Switch, (LocalBuilder) null);
+                               Assert.Fail ("#1");
+                       } catch (ArgumentNullException ex) {
+                               Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
+                               Assert.IsNull (ex.InnerException, "#3");
+                               Assert.IsNotNull (ex.Message, "#4");
+                               Assert.IsNotNull (ex.ParamName, "#5");
+                               Assert.AreEqual ("local", ex.ParamName, "#6");
+                       }
+               }
+
+               [Test] // Emit (OpCode, MethodInfo)
+               public void Emit12_Method_Null ()
+               {
+                       DefineBasicMethod ();
+                       try {
+                               il_gen.Emit (OpCodes.Switch, (MethodInfo) null);
+                               Assert.Fail ("#1");
+                       } catch (ArgumentNullException ex) {
+                               Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
+                               Assert.IsNull (ex.InnerException, "#3");
+                               Assert.IsNotNull (ex.Message, "#4");
+                               Assert.IsNotNull (ex.ParamName, "#5");
+                               Assert.AreEqual ("meth", ex.ParamName, "#6");
+                       }
+               }
+
+               [Test] // Emit (OpCode, SignatureHelper)
+               public void Emit14_Signature_Null ()
+               {
+                       DefineBasicMethod ();
+                       try {
+                               il_gen.Emit (OpCodes.Switch, (SignatureHelper) null);
+                               Assert.Fail ("#1");
+                       } catch (ArgumentNullException ex) {
+                               Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
+                               Assert.IsNull (ex.InnerException, "#3");
+                               Assert.IsNotNull (ex.Message, "#4");
+                               Assert.IsNotNull (ex.ParamName, "#5");
+                       }
+               }
+
+               [Test] // Emit (OpCode, String)
+               public void Emit16_String_Null ()
+               {
+                       DefineBasicMethod ();
+                       try {
+                               il_gen.Emit (OpCodes.Switch, (String) null);
+                               Assert.Fail ("#1");
+                       } catch (ArgumentNullException ex) {
+                               Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
+                               Assert.IsNull (ex.InnerException, "#3");
+                               Assert.IsNotNull (ex.Message, "#4");
+                       }
+               }
+
+               [Test] // Emit (OpCode, Type)
+               public void Emit16_Type_Null ()
+               {
+                       DefineBasicMethod ();
+                       try {
+                               il_gen.Emit (OpCodes.Switch, (Type) null);
+                               Assert.Fail ("#1");
+                       } catch (ArgumentNullException ex) {
+                               Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
+                               Assert.IsNull (ex.InnerException, "#3");
+                               Assert.IsNotNull (ex.Message, "#4");
+                               Assert.IsNotNull (ex.ParamName, "#5");
+                       }
+               }
 
-                       il_gen = myMethod.GetILGenerator();
+               [Test]
+               public void EmitCall_MethodInfo_Null ()
+               {
+                       DefineBasicMethod ();
+                       try {
+                               il_gen.EmitCall (OpCodes.Call, (MethodInfo) null, null);
+                               Assert.Fail ("#1");
+                       } catch (ArgumentNullException ex) {
+                               Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
+                               Assert.IsNull (ex.InnerException, "#3");
+                               Assert.IsNotNull (ex.Message, "#4");
+                               Assert.IsNotNull (ex.ParamName, "#5");
+                               Assert.AreEqual ("methodInfo", ex.ParamName, "#6");
+                       }
+               }
+
+               [Test]
+               public void TestFilterEmittingWithHandlerExecution ()
+               {
+                       DefineTestFilterMethod ();
+                       Type dynt = tb.CreateType ();
+                       
+                       MethodInfo tf = dynt.GetMethod ("TestFilter");
+                       Assert.IsTrue ((bool) tf.Invoke (null, new object [] { true }));
+               }
+
+#if NET_2_0
+               delegate void FooFoo ();
+
+               static void Foo ()
+               {
+               }
+
+               [Test]
+               public void TestEmitCalliWithNullReturnType ()
+               {
+                       MethodBuilder mb = tb.DefineMethod ("F",
+                               MethodAttributes.Public | MethodAttributes.Static, null, new Type [] { typeof (IntPtr) });
+                       mb.SetImplementationFlags (MethodImplAttributes.NoInlining);
+                       il_gen = mb.GetILGenerator ();
+                       il_gen.Emit (OpCodes.Ldarg_0);
+                       il_gen.EmitCalli (OpCodes.Calli, CallingConvention.StdCall, null, Type.EmptyTypes);
+                       il_gen.Emit (OpCodes.Ret);
+       
+                       Type dynt = tb.CreateType ();
+                       dynt.GetMethod ("F", BindingFlags.Public | BindingFlags.Static).Invoke (
+                               null, new object [] { Marshal.GetFunctionPointerForDelegate (new FooFoo (Foo)) });
                }
+#endif
 
                [Test]
-               [ExpectedException (typeof (ArgumentNullException))]
-               public void DeclareLocal_NULL ()
+               [ExpectedException (typeof (Exception))]
+               public void TestFilterEmittingWithoutHandlerExecution ()
                {
-                       il_gen.DeclareLocal (null);
+                       DefineTestFilterMethod ();
+                       Type dynt = tb.CreateType ();
+                       
+                       MethodInfo tf = dynt.GetMethod ("TestFilter");
+                       try {
+                               tf.Invoke (null, new object [] { false });
+                       } catch (TargetInvocationException tie) {
+                               throw tie.InnerException;
+                       }
                }
        }
 }