ExpressionTest_Equal.cs 14 KB

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