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