Fix XMM scanning on Mac x86.
[mono.git] / mcs / class / System.Core / Test / System.Linq.Expressions / ExpressionTest_Call.cs
1 //
2 // ExpressionTest_Call.cs
3 //
4 // Author:
5 //   Federico Di Gregorio <fog@initd.org>
6 //   Jb Evain (jbevain@novell.com)
7 //
8 // (C) 2008 Novell, Inc. (http://www.novell.com)
9 //
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:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
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.
28 //
29
30 using System;
31 using System.Reflection;
32 using System.Reflection.Emit;
33 using System.Collections.Generic;
34 using System.Linq;
35 using System.Linq.Expressions;
36 using NUnit.Framework;
37
38 namespace MonoTests.System.Linq.Expressions {
39
40         [TestFixture]
41         public class ExpressionTest_Call {
42
43                 [Test]
44                 [ExpectedException (typeof (ArgumentNullException))]
45                 public void Arg1Null ()
46                 {
47                         Expression.Call ((Type)null, "TestMethod", null, Expression.Constant (1));
48                 }
49
50                 [Test]
51                 [ExpectedException (typeof (ArgumentNullException))]
52                 public void Arg2Null ()
53                 {
54                         Expression.Call (typeof (MemberClass), null, null, Expression.Constant (1));
55                 }
56
57                 [Test]
58                 [ExpectedException (typeof (InvalidOperationException))]
59                 public void Arg4WrongType ()
60                 {
61                         Expression.Call (typeof (MemberClass), "StaticMethod", null, Expression.Constant (true));
62                 }
63
64                 [Test]
65                 [ExpectedException (typeof (InvalidOperationException))]
66                 public void InstanceMethod ()
67                 {
68                         Expression.Call (typeof (MemberClass), "TestMethod", null, Expression.Constant (1));
69                 }
70
71                 [Test]
72                 public void StaticMethod ()
73                 {
74                         Expression.Call (typeof (MemberClass), "StaticMethod", null, Expression.Constant (1));
75                 }
76
77                 [Test]
78                 public void StaticGenericMethod ()
79                 {
80                         Expression.Call (typeof (MemberClass), "StaticGenericMethod", new [] { typeof (int) }, Expression.Constant (1));
81                 }
82
83                 [Test]
84                 [ExpectedException (typeof (ArgumentNullException))]
85                 public void ArgMethodNull ()
86                 {
87                         Expression.Call (Expression.Constant (new object ()), null);
88                 }
89
90                 [Test]
91                 [ExpectedException (typeof (ArgumentException))]
92                 public void ArgInstanceNullForNonStaticMethod ()
93                 {
94                         Expression.Call (null, typeof (object).GetMethod ("ToString"));
95                 }
96
97                 [Test]
98                 [ExpectedException (typeof (ArgumentException))]
99                 public void InstanceTypeDoesntMatchMethodDeclaringType ()
100                 {
101 #if MOBILE
102                         // ensure that String.Intern won't be removed by the linker
103                         string s = String.Intern (String.Empty);
104 #endif
105                         Expression.Call (Expression.Constant (1), typeof (string).GetMethod ("Intern"));
106                 }
107
108                 [Test]
109                 [ExpectedException (typeof (ArgumentException))]
110                 public void MethodArgumentCountDoesnMatchParameterLength ()
111                 {
112                         Expression.Call (Expression.Constant (new object ()), typeof (object).GetMethod ("ToString"), Expression.Constant (new object ()));
113                 }
114
115                 public class Foo {
116                         public void Bar (string s)
117                         {
118                         }
119                 }
120
121                 [Test]
122                 [ExpectedException (typeof (ArgumentNullException))]
123                 public void MethodHasNullArgument ()
124                 {
125                         Expression.Call (Expression.New (typeof (Foo)), typeof (Foo).GetMethod ("Bar"), null as Expression);
126                 }
127
128                 [Test]
129                 [ExpectedException (typeof (ArgumentException))]
130                 public void MethodArgumentDoesntMatchParameterType ()
131                 {
132                         Expression.Call (Expression.New (typeof (Foo)), typeof (Foo).GetMethod ("Bar"), Expression.Constant (42));
133                 }
134
135                 [Test]
136                 public void CallToString ()
137                 {
138                         var call = Expression.Call (Expression.Constant (new object ()), typeof (object).GetMethod ("ToString"));
139                         Assert.AreEqual ("value(System.Object).ToString()", call.ToString ());
140                 }
141
142                 [Test]
143                 public void CallStringIsNullOrEmpty ()
144                 {
145                         var call = Expression.Call (null, typeof (string).GetMethod ("IsNullOrEmpty"), Expression.Constant (""));
146                         Assert.AreEqual ("IsNullOrEmpty(\"\")", call.ToString ());
147                 }
148
149                 [Test]
150                 [Category ("NotDotNet")] // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=339351
151                 [ExpectedException (typeof (ArgumentException))]
152                 public void CallStaticMethodWithInstanceArgument ()
153                 {
154                         Expression.Call (
155                                 Expression.Parameter (GetType (), "t"),
156                                 GetType ().GetMethod ("Identity"),
157                                 Expression.Constant (null));
158                 }
159
160                 public static object Identity (object o)
161                 {
162                         return o;
163                 }
164
165                 [Test]
166                 public void CompileSimpleStaticCall ()
167                 {
168                         var p = Expression.Parameter (typeof (object), "o");
169                         var lambda = Expression.Lambda<Func<object, object>> (Expression.Call (GetType ().GetMethod ("Identity"), p), p);
170
171                         var i = lambda.Compile ();
172
173                         Assert.AreEqual (2, i (2));
174                         Assert.AreEqual ("Foo", i ("Foo"));
175                 }
176
177                 [Test]
178                 public void CompileSimpleInstanceCall ()
179                 {
180                         var p = Expression.Parameter (typeof (string), "p");
181                         var lambda = Expression.Lambda<Func<string, string>> (
182                                 Expression.Call (
183                                         p, typeof (string).GetMethod ("ToString", Type.EmptyTypes)),
184                                 p);
185
186                         var ts = lambda.Compile ();
187
188                         Assert.AreEqual ("foo", ts ("foo"));
189                         Assert.AreEqual ("bar", ts ("bar"));
190                 }
191
192                 [Test]
193                 [ExpectedException (typeof (InvalidOperationException))]
194                 public void CheckTypeArgsIsNotUsedForParameterLookup ()
195                 {
196                         Expression.Call (GetType (), "EineMethod", new [] { typeof (string), typeof (int) }, "foo".ToConstant (), 2.ToConstant ());
197                 }
198
199                 public static void EineGenericMethod<X, Y> (string foo, int bar)
200                 {
201                 }
202
203                 [Test]
204                 public void CheckTypeArgsIsUsedForGenericArguments ()
205                 {
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 ());
209                 }
210
211                 public struct EineStrukt {
212
213                         public string Foo;
214
215                         public EineStrukt (string foo)
216                         {
217                                 Foo = foo;
218                         }
219
220                         public string GimmeFoo ()
221                         {
222                                 return Foo;
223                         }
224                 }
225
226                 [Test]
227                 [Category ("NotWorkingInterpreter")]
228                 public void CallMethodOnStruct ()
229                 {
230                         var param = Expression.Parameter (typeof (EineStrukt), "s");
231                         var foo = Expression.Lambda<Func<EineStrukt, string>> (
232                                 Expression.Call (param, typeof (EineStrukt).GetMethod ("GimmeFoo")), param).Compile ();
233
234                         var s = new EineStrukt ("foo");
235                         Assert.AreEqual ("foo", foo (s));
236                 }
237
238                 public static int OneStaticMethod ()
239                 {
240                         return 42;
241                 }
242
243                 [Test]
244                 public void CallMethodOnDateTime ()
245                 {
246                         var left = Expression.Call (Expression.Constant (DateTime.Now), typeof(DateTime).GetMethod ("AddDays"), Expression.Constant (-5.0));
247                         var right = Expression.Constant (DateTime.Today.AddDays (1));
248                         var expr = Expression.GreaterThan (left, right);
249
250                         var eq = Expression.Lambda<Func<bool>> (expr).Compile ();
251                         Assert.IsFalse (eq ());
252                 }
253
254                 [Test]
255                 [Category ("NotDotNet")] // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=339351
256                 [ExpectedException (typeof (ArgumentException))]
257                 public void CallStaticMethodOnNonSenseInstanceExpression ()
258                 {
259                         Expression.Call (
260                                 Expression.Constant ("la la la"),
261                                 this.GetType ().GetMethod ("OneStaticMethod"));
262                 }
263
264                 public static int DoSomethingWith (ref int a)
265                 {
266                         return a + 4;
267                 }
268
269                 public static string DoAnotherThing (ref int a, string s)
270                 {
271                         return s + a;
272                 }
273
274                 [Test]
275                 [Category ("NotWorkingInterpreter")]
276                 public void CallStaticMethodWithRefParameter ()
277                 {
278                         var p = Expression.Parameter (typeof (int), "i");
279
280                         var c = Expression.Lambda<Func<int, int>> (
281                                 Expression.Call (GetType ().GetMethod ("DoSomethingWith"), p), p).Compile ();
282
283                         Assert.AreEqual (42, c (38));
284                 }
285
286                 [Test]
287                 [Category ("NotWorkingInterpreter")]
288                 public void CallStaticMethodWithRefParameterAndOtherParameter ()
289                 {
290                         var i = Expression.Parameter (typeof (int), "i");
291                         var s = Expression.Parameter (typeof (string), "s");
292
293                         var lamda = Expression.Lambda<Func<int, string, string>> (
294                                 Expression.Call (GetType ().GetMethod ("DoAnotherThing"), i, s), i, s).Compile ();
295
296                         Assert.AreEqual ("foo42", lamda (42, "foo"));
297                 }
298
299                 [Test]
300                 public void CallDynamicMethod_ToString ()
301                 {
302                         // Regression test for #49686
303                         var m = new DynamicMethod ("intIntId", typeof (int), new Type [] { typeof (int) });
304                         var ilg = m.GetILGenerator ();
305                         ilg.Emit (OpCodes.Ldarg_0);
306                         ilg.Emit (OpCodes.Ret);
307
308                         var i = Expression.Parameter (typeof (int), "i");
309                         var e = Expression.Call (m, i);
310
311                         Assert.IsNotNull (e.ToString ());
312                 }
313
314                 [Test]
315                 public void CallDynamicMethod_CompileInvoke ()
316                 {
317                         var m = new DynamicMethod ("intIntId", typeof (int), new Type [] { typeof (int) });
318                         var ilg = m.GetILGenerator ();
319                         ilg.Emit (OpCodes.Ldarg_0);
320                         ilg.Emit (OpCodes.Ret);
321
322                         var i = Expression.Parameter (typeof (int), "i");
323                         var e = Expression.Call (m, i);
324
325                         var lambda = Expression.Lambda<Func<int, int>> (e, i).Compile ();
326                         Assert.AreEqual (42, lambda (42));
327                 }
328
329                 public static int Bang (Expression i)
330                 {
331                         return (int) (i as ConstantExpression).Value;
332                 }
333                 static bool fout_called = false;
334
335                 public static int FooOut (out int x)
336                 {
337                         fout_called = true;
338                         return x = 0;
339                 }
340
341                 [Test]
342                 [Category ("NotWorkingInterpreter")]
343                 public void Connect282729 ()
344                 {
345                         // test from https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=282729
346
347                         var p = Expression.Parameter (typeof (int), "p");
348                         var lambda = Expression.Lambda<Func<int, int>> (
349                                 Expression.Call (
350                                         GetType ().GetMethod ("FooOut"),
351                                         Expression.ArrayIndex(
352                                                 Expression.NewArrayBounds (
353                                                         typeof(int),
354                                                         1.ToConstant ()),
355                                                 0.ToConstant ())),
356                                 p).Compile ();
357
358                         Assert.AreEqual (0, lambda (0));
359                         Assert.IsTrue (fout_called);
360                 }
361
362                 public static int FooOut2 (out int x)
363                 {
364                         x = 2;
365                         return 3;
366                 }
367
368                 [Test]
369                 [Category ("NotWorking")]
370                 [Category ("NotWorkingInterpreter")]
371                 public void Connect290278 ()
372                 {
373                         // test from https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=290278
374
375                         var p = Expression.Parameter (typeof (int [,]), "p");
376                         var lambda = Expression.Lambda<Func<int [,], int>> (
377                                 Expression.Call (
378                                         GetType ().GetMethod ("FooOut2"),
379                                         Expression.ArrayIndex (p, 0.ToConstant (), 0.ToConstant ())),
380                                 p).Compile ();
381
382                         int [,] data = { { 1 } };
383
384                         Assert.AreEqual (3, lambda (data));
385                         Assert.AreEqual (2, data [0, 0]);
386                 }
387
388                 public static void FooRef (ref string s)
389                 {
390                 }
391
392                 [Test]
393                 [Category ("NotWorkingInterpreter")]
394                 public void Connect297597 ()
395                 {
396                         // test from https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=297597
397
398                         var strings = new string [1];
399
400                         var lambda = Expression.Lambda<Action> (
401                                 Expression.Call (
402                                         GetType ().GetMethod ("FooRef"),
403                                         Expression.ArrayIndex (
404                                                 Expression.Constant (strings), 0.ToConstant ()))).Compile ();
405
406                         lambda ();
407                 }
408
409                 [Test]
410                 [Category ("NotDotNet")] // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=319190
411                 public void Connect319190 ()
412                 {
413                         var lambda = Expression.Lambda<Func<bool>> (
414                                 Expression.TypeIs (
415                                         Expression.New (typeof (TypedReference)),
416                                         typeof (object))).Compile ();
417
418                         Assert.IsTrue (lambda ());
419                 }
420
421                 public static int Truc ()
422                 {
423                         return 42;
424                 }
425
426                 [Test]
427                 public void Connect282702 ()
428                 {
429                         var lambda = Expression.Lambda<Func<Func<int>>> (
430                                 Expression.Convert (
431                                         Expression.Call (
432                                                 typeof (Delegate).GetMethod ("CreateDelegate", new [] { typeof (Type), typeof (object), typeof (MethodInfo) }),
433                                                 Expression.Constant (typeof (Func<int>), typeof (Type)),
434                                                 Expression.Constant (null, typeof (object)),
435                                                 Expression.Constant (GetType ().GetMethod ("Truc"))),
436                                         typeof (Func<int>))).Compile ();
437
438                         Assert.AreEqual (42, lambda ().Invoke ());
439                 }
440
441                 [Test]
442                 public void CallQueryableWhere ()
443                 {
444                         var queryable = new [] { 1, 2, 3 }.AsQueryable ();
445
446                         var parameter = Expression.Parameter (typeof (int), "i");
447                         var lambda = Expression.Lambda<Func<int, bool>> (
448                                 Expression.LessThan (parameter, Expression.Constant (2)),
449                                 parameter);
450
451                         var selector = Expression.Quote (lambda);
452
453                         var call = Expression.Call (
454                                 typeof (Queryable),
455                                 "Where",
456                                 new [] { typeof (int) },
457                                 queryable.Expression,
458                                 selector);
459
460                         Assert.IsNotNull (call);
461                         Assert.IsNotNull (call.Method);
462                 }
463
464                 [Test]
465                 public void CallAsQueryable () // #537768
466                 {
467                         var constant = Expression.Constant (
468                                 new List<string> (),
469                                 typeof (IEnumerable<string>));
470
471                         var call = Expression.Call (
472                                 typeof (Queryable),
473                                 "AsQueryable",
474                                 new [] { typeof (string) },
475                                 constant);
476
477                         Assert.IsNotNull (call);
478                         Assert.AreEqual (1, call.Arguments.Count);
479                         Assert.AreEqual (constant, call.Arguments [0]);
480
481                         var method = call.Method;
482
483                         Assert.AreEqual ("AsQueryable", method.Name);
484                         Assert.IsTrue (method.IsGenericMethod);
485                         Assert.AreEqual (typeof (string), method.GetGenericArguments () [0]);
486                 }
487
488
489                 [Test]
490                 public void CallQueryableSelect () // #536637
491                 {
492                         var parameter = Expression.Parameter (typeof (string), "s");
493                         var string_length = Expression.Property (parameter, typeof (string).GetProperty ("Length"));
494                         var lambda = Expression.Lambda (string_length, parameter);
495
496                         var strings = new [] { "1", "22", "333" };
497
498                         var call = Expression.Call (
499                                 typeof (Queryable),
500                                 "Select",
501                                 new [] { typeof (string), typeof (int) },
502                                 Expression.Constant (strings.AsQueryable ()),
503                                 lambda);
504
505                         Assert.IsNotNull (call);
506
507                         var method = call.Method;
508
509                         Assert.AreEqual ("Select", method.Name);
510                         Assert.IsTrue (method.IsGenericMethod);
511                         Assert.AreEqual (typeof (string), method.GetGenericArguments () [0]);
512                         Assert.AreEqual (typeof (int), method.GetGenericArguments () [1]);
513                 }
514
515                 [Test]
516                 [Category ("NotWorkingInterpreter")]
517                 public void CallNullableGetValueOrDefault () // #568989
518                 {
519                         var value = Expression.Parameter (typeof (int?), "value");
520                         var default_parameter = Expression.Parameter (typeof (int), "default");
521
522                         var getter = Expression.Lambda<Func<int?, int, int>> (
523                                 Expression.Call (
524                                         value,
525                                         "GetValueOrDefault",
526                                         Type.EmptyTypes,
527                                         default_parameter),
528                                 value,
529                                 default_parameter).Compile ();
530
531                         Assert.AreEqual (2, getter (null, 2));
532                         Assert.AreEqual (4, getter (4, 2));
533                 }
534
535                 [Test]
536                 public void CallToStringOnEnum () // #625367
537                 {
538                         var lambda = Expression.Lambda<Func<string>> (
539                                 Expression.Call (
540                                         Expression.Constant (TypeCode.Boolean, typeof (TypeCode)),
541                                         typeof (object).GetMethod ("ToString"))).Compile ();
542
543                         Assert.AreEqual ("Boolean", lambda ());
544                 }
545
546                 public static void AcceptsIEnumerable(IEnumerable<object> o)
547                 {
548                 }
549
550                 [Test]
551                 public void CallIQueryableMethodWithNewArrayBoundExpression () // #2304
552                 {
553                         Expression.Call (
554                                 GetType ().GetMethod ("AcceptsIEnumerable", BindingFlags.Public | BindingFlags.Static),
555                                 Expression.NewArrayBounds (typeof (object), Expression.Constant (0)));
556                 }
557         }
558 }