[sgen] Reenable gc-altstack test
[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)", 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)", 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                 [Category ("NotWorkingInterpreter")]
363                 public void CompileNullableToNotNullable ()
364                 {
365                         var p = Expression.Parameter (typeof (int?), "i");
366                         var c = Expression.Lambda<Func<int?, int>> (
367                                 Expression.Convert (p, typeof (int)), p).Compile ();
368
369                         Assert.AreEqual (0, c ((int?) 0));
370                         Assert.AreEqual (42, c ((int?) 42));
371
372                         Action a = () => c (null);
373
374                         a.AssertThrows (typeof (InvalidOperationException));
375                 }
376
377                 [Test]
378                 public void CompiledConvertToSameType ()
379                 {
380                         var k = new Klang (42);
381
382                         var p = Expression.Parameter (typeof (Klang), "klang");
383                         var c = Expression.Lambda<Func<Klang, Klang>> (
384                                 Expression.Convert (
385                                         p, typeof (Klang)),
386                                 p).Compile ();
387
388                         Assert.AreEqual (k, c (k));
389                 }
390
391                 [Test]
392                 public void CompiledConvertNullableToNullable ()
393                 {
394                         var p = Expression.Parameter (typeof (int?), "i");
395                         var c = Expression.Lambda<Func<int?, short?>> (
396                                 Expression.Convert (p, typeof (short?)), p).Compile ();
397
398                         Assert.AreEqual ((short?) null, c (null));
399                         Assert.AreEqual ((short?) 12, c (12));
400                 }
401
402                 [Test]
403                 public void CompiledNullableBoxing ()
404                 {
405                         var p = Expression.Parameter (typeof (int?), "i");
406                         var c = Expression.Lambda<Func<int?, object>> (
407                                 Expression.Convert (p, typeof (object)), p).Compile ();
408
409                         Assert.AreEqual (null, c (null));
410                         Assert.AreEqual ((object) (int?) 42, c (42));
411                 }
412
413                 [Test]
414                 public void CompiledNullableUnboxing ()
415                 {
416                         var p = Expression.Parameter (typeof (object), "o");
417                         var c = Expression.Lambda<Func<object, int?>> (
418                                 Expression.Convert (p, typeof (int?)), p).Compile ();
419
420                         Assert.AreEqual ((int?) null, c (null));
421                         Assert.AreEqual ((int?) 42, c ((int?) 42));
422                 }
423
424                 [Test]
425                 public void ChainedNullableConvert ()
426                 {
427                         var p = Expression.Parameter (typeof (sbyte?), "a");
428
429                         var test = Expression.Lambda<Func<sbyte?, long?>> (
430                                 Expression.Convert (
431                                         Expression.Convert (
432                                                 p,
433                                                 typeof (int?)),
434                                         typeof (long?)), p).Compile ();
435
436                         Assert.AreEqual ((long?) 3, test ((sbyte?) 3));
437                         Assert.AreEqual (null, test (null));
438                 }
439
440                 struct ImplicitToShort {
441                         short value;
442
443                         public ImplicitToShort (short v)
444                         {
445                                 value = v;
446                         }
447
448                         public static implicit operator short (ImplicitToShort i)
449                         {
450                                 return i.value;
451                         }
452                 }
453
454                 [Test]
455                 [Category ("NotWorkingInterpreter")]
456                 public void ConvertImplicitToShortToNullableInt ()
457                 {
458                         var a = Expression.Parameter (typeof (ImplicitToShort?), "a");
459
460                         var method = typeof (ImplicitToShort).GetMethod ("op_Implicit");
461
462                         var node = Expression.Convert (a, typeof (short), method);
463                         Assert.IsTrue (node.IsLifted);
464                         Assert.IsFalse (node.IsLiftedToNull);
465                         Assert.AreEqual (typeof (short), node.Type);
466                         Assert.AreEqual (method, node.Method);
467
468                         var conv = Expression.Lambda<Func<ImplicitToShort?, int?>> (
469                                 Expression.Convert (
470                                         node,
471                                         typeof (int?)), a).Compile ();
472
473                         Assert.AreEqual ((int?) 42, conv (new ImplicitToShort (42)));
474
475                         Action convnull = () => Assert.AreEqual (null, conv (null));
476
477                         convnull.AssertThrows (typeof (InvalidOperationException));
478                 }
479
480                 [Test]
481                 [Category ("NotWorkingInterpreter")]
482                 public void NullableImplicitToShort ()
483                 {
484                         var i = Expression.Parameter (typeof (ImplicitToShort?), "i");
485
486                         var method = typeof (ImplicitToShort).GetMethod ("op_Implicit");
487
488                         var node = Expression.Convert (i, typeof (short?), method);
489
490                         Assert.IsTrue (node.IsLifted);
491                         Assert.IsTrue (node.IsLiftedToNull);
492                         Assert.AreEqual (typeof (short?), node.Type);
493                         Assert.AreEqual (method, node.Method);
494
495                         var convert = Expression.Lambda<Func<ImplicitToShort?, short?>> (node, i).Compile ();
496
497                         Assert.AreEqual ((short?) 42, convert (new ImplicitToShort (42)));
498                 }
499
500                 [Test]
501                 public void ConvertLongToDecimal ()
502                 {
503                         var p = Expression.Parameter (typeof (long), "l");
504
505                         var node = Expression.Convert (p, typeof (decimal));
506                         Assert.IsFalse (node.IsLifted);
507                         Assert.IsFalse (node.IsLiftedToNull);
508                         Assert.AreEqual (typeof (decimal), node.Type);
509                         Assert.IsNotNull (node.Method);
510
511                         var convert = Expression.Lambda<Func<long, decimal>> (node, p).Compile ();
512
513                         Assert.AreEqual (42, convert (42));
514                 }
515
516                 [Test]
517                 [Category ("NotWorkingInterpreter")]
518                 public void ConvertNullableULongToNullableDecimal ()
519                 {
520                         var p = Expression.Parameter (typeof (ulong?), "l");
521
522                         var node = Expression.Convert (p, typeof (decimal?));
523                         Assert.IsTrue (node.IsLifted);
524                         Assert.IsTrue (node.IsLiftedToNull);
525                         Assert.AreEqual (typeof (decimal?), node.Type);
526                         Assert.IsNotNull (node.Method);
527
528                         var convert = Expression.Lambda<Func<ulong?, decimal?>> (node, p).Compile ();
529
530                         Assert.AreEqual (42, convert (42));
531                         Assert.AreEqual (null, convert (null));
532                 }
533
534                 [Test]
535                 public void ConvertCheckedNullableIntToInt ()
536                 {
537                         var p = Expression.Parameter (typeof (int?), "i");
538
539                         var node = Expression.ConvertChecked (p, typeof (int));
540                         Assert.AreEqual (ExpressionType.ConvertChecked, node.NodeType);
541                         Assert.IsTrue (node.IsLifted);
542                         Assert.IsFalse (node.IsLiftedToNull);
543                         Assert.AreEqual (typeof (int), node.Type);
544                         Assert.IsNull (node.Method);
545                 }
546
547                 struct ImplicitToInt {
548                         int Value;
549
550                         public ImplicitToInt (int v)
551                         {
552                                 Value = v;
553                         }
554
555                         public static implicit operator int (ImplicitToInt i)
556                         {
557                                 return i.Value;
558                         }
559                 }
560
561                 [Test]
562                 [Category ("NotWorkingInterpreter")]
563                 public void ConvertNullableImplictToIntToNullableLong ()
564                 {
565                         var i = Expression.Parameter (typeof (ImplicitToInt?), "i");
566
567                         var method = typeof (ImplicitToInt).GetMethod ("op_Implicit");
568
569                         var node = Expression.Convert (i, typeof (int), method);
570                         node = Expression.Convert (node, typeof (long?));
571                         var conv = Expression.Lambda<Func<ImplicitToInt?, long?>> (node, i).Compile ();
572
573                         Assert.AreEqual ((long?) 42, conv (new ImplicitToInt (42)));
574                         Action convnull = () => Assert.AreEqual (null, conv (null));
575                         convnull.AssertThrows (typeof (InvalidOperationException));
576                 }
577
578                 [Test]
579                 [ExpectedException (typeof (InvalidOperationException))]
580                 [Category ("NotWorking")]
581                 public void ConvertNullableIntToStringWithConvertMethod ()
582                 {
583                         Expression.Convert (
584                                 Expression.Constant ((int?) 0),
585                                 typeof (string),
586                                 typeof (Convert).GetMethod ("ToString", new [] { typeof (object) }));
587                 }
588
589                 [Test] // #678897
590                 public void ConvertEnumValueToEnum ()
591                 {
592                         var node = Expression.Convert (
593                                 Expression.Constant (EineEnum.EineValue, typeof (EineEnum)),
594                                 typeof (Enum));
595
596                         Assert.IsNotNull (node);
597                         Assert.AreEqual (typeof (Enum), node.Type);
598                 }
599         }
600 }