Merge pull request #1909 from esdrubal/reflection
[mono.git] / mcs / class / System.Core / Test / System.Linq.Expressions / ExpressionTest_Equal.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 //
19 // Authors:
20 //    Miguel de Icaza (miguel@novell.com)
21 //    Jb Evain (jbevain@novell.com)
22 //
23
24 using System;
25 using System.Reflection;
26 using System.Linq;
27 using System.Linq.Expressions;
28 using NUnit.Framework;
29
30 namespace MonoTests.System.Linq.Expressions
31 {
32         [TestFixture]
33         public class ExpressionTest_Equal
34         {
35                 [Test]
36                 [ExpectedException (typeof (ArgumentNullException))]
37                 public void Arg1Null ()
38                 {
39                         Expression.Equal (null, Expression.Constant (1));
40                 }
41
42                 [Test]
43                 [ExpectedException (typeof (ArgumentNullException))]
44                 public void Arg2Null ()
45                 {
46                         Expression.Equal (Expression.Constant (1), null);
47                 }
48
49                 [Test]
50                 [ExpectedException (typeof (InvalidOperationException))]
51                 public void ArgTypesDifferent ()
52                 {
53                         Expression.Equal (Expression.Constant (1), Expression.Constant (2.0));
54                 }
55
56                 [Test]
57                 public void ReferenceCompare ()
58                 {
59                         Expression.Equal (Expression.Constant (new NoOpClass ()), Expression.Constant (new NoOpClass ()));
60                 }
61
62                 public struct D {
63                 }
64
65                 [Test]
66                 [ExpectedException (typeof (InvalidOperationException))]
67                 public void NoOperatorClass ()
68                 {
69                         Expression.Equal (Expression.Constant (new D ()), Expression.Constant (new D ()));
70                 }
71
72                 [Test]
73                 public void Numeric ()
74                 {
75                         BinaryExpression expr = Expression.Equal (Expression.Constant (1), Expression.Constant (2));
76                         Assert.AreEqual (ExpressionType.Equal, expr.NodeType);
77                         Assert.AreEqual (typeof (bool), expr.Type);
78                         Assert.IsNull (expr.Method);
79                 }
80
81                 [Test]
82                 public void PrimitiveNonNumeric ()
83                 {
84                         BinaryExpression expr = Expression.Equal (Expression.Constant ('a'), Expression.Constant ('b'));
85                         Assert.AreEqual (ExpressionType.Equal, expr.NodeType);
86                         Assert.AreEqual (typeof (bool), expr.Type);
87                         Assert.IsNull (expr.Method);
88
89                         var eq = Expression.Lambda<Func<bool>> (expr).Compile ();
90                         Assert.IsFalse (eq ());
91                 }
92
93                 [Test]
94                 public void Nullable_LiftToNull_SetToFalse ()
95                 {
96                         int? a = 1;
97                         int? b = 2;
98
99                         BinaryExpression expr = Expression.Equal (Expression.Constant (a, typeof(int?)),
100                                                                   Expression.Constant (b, typeof(int?)),
101                                                                   false, null);
102                         Assert.AreEqual (ExpressionType.Equal, expr.NodeType);
103                         Assert.AreEqual (typeof (bool), expr.Type);
104                         Assert.AreEqual (true, expr.IsLifted);
105                         Assert.AreEqual (false, expr.IsLiftedToNull);
106                         Assert.IsNull (expr.Method);
107                 }
108
109                 [Test]
110                 public void Nullable_LiftToNull_SetToTrue ()
111                 {
112                         int? a = 1;
113                         int? b = 2;
114
115                         BinaryExpression expr = Expression.Equal (Expression.Constant (a, typeof(int?)),
116                                                                   Expression.Constant (b, typeof(int?)),
117                                                                   true, null);
118                         Assert.AreEqual (ExpressionType.Equal, expr.NodeType);
119                         Assert.AreEqual (typeof (bool?), expr.Type);
120                         Assert.AreEqual (true, expr.IsLifted);
121                         Assert.AreEqual (true, expr.IsLiftedToNull);
122                         Assert.IsNull (expr.Method);
123                 }
124
125                 [Test]
126                 [ExpectedException(typeof (InvalidOperationException))]
127                 public void Nullable_Mixed ()
128                 {
129                         int? a = 1;
130                         int b = 2;
131
132                         Expression.Equal (Expression.Constant (a, typeof (int?)),
133                                           Expression.Constant (b, typeof (int)));
134                 }
135
136                 [Test]
137                 public void UserDefinedClass ()
138                 {
139                         // We can use the simplest version of GetMethod because we already know only one
140                         // exists in the very simple class we're using for the tests.
141                         MethodInfo mi = typeof (OpClass).GetMethod ("op_Equality");
142
143                         BinaryExpression expr = Expression.Equal (Expression.Constant (new OpClass ()), Expression.Constant (new OpClass ()));
144                         Assert.AreEqual (ExpressionType.Equal, expr.NodeType);
145                         Assert.AreEqual (typeof (bool), expr.Type);
146                         Assert.AreEqual (mi, expr.Method);
147                         Assert.AreEqual ("op_Equality", expr.Method.Name);
148                 }
149
150                 [Test]
151                 public void NullableInt32Equal ()
152                 {
153                         var l = Expression.Parameter (typeof (int?), "l");
154                         var r = Expression.Parameter (typeof (int?), "r");
155
156                         var eq = Expression.Lambda<Func<int?, int?, bool>> (
157                                 Expression.Equal (l, r), l, r).Compile ();
158
159                         Assert.IsTrue (eq (null, null));
160                         Assert.IsFalse (eq (null, 1));
161                         Assert.IsFalse (eq (1, null));
162                         Assert.IsFalse (eq (1, 2));
163                         Assert.IsTrue (eq (1, 1));
164                         Assert.IsFalse (eq (null, 0));
165                         Assert.IsFalse (eq (0, null));
166                 }
167
168                 [Test]
169                 public void NullableInt32EqualLiftedToNull ()
170                 {
171                         var l = Expression.Parameter (typeof (int?), "l");
172                         var r = Expression.Parameter (typeof (int?), "r");
173
174                         var eq = Expression.Lambda<Func<int?, int?, bool?>> (
175                                 Expression.Equal (l, r, true, null), l, r).Compile ();
176
177                         Assert.AreEqual ((bool?) null, eq (null, null));
178                         Assert.AreEqual ((bool?) null, eq (null, 1));
179                         Assert.AreEqual ((bool?) null, eq (1, null));
180                         Assert.AreEqual ((bool?) false, eq (1, 2));
181                         Assert.AreEqual ((bool?) true, eq (1, 1));
182                         Assert.AreEqual ((bool?) null, eq (null, 0));
183                         Assert.AreEqual ((bool?) null, eq (0, null));
184                 }
185
186                 struct Slot {
187                         public int Value;
188
189                         public Slot (int value)
190                         {
191                                 this.Value = value;
192                         }
193
194                         public override bool Equals (object obj)
195                         {
196                                 if (!(obj is Slot))
197                                         return false;
198
199                                 var other = (Slot) obj;
200                                 return other.Value == this.Value;
201                         }
202
203                         public override int GetHashCode ()
204                         {
205                                 return Value;
206                         }
207
208                         public static bool operator == (Slot a, Slot b)
209                         {
210                                 return a.Value == b.Value;
211                         }
212
213                         public static bool operator != (Slot a, Slot b)
214                         {
215                                 return a.Value != b.Value;
216                         }
217                 }
218
219                 [Test]
220                 public void UserDefinedEqual ()
221                 {
222                         var l = Expression.Parameter (typeof (Slot), "l");
223                         var r = Expression.Parameter (typeof (Slot), "r");
224
225                         var node = Expression.Equal (l, r);
226
227                         Assert.IsFalse (node.IsLifted);
228                         Assert.IsFalse (node.IsLiftedToNull);
229                         Assert.AreEqual (typeof (bool), node.Type);
230                         Assert.IsNotNull (node.Method);
231
232                         var eq = Expression.Lambda<Func<Slot, Slot, bool>> (node, l, r).Compile ();
233
234                         Assert.AreEqual (true, eq (new Slot (21), new Slot (21)));
235                         Assert.AreEqual (false, eq (new Slot (1), new Slot (-1)));
236                 }
237
238                 [Test]
239                 [Category ("NotWorkingInterpreter")]
240                 public void UserDefinedEqualLifted ()
241                 {
242                         var l = Expression.Parameter (typeof (Slot?), "l");
243                         var r = Expression.Parameter (typeof (Slot?), "r");
244
245                         var node = Expression.Equal (l, r);
246
247                         Assert.IsTrue (node.IsLifted);
248                         Assert.IsFalse (node.IsLiftedToNull);
249                         Assert.AreEqual (typeof (bool), node.Type);
250                         Assert.IsNotNull (node.Method);
251
252                         var eq = Expression.Lambda<Func<Slot?, Slot?, bool>> (node, l, r).Compile ();
253
254                         Assert.AreEqual (true, eq (null, null));
255                         Assert.AreEqual (false, eq ((Slot?) new Slot (2), null));
256                         Assert.AreEqual (false, eq (null, (Slot?) new Slot (2)));
257                         Assert.AreEqual (true, eq ((Slot?) new Slot (21), (Slot?) new Slot (21)));
258                 }
259
260                 [Test]
261                 [Category ("NotWorkingInterpreter")]
262                 public void UserDefinedEqualLiftedToNull ()
263                 {
264                         var l = Expression.Parameter (typeof (Slot?), "l");
265                         var r = Expression.Parameter (typeof (Slot?), "r");
266
267                         var node = Expression.Equal (l, r, true, null);
268
269                         Assert.IsTrue (node.IsLifted);
270                         Assert.IsTrue (node.IsLiftedToNull);
271                         Assert.AreEqual (typeof (bool?), node.Type);
272                         Assert.IsNotNull (node.Method);
273
274                         var eq = Expression.Lambda<Func<Slot?, Slot?, bool?>> (node, l, r).Compile ();
275
276                         Assert.AreEqual ((bool?) null, eq (null, null));
277                         Assert.AreEqual ((bool?) null, eq ((Slot?) new Slot (2), null));
278                         Assert.AreEqual ((bool?) null, eq (null, (Slot?) new Slot (2)));
279                         Assert.AreEqual ((bool?) true, eq ((Slot?) new Slot (21), (Slot?) new Slot (21)));
280                         Assert.AreEqual ((bool?) false, eq ((Slot?) new Slot (21), (Slot?) new Slot (-21)));
281                 }
282
283                 struct SlotToNullable {
284                         public int Value;
285
286                         public SlotToNullable (int value)
287                         {
288                                 this.Value = value;
289                         }
290
291                         public override int GetHashCode ()
292                         {
293                                 return Value;
294                         }
295
296                         public override bool Equals (object obj)
297                         {
298                                 if (!(obj is SlotToNullable))
299                                         return false;
300
301                                 var other = (SlotToNullable) obj;
302                                 return other.Value == this.Value;
303                         }
304
305                         public static bool? operator == (SlotToNullable a, SlotToNullable b)
306                         {
307                                 return (bool?) (a.Value == b.Value);
308                         }
309
310                         public static bool? operator != (SlotToNullable a, SlotToNullable b)
311                         {
312                                 return (bool?) (a.Value != b.Value);
313                         }
314                 }
315
316                 [Test]
317                 [ExpectedException (typeof (InvalidOperationException))]
318                 public void UserDefinedToNullableEqualFromNullable ()
319                 {
320                         Expression.Equal (
321                                 Expression.Parameter (typeof (SlotToNullable?), "l"),
322                                 Expression.Parameter (typeof (SlotToNullable?), "r"));
323                 }
324
325                 [Test]
326                 public void UserDefinedToNullableEqual ()
327                 {
328                         var l = Expression.Parameter (typeof (SlotToNullable), "l");
329                         var r = Expression.Parameter (typeof (SlotToNullable), "r");
330
331                         var node = Expression.Equal (l, r, false, null);
332
333                         Assert.IsFalse (node.IsLifted);
334                         Assert.IsFalse (node.IsLiftedToNull);
335                         Assert.AreEqual (typeof (bool?), node.Type);
336                         Assert.IsNotNull (node.Method);
337
338                         var eq = Expression.Lambda<Func<SlotToNullable, SlotToNullable, bool?>> (node, l, r).Compile ();
339
340                         Assert.AreEqual ((bool?) true, eq (new SlotToNullable (2), new SlotToNullable (2)));
341                         Assert.AreEqual ((bool?) false, eq (new SlotToNullable (2), new SlotToNullable (-2)));
342                 }
343
344                 /*struct SlotFromNullableToNullable {
345                         public int Value;
346
347                         public SlotFromNullableToNullable (int value)
348                         {
349                                 this.Value = value;
350                         }
351
352                         public override bool Equals (object obj)
353                         {
354                                 if (!(obj is SlotFromNullableToNullable))
355                                         return false;
356
357                                 var other = (SlotFromNullableToNullable) obj;
358                                 return other.Value == this.Value;
359                         }
360
361                         public override int GetHashCode ()
362                         {
363                                 return Value;
364                         }
365
366                         public static bool? operator == (SlotFromNullableToNullable? a, SlotFromNullableToNullable? b)
367                         {
368                                 if (a.HasValue && b.HasValue)
369                                         return (bool?) (a.Value.Value == b.Value.Value);
370                                 else
371                                         return null;
372                         }
373
374                         public static bool? operator != (SlotFromNullableToNullable? a, SlotFromNullableToNullable? b)
375                         {
376                                 return !(a == b);
377                         }
378                 }
379
380                 [Test]
381                 public void UserDefinedFromNullableToNullableEqual ()
382                 {
383                         var l = Expression.Parameter (typeof (SlotFromNullableToNullable?), "l");
384                         var r = Expression.Parameter (typeof (SlotFromNullableToNullable?), "r");
385
386                         var node = Expression.Equal (l, r);
387
388                         Assert.IsFalse (node.IsLifted);
389                         Assert.IsFalse (node.IsLiftedToNull);
390                         Assert.AreEqual (typeof (bool?), node.Type);
391                         Assert.IsNotNull (node.Method);
392
393                         var eq = Expression.Lambda<Func<SlotFromNullableToNullable?, SlotFromNullableToNullable?, bool?>> (node, l, r).Compile ();
394
395                         Assert.AreEqual ((bool?) null, eq (null, null));
396                         Assert.AreEqual ((bool?) null, eq (new SlotFromNullableToNullable (2), null));
397                         Assert.AreEqual ((bool?) null, eq (null, new SlotFromNullableToNullable (2)));
398                         Assert.AreEqual ((bool?) true, eq (new SlotFromNullableToNullable (2), new SlotFromNullableToNullable (2)));
399                         Assert.AreEqual ((bool?) false, eq (new SlotFromNullableToNullable (2), new SlotFromNullableToNullable (-2)));
400                 }*/
401
402                 [Test]
403                 public void NullableBoolEqualToBool ()
404                 {
405                         var l = Expression.Parameter (typeof (bool?), "l");
406                         var r = Expression.Parameter (typeof (bool?), "r");
407
408                         var node = Expression.Equal (l, r);
409                         Assert.IsTrue (node.IsLifted);
410                         Assert.IsFalse (node.IsLiftedToNull);
411                         Assert.AreEqual (typeof (bool), node.Type);
412                         Assert.IsNull (node.Method);
413
414                         var eq = Expression.Lambda<Func<bool?, bool?, bool>> (node, l, r).Compile ();
415
416                         Assert.AreEqual (false, eq (true, null));
417                         Assert.AreEqual (true, eq (null, null));
418                         Assert.AreEqual (true, eq (false, false));
419                 }
420
421                 public enum Foo {
422                         Bar,
423                         Baz,
424                 }
425
426                 [Test]
427                 public void EnumEqual ()
428                 {
429                         var l = Expression.Parameter (typeof (Foo), "l");
430                         var r = Expression.Parameter (typeof (Foo), "r");
431
432                         var node = Expression.Equal (l, r);
433                         Assert.IsFalse (node.IsLifted);
434                         Assert.IsFalse (node.IsLiftedToNull);
435                         Assert.AreEqual (typeof (bool), node.Type);
436                         Assert.IsNull (node.Method);
437
438                         var eq = Expression.Lambda<Func<Foo, Foo, bool>> (node, l, r).Compile ();
439
440                         Assert.AreEqual (true, eq (Foo.Bar, Foo.Bar));
441                         Assert.AreEqual (false, eq (Foo.Bar, Foo.Baz));
442                 }
443
444                 [Test]
445                 public void LiftedEnumEqual ()
446                 {
447                         var l = Expression.Parameter (typeof (Foo?), "l");
448                         var r = Expression.Parameter (typeof (Foo?), "r");
449
450                         var node = Expression.Equal (l, r);
451                         Assert.IsTrue (node.IsLifted);
452                         Assert.IsFalse (node.IsLiftedToNull);
453                         Assert.AreEqual (typeof (bool), node.Type);
454                         Assert.IsNull (node.Method);
455
456                         var eq = Expression.Lambda<Func<Foo?, Foo?, bool>> (node, l, r).Compile ();
457
458                         Assert.AreEqual (true, eq (Foo.Bar, Foo.Bar));
459                         Assert.AreEqual (false, eq (Foo.Bar, Foo.Baz));
460                         Assert.AreEqual (false, eq (Foo.Bar, null));
461                         Assert.AreEqual (true, eq (null, null));
462                 }
463
464                 [Test]
465                 [Category ("NotWorkingInterpreter")]
466                 public void NullableNullEqual ()
467                 {
468                         var param = Expression.Parameter (typeof (DateTime?), "x");
469
470                         var node = Expression.Equal (param, Expression.Constant (null));
471
472                         Assert.IsTrue (node.IsLifted);
473                         Assert.IsFalse (node.IsLiftedToNull);
474                         Assert.AreEqual (typeof (bool), node.Type);
475                         Assert.IsNull (node.Method);
476
477                         var eq = Expression.Lambda<Func<DateTime?, bool>> (node, new [] { param }).Compile ();
478
479                         Assert.AreEqual (true, eq (null));
480                         Assert.AreEqual (false, eq (DateTime.Now));
481                 }
482         }
483 }