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