2 // ExpressionTest_Call.cs
5 // Federico Di Gregorio <fog@initd.org>
6 // Jb Evain (jbevain@novell.com)
8 // (C) 2008 Novell, Inc. (http://www.novell.com)
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Reflection;
32 using System.Reflection.Emit;
33 using System.Collections.Generic;
35 using System.Linq.Expressions;
36 using NUnit.Framework;
38 namespace MonoTests.System.Linq.Expressions {
41 public class ExpressionTest_Call {
44 [ExpectedException (typeof (ArgumentNullException))]
45 public void Arg1Null ()
47 Expression.Call ((Type)null, "TestMethod", null, Expression.Constant (1));
51 [ExpectedException (typeof (ArgumentNullException))]
52 public void Arg2Null ()
54 Expression.Call (typeof (MemberClass), null, null, Expression.Constant (1));
58 [ExpectedException (typeof (InvalidOperationException))]
59 public void Arg4WrongType ()
61 Expression.Call (typeof (MemberClass), "StaticMethod", null, Expression.Constant (true));
65 [ExpectedException (typeof (InvalidOperationException))]
66 public void InstanceMethod ()
68 Expression.Call (typeof (MemberClass), "TestMethod", null, Expression.Constant (1));
72 public void StaticMethod ()
74 Expression.Call (typeof (MemberClass), "StaticMethod", null, Expression.Constant (1));
78 public void StaticGenericMethod ()
80 Expression.Call (typeof (MemberClass), "StaticGenericMethod", new [] { typeof (int) }, Expression.Constant (1));
84 [ExpectedException (typeof (ArgumentNullException))]
85 public void ArgMethodNull ()
87 Expression.Call (Expression.Constant (new object ()), null);
91 [ExpectedException (typeof (ArgumentException))]
92 public void ArgInstanceNullForNonStaticMethod ()
94 Expression.Call (null, typeof (object).GetMethod ("ToString"));
98 [ExpectedException (typeof (ArgumentException))]
99 public void InstanceTypeDoesntMatchMethodDeclaringType ()
102 // ensure that String.Intern won't be removed by the linker
103 string s = String.Intern (String.Empty);
105 Expression.Call (Expression.Constant (1), typeof (string).GetMethod ("Intern"));
109 [ExpectedException (typeof (ArgumentException))]
110 public void MethodArgumentCountDoesnMatchParameterLength ()
112 Expression.Call (Expression.Constant (new object ()), typeof (object).GetMethod ("ToString"), Expression.Constant (new object ()));
116 public void Bar (string s)
122 [ExpectedException (typeof (ArgumentNullException))]
123 public void MethodHasNullArgument ()
125 Expression.Call (Expression.New (typeof (Foo)), typeof (Foo).GetMethod ("Bar"), null as Expression);
129 [ExpectedException (typeof (ArgumentException))]
130 public void MethodArgumentDoesntMatchParameterType ()
132 Expression.Call (Expression.New (typeof (Foo)), typeof (Foo).GetMethod ("Bar"), Expression.Constant (42));
136 public void CallToString ()
138 var call = Expression.Call (Expression.Constant (new object ()), typeof (object).GetMethod ("ToString"));
139 Assert.AreEqual ("value(System.Object).ToString()", call.ToString ());
143 public void CallStringIsNullOrEmpty ()
145 var call = Expression.Call (null, typeof (string).GetMethod ("IsNullOrEmpty"), Expression.Constant (""));
146 Assert.AreEqual ("IsNullOrEmpty(\"\")", call.ToString ());
150 [Category ("NotDotNet")] // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=339351
151 [ExpectedException (typeof (ArgumentException))]
152 public void CallStaticMethodWithInstanceArgument ()
155 Expression.Parameter (GetType (), "t"),
156 GetType ().GetMethod ("Identity"),
157 Expression.Constant (null));
160 public static object Identity (object o)
166 public void CompileSimpleStaticCall ()
168 var p = Expression.Parameter (typeof (object), "o");
169 var lambda = Expression.Lambda<Func<object, object>> (Expression.Call (GetType ().GetMethod ("Identity"), p), p);
171 var i = lambda.Compile ();
173 Assert.AreEqual (2, i (2));
174 Assert.AreEqual ("Foo", i ("Foo"));
178 public void CompileSimpleInstanceCall ()
180 var p = Expression.Parameter (typeof (string), "p");
181 var lambda = Expression.Lambda<Func<string, string>> (
183 p, typeof (string).GetMethod ("ToString", Type.EmptyTypes)),
186 var ts = lambda.Compile ();
188 Assert.AreEqual ("foo", ts ("foo"));
189 Assert.AreEqual ("bar", ts ("bar"));
193 [ExpectedException (typeof (InvalidOperationException))]
194 public void CheckTypeArgsIsNotUsedForParameterLookup ()
196 Expression.Call (GetType (), "EineMethod", new [] { typeof (string), typeof (int) }, "foo".ToConstant (), 2.ToConstant ());
199 public static void EineGenericMethod<X, Y> (string foo, int bar)
204 public void CheckTypeArgsIsUsedForGenericArguments ()
206 var m = Expression.Call (GetType (), "EineGenericMethod", new [] { typeof (string), typeof (int) }, "foo".ToConstant (), 2.ToConstant ());
207 Assert.IsNotNull (m.Method);
208 Assert.AreEqual ("Void EineGenericMethod[String,Int32](System.String, Int32)", m.Method.ToString ());
211 public struct EineStrukt {
215 public EineStrukt (string foo)
220 public string GimmeFoo ()
227 public void CallMethodOnStruct ()
229 var param = Expression.Parameter (typeof (EineStrukt), "s");
230 var foo = Expression.Lambda<Func<EineStrukt, string>> (
231 Expression.Call (param, typeof (EineStrukt).GetMethod ("GimmeFoo")), param).Compile ();
233 var s = new EineStrukt ("foo");
234 Assert.AreEqual ("foo", foo (s));
237 public static int OneStaticMethod ()
243 public void CallMethodOnDateTime ()
245 var left = Expression.Call (Expression.Constant (DateTime.Now), typeof(DateTime).GetMethod ("AddDays"), Expression.Constant (-5.0));
246 var right = Expression.Constant (DateTime.Today.AddDays (1));
247 var expr = Expression.GreaterThan (left, right);
249 var eq = Expression.Lambda<Func<bool>> (expr).Compile ();
250 Assert.IsFalse (eq ());
254 [Category ("NotDotNet")] // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=339351
255 [ExpectedException (typeof (ArgumentException))]
256 public void CallStaticMethodOnNonSenseInstanceExpression ()
259 Expression.Constant ("la la la"),
260 this.GetType ().GetMethod ("OneStaticMethod"));
263 public static int DoSomethingWith (ref int a)
268 public static string DoAnotherThing (ref int a, string s)
274 public void CallStaticMethodWithRefParameter ()
276 var p = Expression.Parameter (typeof (int), "i");
278 var c = Expression.Lambda<Func<int, int>> (
279 Expression.Call (GetType ().GetMethod ("DoSomethingWith"), p), p).Compile ();
281 Assert.AreEqual (42, c (38));
285 public void CallStaticMethodWithRefParameterAndOtherParameter ()
287 var i = Expression.Parameter (typeof (int), "i");
288 var s = Expression.Parameter (typeof (string), "s");
290 var lamda = Expression.Lambda<Func<int, string, string>> (
291 Expression.Call (GetType ().GetMethod ("DoAnotherThing"), i, s), i, s).Compile ();
293 Assert.AreEqual ("foo42", lamda (42, "foo"));
296 #if !FULL_AOT_RUNTIME
298 public void CallDynamicMethod_ToString ()
300 // Regression test for #49686
301 var m = new DynamicMethod ("intIntId", typeof (int), new Type [] { typeof (int) });
302 var ilg = m.GetILGenerator ();
303 ilg.Emit (OpCodes.Ldarg_0);
304 ilg.Emit (OpCodes.Ret);
306 var i = Expression.Parameter (typeof (int), "i");
307 var e = Expression.Call (m, i);
309 Assert.IsNotNull (e.ToString ());
313 public void CallDynamicMethod_CompileInvoke ()
315 var m = new DynamicMethod ("intIntId", typeof (int), new Type [] { typeof (int) });
316 var ilg = m.GetILGenerator ();
317 ilg.Emit (OpCodes.Ldarg_0);
318 ilg.Emit (OpCodes.Ret);
320 var i = Expression.Parameter (typeof (int), "i");
321 var e = Expression.Call (m, i);
323 var lambda = Expression.Lambda<Func<int, int>> (e, i).Compile ();
324 Assert.AreEqual (42, lambda (42));
328 public static int Bang (Expression i)
330 return (int) (i as ConstantExpression).Value;
332 static bool fout_called = false;
334 public static int FooOut (out int x)
341 public void Connect282729 ()
343 // test from https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=282729
345 var p = Expression.Parameter (typeof (int), "p");
346 var lambda = Expression.Lambda<Func<int, int>> (
348 GetType ().GetMethod ("FooOut"),
349 Expression.ArrayIndex(
350 Expression.NewArrayBounds (
356 Assert.AreEqual (0, lambda (0));
357 Assert.IsTrue (fout_called);
360 public static int FooOut2 (out int x)
367 public void Connect290278 ()
369 // test from https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=290278
371 var p = Expression.Parameter (typeof (int [,]), "p");
372 var lambda = Expression.Lambda<Func<int [,], int>> (
374 GetType ().GetMethod ("FooOut2"),
375 Expression.ArrayIndex (p, 0.ToConstant (), 0.ToConstant ())),
378 int [,] data = { { 1 } };
380 Assert.AreEqual (3, lambda (data));
381 Assert.AreEqual (2, data [0, 0]);
384 public static void FooRef (ref string s)
389 public void Connect297597 ()
391 // test from https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=297597
393 var strings = new string [1];
395 var lambda = Expression.Lambda<Action> (
397 GetType ().GetMethod ("FooRef"),
398 Expression.ArrayIndex (
399 Expression.Constant (strings), 0.ToConstant ()))).Compile ();
405 [Category ("NotDotNet")] // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=319190
406 [Category ("NotWorkingInterpreter")]
407 public void Connect319190 ()
409 var lambda = Expression.Lambda<Func<bool>> (
411 Expression.New (typeof (TypedReference)),
412 typeof (object))).Compile ();
414 Assert.IsTrue (lambda ());
417 public static int Truc ()
423 public void Connect282702 ()
425 var lambda = Expression.Lambda<Func<Func<int>>> (
428 typeof (Delegate).GetMethod ("CreateDelegate", new [] { typeof (Type), typeof (object), typeof (MethodInfo) }),
429 Expression.Constant (typeof (Func<int>), typeof (Type)),
430 Expression.Constant (null, typeof (object)),
431 Expression.Constant (GetType ().GetMethod ("Truc"))),
432 typeof (Func<int>))).Compile ();
434 Assert.AreEqual (42, lambda ().Invoke ());
438 public void CallQueryableWhere ()
440 var queryable = new [] { 1, 2, 3 }.AsQueryable ();
442 var parameter = Expression.Parameter (typeof (int), "i");
443 var lambda = Expression.Lambda<Func<int, bool>> (
444 Expression.LessThan (parameter, Expression.Constant (2)),
447 var selector = Expression.Quote (lambda);
449 var call = Expression.Call (
452 new [] { typeof (int) },
453 queryable.Expression,
456 Assert.IsNotNull (call);
457 Assert.IsNotNull (call.Method);
461 public void CallAsQueryable () // #537768
463 var constant = Expression.Constant (
465 typeof (IEnumerable<string>));
467 var call = Expression.Call (
470 new [] { typeof (string) },
473 Assert.IsNotNull (call);
474 Assert.AreEqual (1, call.Arguments.Count);
475 Assert.AreEqual (constant, call.Arguments [0]);
477 var method = call.Method;
479 Assert.AreEqual ("AsQueryable", method.Name);
480 Assert.IsTrue (method.IsGenericMethod);
481 Assert.AreEqual (typeof (string), method.GetGenericArguments () [0]);
486 public void CallQueryableSelect () // #536637
488 var parameter = Expression.Parameter (typeof (string), "s");
489 var string_length = Expression.Property (parameter, typeof (string).GetProperty ("Length"));
490 var lambda = Expression.Lambda (string_length, parameter);
492 var strings = new [] { "1", "22", "333" };
494 var call = Expression.Call (
497 new [] { typeof (string), typeof (int) },
498 Expression.Constant (strings.AsQueryable ()),
501 Assert.IsNotNull (call);
503 var method = call.Method;
505 Assert.AreEqual ("Select", method.Name);
506 Assert.IsTrue (method.IsGenericMethod);
507 Assert.AreEqual (typeof (string), method.GetGenericArguments () [0]);
508 Assert.AreEqual (typeof (int), method.GetGenericArguments () [1]);
512 public void CallNullableGetValueOrDefault () // #568989
514 var value = Expression.Parameter (typeof (int?), "value");
515 var default_parameter = Expression.Parameter (typeof (int), "default");
517 var getter = Expression.Lambda<Func<int?, int, int>> (
524 default_parameter).Compile ();
526 Assert.AreEqual (2, getter (null, 2));
527 Assert.AreEqual (4, getter (4, 2));
531 public void CallToStringOnEnum () // #625367
533 var lambda = Expression.Lambda<Func<string>> (
535 Expression.Constant (TypeCode.Boolean, typeof (TypeCode)),
536 typeof (object).GetMethod ("ToString"))).Compile ();
538 Assert.AreEqual ("Boolean", lambda ());
541 public static void AcceptsIEnumerable(IEnumerable<object> o)
546 public void CallIQueryableMethodWithNewArrayBoundExpression () // #2304
549 GetType ().GetMethod ("AcceptsIEnumerable", BindingFlags.Public | BindingFlags.Static),
550 Expression.NewArrayBounds (typeof (object), Expression.Constant (0)));