we're passing the enum comparison tests
[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                         Assert.AreEqual ("(1 = 2)", expr.ToString ());
80                 }
81
82                 [Test]
83                 public void Nullable_LiftToNull_SetToFalse ()
84                 {
85                         int? a = 1;
86                         int? b = 2;
87
88                         BinaryExpression expr = Expression.Equal (Expression.Constant (a, typeof(int?)),
89                                                                   Expression.Constant (b, typeof(int?)),
90                                                                   false, null);
91                         Assert.AreEqual (ExpressionType.Equal, expr.NodeType);
92                         Assert.AreEqual (typeof (bool), expr.Type);
93                         Assert.AreEqual (true, expr.IsLifted);
94                         Assert.AreEqual (false, expr.IsLiftedToNull);
95                         Assert.IsNull (expr.Method);
96                         Assert.AreEqual ("(1 = 2)", expr.ToString ());
97                 }
98
99                 [Test]
100                 public void Nullable_LiftToNull_SetToTrue ()
101                 {
102                         int? a = 1;
103                         int? b = 2;
104
105                         BinaryExpression expr = Expression.Equal (Expression.Constant (a, typeof(int?)),
106                                                                   Expression.Constant (b, typeof(int?)),
107                                                                   true, null);
108                         Assert.AreEqual (ExpressionType.Equal, expr.NodeType);
109                         Assert.AreEqual (typeof (bool?), expr.Type);
110                         Assert.AreEqual (true, expr.IsLifted);
111                         Assert.AreEqual (true, expr.IsLiftedToNull);
112                         Assert.IsNull (expr.Method);
113                         Assert.AreEqual ("(1 = 2)", expr.ToString ());
114                 }
115
116                 [Test]
117                 [ExpectedException(typeof (InvalidOperationException))]
118                 public void Nullable_Mixed ()
119                 {
120                         int? a = 1;
121                         int b = 2;
122
123                         Expression.Equal (Expression.Constant (a, typeof (int?)),
124                                           Expression.Constant (b, typeof (int)));
125                 }
126
127                 [Test]
128                 public void UserDefinedClass ()
129                 {
130                         // We can use the simplest version of GetMethod because we already know only one
131                         // exists in the very simple class we're using for the tests.
132                         MethodInfo mi = typeof (OpClass).GetMethod ("op_Equality");
133
134                         BinaryExpression expr = Expression.Equal (Expression.Constant (new OpClass ()), Expression.Constant (new OpClass ()));
135                         Assert.AreEqual (ExpressionType.Equal, expr.NodeType);
136                         Assert.AreEqual (typeof (bool), expr.Type);
137                         Assert.AreEqual (mi, expr.Method);
138                         Assert.AreEqual ("op_Equality", expr.Method.Name);
139
140                         Assert.AreEqual ("(value(MonoTests.System.Linq.Expressions.OpClass) = value(MonoTests.System.Linq.Expressions.OpClass))", expr.ToString ());
141                 }
142
143                 [Test]
144                 public void NullableInt32Equal ()
145                 {
146                         var l = Expression.Parameter (typeof (int?), "l");
147                         var r = Expression.Parameter (typeof (int?), "r");
148
149                         var eq = Expression.Lambda<Func<int?, int?, bool>> (
150                                 Expression.Equal (l, r), l, r).Compile ();
151
152                         Assert.IsTrue (eq (null, null));
153                         Assert.IsFalse (eq (null, 1));
154                         Assert.IsFalse (eq (1, null));
155                         Assert.IsFalse (eq (1, 2));
156                         Assert.IsTrue (eq (1, 1));
157                         Assert.IsFalse (eq (null, 0));
158                         Assert.IsFalse (eq (0, null));
159                 }
160
161                 [Test]
162                 public void NullableInt32EqualLiftedToNull ()
163                 {
164                         var l = Expression.Parameter (typeof (int?), "l");
165                         var r = Expression.Parameter (typeof (int?), "r");
166
167                         var eq = Expression.Lambda<Func<int?, int?, bool?>> (
168                                 Expression.Equal (l, r, true, null), l, r).Compile ();
169
170                         Assert.AreEqual ((bool?) null, eq (null, null));
171                         Assert.AreEqual ((bool?) null, eq (null, 1));
172                         Assert.AreEqual ((bool?) null, eq (1, null));
173                         Assert.AreEqual ((bool?) false, eq (1, 2));
174                         Assert.AreEqual ((bool?) true, eq (1, 1));
175                         Assert.AreEqual ((bool?) null, eq (null, 0));
176                         Assert.AreEqual ((bool?) null, eq (0, null));
177                 }
178
179                 struct Slot {
180                         public int Value;
181
182                         public Slot (int value)
183                         {
184                                 this.Value = value;
185                         }
186
187                         public override bool Equals (object obj)
188                         {
189                                 if (!(obj is Slot))
190                                         return false;
191
192                                 var other = (Slot) obj;
193                                 return other.Value == this.Value;
194                         }
195
196                         public override int GetHashCode ()
197                         {
198                                 return Value;
199                         }
200
201                         public static bool operator == (Slot a, Slot b)
202                         {
203                                 return a.Value == b.Value;
204                         }
205
206                         public static bool operator != (Slot a, Slot b)
207                         {
208                                 return a.Value != b.Value;
209                         }
210                 }
211
212                 [Test]
213                 public void UserDefinedEqual ()
214                 {
215                         var l = Expression.Parameter (typeof (Slot), "l");
216                         var r = Expression.Parameter (typeof (Slot), "r");
217
218                         var node = Expression.Equal (l, r);
219
220                         Assert.IsFalse (node.IsLifted);
221                         Assert.IsFalse (node.IsLiftedToNull);
222                         Assert.AreEqual (typeof (bool), node.Type);
223                         Assert.IsNotNull (node.Method);
224
225                         var eq = Expression.Lambda<Func<Slot, Slot, bool>> (node, l, r).Compile ();
226
227                         Assert.AreEqual (true, eq (new Slot (21), new Slot (21)));
228                         Assert.AreEqual (false, eq (new Slot (1), new Slot (-1)));
229                 }
230
231                 [Test]
232                 public void UserDefinedEqualLifted ()
233                 {
234                         var l = Expression.Parameter (typeof (Slot?), "l");
235                         var r = Expression.Parameter (typeof (Slot?), "r");
236
237                         var node = Expression.Equal (l, r);
238
239                         Assert.IsTrue (node.IsLifted);
240                         Assert.IsFalse (node.IsLiftedToNull);
241                         Assert.AreEqual (typeof (bool), node.Type);
242                         Assert.IsNotNull (node.Method);
243
244                         var eq = Expression.Lambda<Func<Slot?, Slot?, bool>> (node, l, r).Compile ();
245
246                         Assert.AreEqual (true, eq (null, null));
247                         Assert.AreEqual (false, eq ((Slot?) new Slot (2), null));
248                         Assert.AreEqual (false, eq (null, (Slot?) new Slot (2)));
249                         Assert.AreEqual (true, eq ((Slot?) new Slot (21), (Slot?) new Slot (21)));
250                 }
251
252                 [Test]
253                 public void UserDefinedEqualLiftedToNull ()
254                 {
255                         var l = Expression.Parameter (typeof (Slot?), "l");
256                         var r = Expression.Parameter (typeof (Slot?), "r");
257
258                         var node = Expression.Equal (l, r, true, null);
259
260                         Assert.IsTrue (node.IsLifted);
261                         Assert.IsTrue (node.IsLiftedToNull);
262                         Assert.AreEqual (typeof (bool?), node.Type);
263                         Assert.IsNotNull (node.Method);
264
265                         var eq = Expression.Lambda<Func<Slot?, Slot?, bool?>> (node, l, r).Compile ();
266
267                         Assert.AreEqual ((bool?) null, eq (null, null));
268                         Assert.AreEqual ((bool?) null, eq ((Slot?) new Slot (2), null));
269                         Assert.AreEqual ((bool?) null, eq (null, (Slot?) new Slot (2)));
270                         Assert.AreEqual ((bool?) true, eq ((Slot?) new Slot (21), (Slot?) new Slot (21)));
271                         Assert.AreEqual ((bool?) false, eq ((Slot?) new Slot (21), (Slot?) new Slot (-21)));
272                 }
273
274                 struct SlotToNullable {
275                         public int Value;
276
277                         public SlotToNullable (int value)
278                         {
279                                 this.Value = value;
280                         }
281
282                         public override int GetHashCode ()
283                         {
284                                 return Value;
285                         }
286
287                         public override bool Equals (object obj)
288                         {
289                                 if (!(obj is SlotToNullable))
290                                         return false;
291
292                                 var other = (SlotToNullable) obj;
293                                 return other.Value == this.Value;
294                         }
295
296                         public static bool? operator == (SlotToNullable a, SlotToNullable b)
297                         {
298                                 return (bool?) (a.Value == b.Value);
299                         }
300
301                         public static bool? operator != (SlotToNullable a, SlotToNullable b)
302                         {
303                                 return (bool?) (a.Value != b.Value);
304                         }
305                 }
306
307                 [Test]
308                 [ExpectedException (typeof (InvalidOperationException))]
309                 public void UserDefinedToNullableEqualFromNullable ()
310                 {
311                         Expression.Equal (
312                                 Expression.Parameter (typeof (SlotToNullable?), "l"),
313                                 Expression.Parameter (typeof (SlotToNullable?), "r"));
314                 }
315
316                 [Test]
317                 public void UserDefinedToNullableEqual ()
318                 {
319                         var l = Expression.Parameter (typeof (SlotToNullable), "l");
320                         var r = Expression.Parameter (typeof (SlotToNullable), "r");
321
322                         var node = Expression.Equal (l, r, false, null);
323
324                         Assert.IsFalse (node.IsLifted);
325                         Assert.IsFalse (node.IsLiftedToNull);
326                         Assert.AreEqual (typeof (bool?), node.Type);
327                         Assert.IsNotNull (node.Method);
328
329                         var eq = Expression.Lambda<Func<SlotToNullable, SlotToNullable, bool?>> (node, l, r).Compile ();
330
331                         Assert.AreEqual ((bool?) true, eq (new SlotToNullable (2), new SlotToNullable (2)));
332                         Assert.AreEqual ((bool?) false, eq (new SlotToNullable (2), new SlotToNullable (-2)));
333                 }
334
335                 /*struct SlotFromNullableToNullable {
336                         public int Value;
337
338                         public SlotFromNullableToNullable (int value)
339                         {
340                                 this.Value = value;
341                         }
342
343                         public override bool Equals (object obj)
344                         {
345                                 if (!(obj is SlotFromNullableToNullable))
346                                         return false;
347
348                                 var other = (SlotFromNullableToNullable) obj;
349                                 return other.Value == this.Value;
350                         }
351
352                         public override int GetHashCode ()
353                         {
354                                 return Value;
355                         }
356
357                         public static bool? operator == (SlotFromNullableToNullable? a, SlotFromNullableToNullable? b)
358                         {
359                                 if (a.HasValue && b.HasValue)
360                                         return (bool?) (a.Value.Value == b.Value.Value);
361                                 else
362                                         return null;
363                         }
364
365                         public static bool? operator != (SlotFromNullableToNullable? a, SlotFromNullableToNullable? b)
366                         {
367                                 return !(a == b);
368                         }
369                 }
370
371                 [Test]
372                 public void UserDefinedFromNullableToNullableEqual ()
373                 {
374                         var l = Expression.Parameter (typeof (SlotFromNullableToNullable?), "l");
375                         var r = Expression.Parameter (typeof (SlotFromNullableToNullable?), "r");
376
377                         var node = Expression.Equal (l, r);
378
379                         Assert.IsFalse (node.IsLifted);
380                         Assert.IsFalse (node.IsLiftedToNull);
381                         Assert.AreEqual (typeof (bool?), node.Type);
382                         Assert.IsNotNull (node.Method);
383
384                         var eq = Expression.Lambda<Func<SlotFromNullableToNullable?, SlotFromNullableToNullable?, bool?>> (node, l, r).Compile ();
385
386                         Assert.AreEqual ((bool?) null, eq (null, null));
387                         Assert.AreEqual ((bool?) null, eq (new SlotFromNullableToNullable (2), null));
388                         Assert.AreEqual ((bool?) null, eq (null, new SlotFromNullableToNullable (2)));
389                         Assert.AreEqual ((bool?) true, eq (new SlotFromNullableToNullable (2), new SlotFromNullableToNullable (2)));
390                         Assert.AreEqual ((bool?) false, eq (new SlotFromNullableToNullable (2), new SlotFromNullableToNullable (-2)));
391                 }*/
392
393                 [Test]
394                 public void NullableBoolEqualToBool ()
395                 {
396                         var l = Expression.Parameter (typeof (bool?), "l");
397                         var r = Expression.Parameter (typeof (bool?), "r");
398
399                         var node = Expression.Equal (l, r);
400                         Assert.IsTrue (node.IsLifted);
401                         Assert.IsFalse (node.IsLiftedToNull);
402                         Assert.AreEqual (typeof (bool), node.Type);
403                         Assert.IsNull (node.Method);
404
405                         var eq = Expression.Lambda<Func<bool?, bool?, bool>> (node, l, r).Compile ();
406
407                         Assert.AreEqual (false, eq (true, null));
408                         Assert.AreEqual (true, eq (null, null));
409                         Assert.AreEqual (true, eq (false, false));
410                 }
411
412                 public enum Foo {
413                         Bar,
414                         Baz,
415                 }
416
417                 [Test]
418                 public void EnumEqual ()
419                 {
420                         var l = Expression.Parameter (typeof (Foo), "l");
421                         var r = Expression.Parameter (typeof (Foo), "r");
422
423                         var node = Expression.Equal (l, r);
424                         Assert.IsFalse (node.IsLifted);
425                         Assert.IsFalse (node.IsLiftedToNull);
426                         Assert.AreEqual (typeof (bool), node.Type);
427                         Assert.IsNull (node.Method);
428
429                         var eq = Expression.Lambda<Func<Foo, Foo, bool>> (node, l, r).Compile ();
430
431                         Assert.AreEqual (true, eq (Foo.Bar, Foo.Bar));
432                         Assert.AreEqual (false, eq (Foo.Bar, Foo.Baz));
433                 }
434
435                 [Test]
436                 public void LiftedEnumEqual ()
437                 {
438                         var l = Expression.Parameter (typeof (Foo?), "l");
439                         var r = Expression.Parameter (typeof (Foo?), "r");
440
441                         var node = Expression.Equal (l, r);
442                         Assert.IsTrue (node.IsLifted);
443                         Assert.IsFalse (node.IsLiftedToNull);
444                         Assert.AreEqual (typeof (bool), node.Type);
445                         Assert.IsNull (node.Method);
446
447                         var eq = Expression.Lambda<Func<Foo?, Foo?, bool>> (node, l, r).Compile ();
448
449                         Assert.AreEqual (true, eq (Foo.Bar, Foo.Bar));
450                         Assert.AreEqual (false, eq (Foo.Bar, Foo.Baz));
451                         Assert.AreEqual (false, eq (Foo.Bar, null));
452                         Assert.AreEqual (true, eq (null, null));
453                 }
454         }
455 }