2009-07-11 Michael Barker <mike@middlesoft.co.uk>
[mono.git] / mcs / class / corlib / Test / System.Reflection / BinderTests.cs
index d28137ff4fe46069aa8dd35db7dddbdd7bb84b56..e7496f7fd7058c33d693b3cdc70973c3820b45eb 100644 (file)
@@ -9,6 +9,7 @@
 
 using NUnit.Framework;
 using System;
+using System.Globalization;
 using System.IO;
 using System.Reflection;
 
@@ -203,6 +204,47 @@ namespace MonoTests.System.Reflection
                        Assert.IsNotNull (prop, "short");
                }
 
+               [Test]
+               public void SelectMethod_ByRef ()
+               {
+                       Type type = typeof (ByRefMatch);
+                       BindingFlags flags = BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance;
+                       MethodBase [] match;
+                       Type [] types;
+                       MethodBase selected;
+
+                       MethodInfo mi_run = type.GetMethod ("Run", flags, binder,
+                               new Type [] { typeof (int) }, null);
+                       Assert.IsFalse (mi_run.GetParameters () [0].ParameterType.IsByRef, "#A1");
+                       MethodInfo mi_run_ref = type.GetMethod ("Run", flags, binder,
+                               new Type [] { typeof (int).MakeByRefType () }, null);
+                       Assert.IsTrue (mi_run_ref.GetParameters () [0].ParameterType.IsByRef, "#A2");
+
+                       match = new MethodBase [] { mi_run_ref };
+                       types = new Type [] { typeof (int) };
+                       selected = binder.SelectMethod (flags, match, types, null);
+                       Assert.IsNull (selected, "#B1");
+                       types = new Type [] { typeof (int).MakeByRefType () };
+                       selected = binder.SelectMethod (flags, match, types, null);
+                       Assert.AreSame (mi_run_ref, selected, "#B2");
+
+                       match = new MethodBase [] { mi_run };
+                       types = new Type [] { typeof (int) };
+                       selected = binder.SelectMethod (flags, match, types, null);
+                       Assert.AreSame (mi_run, selected, "#C1");
+                       types = new Type [] { typeof (int).MakeByRefType () };
+                       selected = binder.SelectMethod (flags, match, types, null);
+                       Assert.IsNull (selected, "#C1");
+
+                       match = new MethodBase [] { mi_run, mi_run_ref };
+                       types = new Type [] { typeof (int) };
+                       selected = binder.SelectMethod (flags, match, types, null);
+                       Assert.AreSame (mi_run, selected, "#D1");
+                       types = new Type [] { typeof (int).MakeByRefType () };
+                       selected = binder.SelectMethod (flags, match, types, null);
+                       Assert.AreSame (mi_run_ref, selected, "#D2");
+               }
+
                [Test]
                public void ArgNullOnMethod () // see bug 58846. We throwed nullref here.
                {
@@ -223,6 +265,45 @@ namespace MonoTests.System.Reflection
                        Assert.IsNotNull (prop);
                }
 
+               [Test]
+               public void BindToMethod_ByRef ()
+               {
+                       Type type = typeof (ByRefMatch);
+                       BindingFlags flags = BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance;
+                       MethodBase [] match;
+                       object [] args = new object [] { 5 };
+                       object state;
+                       MethodBase selected;
+                       CultureInfo culture = CultureInfo.InvariantCulture;
+
+                       MethodInfo mi_run = type.GetMethod ("Run", flags, binder,
+                               new Type [] { typeof (int) }, null);
+                       Assert.IsFalse (mi_run.GetParameters () [0].ParameterType.IsByRef, "#A1");
+                       MethodInfo mi_run_ref = type.GetMethod ("Run", flags, binder,
+                               new Type [] { typeof (int).MakeByRefType () }, null);
+                       Assert.IsTrue (mi_run_ref.GetParameters () [0].ParameterType.IsByRef, "#A2");
+
+                       match = new MethodBase [] { mi_run };
+                       selected = binder.BindToMethod (flags, match, ref args, null, culture,
+                               null, out state);
+                       Assert.AreSame (mi_run, selected, "#1");
+
+                       match = new MethodBase [] { mi_run_ref };
+                       selected = binder.BindToMethod (flags, match, ref args, null, culture,
+                               null, out state);
+                       Assert.AreSame (mi_run_ref, selected, "#2");
+
+                       match = new MethodBase [] { mi_run, mi_run_ref };
+                       selected = binder.BindToMethod (flags, match, ref args, null, culture,
+                               null, out state);
+                       Assert.AreSame (mi_run, selected, "#3");
+
+                       match = new MethodBase [] { mi_run_ref, mi_run };
+                       selected = binder.BindToMethod (flags, match, ref args, null, culture,
+                               null, out state);
+                       Assert.AreSame (mi_run, selected, "#4");
+               }
+
                [Test] // bug #41691
                public void BindToMethodNamedArgs ()
                {
@@ -293,10 +374,56 @@ namespace MonoTests.System.Reflection
                        Assert.AreEqual (3, bug42457_2, "#6");
                }
 
+#if NET_2_0
+               [Test]
+               public void NullableArg () {
+                       MethodInfo method = (typeof (BinderTest)).GetMethod("SetA", new [] {typeof (Int32)});
+                       Assert.AreEqual (5, method.Invoke (new BinderTest (), new object [] { 5 }));
+               }
+
+               public int SetA(Int32? a) {
+                       return (int)a;
+               }
+#endif
+
                static void MethodWithLongParam(long param)
                {
                }
 
+               [Test]
+               public void TestParamsAttribute ()
+               {
+                       MethodInfo mi = typeof (BinderTest).GetMethod ("params_method1", BindingFlags.Static|BindingFlags.Public, null, new Type [] { typeof (object), typeof (object) }, null);
+                       Assert.AreEqual (typeof (object), mi.GetParameters ()[1].ParameterType);
+
+                       MethodInfo mi2 = typeof (BinderTest).GetMethod ("params_method1", BindingFlags.Static|BindingFlags.Public, null, new Type [] { typeof (object), typeof (object), typeof (object) }, null);
+                       Assert.AreEqual (typeof (object[]), mi2.GetParameters ()[1].ParameterType);
+               }
+
+               public static void params_method1 (object o, params object[] o2) {
+               }
+
+               public static void params_method1 (object o, object o2) {
+               }
+
+               public static double DoubleMethod (double d) {
+                       return d;
+               }
+
+               public static float FloatMethod (float f) {
+                       return f;
+               }
+
+               [Test]
+               public void ChangeType ()
+               {
+                       // Char -> Double
+                       Assert.AreEqual (42.0, typeof (BinderTest).GetMethod ("DoubleMethod").Invoke (null, new object[] { (char)42 }));
+
+                       // Char -> Float
+                       Assert.AreEqual (42.0f, typeof (BinderTest).GetMethod ("FloatMethod").Invoke (null, new object[] { (char)42 }));
+               }
+
                [Test]
                public void TestExactBinding ()
                {
@@ -372,6 +499,240 @@ namespace MonoTests.System.Reflection
                public class Bug77079C : Bug77079B
                {
                }
+
+               [Test] // bug #76083
+               public void GetMethodAvoidAmbiguity3 ()
+               {
+                       Type[] types = new Type[] { typeof (Bug76083ArgDerived) };
+                       MethodInfo m = typeof (Bug76083Derived).GetMethod ("Foo", types);
+                       Assert.AreEqual (typeof (Bug76083Derived), m.DeclaringType);
+               }
+
+               public class Bug76083ArgBase {}
+               public class Bug76083ArgDerived : Bug76083ArgBase {}
+
+               public class Bug76083Base
+               {
+                       public void Foo (Bug76083ArgBase a) {}
+               }
+
+               public class Bug76083Derived : Bug76083Base
+               {
+                       public new void Foo (Bug76083ArgBase a) {}
+               }
+
+               private const BindingFlags BUG324998_BINDING_FLAGS
+                       = BindingFlags.Public | BindingFlags.NonPublic
+                       | BindingFlags.Instance | BindingFlags.Static
+                       | BindingFlags.IgnoreCase;
+
+               class Bug324998AGood { public virtual void f(int i1, int i2, bool b) {} }
+
+               class Bug324998BGood : Bug324998AGood { public override void f(int i1, int i2, bool b) {} }
+
+               class Bug324998ABad {
+                       public virtual void f(int i1, int i2) {}
+                       public virtual void f(int i1, int i2, bool b) {}
+               }
+
+               class Bug324998BBad : Bug324998ABad { public override void f(int i1, int i2, bool b) {} }
+
+               [Test]
+               public void Bug324998Good () {
+                       if (typeof(Bug324998BGood).GetMethod("f", BUG324998_BINDING_FLAGS) == null)
+                               throw new Exception("Bug324998Good");
+               }
+
+               [Test]
+               [ExpectedException (typeof (AmbiguousMatchException))]
+               public void Bug324998Bad () {
+                       typeof(Bug324998BBad).GetMethod("f", BUG324998_BINDING_FLAGS);
+               }
+
+        void Bug380361 (MyEnum e) { }
+
+        [Test]
+        public void TestEnumConversion ()
+        {
+            Type type = this.GetType ();
+            MethodInfo mi = type.GetMethod ("Bug380361", BindingFlags.NonPublic | BindingFlags.Instance, binder, new Type [] { typeof (MyEnum) }, null);
+            mi.Invoke (this, new object [] { (int)MyEnum.Zero });
+        }
+
+        [Test]
+        [ExpectedException(typeof (ArgumentException))]
+        public void TestEnumConversion2 ()
+        {
+            Type type = this.GetType ();
+            MethodInfo mi = type.GetMethod ("Bug380361", BindingFlags.NonPublic | BindingFlags.Instance, binder, new Type [] { typeof (MyEnum) }, null);
+            mi.Invoke (this, new object [] { (long)MyEnum.Zero });
+        }
+
+               class AssertingBinder : Binder {
+
+                       public static readonly AssertingBinder Instance = new AssertingBinder ();
+
+                       public override FieldInfo BindToField (BindingFlags bindingAttr, FieldInfo [] match, object value, CultureInfo culture)
+                       {
+                               Assert.IsNotNull (match);
+
+                               return Type.DefaultBinder.BindToField (bindingAttr, match, value, culture);
+                       }
+
+                       public override MethodBase BindToMethod (BindingFlags bindingAttr, MethodBase [] match, ref object [] args, ParameterModifier [] modifiers, CultureInfo culture, string [] names, out object state)
+                       {
+                               Assert.IsNotNull (match);
+                               Assert.IsNotNull (args);
+
+                               return Type.DefaultBinder.BindToMethod (bindingAttr, match, ref args, modifiers, culture, names, out state);
+                       }
+
+                       public override object ChangeType (object value, Type type, CultureInfo culture)
+                       {
+                               Assert.IsNotNull (value);
+                               Assert.IsNotNull (type);
+
+                               return Type.DefaultBinder.ChangeType (value, type, culture);
+                       }
+
+                       public override void ReorderArgumentArray (ref object [] args, object state)
+                       {
+                               Assert.IsNotNull (args);
+
+                               Type.DefaultBinder.ReorderArgumentArray (ref args, state);
+                       }
+
+                       public override MethodBase SelectMethod (BindingFlags bindingAttr, MethodBase [] match, Type [] types, ParameterModifier [] modifiers)
+                       {
+                               Assert.IsNotNull (match);
+                               Assert.IsNotNull (types);
+
+                               return Type.DefaultBinder.SelectMethod (bindingAttr, match, types, modifiers);
+                       }
+
+                       public override PropertyInfo SelectProperty (BindingFlags bindingAttr, PropertyInfo [] match, Type returnType, Type [] indexes, ParameterModifier [] modifiers)
+                       {
+                               Assert.IsNotNull (match);
+
+                               return Type.DefaultBinder.SelectProperty (bindingAttr, match, returnType, indexes, modifiers);
+                       }
+               }
+
+               class BaseFoo {
+                       public void Bar ()
+                       {
+                       }
+
+                       public int Add(int x, int y)
+                       {
+                               return x + y;   
+                       }
+               }
+
+               class Foo : BaseFoo {
+
+                       public bool Barred;
+
+                       public new void Bar ()
+                       {
+                               Barred = true;
+                       }
+               }
+
+               class ByRefMatch {
+                       public void Run (int i)
+                       {
+                       }
+
+                       public void Run (out int i)
+                       {
+                               i = 0;
+                       }
+               }
+
+               [Test] // bug  #471257
+               public void TestCustomBinderNonNullArgs ()
+               {
+                       var foo = new Foo ();
+
+                       typeof (Foo).InvokeMember (
+                               "Bar",
+                               BindingFlags.InvokeMethod,
+                               AssertingBinder.Instance,
+                               foo,
+                               null);
+
+                       Assert.IsTrue (foo.Barred);
+               }
+
+               class Int32Binder : AssertingBinder
+               {
+                       public override object ChangeType(Object value, Type type, CultureInfo ci)
+                       {
+                               if (value.GetType() == type) {
+                                       return value;
+                               } else if (type.IsPrimitive) {
+                                       if (type == typeof(Int32))
+                                               return Convert.ToInt32(value);
+
+                                       throw new ArgumentException("missing support for primitive: " + type);
+                               }
+
+                               throw new ArgumentException("Could not ChangeType to " + type.FullName);
+                       }
+               }
+
+               [Test]
+               [ExpectedException(typeof (TargetParameterCountException))]
+               public void TestTargetParameterCountExceptionA ()
+               {
+                       MethodInfo method = typeof (Foo).GetMethod ("Add");
+                       method.Invoke((new Foo ()), 0, null, null, null);
+               }
+
+               [Test]
+               [ExpectedException(typeof (TargetParameterCountException))]
+               public void TestTargetParameterCountExceptionB ()
+               {
+                       MethodInfo method = typeof (Foo).GetMethod ("Add");
+                       method.Invoke(new Foo (), 0, null, new object [] {1}, null);
+               }
+
+               [Test]
+               public void TestBindingFlagsA ()
+               {
+                       MethodInfo method = typeof (Foo).GetMethod ("Add");
+                       method.Invoke((new Foo ()), 0, null, new object [] {1, 2}, null);
+               }
+
+               [Test]
+               [ExpectedException(typeof (ArgumentException))]
+               public void TestBindingFlagsB ()
+               {
+                       MethodInfo method = typeof (Foo).GetMethod ("Add");
+                       method.Invoke((new Foo ()), 0, null, new object [] {1, "2"}, null);
+               }
+
+               [Test]
+               public void TestBindingFlagsExactBindingA ()
+               {
+                       MethodInfo method = typeof (Foo).GetMethod ("Add");
+                       method.Invoke((new Foo ()), BindingFlags.ExactBinding, null, new object [] {1, 2}, null);
+               }
+
+               [Test]
+               [ExpectedException(typeof (ArgumentException))]
+               public void TestBindingFlagsExactBindingB ()
+               {
+                       MethodInfo method = typeof (Foo).GetMethod ("Add");
+                       method.Invoke((new Foo ()), BindingFlags.ExactBinding, new Int32Binder (), new object [] {1, "2"}, null);
+               }
+
+               [Test]
+               public void TestBindingFlagsExactBindingC ()
+               {
+                       MethodInfo method = typeof (Foo).GetMethod ("Add");
+                       method.Invoke((new Foo ()), 0, new Int32Binder (), new object [] {1, "2"}, null);
+               }
        }
 }
-