PageRenderTime 73ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/Main/FluentAssertions.Net35/Assertions/FloatingPointExtensions.cs

#
C# | 442 lines | 137 code | 30 blank | 275 comment | 9 complexity | 330c2411d6730327d99af58db51ee625 MD5 | raw file
  1. using System;
  2. namespace FluentAssertions.Assertions
  3. {
  4. /// <summary>
  5. /// Contains a number of extension methods for floating point <see cref="NumericAssertions{T}"/>.
  6. /// </summary>
  7. public static class FloatingPointExtensions
  8. {
  9. /// <summary>
  10. /// Asserts that the floating point value is exactly the same as the <paramref name="expected"/> value.
  11. /// </summary>
  12. /// <param name="parent">The <see cref="NumericAssertions{T}"/> object that is being extended.</param>
  13. /// <param name="expected">
  14. /// The expected value to compare the actual value with.
  15. /// </param>
  16. /// <remarks>
  17. /// Beware that floating point math is not exact. Simple values like 0.2 cannot be precisely represented
  18. /// using binary floating point numbers, and the limited precision of floating point numbers means that
  19. /// slight changes in the order of operations can change the result. Different compilers and CPU architectures store
  20. /// temporary results at different precisions, so results will differ depending on the details of your
  21. /// environment. If you do a calculation and then compare the results against some expected value it is highly
  22. /// unlikely that you will get exactly the result you intended.<br />
  23. /// Source: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm. <br />
  24. /// It might be better to use <see cref="BeApproximately(FluentAssertions.Assertions.NumericAssertions{float},float,float)"/>
  25. /// </remarks>
  26. public static AndConstraint<NumericAssertions<float>> Be(this NumericAssertions<float> parent,
  27. float expected)
  28. {
  29. return Be(parent, expected, string.Empty);
  30. }
  31. /// <summary>
  32. /// Asserts that the floating point value is exactly the same as the <paramref name="expected"/> value.
  33. /// </summary>
  34. /// <param name="parent">The <see cref="NumericAssertions{T}"/> object that is being extended.</param>
  35. /// <param name="expected">
  36. /// The expected value to compare the actual value with.
  37. /// </param>
  38. /// <param name="reason">
  39. /// A formatted phrase as is supported by <see cref="string.Format(string,object[])"/> explaining why the assertion
  40. /// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
  41. /// </param>
  42. /// <param name="reasonArgs">
  43. /// Zero or more objects to format using the placeholders in <see cref="reason"/>.
  44. /// </param>
  45. /// <remarks>
  46. /// Beware that floating point math is not exact. Simple values like 0.2 cannot be precisely represented
  47. /// using binary floating point numbers, and the limited precision of floating point numbers means that
  48. /// slight changes in the order of operations can change the result. Different compilers and CPU architectures store
  49. /// temporary results at different precisions, so results will differ depending on the details of your
  50. /// environment. If you do a calculation and then compare the results against some expected value it is highly
  51. /// unlikely that you will get exactly the result you intended.<br />
  52. /// Source: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm. <br />
  53. /// It might be better to use <see cref="BeApproximately(FluentAssertions.Assertions.NumericAssertions{float},float,float)"/>
  54. /// </remarks>
  55. public static AndConstraint<NumericAssertions<float>> Be(this NumericAssertions<float> parent,
  56. float expected, string reason, params object[] reasonArgs)
  57. {
  58. Execute.Verification
  59. .ForCondition(ReferenceEquals(parent.Subject, expected) || (parent.Subject.CompareTo(expected) == 0))
  60. .BecauseOf(reason, reasonArgs)
  61. .FailWith("Expected value {0} to be exactly {1}{reason}.", parent.Subject, expected);
  62. return new AndConstraint<NumericAssertions<float>>(parent);
  63. }
  64. /// <summary>
  65. /// Asserts that the floating point value is exactly the same as the <paramref name="expected"/> value.
  66. /// </summary>
  67. /// <param name="parent">The <see cref="NumericAssertions{T}"/> object that is being extended.</param>
  68. /// <param name="expected">
  69. /// The expected value to compare the actual value with.
  70. /// </param>
  71. /// <remarks>
  72. /// Beware that floating point math is not exact. Simple values like 0.2 cannot be precisely represented
  73. /// using binary floating point numbers, and the limited precision of floating point numbers means that
  74. /// slight changes in the order of operations can change the result. Different compilers and CPU architectures store
  75. /// temporary results at different precisions, so results will differ depending on the details of your
  76. /// environment. If you do a calculation and then compare the results against some expected value it is highly
  77. /// unlikely that you will get exactly the result you intended.<br />
  78. /// Source: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm. <br />
  79. /// It might be better to use <see cref="BeApproximately(FluentAssertions.Assertions.NumericAssertions{System.Nullable{float}},float,float)"/>
  80. /// </remarks>
  81. public static AndConstraint<NumericAssertions<float?>> Be(this NumericAssertions<float?> parent,
  82. float expected)
  83. {
  84. return Be(parent, expected, string.Empty);
  85. }
  86. /// <summary>
  87. /// Asserts that the floating point value is exactly the same as the <paramref name="expected"/> value.
  88. /// </summary>
  89. /// <param name="parent">The <see cref="NumericAssertions{T}"/> object that is being extended.</param>
  90. /// <param name="expected">
  91. /// The expected value to compare the actual value with.
  92. /// </param>
  93. /// <param name="reason">
  94. /// A formatted phrase as is supported by <see cref="string.Format(string,object[])"/> explaining why the assertion
  95. /// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
  96. /// </param>
  97. /// <param name="reasonArgs">
  98. /// Zero or more objects to format using the placeholders in <see cref="reason"/>.
  99. /// </param>
  100. /// <remarks>
  101. /// Beware that floating point math is not exact. Simple values like 0.2 cannot be precisely represented
  102. /// using binary floating point numbers, and the limited precision of floating point numbers means that
  103. /// slight changes in the order of operations can change the result. Different compilers and CPU architectures store
  104. /// temporary results at different precisions, so results will differ depending on the details of your
  105. /// environment. If you do a calculation and then compare the results against some expected value it is highly
  106. /// unlikely that you will get exactly the result you intended.<br />
  107. /// Source: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm. <br />
  108. /// It might be better to use <see cref="BeApproximately(FluentAssertions.Assertions.NumericAssertions{System.Nullable{float}},float,float)"/>
  109. /// </remarks>
  110. public static AndConstraint<NumericAssertions<float?>> Be(this NumericAssertions<float?> parent,
  111. float expected, string reason, params object[] reasonArgs)
  112. {
  113. Execute.Verification
  114. .ForCondition(parent.Subject != null)
  115. .BecauseOf(reason, reasonArgs)
  116. .FailWith("Expected value to be exactly {0}{reason}, but it was <null>.", expected);
  117. var nonNullableAssertions = new NumericAssertions<float>(expected);
  118. nonNullableAssertions.Be(expected, reason, reasonArgs);
  119. return new AndConstraint<NumericAssertions<float?>>(parent);
  120. }
  121. /// <summary>
  122. /// Asserts a floating point value approximates another value as close as possible.
  123. /// </summary>
  124. /// <param name="parent">The <see cref="NumericAssertions{T}"/> object that is being extended.</param>
  125. /// <param name="expectedValue">
  126. /// The expected value to compare the actual value with.
  127. /// </param>
  128. /// <param name="precision">
  129. /// The maximum amount of which the two values may differ.
  130. /// </param>
  131. public static AndConstraint<NumericAssertions<float?>> BeApproximately(this NumericAssertions<float?> parent,
  132. float expectedValue, float precision)
  133. {
  134. return BeApproximately(parent, expectedValue, precision, string.Empty);
  135. }
  136. /// <summary>
  137. /// Asserts a floating point value approximates another value as close as possible.
  138. /// </summary>
  139. /// <param name="parent">The <see cref="NumericAssertions{T}"/> object that is being extended.</param>
  140. /// <param name="expectedValue">
  141. /// The expected value to compare the actual value with.
  142. /// </param>
  143. /// <param name="precision">
  144. /// The maximum amount of which the two values may differ.
  145. /// </param>
  146. /// <param name="reason">
  147. /// A formatted phrase as is supported by <see cref="string.Format(string,object[])"/> explaining why the assertion
  148. /// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
  149. /// </param>
  150. /// <param name="reasonArgs">
  151. /// Zero or more objects to format using the placeholders in <see cref="reason"/>.
  152. /// </param>
  153. public static AndConstraint<NumericAssertions<float?>> BeApproximately(this NumericAssertions<float?> parent,
  154. float expectedValue, float precision, string reason,
  155. params object [] reasonArgs)
  156. {
  157. Execute.Verification
  158. .ForCondition(parent.Subject != null)
  159. .BecauseOf(reason, reasonArgs)
  160. .FailWith("Expected value to approximate {0} +/- {1}{reason}, but it was <null>.", expectedValue, precision);
  161. var nonNullableAssertions = new NumericAssertions<float>(expectedValue);
  162. nonNullableAssertions.BeApproximately(expectedValue, precision, reason, reasonArgs);
  163. return new AndConstraint<NumericAssertions<float?>>(parent);
  164. }
  165. /// <summary>
  166. /// Asserts a floating point value approximates another value as close as possible.
  167. /// </summary>
  168. /// <param name="parent">The <see cref="NumericAssertions{T}"/> object that is being extended.</param>
  169. /// <param name="expectedValue">
  170. /// The expected value to compare the actual value with.
  171. /// </param>
  172. /// <param name="precision">
  173. /// The maximum amount of which the two values may differ.
  174. /// </param>
  175. public static AndConstraint<NumericAssertions<float>> BeApproximately(this NumericAssertions<float> parent,
  176. float expectedValue, float precision)
  177. {
  178. return BeApproximately(parent, expectedValue, precision, string.Empty);
  179. }
  180. /// <summary>
  181. /// Asserts a floating point value approximates another value as close as possible.
  182. /// </summary>
  183. /// <param name="parent">The <see cref="NumericAssertions{T}"/> object that is being extended.</param>
  184. /// <param name="expectedValue">
  185. /// The expected value to compare the actual value with.
  186. /// </param>
  187. /// <param name="precision">
  188. /// The maximum amount of which the two values may differ.
  189. /// </param>
  190. /// <param name="reason">
  191. /// A formatted phrase as is supported by <see cref="string.Format(string,object[])"/> explaining why the assertion
  192. /// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
  193. /// </param>
  194. /// <param name="reasonArgs">
  195. /// Zero or more objects to format using the placeholders in <see cref="reason"/>.
  196. /// </param>
  197. public static AndConstraint<NumericAssertions<float>> BeApproximately(this NumericAssertions<float> parent,
  198. float expectedValue, float precision, string reason,
  199. params object [] reasonArgs)
  200. {
  201. float actualDifference = Math.Abs(expectedValue - (float) parent.Subject);
  202. if (actualDifference > precision)
  203. {
  204. Execute.Verification
  205. .BecauseOf(reason, reasonArgs)
  206. .FailWith("Expected value {0} to approximate {1} +/- {2}{reason}, but it differed by {3}.",
  207. parent.Subject, expectedValue, precision, actualDifference);
  208. }
  209. return new AndConstraint<NumericAssertions<float>>(parent);
  210. }
  211. /// <summary>
  212. /// Asserts that the double value is exactly the same as the <paramref name="expected"/> value.
  213. /// </summary>
  214. /// <param name="parent">The <see cref="NumericAssertions{T}"/> object that is being extended.</param>
  215. /// <param name="expected">
  216. /// The expected value to compare the actual value with.
  217. /// </param>
  218. /// <remarks>
  219. /// Beware that floating point math is not exact. Simple values like 0.2 cannot be precisely represented
  220. /// using binary floating point numbers, and the limited precision of floating point numbers means that
  221. /// slight changes in the order of operations can change the result. Different compilers and CPU architectures store
  222. /// temporary results at different precisions, so results will differ depending on the details of your
  223. /// environment. If you do a calculation and then compare the results against some expected value it is highly
  224. /// unlikely that you will get exactly the result you intended.<br />
  225. /// Source: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm. <br />
  226. /// It might be better to use <see cref="BeApproximately(FluentAssertions.Assertions.NumericAssertions{double},double,double)"/>
  227. /// </remarks>
  228. public static AndConstraint<NumericAssertions<double>> Be(this NumericAssertions<double> parent,
  229. double expected)
  230. {
  231. return Be(parent, expected, string.Empty);
  232. }
  233. /// <summary>
  234. /// Asserts that the double value is exactly the same as the <paramref name="expected"/> value.
  235. /// </summary>
  236. /// <param name="parent">The <see cref="NumericAssertions{T}"/> object that is being extended.</param>
  237. /// <param name="expected">
  238. /// The expected value to compare the actual value with.
  239. /// </param>
  240. /// <param name="reason">
  241. /// A formatted phrase as is supported by <see cref="string.Format(string,object[])"/> explaining why the assertion
  242. /// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
  243. /// </param>
  244. /// <param name="reasonArgs">
  245. /// Zero or more objects to format using the placeholders in <see cref="reason"/>.
  246. /// </param>
  247. /// <remarks>
  248. /// Beware that floating point math is not exact. Simple values like 0.2 cannot be precisely represented
  249. /// using binary floating point numbers, and the limited precision of floating point numbers means that
  250. /// slight changes in the order of operations can change the result. Different compilers and CPU architectures store
  251. /// temporary results at different precisions, so results will differ depending on the details of your
  252. /// environment. If you do a calculation and then compare the results against some expected value it is highly
  253. /// unlikely that you will get exactly the result you intended.<br />
  254. /// Source: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm. <br />
  255. /// It might be better to use <see cref="BeApproximately(FluentAssertions.Assertions.NumericAssertions{double},double,double)"/>
  256. /// </remarks>
  257. public static AndConstraint<NumericAssertions<double>> Be(this NumericAssertions<double> parent,
  258. double expected, string reason, params object[] reasonArgs)
  259. {
  260. Execute.Verification
  261. .ForCondition(ReferenceEquals(parent.Subject, expected) || (parent.Subject.CompareTo(expected) == 0))
  262. .BecauseOf(reason, reasonArgs)
  263. .FailWith("Expected value {0} to be exactly {1}{reason}.", parent.Subject, expected);
  264. return new AndConstraint<NumericAssertions<double>>(parent);
  265. }
  266. /// <summary>
  267. /// Asserts that the double value is exactly the same as the <paramref name="expected"/> value.
  268. /// </summary>
  269. /// <param name="parent">The <see cref="NumericAssertions{T}"/> object that is being extended.</param>
  270. /// <param name="expected">
  271. /// The expected value to compare the actual value with.
  272. /// </param>
  273. /// <remarks>
  274. /// Beware that floating point math is not exact. Simple values like 0.2 cannot be precisely represented
  275. /// using binary floating point numbers, and the limited precision of floating point numbers means that
  276. /// slight changes in the order of operations can change the result. Different compilers and CPU architectures store
  277. /// temporary results at different precisions, so results will differ depending on the details of your
  278. /// environment. If you do a calculation and then compare the results against some expected value it is highly
  279. /// unlikely that you will get exactly the result you intended.<br />
  280. /// Source: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm. <br />
  281. /// It might be better to use <see cref="BeApproximately(FluentAssertions.Assertions.NumericAssertions{System.Nullable{double}},double,double)"/>
  282. /// </remarks>
  283. public static AndConstraint<NumericAssertions<double?>> Be(this NumericAssertions<double?> parent,
  284. double expected)
  285. {
  286. return Be(parent, expected, string.Empty);
  287. }
  288. /// <summary>
  289. /// Asserts that the double value is exactly the same as the <paramref name="expected"/> value.
  290. /// </summary>
  291. /// <param name="parent">The <see cref="NumericAssertions{T}"/> object that is being extended.</param>
  292. /// <param name="expected">
  293. /// The expected value to compare the actual value with.
  294. /// </param>
  295. /// <param name="reason">
  296. /// A formatted phrase as is supported by <see cref="string.Format(string,object[])"/> explaining why the assertion
  297. /// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
  298. /// </param>
  299. /// <param name="reasonArgs">
  300. /// Zero or more objects to format using the placeholders in <see cref="reason"/>.
  301. /// </param>
  302. /// <remarks>
  303. /// Beware that floating point math is not exact. Simple values like 0.2 cannot be precisely represented
  304. /// using binary floating point numbers, and the limited precision of floating point numbers means that
  305. /// slight changes in the order of operations can change the result. Different compilers and CPU architectures store
  306. /// temporary results at different precisions, so results will differ depending on the details of your
  307. /// environment. If you do a calculation and then compare the results against some expected value it is highly
  308. /// unlikely that you will get exactly the result you intended.<br />
  309. /// Source: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm. <br />
  310. /// It might be better to use <see cref="BeApproximately(FluentAssertions.Assertions.NumericAssertions{System.Nullable{double}},double,double)"/>
  311. /// </remarks>
  312. public static AndConstraint<NumericAssertions<double?>> Be(this NumericAssertions<double?> parent,
  313. double expected, string reason, params object[] reasonArgs)
  314. {
  315. Execute.Verification
  316. .ForCondition(parent.Subject != null)
  317. .BecauseOf(reason, reasonArgs)
  318. .FailWith("Expected value to be exactly {0}{reason}, but it was <null>.", expected);
  319. var nonNullableAssertions = new NumericAssertions<double>(expected);
  320. nonNullableAssertions.Be(expected, reason, reasonArgs);
  321. return new AndConstraint<NumericAssertions<double?>>(parent);
  322. }
  323. /// <summary>
  324. /// Asserts a floating point value approximates another value as close as possible.
  325. /// </summary>
  326. /// <param name="parent">The <see cref="NumericAssertions{T}"/> object that is being extended.</param>
  327. /// <param name="expectedValue">
  328. /// The expected value to compare the actual value with.
  329. /// </param>
  330. /// <param name="precision">
  331. /// The maximum amount of which the two values may differ.
  332. /// </param>
  333. public static AndConstraint<NumericAssertions<double?>> BeApproximately(this NumericAssertions<double?> parent,
  334. double expectedValue, double precision)
  335. {
  336. return BeApproximately(parent, expectedValue, precision, string.Empty);
  337. }
  338. /// <summary>
  339. /// Asserts a floating point value approximates another value as close as possible.
  340. /// </summary>
  341. /// <param name="parent">The <see cref="NumericAssertions{T}"/> object that is being extended.</param>
  342. /// <param name="expectedValue">
  343. /// The expected value to compare the actual value with.
  344. /// </param>
  345. /// <param name="precision">
  346. /// The maximum amount of which the two values may differ.
  347. /// </param>
  348. /// <param name="reason">
  349. /// A formatted phrase as is supported by <see cref="string.Format(string,object[])"/> explaining why the assertion
  350. /// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
  351. /// </param>
  352. /// <param name="reasonArgs">
  353. /// Zero or more objects to format using the placeholders in <see cref="reason"/>.
  354. /// </param>
  355. public static AndConstraint<NumericAssertions<double?>> BeApproximately(this NumericAssertions<double?> parent,
  356. double expectedValue, double precision, string reason,
  357. params object [] reasonArgs)
  358. {
  359. Execute.Verification
  360. .ForCondition(parent.Subject != null)
  361. .BecauseOf(reason, reasonArgs)
  362. .FailWith("Expected value to approximate {0} +/- {1}{reason}, but it was <null>.", expectedValue, precision);
  363. var nonNullableAssertions = new NumericAssertions<double>(expectedValue);
  364. BeApproximately(nonNullableAssertions, expectedValue, precision, reason, reasonArgs);
  365. return new AndConstraint<NumericAssertions<double?>>(parent);
  366. }
  367. /// <summary>
  368. /// Asserts a floating point value approximates another value as close as possible.
  369. /// </summary>
  370. /// <param name="parent">The <see cref="NumericAssertions{T}"/> object that is being extended.</param>
  371. /// <param name="expectedValue">
  372. /// The expected value to compare the actual value with.
  373. /// </param>
  374. /// <param name="precision">
  375. /// The maximum amount of which the two values may differ.
  376. /// </param>
  377. public static AndConstraint<NumericAssertions<double>> BeApproximately(this NumericAssertions<double> parent,
  378. double expectedValue, double precision)
  379. {
  380. return BeApproximately(parent, expectedValue, precision, string.Empty);
  381. }
  382. /// <summary>
  383. /// Asserts a floating point value approximates another value as close as possible.
  384. /// </summary>
  385. /// <param name="parent">The <see cref="NumericAssertions{T}"/> object that is being extended.</param>
  386. /// <param name="expectedValue">
  387. /// The expected value to compare the actual value with.
  388. /// </param>
  389. /// <param name="precision">
  390. /// The maximum amount of which the two values may differ.
  391. /// </param>
  392. /// <param name="reason">
  393. /// A formatted phrase as is supported by <see cref="string.Format(string,object[])"/> explaining why the assertion
  394. /// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
  395. /// </param>
  396. /// <param name="reasonArgs">
  397. /// Zero or more objects to format using the placeholders in <see cref="reason"/>.
  398. /// </param>
  399. public static AndConstraint<NumericAssertions<double>> BeApproximately(this NumericAssertions<double> parent,
  400. double expectedValue, double precision, string reason,
  401. params object [] reasonArgs)
  402. {
  403. double actualDifference = Math.Abs(expectedValue - (double) parent.Subject);
  404. Execute.Verification
  405. .ForCondition(actualDifference <= precision)
  406. .BecauseOf(reason, reasonArgs)
  407. .FailWith("Expected value {0} to approximate {1} +/- {2}{reason}, but it differed by {3}.",
  408. parent.Subject, expectedValue, precision, actualDifference);
  409. return new AndConstraint<NumericAssertions<double>>(parent);
  410. }
  411. }
  412. }