Merge pull request #4152 from BrzVlad/misc-gc-altstack
[mono.git] / mcs / class / System.Core / Test / System.Linq.Expressions / ExpressionTest_Convert.cs
1 //
2 // ExpressionTest_Convert.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@novell.com)
6 //
7 // (C) 2008 Novell, Inc. (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System;
30 using System.Reflection;
31 using System.Linq;
32 using System.Linq.Expressions;
33 using NUnit.Framework;
34
35 namespace MonoTests.System.Linq.Expressions {
36
37         [TestFixture]
38         public class ExpressionTest_Convert {
39
40                 [Test]
41                 [ExpectedException (typeof (ArgumentNullException))]
42                 public void NullExpression ()
43                 {
44                         Expression.Convert (null, typeof (int));
45                 }
46
47                 [Test]
48                 [ExpectedException (typeof (ArgumentNullException))]
49                 public void NullType ()
50                 {
51                         Expression.Convert (1.ToConstant (), null);
52                 }
53
54                 [Test]
55                 [ExpectedException (typeof (InvalidOperationException))]
56                 public void ConvertIntToString ()
57                 {
58                         Expression.Convert (1.ToConstant (), typeof (string));
59                 }
60
61                 interface IFoo { }
62                 class Foo : IFoo { }
63                 class Bar : Foo { }
64                 class Baz { }
65
66                 interface ITzap { }
67
68                 [Test]
69                 public void ConvertBackwardAssignability ()
70                 {
71                         var c = Expression.Convert (
72                                 Expression.Constant (null, typeof (Bar)), typeof (Foo));
73
74                         Assert.AreEqual ("Convert(null, Foo)", c.ToString ());
75                 }
76
77                 [Test]
78                 public void ConvertInterfaces ()
79                 {
80                         var p = Expression.Parameter (typeof (IFoo), null);
81
82                         var conv = Expression.Convert (p, typeof (ITzap));
83                         Assert.AreEqual (typeof (ITzap), conv.Type);
84                         p = Expression.Parameter (typeof (ITzap), null);
85                         conv = Expression.Convert (p, typeof (IFoo));
86
87                         Assert.AreEqual (typeof (IFoo), conv.Type);
88                 }
89
90                 [Test]
91                 public void ConvertCheckedInt32ToInt64 ()
92                 {
93                         var c = Expression.ConvertChecked (
94                                 Expression.Constant (2, typeof (int)), typeof (long));
95
96                         Assert.AreEqual (ExpressionType.ConvertChecked, c.NodeType);
97                         Assert.AreEqual ("ConvertChecked(2, Int64)", c.ToString ());
98                 }
99
100                 [Test]
101                 public void ConvertCheckedFallbackToConvertForNonPrimitives ()
102                 {
103                         var p = Expression.ConvertChecked (
104                                 Expression.Constant (null, typeof (object)), typeof (IFoo));
105
106                         Assert.AreEqual (ExpressionType.Convert, p.NodeType);
107                 }
108
109                 [Test]
110                 [ExpectedException (typeof (InvalidOperationException))]
111                 public void ConvertBazToFoo ()
112                 {
113                         Expression.Convert (Expression.Parameter (typeof (Baz), ""), typeof (Foo));
114                 }
115
116                 struct EineStrukt { }
117
118                 [Test]
119                 [ExpectedException (typeof (InvalidOperationException))]
120                 public void ConvertStructToFoo ()
121                 {
122                         Expression.Convert (Expression.Parameter (typeof (EineStrukt), ""), typeof (Foo));
123                 }
124
125                 [Test]
126                 [ExpectedException (typeof (InvalidOperationException))]
127                 public void ConvertInt32ToBool ()
128                 {
129                         Expression.Convert (Expression.Parameter (typeof (int), ""), typeof (bool));
130                 }
131
132                 [Test]
133                 public void ConvertIFooToFoo ()
134                 {
135                         var c = Expression.Convert (Expression.Parameter (typeof (IFoo), ""), typeof (Foo));
136                         Assert.AreEqual (typeof (Foo), c.Type);
137                         Assert.IsFalse (c.IsLifted);
138                         Assert.IsFalse (c.IsLiftedToNull);
139                         Assert.IsNull (c.Method);
140                 }
141
142                 [Test]
143                 public void BoxInt32 ()
144                 {
145                         var c = Expression.Convert (Expression.Parameter (typeof (int), ""), typeof (object));
146                         Assert.AreEqual (typeof (object), c.Type);
147                         Assert.IsFalse (c.IsLifted);
148                         Assert.IsFalse (c.IsLiftedToNull);
149                         Assert.IsNull (c.Method);
150                 }
151
152                 [Test]
153                 public void UnBoxInt32 ()
154                 {
155                         var c = Expression.Convert (Expression.Parameter (typeof (object), ""), typeof (int));
156                         Assert.AreEqual (typeof (int), c.Type);
157                         Assert.IsFalse (c.IsLifted);
158                         Assert.IsFalse (c.IsLiftedToNull);
159                         Assert.IsNull (c.Method);
160                 }
161
162                 [Test]
163                 public void ConvertInt32ToInt64 ()
164                 {
165                         var c = Expression.Convert (Expression.Parameter (typeof (int), ""), typeof (long));
166                         Assert.AreEqual (typeof (long), c.Type);
167                         Assert.IsFalse (c.IsLifted);
168                         Assert.IsFalse (c.IsLiftedToNull);
169                         Assert.IsNull (c.Method);
170                 }
171
172                 [Test]
173                 public void ConvertInt64ToInt32 ()
174                 {
175                         var c = Expression.Convert (Expression.Parameter (typeof (long), ""), typeof (int));
176                         Assert.AreEqual (typeof (int), c.Type);
177                         Assert.IsFalse (c.IsLifted);
178                         Assert.IsFalse (c.IsLiftedToNull);
179                         Assert.IsNull (c.Method);
180                 }
181
182                 enum EineEnum {
183                         EineValue,
184                 }
185
186                 [Test]
187                 public void ConvertEnumToInt32 ()
188                 {
189                         var c = Expression.Convert (Expression.Parameter (typeof (EineEnum), ""), typeof (int));
190                         Assert.AreEqual (typeof (int), c.Type);
191                         Assert.IsFalse (c.IsLifted);
192                         Assert.IsFalse (c.IsLiftedToNull);
193                         Assert.IsNull (c.Method);
194                 }
195
196                 [Test]
197                 public void ConvertNullableInt32ToInt32 ()
198                 {
199                         var c = Expression.Convert (Expression.Parameter (typeof (int?), ""), typeof (int));
200                         Assert.AreEqual (typeof (int), c.Type);
201                         Assert.IsTrue (c.IsLifted);
202                         Assert.IsFalse (c.IsLiftedToNull);
203                         Assert.IsNull (c.Method);
204                 }
205
206                 [Test]
207                 public void ConvertInt32ToNullableInt32 ()
208                 {
209                         var c = Expression.Convert (Expression.Parameter (typeof (int), ""), typeof (int?));
210                         Assert.AreEqual (typeof (int?), c.Type);
211                         Assert.IsTrue (c.IsLifted);
212                         Assert.IsTrue (c.IsLiftedToNull);
213                         Assert.IsNull (c.Method);
214                 }
215
216
217                 class Klang {
218                         int i;
219
220                         public Klang (int i)
221                         {
222                                 this.i = i;
223                         }
224
225                         public static explicit operator int (Klang k)
226                         {
227                                 return k.i;
228                         }
229                 }
230
231                 [Test]
232                 public void ConvertClassWithExplicitOp ()
233                 {
234                         var c = Expression.Convert (Expression.Parameter (typeof (Klang), ""), typeof (int));
235                         Assert.AreEqual (typeof (int), c.Type);
236                         Assert.IsFalse (c.IsLifted);
237                         Assert.IsFalse (c.IsLiftedToNull);
238                         Assert.IsNotNull (c.Method);
239                 }
240
241                 [Test]
242                 public void CompileConvertClassWithExplicitOp ()
243                 {
244                         var p = Expression.Parameter (typeof (Klang), "klang");
245                         var c = Expression.Lambda<Func<Klang, int>> (
246                                 Expression.Convert (p, typeof (int)), p).Compile ();
247
248                         Assert.AreEqual (42, c (new Klang (42)));
249                 }
250
251                 [Test]
252                 public void ConvertClassWithExplicitOpToNullableInt ()
253                 {
254                         var c = Expression.Convert (Expression.Parameter (typeof (Klang), ""), typeof (int?));
255                         Assert.AreEqual (typeof (int?), c.Type);
256                         Assert.IsTrue (c.IsLifted);
257                         Assert.IsTrue (c.IsLiftedToNull);
258                         Assert.IsNotNull (c.Method);
259                 }
260
261                 struct Kling {
262                         int i;
263
264                         public Kling (int i)
265                         {
266                                 this.i = i;
267                         }
268
269                         public static implicit operator int (Kling k)
270                         {
271                                 return k.i;
272                         }
273                 }
274
275                 [Test]
276                 public void ConvertStructWithImplicitOp ()
277                 {
278                         var c = Expression.Convert (Expression.Parameter (typeof (Kling), ""), typeof (int));
279                         Assert.AreEqual (typeof (int), c.Type);
280                         Assert.IsFalse (c.IsLifted);
281                         Assert.IsFalse (c.IsLiftedToNull);
282                         Assert.IsNotNull (c.Method);
283                 }
284
285                 [Test]
286                 public void CompileConvertStructWithImplicitOp ()
287                 {
288                         var p = Expression.Parameter (typeof (Kling), "kling");
289                         var c = Expression.Lambda<Func<Kling, int>> (
290                                 Expression.Convert (p, typeof (int)), p).Compile ();
291
292                         Assert.AreEqual (42, c (new Kling (42)));
293                 }
294
295                 [Test]
296                 public void ConvertStructWithImplicitOpToNullableInt ()
297                 {
298                         var c = Expression.Convert (Expression.Parameter (typeof (Kling), ""), typeof (int?));
299                         Assert.AreEqual (typeof (int?), c.Type);
300                         Assert.IsTrue (c.IsLifted);
301                         Assert.IsTrue (c.IsLiftedToNull);
302                         Assert.IsNotNull (c.Method);
303                 }
304
305                 [Test]
306                 public void ConvertNullableStructWithImplicitOpToNullableInt ()
307                 {
308                         var c = Expression.Convert (Expression.Parameter (typeof (Kling?), ""), typeof (int?));
309                         Assert.AreEqual (typeof (int?), c.Type);
310                         Assert.IsTrue (c.IsLifted);
311                         Assert.IsTrue (c.IsLiftedToNull);
312                         Assert.IsNotNull (c.Method);
313                 }
314
315                 [Test]
316                 public void CompiledBoxing ()
317                 {
318                         var b = Expression.Lambda<Func<object>> (
319                                 Expression.Convert (42.ToConstant (), typeof (object))).Compile ();
320
321                         Assert.AreEqual ((object) 42, b ());
322                 }
323
324                 [Test]
325                 public void CompiledUnBoxing ()
326                 {
327                         var p = Expression.Parameter (typeof (object), "o");
328
329                         var u = Expression.Lambda<Func<object, int>> (
330                                 Expression.Convert (p, typeof (int)), p).Compile ();
331
332                         Assert.AreEqual (42, u ((object) 42));
333                 }
334
335                 [Test]
336                 public void CompiledCast ()
337                 {
338                         var p = Expression.Parameter (typeof (IFoo), "foo");
339
340                         var c = Expression.Lambda<Func<IFoo, Bar>> (
341                                 Expression.Convert (p, typeof (Bar)), p).Compile ();
342
343                         IFoo foo = new Bar ();
344
345                         Bar b = c (foo);
346
347                         Assert.AreEqual (b, foo);
348                 }
349
350                 [Test]
351                 public void CompileNotNullableToNullable ()
352                 {
353                         var p = Expression.Parameter (typeof (int), "i");
354                         var c = Expression.Lambda<Func<int, int?>> (
355                                 Expression.Convert (p, typeof (int?)), p).Compile ();
356
357                         Assert.AreEqual ((int?) 0, c (0));
358                         Assert.AreEqual ((int?) 42, c (42));
359                 }
360
361                 [Test]
362                 public void CompileNullableToNotNullable ()
363                 {
364                         var p = Expression.Parameter (typeof (int?), "i");
365                         var c = Expression.Lambda<Func<int?, int>> (
366                                 Expression.Convert (p, typeof (int)), p).Compile ();
367
368                         Assert.AreEqual (0, c ((int?) 0));
369                         Assert.AreEqual (42, c ((int?) 42));
370
371                         Action a = () => c (null);
372
373                         a.AssertThrows (typeof (InvalidOperationException));
374                 }
375
376                 [Test]
377                 public void CompiledConvertToSameType ()
378                 {
379                         var k = new Klang (42);
380
381                         var p = Expression.Parameter (typeof (Klang), "klang");
382                         var c = Expression.Lambda<Func<Klang, Klang>> (
383                                 Expression.Convert (
384                                         p, typeof (Klang)),
385                                 p).Compile ();
386
387                         Assert.AreEqual (k, c (k));
388                 }
389
390                 [Test]
391                 public void CompiledConvertNullableToNullable ()
392                 {
393                         var p = Expression.Parameter (typeof (int?), "i");
394                         var c = Expression.Lambda<Func<int?, short?>> (
395                                 Expression.Convert (p, typeof (short?)), p).Compile ();
396
397                         Assert.AreEqual ((short?) null, c (null));
398                         Assert.AreEqual ((short?) 12, c (12));
399                 }
400
401                 [Test]
402                 public void CompiledNullableBoxing ()
403                 {
404                         var p = Expression.Parameter (typeof (int?), "i");
405                         var c = Expression.Lambda<Func<int?, object>> (
406                                 Expression.Convert (p, typeof (object)), p).Compile ();
407
408                         Assert.AreEqual (null, c (null));
409                         Assert.AreEqual ((object) (int?) 42, c (42));
410                 }
411
412                 [Test]
413                 public void CompiledNullableUnboxing ()
414                 {
415                         var p = Expression.Parameter (typeof (object), "o");
416                         var c = Expression.Lambda<Func<object, int?>> (
417                                 Expression.Convert (p, typeof (int?)), p).Compile ();
418
419                         Assert.AreEqual ((int?) null, c (null));
420                         Assert.AreEqual ((int?) 42, c ((int?) 42));
421                 }
422
423                 [Test]
424                 public void ChainedNullableConvert ()
425                 {
426                         var p = Expression.Parameter (typeof (sbyte?), "a");
427
428                         var test = Expression.Lambda<Func<sbyte?, long?>> (
429                                 Expression.Convert (
430                                         Expression.Convert (
431                                                 p,
432                                                 typeof (int?)),
433                                         typeof (long?)), p).Compile ();
434
435                         Assert.AreEqual ((long?) 3, test ((sbyte?) 3));
436                         Assert.AreEqual (null, test (null));
437                 }
438
439                 struct ImplicitToShort {
440                         short value;
441
442                         public ImplicitToShort (short v)
443                         {
444                                 value = v;
445                         }
446
447                         public static implicit operator short (ImplicitToShort i)
448                         {
449                                 return i.value;
450                         }
451                 }
452
453                 [Test]
454                 public void ConvertImplicitToShortToNullableInt ()
455                 {
456                         var a = Expression.Parameter (typeof (ImplicitToShort?), "a");
457
458                         var method = typeof (ImplicitToShort).GetMethod ("op_Implicit");
459
460                         var node = Expression.Convert (a, typeof (short), method);
461                         Assert.IsTrue (node.IsLifted);
462                         Assert.IsFalse (node.IsLiftedToNull);
463                         Assert.AreEqual (typeof (short), node.Type);
464                         Assert.AreEqual (method, node.Method);
465
466                         var conv = Expression.Lambda<Func<ImplicitToShort?, int?>> (
467                                 Expression.Convert (
468                                         node,
469                                         typeof (int?)), a).Compile ();
470
471                         Assert.AreEqual ((int?) 42, conv (new ImplicitToShort (42)));
472
473                         Action convnull = () => Assert.AreEqual (null, conv (null));
474
475                         convnull.AssertThrows (typeof (InvalidOperationException));
476                 }
477
478                 [Test]
479                 public void NullableImplicitToShort ()
480                 {
481                         var i = Expression.Parameter (typeof (ImplicitToShort?), "i");
482
483                         var method = typeof (ImplicitToShort).GetMethod ("op_Implicit");
484
485                         var node = Expression.Convert (i, typeof (short?), method);
486
487                         Assert.IsTrue (node.IsLifted);
488                         Assert.IsTrue (node.IsLiftedToNull);
489                         Assert.AreEqual (typeof (short?), node.Type);
490                         Assert.AreEqual (method, node.Method);
491
492                         var convert = Expression.Lambda<Func<ImplicitToShort?, short?>> (node, i).Compile ();
493
494                         Assert.AreEqual ((short?) 42, convert (new ImplicitToShort (42)));
495                 }
496
497                 [Test]
498                 public void ConvertLongToDecimal ()
499                 {
500                         var p = Expression.Parameter (typeof (long), "l");
501
502                         var node = Expression.Convert (p, typeof (decimal));
503                         Assert.IsFalse (node.IsLifted);
504                         Assert.IsFalse (node.IsLiftedToNull);
505                         Assert.AreEqual (typeof (decimal), node.Type);
506                         Assert.IsNotNull (node.Method);
507
508                         var convert = Expression.Lambda<Func<long, decimal>> (node, p).Compile ();
509
510                         Assert.AreEqual (42, convert (42));
511                 }
512
513                 [Test]
514                 public void ConvertNullableULongToNullableDecimal ()
515                 {
516                         var p = Expression.Parameter (typeof (ulong?), "l");
517
518                         var node = Expression.Convert (p, typeof (decimal?));
519                         Assert.IsTrue (node.IsLifted);
520                         Assert.IsTrue (node.IsLiftedToNull);
521                         Assert.AreEqual (typeof (decimal?), node.Type);
522                         Assert.IsNotNull (node.Method);
523
524                         var convert = Expression.Lambda<Func<ulong?, decimal?>> (node, p).Compile ();
525
526                         Assert.AreEqual (42, convert (42));
527                         Assert.AreEqual (null, convert (null));
528                 }
529
530                 [Test]
531                 public void ConvertCheckedNullableIntToInt ()
532                 {
533                         var p = Expression.Parameter (typeof (int?), "i");
534
535                         var node = Expression.ConvertChecked (p, typeof (int));
536                         Assert.AreEqual (ExpressionType.ConvertChecked, node.NodeType);
537                         Assert.IsTrue (node.IsLifted);
538                         Assert.IsFalse (node.IsLiftedToNull);
539                         Assert.AreEqual (typeof (int), node.Type);
540                         Assert.IsNull (node.Method);
541                 }
542
543                 struct ImplicitToInt {
544                         int Value;
545
546                         public ImplicitToInt (int v)
547                         {
548                                 Value = v;
549                         }
550
551                         public static implicit operator int (ImplicitToInt i)
552                         {
553                                 return i.Value;
554                         }
555                 }
556
557                 [Test]
558                 public void ConvertNullableImplictToIntToNullableLong ()
559                 {
560                         var i = Expression.Parameter (typeof (ImplicitToInt?), "i");
561
562                         var method = typeof (ImplicitToInt).GetMethod ("op_Implicit");
563
564                         var node = Expression.Convert (i, typeof (int), method);
565                         node = Expression.Convert (node, typeof (long?));
566                         var conv = Expression.Lambda<Func<ImplicitToInt?, long?>> (node, i).Compile ();
567
568                         Assert.AreEqual ((long?) 42, conv (new ImplicitToInt (42)));
569                         Action convnull = () => Assert.AreEqual (null, conv (null));
570                         convnull.AssertThrows (typeof (InvalidOperationException));
571                 }
572
573                 [Test]
574                 [ExpectedException (typeof (InvalidOperationException))]
575                 public void ConvertNullableIntToStringWithConvertMethod ()
576                 {
577                         Expression.Convert (
578                                 Expression.Constant ((int?) 0),
579                                 typeof (string),
580                                 typeof (Convert).GetMethod ("ToString", new [] { typeof (object) }));
581                 }
582
583                 [Test] // #678897
584                 public void ConvertEnumValueToEnum ()
585                 {
586                         var node = Expression.Convert (
587                                 Expression.Constant (EineEnum.EineValue, typeof (EineEnum)),
588                                 typeof (Enum));
589
590                         Assert.IsNotNull (node);
591                         Assert.AreEqual (typeof (Enum), node.Type);
592                 }
593         }
594 }