[bcl] Remove NET_4_0 defines from class libs
[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                 [ExpectedException (typeof (ArgumentException))]
91                 public void ArgInstanceNullForNonStaticMethod ()
92                 {
93                         Expression.Call (null, typeof (object).GetMethod ("ToString"));
94                 }
95
96                 [Test]
97                 [ExpectedException (typeof (ArgumentException))]
98                 public void InstanceTypeDoesntMatchMethodDeclaringType ()
99                 {
100 #if MOBILE
101                         // ensure that String.Intern won't be removed by the linker
102                         string s = String.Intern (String.Empty);
103 #endif
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                 [Category ("NotWorkingInterpreter")]
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                 [Category ("NotDotNet")] // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=339351
244                 [ExpectedException (typeof (ArgumentException))]
245                 public void CallStaticMethodOnNonSenseInstanceExpression ()
246                 {
247                         Expression.Call (
248                                 Expression.Constant ("la la la"),
249                                 this.GetType ().GetMethod ("OneStaticMethod"));
250                 }
251
252                 public static int DoSomethingWith (ref int a)
253                 {
254                         return a + 4;
255                 }
256
257                 public static string DoAnotherThing (ref int a, string s)
258                 {
259                         return s + a;
260                 }
261
262                 [Test]
263                 [Category ("NotWorkingInterpreter")]
264                 public void CallStaticMethodWithRefParameter ()
265                 {
266                         var p = Expression.Parameter (typeof (int), "i");
267
268                         var c = Expression.Lambda<Func<int, int>> (
269                                 Expression.Call (GetType ().GetMethod ("DoSomethingWith"), p), p).Compile ();
270
271                         Assert.AreEqual (42, c (38));
272                 }
273
274                 [Test]
275                 [Category ("NotWorkingInterpreter")]
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                 static bool fout_called = false;
292
293                 public static int FooOut (out int x)
294                 {
295                         fout_called = true;
296                         return x = 0;
297                 }
298
299                 [Test]
300                 [Category ("NotWorkingInterpreter")]
301                 public void Connect282729 ()
302                 {
303                         // test from https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=282729
304
305                         var p = Expression.Parameter (typeof (int), "p");
306                         var lambda = Expression.Lambda<Func<int, int>> (
307                                 Expression.Call (
308                                         GetType ().GetMethod ("FooOut"),
309                                         Expression.ArrayIndex(
310                                                 Expression.NewArrayBounds (
311                                                         typeof(int),
312                                                         1.ToConstant ()),
313                                                 0.ToConstant ())),
314                                 p).Compile ();
315
316                         Assert.AreEqual (0, lambda (0));
317                         Assert.IsTrue (fout_called);
318                 }
319
320                 public static int FooOut2 (out int x)
321                 {
322                         x = 2;
323                         return 3;
324                 }
325
326                 [Test]
327                 [Category ("NotWorking")]
328                 [Category ("NotWorkingInterpreter")]
329                 public void Connect290278 ()
330                 {
331                         // test from https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=290278
332
333                         var p = Expression.Parameter (typeof (int [,]), "p");
334                         var lambda = Expression.Lambda<Func<int [,], int>> (
335                                 Expression.Call (
336                                         GetType ().GetMethod ("FooOut2"),
337                                         Expression.ArrayIndex (p, 0.ToConstant (), 0.ToConstant ())),
338                                 p).Compile ();
339
340                         int [,] data = { { 1 } };
341
342                         Assert.AreEqual (3, lambda (data));
343                         Assert.AreEqual (2, data [0, 0]);
344                 }
345
346                 public static void FooRef (ref string s)
347                 {
348                 }
349
350                 [Test]
351                 [Category ("NotWorkingInterpreter")]
352                 public void Connect297597 ()
353                 {
354                         // test from https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=297597
355
356                         var strings = new string [1];
357
358                         var lambda = Expression.Lambda<Action> (
359                                 Expression.Call (
360                                         GetType ().GetMethod ("FooRef"),
361                                         Expression.ArrayIndex (
362                                                 Expression.Constant (strings), 0.ToConstant ()))).Compile ();
363
364                         lambda ();
365                 }
366
367                 [Test]
368                 [Category ("NotDotNet")] // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=319190
369                 public void Connect319190 ()
370                 {
371                         var lambda = Expression.Lambda<Func<bool>> (
372                                 Expression.TypeIs (
373                                         Expression.New (typeof (TypedReference)),
374                                         typeof (object))).Compile ();
375
376                         Assert.IsTrue (lambda ());
377                 }
378
379                 public static int Truc ()
380                 {
381                         return 42;
382                 }
383
384                 [Test]
385                 [Category ("NotWorkingInterpreter")]
386                 public void Connect282702 ()
387                 {
388                         var lambda = Expression.Lambda<Func<Func<int>>> (
389                                 Expression.Convert (
390                                         Expression.Call (
391                                                 typeof (Delegate).GetMethod ("CreateDelegate", new [] { typeof (Type), typeof (object), typeof (MethodInfo) }),
392                                                 Expression.Constant (typeof (Func<int>), typeof (Type)),
393                                                 Expression.Constant (null, typeof (object)),
394                                                 Expression.Constant (GetType ().GetMethod ("Truc"))),
395                                         typeof (Func<int>))).Compile ();
396
397                         Assert.AreEqual (42, lambda ().Invoke ());
398                 }
399
400                 [Test]
401                 public void CallQueryableWhere ()
402                 {
403                         var queryable = new [] { 1, 2, 3 }.AsQueryable ();
404
405                         var parameter = Expression.Parameter (typeof (int), "i");
406                         var lambda = Expression.Lambda<Func<int, bool>> (
407                                 Expression.LessThan (parameter, Expression.Constant (2)),
408                                 parameter);
409
410                         var selector = Expression.Quote (lambda);
411
412                         var call = Expression.Call (
413                                 typeof (Queryable),
414                                 "Where",
415                                 new [] { typeof (int) },
416                                 queryable.Expression,
417                                 selector);
418
419                         Assert.IsNotNull (call);
420                         Assert.IsNotNull (call.Method);
421                 }
422
423                 [Test]
424                 public void CallAsQueryable () // #537768
425                 {
426                         var constant = Expression.Constant (
427                                 new List<string> (),
428                                 typeof (IEnumerable<string>));
429
430                         var call = Expression.Call (
431                                 typeof (Queryable),
432                                 "AsQueryable",
433                                 new [] { typeof (string) },
434                                 constant);
435
436                         Assert.IsNotNull (call);
437                         Assert.AreEqual (1, call.Arguments.Count);
438                         Assert.AreEqual (constant, call.Arguments [0]);
439
440                         var method = call.Method;
441
442                         Assert.AreEqual ("AsQueryable", method.Name);
443                         Assert.IsTrue (method.IsGenericMethod);
444                         Assert.AreEqual (typeof (string), method.GetGenericArguments () [0]);
445                 }
446
447
448                 [Test]
449                 public void CallQueryableSelect () // #536637
450                 {
451                         var parameter = Expression.Parameter (typeof (string), "s");
452                         var string_length = Expression.Property (parameter, typeof (string).GetProperty ("Length"));
453                         var lambda = Expression.Lambda (string_length, parameter);
454
455                         var strings = new [] { "1", "22", "333" };
456
457                         var call = Expression.Call (
458                                 typeof (Queryable),
459                                 "Select",
460                                 new [] { typeof (string), typeof (int) },
461                                 Expression.Constant (strings.AsQueryable ()),
462                                 lambda);
463
464                         Assert.IsNotNull (call);
465
466                         var method = call.Method;
467
468                         Assert.AreEqual ("Select", method.Name);
469                         Assert.IsTrue (method.IsGenericMethod);
470                         Assert.AreEqual (typeof (string), method.GetGenericArguments () [0]);
471                         Assert.AreEqual (typeof (int), method.GetGenericArguments () [1]);
472                 }
473
474                 [Test]
475                 [Category ("NotWorkingInterpreter")]
476                 public void CallNullableGetValueOrDefault () // #568989
477                 {
478                         var value = Expression.Parameter (typeof (int?), "value");
479                         var default_parameter = Expression.Parameter (typeof (int), "default");
480
481                         var getter = Expression.Lambda<Func<int?, int, int>> (
482                                 Expression.Call (
483                                         value,
484                                         "GetValueOrDefault",
485                                         Type.EmptyTypes,
486                                         default_parameter),
487                                 value,
488                                 default_parameter).Compile ();
489
490                         Assert.AreEqual (2, getter (null, 2));
491                         Assert.AreEqual (4, getter (4, 2));
492                 }
493
494                 [Test]
495                 public void CallToStringOnEnum () // #625367
496                 {
497                         var lambda = Expression.Lambda<Func<string>> (
498                                 Expression.Call (
499                                         Expression.Constant (TypeCode.Boolean, typeof (TypeCode)),
500                                         typeof (object).GetMethod ("ToString"))).Compile ();
501
502                         Assert.AreEqual ("Boolean", lambda ());
503                 }
504
505                 public static void AcceptsIEnumerable(IEnumerable<object> o)
506                 {
507                 }
508
509                 [Test]
510                 public void CallIQueryableMethodWithNewArrayBoundExpression () // #2304
511                 {
512                         Expression.Call (
513                                 GetType ().GetMethod ("AcceptsIEnumerable", BindingFlags.Public | BindingFlags.Static),
514                                 Expression.NewArrayBounds (typeof (object), Expression.Constant (0)));
515                 }
516         }
517 }