ExpressionTest_Coalesce.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  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. // Federico Di Gregorio <[email protected]>
  21. // Jb Evain <[email protected]>
  22. using System;
  23. using System.Reflection;
  24. using System.Linq;
  25. using System.Linq.Expressions;
  26. using NUnit.Framework;
  27. namespace MonoTests.System.Linq.Expressions
  28. {
  29. [TestFixture]
  30. public class ExpressionTest_Coalesce
  31. {
  32. [Test]
  33. [ExpectedException (typeof (ArgumentNullException))]
  34. public void Arg1Null ()
  35. {
  36. Expression.Coalesce (null, Expression.Constant (1));
  37. }
  38. [Test]
  39. [ExpectedException (typeof (ArgumentNullException))]
  40. public void Arg2Null ()
  41. {
  42. Expression.Coalesce (Expression.Constant (1), null);
  43. }
  44. [Test]
  45. [ExpectedException (typeof (InvalidOperationException))]
  46. public void NonNullLeftParameter ()
  47. {
  48. // This throws because they are both doubles, which are never
  49. Expression.Coalesce (Expression.Constant (1.0), Expression.Constant (2.0));
  50. }
  51. [Test]
  52. [ExpectedException (typeof (ArgumentException))]
  53. public void Incompatible_Arguments ()
  54. {
  55. // The artuments are not compatible
  56. Expression.Coalesce (Expression.Parameter (typeof (int?), "a"),
  57. Expression.Parameter (typeof (bool), "b"));
  58. }
  59. [Test]
  60. public void IsCoalesceStringLifted ()
  61. {
  62. var coalesce = Expression.Coalesce (
  63. Expression.Parameter (typeof (string), "a"),
  64. Expression.Parameter (typeof (string), "b"));
  65. Assert.AreEqual ("(a ?? b)", coalesce.ToString ());
  66. Assert.IsFalse (coalesce.IsLifted);
  67. Assert.IsFalse (coalesce.IsLiftedToNull);
  68. }
  69. [Test]
  70. public void IsCoalesceNullableIntLifted ()
  71. {
  72. var coalesce = Expression.Coalesce (
  73. Expression.Parameter (typeof (int?), "a"),
  74. Expression.Parameter (typeof (int?), "b"));
  75. Assert.IsFalse (coalesce.IsLifted);
  76. Assert.IsFalse (coalesce.IsLiftedToNull);
  77. }
  78. [Test]
  79. public void CoalesceNullableInt ()
  80. {
  81. var a = Expression.Parameter (typeof (int?), "a");
  82. var b = Expression.Parameter (typeof (int?), "b");
  83. var coalesce = Expression.Lambda<Func<int?, int?, int?>> (
  84. Expression.Coalesce (a, b), a, b).Compile ();
  85. Assert.AreEqual ((int?) 1, coalesce (1, 2));
  86. Assert.AreEqual ((int?) null, coalesce (null, null));
  87. Assert.AreEqual ((int?) 2, coalesce (null, 2));
  88. Assert.AreEqual ((int?) 2, coalesce (2, null));
  89. }
  90. [Test]
  91. public void CoalesceString ()
  92. {
  93. var a = Expression.Parameter (typeof (string), "a");
  94. var b = Expression.Parameter (typeof (string), "b");
  95. var coalesce = Expression.Lambda<Func<string, string, string>> (
  96. Expression.Coalesce (a, b), a, b).Compile ();
  97. Assert.AreEqual ("foo", coalesce ("foo", "bar"));
  98. Assert.AreEqual (null, coalesce (null, null));
  99. Assert.AreEqual ("bar", coalesce (null, "bar"));
  100. Assert.AreEqual ("foo", coalesce ("foo", null));
  101. }
  102. [Test]
  103. public void CoalesceNullableToNonNullable ()
  104. {
  105. var a = Expression.Parameter (typeof (int?), "a");
  106. var node = Expression.Coalesce (a, Expression.Constant (99, typeof (int)));
  107. Assert.AreEqual (typeof (int), node.Type);
  108. Assert.IsFalse (node.IsLifted);
  109. Assert.IsFalse (node.IsLiftedToNull);
  110. var coalesce = Expression.Lambda<Func<int?, int>> (node, a).Compile ();
  111. Assert.AreEqual (5, coalesce (5));
  112. Assert.AreEqual (99, coalesce (null));
  113. }
  114. [Test]
  115. [Category ("NotDotNet")] // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=349822
  116. public void CoalesceUserDefinedConversion ()
  117. {
  118. var s = Expression.Parameter (typeof (string), "s");
  119. var coalesce = Expression.Lambda<Func<string, int>> (
  120. Expression.Coalesce (
  121. s,
  122. Expression.Constant (42),
  123. Expression.Lambda<Func<string, int>> (
  124. Expression.Call (typeof (int).GetMethod ("Parse", new [] { typeof (string) }), s), s)), s).Compile ();
  125. Assert.AreEqual (12, coalesce ("12"));
  126. Assert.AreEqual (42, coalesce (null));
  127. }
  128. struct Slot {
  129. int Value;
  130. public Slot (int v)
  131. {
  132. Value = v;
  133. }
  134. public static implicit operator int (Slot s)
  135. {
  136. return s.Value;
  137. }
  138. }
  139. [Test]
  140. public void CoalesceNullableSlotIntoInteger ()
  141. {
  142. var s = Expression.Parameter (typeof (Slot?), "s");
  143. var method = typeof (Slot).GetMethod ("op_Implicit");
  144. var coalesce = Expression.Lambda<Func<Slot?, int>> (
  145. Expression.Coalesce (
  146. s,
  147. Expression.Constant (-3),
  148. Expression.Lambda (
  149. Expression.Convert (s, typeof (int), method),
  150. s)), s).Compile ();
  151. Assert.AreEqual (-3, coalesce (null));
  152. Assert.AreEqual (42, coalesce (new Slot (42)));
  153. }
  154. [Test]
  155. [ExpectedException (typeof (ArgumentException))]
  156. public void WrongCoalesceConversionParameterCount ()
  157. {
  158. var s = Expression.Parameter (typeof (string), "s");
  159. var p = Expression.Parameter (typeof (string), "foo");
  160. Expression.Coalesce (
  161. s,
  162. 42.ToConstant (),
  163. Expression.Lambda<Func<string, string, int>> (
  164. Expression.Call (typeof (int).GetMethod ("Parse", new [] { typeof (string) }), s), s, p));
  165. }
  166. [Test]
  167. [ExpectedException (typeof (InvalidOperationException))]
  168. public void WrongCoalesceConversionParameterType ()
  169. {
  170. var s = Expression.Parameter (typeof (string), "s");
  171. var i = Expression.Parameter (typeof (int), "i");
  172. Expression.Coalesce (
  173. s,
  174. 42.ToConstant (),
  175. Expression.Lambda<Func<int, int>> (
  176. i, i));
  177. }
  178. [Test]
  179. [ExpectedException (typeof (InvalidOperationException))]
  180. public void WrongCoalesceConversionReturnType ()
  181. {
  182. var s = Expression.Parameter (typeof (string), "s");
  183. Expression.Coalesce (
  184. s,
  185. 42.ToConstant (),
  186. Expression.Lambda<Func<string, string>> (
  187. s, s));
  188. }
  189. [Test]
  190. [ExpectedException (typeof (ArgumentException))]
  191. public void CoalesceVoidUserDefinedConversion ()
  192. {
  193. var s = Expression.Parameter (typeof (string), "s");
  194. Expression.Coalesce (
  195. s,
  196. 42.ToConstant (),
  197. Expression.Lambda<Action<string>> (
  198. Expression.Call (typeof (int).GetMethod ("Parse", new [] { typeof (string) }), s), s));
  199. }
  200. }
  201. }