tests for not lifted/lifted/lifted to null user defined binary operators
[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 //
22
23 using System;
24 using System.Reflection;
25 using System.Linq;
26 using System.Linq.Expressions;
27 using NUnit.Framework;
28
29 namespace MonoTests.System.Linq.Expressions
30 {
31         [TestFixture]
32         public class ExpressionTest_Equal
33         {
34                 [Test]
35                 [ExpectedException (typeof (ArgumentNullException))]
36                 public void Arg1Null ()
37                 {
38                         Expression.Equal (null, Expression.Constant (1));
39                 }
40
41                 [Test]
42                 [ExpectedException (typeof (ArgumentNullException))]
43                 public void Arg2Null ()
44                 {
45                         Expression.Equal (Expression.Constant (1), null);
46                 }
47
48                 [Test]
49                 [ExpectedException (typeof (InvalidOperationException))]
50                 public void ArgTypesDifferent ()
51                 {
52                         Expression.Equal (Expression.Constant (1), Expression.Constant (2.0));
53                 }
54
55                 [Test]
56                 public void ReferenceCompare ()
57                 {
58                         Expression.Equal (Expression.Constant (new NoOpClass ()), Expression.Constant (new NoOpClass ()));
59                 }
60
61                 public struct D {
62                 }
63
64                 [Test]
65                 [ExpectedException (typeof (InvalidOperationException))]
66                 public void NoOperatorClass ()
67                 {
68                         Expression.Equal (Expression.Constant (new D ()), Expression.Constant (new D ()));
69                 }
70
71                 [Test]
72                 public void Numeric ()
73                 {
74                         BinaryExpression expr = Expression.Equal (Expression.Constant (1), Expression.Constant (2));
75                         Assert.AreEqual (ExpressionType.Equal, expr.NodeType);
76                         Assert.AreEqual (typeof (bool), expr.Type);
77                         Assert.IsNull (expr.Method);
78                         Assert.AreEqual ("(1 = 2)", expr.ToString ());
79                 }
80
81                 [Test]
82                 public void Nullable_LiftToNull_SetToFalse ()
83                 {
84                         int? a = 1;
85                         int? b = 2;
86
87                         BinaryExpression expr = Expression.Equal (Expression.Constant (a, typeof(int?)),
88                                                                   Expression.Constant (b, typeof(int?)),
89                                                                   false, null);
90                         Assert.AreEqual (ExpressionType.Equal, expr.NodeType);
91                         Assert.AreEqual (typeof (bool), expr.Type);
92                         Assert.AreEqual (true, expr.IsLifted);
93                         Assert.AreEqual (false, expr.IsLiftedToNull);
94                         Assert.IsNull (expr.Method);
95                         Assert.AreEqual ("(1 = 2)", expr.ToString ());
96                 }
97
98                 [Test]
99                 public void Nullable_LiftToNull_SetToTrue ()
100                 {
101                         int? a = 1;
102                         int? b = 2;
103
104                         BinaryExpression expr = Expression.Equal (Expression.Constant (a, typeof(int?)),
105                                                                   Expression.Constant (b, typeof(int?)),
106                                                                   true, null);
107                         Assert.AreEqual (ExpressionType.Equal, expr.NodeType);
108                         Assert.AreEqual (typeof (bool?), expr.Type);
109                         Assert.AreEqual (true, expr.IsLifted);
110                         Assert.AreEqual (true, expr.IsLiftedToNull);
111                         Assert.IsNull (expr.Method);
112                         Assert.AreEqual ("(1 = 2)", expr.ToString ());
113                 }
114
115                 [Test]
116                 [ExpectedException(typeof (InvalidOperationException))]
117                 public void Nullable_Mixed ()
118                 {
119                         int? a = 1;
120                         int b = 2;
121
122                         Expression.Equal (Expression.Constant (a, typeof (int?)),
123                                           Expression.Constant (b, typeof (int)));
124                 }
125
126                 [Test]
127                 public void UserDefinedClass ()
128                 {
129                         // We can use the simplest version of GetMethod because we already know only one
130                         // exists in the very simple class we're using for the tests.
131                         MethodInfo mi = typeof (OpClass).GetMethod ("op_Equality");
132
133                         BinaryExpression expr = Expression.Equal (Expression.Constant (new OpClass ()), Expression.Constant (new OpClass ()));
134                         Assert.AreEqual (ExpressionType.Equal, expr.NodeType);
135                         Assert.AreEqual (typeof (bool), expr.Type);
136                         Assert.AreEqual (mi, expr.Method);
137                         Assert.AreEqual ("op_Equality", expr.Method.Name);
138
139                         Assert.AreEqual ("(value(MonoTests.System.Linq.Expressions.OpClass) = value(MonoTests.System.Linq.Expressions.OpClass))", expr.ToString ());
140                 }
141
142                 [Test]
143                 public void NullableInt32Equal ()
144                 {
145                         var l = Expression.Parameter (typeof (int?), "l");
146                         var r = Expression.Parameter (typeof (int?), "r");
147
148                         var eq = Expression.Lambda<Func<int?, int?, bool>> (
149                                 Expression.Equal (l, r), l, r).Compile ();
150
151                         Assert.IsTrue (eq (null, null));
152                         Assert.IsFalse (eq (null, 1));
153                         Assert.IsFalse (eq (1, null));
154                         Assert.IsFalse (eq (1, 2));
155                         Assert.IsTrue (eq (1, 1));
156                         Assert.IsFalse (eq (null, 0));
157                         Assert.IsFalse (eq (0, null));
158                 }
159
160                 [Test]
161                 public void NullableInt32EqualLiftedToNull ()
162                 {
163                         var l = Expression.Parameter (typeof (int?), "l");
164                         var r = Expression.Parameter (typeof (int?), "r");
165
166                         var eq = Expression.Lambda<Func<int?, int?, bool?>> (
167                                 Expression.Equal (l, r, true, null), l, r).Compile ();
168
169                         Assert.AreEqual ((bool?) null, eq (null, null));
170                         Assert.AreEqual ((bool?) null, eq (null, 1));
171                         Assert.AreEqual ((bool?) null, eq (1, null));
172                         Assert.AreEqual ((bool?) false, eq (1, 2));
173                         Assert.AreEqual ((bool?) true, eq (1, 1));
174                         Assert.AreEqual ((bool?) null, eq (null, 0));
175                         Assert.AreEqual ((bool?) null, eq (0, null));
176                 }
177
178                 struct Slot {
179                         public int Value;
180
181                         public Slot (int value)
182                         {
183                                 this.Value = value;
184                         }
185
186                         public override bool Equals (object obj)
187                         {
188                                 if (!(obj is Slot))
189                                         return false;
190
191                                 var other = (Slot) obj;
192                                 return other.Value == this.Value;
193                         }
194
195                         public override int GetHashCode ()
196                         {
197                                 return Value;
198                         }
199
200                         public static bool operator == (Slot a, Slot b)
201                         {
202                                 return a.Value == b.Value;
203                         }
204
205                         public static bool operator != (Slot a, Slot b)
206                         {
207                                 return a.Value != b.Value;
208                         }
209                 }
210
211                 [Test]
212                 [Category ("NotWorking")]
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                 [Category ("NotWorking")]
233                 public void UserDefinedEqualLifted ()
234                 {
235                         var l = Expression.Parameter (typeof (Slot?), "l");
236                         var r = Expression.Parameter (typeof (Slot?), "r");
237
238                         var node = Expression.Equal (l, r);
239
240                         Assert.IsTrue (node.IsLifted);
241                         Assert.IsFalse (node.IsLiftedToNull);
242                         Assert.AreEqual (typeof (bool), node.Type);
243                         Assert.IsNotNull (node.Method);
244
245                         var eq = Expression.Lambda<Func<Slot?, Slot?, bool>> (node, l, r).Compile ();
246
247                         Assert.AreEqual (true, eq (null, null));
248                         Assert.AreEqual (false, eq ((Slot?) new Slot (2), null));
249                         Assert.AreEqual (false, eq (null, (Slot?) new Slot (2)));
250                         Assert.AreEqual (true, eq ((Slot?) new Slot (21), (Slot?) new Slot (21)));
251                 }
252
253                 [Test]
254                 [Category ("NotWorking")]
255                 public void UserDefinedEqualLiftedToNull ()
256                 {
257                         var l = Expression.Parameter (typeof (Slot?), "l");
258                         var r = Expression.Parameter (typeof (Slot?), "r");
259
260                         var node = Expression.Equal (l, r, true, null);
261
262                         Assert.IsTrue (node.IsLifted);
263                         Assert.IsTrue (node.IsLiftedToNull);
264                         Assert.AreEqual (typeof (bool?), node.Type);
265                         Assert.IsNotNull (node.Method);
266
267                         var eq = Expression.Lambda<Func<Slot?, Slot?, bool?>> (node, l, r).Compile ();
268
269                         Assert.AreEqual ((bool?) null, eq (null, null));
270                         Assert.AreEqual ((bool?) null, eq ((Slot?) new Slot (2), null));
271                         Assert.AreEqual ((bool?) null, eq (null, (Slot?) new Slot (2)));
272                         Assert.AreEqual ((bool?) true, eq ((Slot?) new Slot (21), (Slot?) new Slot (21)));
273                         Assert.AreEqual ((bool?) false, eq ((Slot?) new Slot (21), (Slot?) new Slot (-21)));
274                 }
275
276                 struct SlotToNullable {
277                         public int Value;
278
279                         public SlotToNullable (int value)
280                         {
281                                 this.Value = value;
282                         }
283
284                         public override int GetHashCode ()
285                         {
286                                 return Value;
287                         }
288
289                         public override bool Equals (object obj)
290                         {
291                                 if (!(obj is SlotToNullable))
292                                         return false;
293
294                                 var other = (SlotToNullable) obj;
295                                 return other.Value == this.Value;
296                         }
297
298                         public static bool? operator == (SlotToNullable a, SlotToNullable b)
299                         {
300                                 return (bool?) (a.Value == b.Value);
301                         }
302
303                         public static bool? operator != (SlotToNullable a, SlotToNullable b)
304                         {
305                                 return (bool?) (a.Value != b.Value);
306                         }
307                 }
308
309                 [Test]
310                 [Category ("NotWorking")]
311                 [ExpectedException (typeof (InvalidOperationException))]
312                 public void UserDefinedToNullableEqualFromNullable ()
313                 {
314                         Expression.Equal (
315                                 Expression.Parameter (typeof (SlotToNullable?), "l"),
316                                 Expression.Parameter (typeof (SlotToNullable?), "r"));
317                 }
318
319                 [Test]
320                 [Category ("NotWorking")]
321                 public void UserDefinedToNullableEqual ()
322                 {
323                         var l = Expression.Parameter (typeof (SlotToNullable), "l");
324                         var r = Expression.Parameter (typeof (SlotToNullable), "r");
325
326                         var node = Expression.Equal (l, r, false, null);
327
328                         Assert.IsFalse (node.IsLifted);
329                         Assert.IsFalse (node.IsLiftedToNull);
330                         Assert.AreEqual (typeof (bool?), node.Type);
331                         Assert.IsNotNull (node.Method);
332
333                         var eq = Expression.Lambda<Func<SlotToNullable, SlotToNullable, bool?>> (node, l, r).Compile ();
334
335                         Assert.AreEqual ((bool?) true, eq (new SlotToNullable (2), new SlotToNullable (2)));
336                         Assert.AreEqual ((bool?) false, eq (new SlotToNullable (2), new SlotToNullable (-2)));
337                 }
338
339                 struct SlotFromNullableToNullable {
340                         public int Value;
341
342                         public SlotFromNullableToNullable (int value)
343                         {
344                                 this.Value = value;
345                         }
346
347                         public override bool Equals (object obj)
348                         {
349                                 if (!(obj is SlotFromNullableToNullable))
350                                         return false;
351
352                                 var other = (SlotFromNullableToNullable) obj;
353                                 return other.Value == this.Value;
354                         }
355
356                         public override int GetHashCode ()
357                         {
358                                 return Value;
359                         }
360
361                         public static bool? operator == (SlotFromNullableToNullable? a, SlotFromNullableToNullable? b)
362                         {
363                                 if (a.HasValue && b.HasValue)
364                                         return (bool?) (a.Value.Value == b.Value.Value);
365                                 else
366                                         return null;
367                         }
368
369                         public static bool? operator != (SlotFromNullableToNullable? a, SlotFromNullableToNullable? b)
370                         {
371                                 return !(a == b);
372                         }
373                 }
374
375                 [Test]
376                 [Category ("NotWorking")]
377                 public void UserDefinedFromNullableToNullableEqual ()
378                 {
379                         var l = Expression.Parameter (typeof (SlotFromNullableToNullable?), "l");
380                         var r = Expression.Parameter (typeof (SlotFromNullableToNullable?), "r");
381
382                         var node = Expression.Equal (l, r);
383
384                         Assert.IsFalse (node.IsLifted);
385                         Assert.IsFalse (node.IsLiftedToNull);
386                         Assert.AreEqual (typeof (bool?), node.Type);
387                         Assert.IsNotNull (node.Method);
388
389                         var eq = Expression.Lambda<Func<SlotFromNullableToNullable?, SlotFromNullableToNullable?, bool?>> (node, l, r).Compile ();
390
391                         Assert.AreEqual ((bool?) null, eq (null, null));
392                         Assert.AreEqual ((bool?) null, eq (new SlotFromNullableToNullable (2), null));
393                         Assert.AreEqual ((bool?) null, eq (null, new SlotFromNullableToNullable (2)));
394                         Assert.AreEqual ((bool?) true, eq (new SlotFromNullableToNullable (2), new SlotFromNullableToNullable (2)));
395                         Assert.AreEqual ((bool?) false, eq (new SlotFromNullableToNullable (2), new SlotFromNullableToNullable (-2)));
396                 }
397         }
398 }