[test] Use FULL_AOT_RUNTIME instead of MONOTOUCH.
[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                 public void CallMethodOnStruct ()
228                 {
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 ();
232
233                         var s = new EineStrukt ("foo");
234                         Assert.AreEqual ("foo", foo (s));
235                 }
236
237                 public static int OneStaticMethod ()
238                 {
239                         return 42;
240                 }
241
242                 [Test]
243                 public void CallMethodOnDateTime ()
244                 {
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);
248
249                         var eq = Expression.Lambda<Func<bool>> (expr).Compile ();
250                         Assert.IsFalse (eq ());
251                 }
252
253                 [Test]
254                 [Category ("NotDotNet")] // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=339351
255                 [ExpectedException (typeof (ArgumentException))]
256                 public void CallStaticMethodOnNonSenseInstanceExpression ()
257                 {
258                         Expression.Call (
259                                 Expression.Constant ("la la la"),
260                                 this.GetType ().GetMethod ("OneStaticMethod"));
261                 }
262
263                 public static int DoSomethingWith (ref int a)
264                 {
265                         return a + 4;
266                 }
267
268                 public static string DoAnotherThing (ref int a, string s)
269                 {
270                         return s + a;
271                 }
272
273                 [Test]
274                 public void CallStaticMethodWithRefParameter ()
275                 {
276                         var p = Expression.Parameter (typeof (int), "i");
277
278                         var c = Expression.Lambda<Func<int, int>> (
279                                 Expression.Call (GetType ().GetMethod ("DoSomethingWith"), p), p).Compile ();
280
281                         Assert.AreEqual (42, c (38));
282                 }
283
284                 [Test]
285                 public void CallStaticMethodWithRefParameterAndOtherParameter ()
286                 {
287                         var i = Expression.Parameter (typeof (int), "i");
288                         var s = Expression.Parameter (typeof (string), "s");
289
290                         var lamda = Expression.Lambda<Func<int, string, string>> (
291                                 Expression.Call (GetType ().GetMethod ("DoAnotherThing"), i, s), i, s).Compile ();
292
293                         Assert.AreEqual ("foo42", lamda (42, "foo"));
294                 }
295
296 #if !FULL_AOT_RUNTIME
297                 [Test]
298                 public void CallDynamicMethod_ToString ()
299                 {
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);
305
306                         var i = Expression.Parameter (typeof (int), "i");
307                         var e = Expression.Call (m, i);
308
309                         Assert.IsNotNull (e.ToString ());
310                 }
311
312                 [Test]
313                 public void CallDynamicMethod_CompileInvoke ()
314                 {
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);
319
320                         var i = Expression.Parameter (typeof (int), "i");
321                         var e = Expression.Call (m, i);
322
323                         var lambda = Expression.Lambda<Func<int, int>> (e, i).Compile ();
324                         Assert.AreEqual (42, lambda (42));
325                 }
326 #endif
327
328                 public static int Bang (Expression i)
329                 {
330                         return (int) (i as ConstantExpression).Value;
331                 }
332                 static bool fout_called = false;
333
334                 public static int FooOut (out int x)
335                 {
336                         fout_called = true;
337                         return x = 0;
338                 }
339
340                 [Test]
341                 public void Connect282729 ()
342                 {
343                         // test from https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=282729
344
345                         var p = Expression.Parameter (typeof (int), "p");
346                         var lambda = Expression.Lambda<Func<int, int>> (
347                                 Expression.Call (
348                                         GetType ().GetMethod ("FooOut"),
349                                         Expression.ArrayIndex(
350                                                 Expression.NewArrayBounds (
351                                                         typeof(int),
352                                                         1.ToConstant ()),
353                                                 0.ToConstant ())),
354                                 p).Compile ();
355
356                         Assert.AreEqual (0, lambda (0));
357                         Assert.IsTrue (fout_called);
358                 }
359
360                 public static int FooOut2 (out int x)
361                 {
362                         x = 2;
363                         return 3;
364                 }
365
366                 [Test]
367                 public void Connect290278 ()
368                 {
369                         // test from https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=290278
370
371                         var p = Expression.Parameter (typeof (int [,]), "p");
372                         var lambda = Expression.Lambda<Func<int [,], int>> (
373                                 Expression.Call (
374                                         GetType ().GetMethod ("FooOut2"),
375                                         Expression.ArrayIndex (p, 0.ToConstant (), 0.ToConstant ())),
376                                 p).Compile ();
377
378                         int [,] data = { { 1 } };
379
380                         Assert.AreEqual (3, lambda (data));
381                         Assert.AreEqual (2, data [0, 0]);
382                 }
383
384                 public static void FooRef (ref string s)
385                 {
386                 }
387
388                 [Test]
389                 public void Connect297597 ()
390                 {
391                         // test from https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=297597
392
393                         var strings = new string [1];
394
395                         var lambda = Expression.Lambda<Action> (
396                                 Expression.Call (
397                                         GetType ().GetMethod ("FooRef"),
398                                         Expression.ArrayIndex (
399                                                 Expression.Constant (strings), 0.ToConstant ()))).Compile ();
400
401                         lambda ();
402                 }
403
404                 [Test]
405                 [Category ("NotDotNet")] // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=319190
406                 [Category ("NotWorkingInterpreter")]
407                 public void Connect319190 ()
408                 {
409                         var lambda = Expression.Lambda<Func<bool>> (
410                                 Expression.TypeIs (
411                                         Expression.New (typeof (TypedReference)),
412                                         typeof (object))).Compile ();
413
414                         Assert.IsTrue (lambda ());
415                 }
416
417                 public static int Truc ()
418                 {
419                         return 42;
420                 }
421
422                 [Test]
423                 public void Connect282702 ()
424                 {
425                         var lambda = Expression.Lambda<Func<Func<int>>> (
426                                 Expression.Convert (
427                                         Expression.Call (
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 ();
433
434                         Assert.AreEqual (42, lambda ().Invoke ());
435                 }
436
437                 [Test]
438                 public void CallQueryableWhere ()
439                 {
440                         var queryable = new [] { 1, 2, 3 }.AsQueryable ();
441
442                         var parameter = Expression.Parameter (typeof (int), "i");
443                         var lambda = Expression.Lambda<Func<int, bool>> (
444                                 Expression.LessThan (parameter, Expression.Constant (2)),
445                                 parameter);
446
447                         var selector = Expression.Quote (lambda);
448
449                         var call = Expression.Call (
450                                 typeof (Queryable),
451                                 "Where",
452                                 new [] { typeof (int) },
453                                 queryable.Expression,
454                                 selector);
455
456                         Assert.IsNotNull (call);
457                         Assert.IsNotNull (call.Method);
458                 }
459
460                 [Test]
461                 public void CallAsQueryable () // #537768
462                 {
463                         var constant = Expression.Constant (
464                                 new List<string> (),
465                                 typeof (IEnumerable<string>));
466
467                         var call = Expression.Call (
468                                 typeof (Queryable),
469                                 "AsQueryable",
470                                 new [] { typeof (string) },
471                                 constant);
472
473                         Assert.IsNotNull (call);
474                         Assert.AreEqual (1, call.Arguments.Count);
475                         Assert.AreEqual (constant, call.Arguments [0]);
476
477                         var method = call.Method;
478
479                         Assert.AreEqual ("AsQueryable", method.Name);
480                         Assert.IsTrue (method.IsGenericMethod);
481                         Assert.AreEqual (typeof (string), method.GetGenericArguments () [0]);
482                 }
483
484
485                 [Test]
486                 public void CallQueryableSelect () // #536637
487                 {
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);
491
492                         var strings = new [] { "1", "22", "333" };
493
494                         var call = Expression.Call (
495                                 typeof (Queryable),
496                                 "Select",
497                                 new [] { typeof (string), typeof (int) },
498                                 Expression.Constant (strings.AsQueryable ()),
499                                 lambda);
500
501                         Assert.IsNotNull (call);
502
503                         var method = call.Method;
504
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]);
509                 }
510
511                 [Test]
512                 public void CallNullableGetValueOrDefault () // #568989
513                 {
514                         var value = Expression.Parameter (typeof (int?), "value");
515                         var default_parameter = Expression.Parameter (typeof (int), "default");
516
517                         var getter = Expression.Lambda<Func<int?, int, int>> (
518                                 Expression.Call (
519                                         value,
520                                         "GetValueOrDefault",
521                                         Type.EmptyTypes,
522                                         default_parameter),
523                                 value,
524                                 default_parameter).Compile ();
525
526                         Assert.AreEqual (2, getter (null, 2));
527                         Assert.AreEqual (4, getter (4, 2));
528                 }
529
530                 [Test]
531                 public void CallToStringOnEnum () // #625367
532                 {
533                         var lambda = Expression.Lambda<Func<string>> (
534                                 Expression.Call (
535                                         Expression.Constant (TypeCode.Boolean, typeof (TypeCode)),
536                                         typeof (object).GetMethod ("ToString"))).Compile ();
537
538                         Assert.AreEqual ("Boolean", lambda ());
539                 }
540
541                 public static void AcceptsIEnumerable(IEnumerable<object> o)
542                 {
543                 }
544
545                 [Test]
546                 public void CallIQueryableMethodWithNewArrayBoundExpression () // #2304
547                 {
548                         Expression.Call (
549                                 GetType ().GetMethod ("AcceptsIEnumerable", BindingFlags.Public | BindingFlags.Static),
550                                 Expression.NewArrayBounds (typeof (object), Expression.Constant (0)));
551                 }
552         }
553 }