From 6cb0ed3e24c7f619eb8c216d939ccebac0656e82 Mon Sep 17 00:00:00 2001 From: Dennis Doomen Date: Sun, 20 Feb 2022 13:40:29 +0100 Subject: [PATCH] Better handling of NaN in numeric assertions. --- Src/FluentAssertions/AssertionExtensions.cs | 4 +- .../Numeric/DoubleAssertions.cs | 12 + .../Numeric/FloatAssertions.cs | 12 + .../Numeric/NumericAssertions.cs | 40 +- .../NumericAssertionsExtensions.cs | 20 + .../Numeric/NullableNumericAssertionSpecs.cs | 1839 +++++++++-------- .../Numeric/NumericAssertionSpecs.cs | 585 +++++- docs/_pages/releases.md | 1 + 8 files changed, 1614 insertions(+), 899 deletions(-) create mode 100644 Src/FluentAssertions/Numeric/DoubleAssertions.cs create mode 100644 Src/FluentAssertions/Numeric/FloatAssertions.cs diff --git a/Src/FluentAssertions/AssertionExtensions.cs b/Src/FluentAssertions/AssertionExtensions.cs index 4940cffe48..13a8085231 100644 --- a/Src/FluentAssertions/AssertionExtensions.cs +++ b/Src/FluentAssertions/AssertionExtensions.cs @@ -631,7 +631,7 @@ public static NullableNumericAssertions Should(this ulong? actualValue) [Pure] public static NumericAssertions Should(this float actualValue) { - return new NumericAssertions(actualValue); + return new FloatAssertions(actualValue); } /// @@ -651,7 +651,7 @@ public static NullableNumericAssertions Should(this float? actualValue) [Pure] public static NumericAssertions Should(this double actualValue) { - return new NumericAssertions(actualValue); + return new DoubleAssertions(actualValue); } /// diff --git a/Src/FluentAssertions/Numeric/DoubleAssertions.cs b/Src/FluentAssertions/Numeric/DoubleAssertions.cs new file mode 100644 index 0000000000..d939c16e97 --- /dev/null +++ b/Src/FluentAssertions/Numeric/DoubleAssertions.cs @@ -0,0 +1,12 @@ +namespace FluentAssertions.Numeric +{ + internal class DoubleAssertions : NumericAssertions + { + public DoubleAssertions(double value) + : base(value) + { + } + + private protected override bool IsNaN(double value) => double.IsNaN(value); + } +} diff --git a/Src/FluentAssertions/Numeric/FloatAssertions.cs b/Src/FluentAssertions/Numeric/FloatAssertions.cs new file mode 100644 index 0000000000..abf6ff75cb --- /dev/null +++ b/Src/FluentAssertions/Numeric/FloatAssertions.cs @@ -0,0 +1,12 @@ +namespace FluentAssertions.Numeric +{ + internal class FloatAssertions : NumericAssertions + { + public FloatAssertions(float value) + : base(value) + { + } + + private protected override bool IsNaN(float value) => float.IsNaN(value); + } +} diff --git a/Src/FluentAssertions/Numeric/NumericAssertions.cs b/Src/FluentAssertions/Numeric/NumericAssertions.cs index 842f08a374..d9e13f4994 100644 --- a/Src/FluentAssertions/Numeric/NumericAssertions.cs +++ b/Src/FluentAssertions/Numeric/NumericAssertions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; @@ -165,7 +165,7 @@ public AndConstraint BePositive(string because = "", params object[ public AndConstraint BeNegative(string because = "", params object[] becauseArgs) { Execute.Assertion - .ForCondition(Subject.HasValue && Subject.Value.CompareTo(default(T)) < 0) + .ForCondition(Subject.HasValue && !IsNaN(Subject.Value) && Subject.Value.CompareTo(default(T)) < 0) .BecauseOf(because, becauseArgs) .FailWith("Expected {context:value} to be negative{reason}, but found {0}.", Subject); @@ -185,8 +185,13 @@ public AndConstraint BeNegative(string because = "", params object[ /// public AndConstraint BeLessThan(T expected, string because = "", params object[] becauseArgs) { + if (IsNaN(expected)) + { + throw new ArgumentException("A value can never be less than NaN", nameof(expected)); + } + Execute.Assertion - .ForCondition(Subject.HasValue && Subject.Value.CompareTo(expected) < 0) + .ForCondition(Subject.HasValue && !IsNaN(Subject.Value) && Subject.Value.CompareTo(expected) < 0) .BecauseOf(because, becauseArgs) .FailWith("Expected {context:value} to be less than {0}{reason}, but found {1}.", expected, Subject); @@ -207,8 +212,13 @@ public AndConstraint BeLessThan(T expected, string because = "", pa public AndConstraint BeLessThanOrEqualTo(T expected, string because = "", params object[] becauseArgs) { + if (IsNaN(expected)) + { + throw new ArgumentException("A value can never be less than or equal to NaN", nameof(expected)); + } + Execute.Assertion - .ForCondition(Subject.HasValue && Subject.Value.CompareTo(expected) <= 0) + .ForCondition(Subject.HasValue && !IsNaN(Subject.Value) && Subject.Value.CompareTo(expected) <= 0) .BecauseOf(because, becauseArgs) .FailWith("Expected {context:value} to be less than or equal to {0}{reason}, but found {1}.", expected, Subject); @@ -232,6 +242,11 @@ public AndConstraint BeLessThan(T expected, string because = "", pa public AndConstraint BeGreaterThan(T expected, string because = "", params object[] becauseArgs) { + if (IsNaN(expected)) + { + throw new ArgumentException("A value can never be greater than NaN", nameof(expected)); + } + Execute.Assertion .ForCondition(Subject.HasValue && Subject.Value.CompareTo(expected) > 0) .BecauseOf(because, becauseArgs) @@ -254,6 +269,11 @@ public AndConstraint BeLessThan(T expected, string because = "", pa public AndConstraint BeGreaterThanOrEqualTo(T expected, string because = "", params object[] becauseArgs) { + if (IsNaN(expected)) + { + throw new ArgumentException("A value can never be greater than or equal to a NaN", nameof(expected)); + } + Execute.Assertion .ForCondition(Subject.HasValue && Subject.Value.CompareTo(expected) >= 0) .BecauseOf(because, becauseArgs) @@ -287,6 +307,11 @@ public AndConstraint BeLessThan(T expected, string because = "", pa public AndConstraint BeInRange(T minimumValue, T maximumValue, string because = "", params object[] becauseArgs) { + if (IsNaN(minimumValue) || IsNaN(maximumValue)) + { + throw new ArgumentException("A range cannot begin or end with NaN"); + } + Execute.Assertion .ForCondition(Subject.HasValue && (Subject.Value.CompareTo(minimumValue) >= 0) && (Subject.Value.CompareTo(maximumValue) <= 0)) .BecauseOf(because, becauseArgs) @@ -318,6 +343,11 @@ public AndConstraint BeLessThan(T expected, string because = "", pa public AndConstraint NotBeInRange(T minimumValue, T maximumValue, string because = "", params object[] becauseArgs) { + if (IsNaN(minimumValue) || IsNaN(maximumValue)) + { + throw new ArgumentException("A range cannot begin or end with NaN"); + } + Execute.Assertion .ForCondition(Subject.HasValue && !((Subject.Value.CompareTo(minimumValue) >= 0) && (Subject.Value.CompareTo(maximumValue) <= 0))) .BecauseOf(because, becauseArgs) @@ -449,5 +479,7 @@ public AndConstraint NotBeOfType(Type unexpectedType, string becaus /// public override bool Equals(object obj) => throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); + + private protected virtual bool IsNaN(T value) => false; } } diff --git a/Src/FluentAssertions/NumericAssertionsExtensions.cs b/Src/FluentAssertions/NumericAssertionsExtensions.cs index af2a54ef6b..0e98765a5d 100644 --- a/Src/FluentAssertions/NumericAssertionsExtensions.cs +++ b/Src/FluentAssertions/NumericAssertionsExtensions.cs @@ -752,6 +752,11 @@ public static class NumericAssertionsExtensions float expectedValue, float precision, string because = "", params object[] becauseArgs) { + if (float.IsNaN(expectedValue)) + { + throw new ArgumentException("Cannot determine approximation of a float to NaN", nameof(expectedValue)); + } + if (precision < 0) { throw new ArgumentOutOfRangeException(nameof(precision), $"The value of {nameof(precision)} must be non-negative."); @@ -879,6 +884,11 @@ public static class NumericAssertionsExtensions double expectedValue, double precision, string because = "", params object[] becauseArgs) { + if (double.IsNaN(expectedValue)) + { + throw new ArgumentException("Cannot determine approximation of a double to NaN", nameof(expectedValue)); + } + if (precision < 0) { throw new ArgumentOutOfRangeException(nameof(precision), $"The value of {nameof(precision)} must be non-negative."); @@ -1137,6 +1147,11 @@ public static class NumericAssertionsExtensions float unexpectedValue, float precision, string because = "", params object[] becauseArgs) { + if (float.IsNaN(unexpectedValue)) + { + throw new ArgumentException("Cannot determine approximation of a float to NaN", nameof(unexpectedValue)); + } + if (precision < 0) { throw new ArgumentOutOfRangeException(nameof(precision), $"The value of {nameof(precision)} must be non-negative."); @@ -1262,6 +1277,11 @@ public static class NumericAssertionsExtensions double unexpectedValue, double precision, string because = "", params object[] becauseArgs) { + if (double.IsNaN(unexpectedValue)) + { + throw new ArgumentException("Cannot determine approximation of a double to NaN", nameof(unexpectedValue)); + } + if (precision < 0) { throw new ArgumentOutOfRangeException(nameof(precision), $"The value of {nameof(precision)} must be non-negative."); diff --git a/Tests/FluentAssertions.Specs/Numeric/NullableNumericAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Numeric/NullableNumericAssertionSpecs.cs index 90783d62f2..1ce92ca196 100644 --- a/Tests/FluentAssertions.Specs/Numeric/NullableNumericAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Numeric/NullableNumericAssertionSpecs.cs @@ -199,900 +199,967 @@ public void Should_fail_with_descriptive_message_when_asserting_nullable_numeric int? nullableIntegerB = 2; // Act - Action act = () => nullableIntegerA.Should().Be(nullableIntegerB, "because we want to test the failure {0}", "message"); + Action act = () => + nullableIntegerA.Should().Be(nullableIntegerB, "because we want to test the failure {0}", "message"); // Assert act.Should().Throw() .WithMessage("Expected*2 because we want to test the failure message, but found 1."); } - #region Be Approximately - - [Fact] - public void When_approximating_a_nullable_double_with_a_negative_precision_it_should_throw() - { - // Arrange - double? value = 3.1415927; - - // Act - Action act = () => value.Should().BeApproximately(3.14, -0.1); - - // Assert - act.Should().Throw() - .WithMessage("* value of precision must be non-negative*"); - } - - [Fact] - public void When_approximating_two_nullable_doubles_with_a_negative_precision_it_should_throw() - { - // Arrange - double? value = 3.1415927; - double? expected = 3.14; - - // Act - Action act = () => value.Should().BeApproximately(expected, -0.1); - - // Assert - act.Should().Throw() - .WithMessage("* value of precision must be non-negative*"); - } - - [Fact] - public void When_nullable_double_is_indeed_approximating_a_value_it_should_not_throw() - { - // Arrange - double? value = 3.1415927; - - // Act - Action act = () => value.Should().BeApproximately(3.14, 0.1); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_nullable_double_is_indeed_approximating_a_nullable_value_it_should_not_throw() - { - // Arrange - double? value = 3.1415927; - double? expected = 3.142; - - // Act - Action act = () => value.Should().BeApproximately(expected, 0.1); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_nullable_double_is_null_approximating_a_nullable_null_value_it_should_not_throw() - { - // Arrange - double? value = null; - double? expected = null; - - // Act - Action act = () => value.Should().BeApproximately(expected, 0.1); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_nullable_double_with_value_is_not_approximating_a_non_null_nullable_value_it_should_throw() - { - // Arrange - double? value = 13; - double? expected = 12; - - // Act - Action act = () => value.Should().BeApproximately(expected, 0.1); - - // Assert - act.Should().Throw().WithMessage("Expected*12.0*0.1*13.0*"); - } - - [Fact] - public void When_nullable_double_is_null_approximating_a_non_null_nullable_value_it_should_throw() - { - // Arrange - double? value = null; - double? expected = 12; - - // Act - Action act = () => value.Should().BeApproximately(expected, 0.1); - - // Assert - act.Should().Throw().WithMessage( - "Expected value to approximate 12.0 +/- 0.1, but it was ."); - } - - [Fact] - public void When_nullable_double_is_not_null_approximating_a_null_value_it_should_throw() - { - // Arrange - double? value = 12; - double? expected = null; - - // Act - Action act = () => value.Should().BeApproximately(expected, 0.1); - - // Assert - act.Should().Throw().WithMessage( - "Expected value to approximate +/- 0.1, but it was 12.0."); - } - - [Fact] - public void When_nullable_double_has_no_value_it_should_throw() - { - // Arrange - double? value = null; - - // Act - Action act = () => value.Should().BeApproximately(3.14, 0.001); - - // Assert - act.Should().Throw().WithMessage( - "Expected value to approximate 3.14 +/- 0.001, but it was ."); - } - - [Fact] - public void When_nullable_double_is_not_approximating_a_value_it_should_throw() - { - // Arrange - double? value = 3.1415927F; - - // Act - Action act = () => value.Should().BeApproximately(1.0, 0.1); - - // Assert - act - .Should().Throw() - .WithMessage("Expected value to approximate 1.0 +/- 0.1, but 3.14* differed by*"); - } - - [Fact] - public void When_approximating_a_nullable_float_with_a_negative_precision_it_should_throw() - { - // Arrange - float? value = 3.1415927F; - - // Act - Action act = () => value.Should().BeApproximately(3.14F, -0.1F); - - // Assert - act.Should().Throw() - .WithMessage("* value of precision must be non-negative*"); - } - - [Fact] - public void When_approximating_two_nullable_floats_with_a_negative_precision_it_should_throw() - { - // Arrange - float? value = 3.1415927F; - float? expected = 3.14F; - - // Act - Action act = () => value.Should().BeApproximately(expected, -0.1F); - - // Assert - act.Should().Throw() - .WithMessage("* value of precision must be non-negative*"); - } - - [Fact] - public void When_nullable_float_is_indeed_approximating_a_value_it_should_not_throw() - { - // Arrange - float? value = 3.1415927F; - - // Act - Action act = () => value.Should().BeApproximately(3.14F, 0.1F); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_nullable_float_is_indeed_approximating_a_nullable_value_it_should_not_throw() - { - // Arrange - float? value = 3.1415927f; - float? expected = 3.142f; - - // Act - Action act = () => value.Should().BeApproximately(expected, 0.1f); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_nullable_float_is_null_approximating_a_nullable_null_value_it_should_not_throw() - { - // Arrange - float? value = null; - float? expected = null; - - // Act - Action act = () => value.Should().BeApproximately(expected, 0.1f); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_nullable_float_with_value_is_not_approximating_a_non_null_nullable_value_it_should_throw() - { - // Arrange - float? value = 13; - float? expected = 12; - - // Act - Action act = () => value.Should().BeApproximately(expected, 0.1f); - - // Assert - act.Should().Throw().WithMessage("Expected*12*0.1*13*"); - } - - [Fact] - public void When_nullable_float_is_null_approximating_a_non_null_nullable_value_it_should_throw() - { - // Arrange - float? value = null; - float? expected = 12; - - // Act - Action act = () => value.Should().BeApproximately(expected, 0.1f); - - // Assert - act.Should().Throw().WithMessage( - "Expected value to approximate 12F +/- 0.1F, but it was ."); - } - - [Fact] - public void When_nullable_float_is_not_null_approximating_a_null_value_it_should_throw() - { - // Arrange - float? value = 12; - float? expected = null; - - // Act - Action act = () => value.Should().BeApproximately(expected, 0.1f); - - // Assert - act.Should().Throw().WithMessage( - "Expected value to approximate +/- 0.1F, but it was 12F."); - } - - [Fact] - public void When_nullable_float_is_not_approximating_a_value_it_should_throw() - { - // Arrange - float? value = 3.1415927F; - - // Act - Action act = () => value.Should().BeApproximately(1.0F, 0.1F); - - // Assert - act - .Should().Throw() - .WithMessage( - "Expected value to approximate *1* +/- *0.1* but 3.14* differed by*"); - } - - [Fact] - public void When_approximating_a_nullable_decimal_with_a_negative_precision_it_should_throw() - { - // Arrange - decimal? value = 3.1415927m; - - // Act - Action act = () => value.Should().BeApproximately(3.14m, -0.1m); - - // Assert - act.Should().Throw() - .WithMessage("* value of precision must be non-negative*"); - } - - [Fact] - public void When_approximating_two_nullable_decimals_with_a_negative_precision_it_should_throw() - { - // Arrange - decimal? value = 3.1415927m; - decimal? expected = 3.14m; - - // Act - Action act = () => value.Should().BeApproximately(expected, -0.1m); - - // Assert - act.Should().Throw() - .WithMessage("* value of precision must be non-negative*"); - } - - [Fact] - public void When_nullable_decimal_is_indeed_approximating_a_value_it_should_not_throw() - { - // Arrange - decimal? value = 3.1415927m; - - // Act - Action act = () => value.Should().BeApproximately(3.14m, 0.1m); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_nullable_decimal_is_indeed_approximating_a_nullable_value_it_should_not_throw() - { - // Arrange - decimal? value = 3.1415927m; - decimal? expected = 3.142m; - - // Act - Action act = () => value.Should().BeApproximately(expected, 0.1m); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_nullable_decimal_is_null_approximating_a_nullable_null_value_it_should_not_throw() - { - // Arrange - decimal? value = null; - decimal? expected = null; - - // Act - Action act = () => value.Should().BeApproximately(expected, 0.1m); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_nullable_decimal_with_value_is_not_approximating_a_non_null_nullable_value_it_should_throw() - { - // Arrange - decimal? value = 13; - decimal? expected = 12; - - // Act - Action act = () => value.Should().BeApproximately(expected, 0.1m); - - // Assert - act.Should().Throw().WithMessage("Expected*12*0.1*13*"); - } - - [Fact] - public void When_nullable_decimal_is_null_approximating_a_non_null_nullable_value_it_should_throw() - { - // Arrange - decimal? value = null; - decimal? expected = 12; - - // Act - Action act = () => value.Should().BeApproximately(expected, 0.1m); - - // Assert - act.Should().Throw().WithMessage( - "Expected value to approximate 12M +/- 0.1M, but it was ."); - } - - [Fact] - public void When_nullable_decimal_is_not_null_approximating_a_null_value_it_should_throw() - { - // Arrange - decimal? value = 12; - decimal? expected = null; - - // Act - Action act = () => value.Should().BeApproximately(expected, 0.1m); - - // Assert - act.Should().Throw().WithMessage( - "Expected value to approximate +/- 0.1M, but it was 12M."); - } - - [Fact] - public void When_nullable_decimal_has_no_value_it_should_throw() - { - // Arrange - decimal? value = null; - - // Act - Action act = () => value.Should().BeApproximately(3.14m, 0.001m); - - // Assert - act.Should().Throw().WithMessage("Expected value to approximate*3.14* +/-*0.001*, but it was ."); - } - - [Fact] - public void When_nullable_decimal_is_not_approximating_a_value_it_should_throw() - { - // Arrange - decimal? value = 3.1415927m; - - // Act - Action act = () => value.Should().BeApproximately(1.0m, 0.1m); - - // Assert - act - .Should().Throw() - .WithMessage("Expected value to approximate*1.0* +/-*0.1*, but 3.14* differed by*"); - } - - #endregion - - #region Not Be Approximately - - [Fact] - public void When_not_approximating_a_nullable_double_with_a_negative_precision_it_should_throw() - { - // Arrange - double? value = 3.1415927; - - // Act - Action act = () => value.Should().NotBeApproximately(3.14, -0.1); - - // Assert - act.Should().Throw() - .WithMessage("* value of precision must be non-negative*"); - } - - [Fact] - public void When_not_approximating_two_nullable_doubles_with_a_negative_precision_it_should_throw() - { - // Arrange - double? value = 3.1415927; - double? expected = 3.14; - - // Act - Action act = () => value.Should().NotBeApproximately(expected, -0.1); - - // Assert - act.Should().Throw() - .WithMessage("* value of precision must be non-negative*"); - } - - [Fact] - public void When_asserting_not_approximately_and_nullable_double_is_not_approximating_a_value_it_should_not_throw() - { - // Arrange - double? value = 3.1415927; - - // Act - Action act = () => value.Should().NotBeApproximately(1.0, 0.1); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_asserting_not_approximately_and_nullable_double_has_no_value_it_should_throw() - { - // Arrange - double? value = null; - - // Act - Action act = () => value.Should().NotBeApproximately(3.14, 0.001); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_asserting_not_approximately_and_nullable_double_is_indeed_approximating_a_value_it_should_throw() - { - // Arrange - double? value = 3.1415927; - - // Act - Action act = () => value.Should().NotBeApproximately(3.14, 0.1); - - // Assert - act - .Should().Throw() - .WithMessage("Expected value to not approximate 3.14 +/- 0.1, but 3.14*only differed by*"); - } - - [Fact] - public void When_asserting_not_approximately_and_nullable_double_is_not_approximating_a_nullable_value_it_should_not_throw() - { - // Arrange - double? value = 3.1415927; - double? expected = 1.0; - - // Act - Action act = () => value.Should().NotBeApproximately(expected, 0.1); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_asserting_not_approximately_and_nullable_double_is_not_approximating_a_null_value_it_should_throw() - { - // Arrange - double? value = 3.1415927; - double? expected = null; - - // Act - Action act = () => value.Should().NotBeApproximately(expected, 0.1); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_asserting_not_approximately_and_null_double_is_not_approximating_a_nullable_double_value_it_should_throw() - { - // Arrange - double? value = null; - double? expected = 20.0; - - // Act - Action act = () => value.Should().NotBeApproximately(expected, 0.1); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_asserting_not_approximately_and_null_double_is_not_approximating_a_null_value_it_should_not_throw() - { - // Arrange - double? value = null; - double? expected = null; - - // Act - Action act = () => value.Should().NotBeApproximately(expected, 0.1); - - // Assert - act.Should().Throw() - .WithMessage("Expected*null*0.1*but*null*"); - } - - [Fact] - public void When_asserting_not_approximately_and_nullable_double_is_approximating_a_nullable_value_it_should_throw() - { - // Arrange - double? value = 3.1415927; - double? expected = 3.1; - - // Act - Action act = () => value.Should().NotBeApproximately(expected, 0.1F); - - // Assert - act.Should().Throw(); - } - - [Fact] - public void When_not_approximating_a_nullable_float_with_a_negative_precision_it_should_throw() - { - // Arrange - float? value = 3.1415927F; - - // Act - Action act = () => value.Should().NotBeApproximately(3.14F, -0.1F); - - // Assert - act.Should().Throw() - .WithMessage("* value of precision must be non-negative*"); - } - - [Fact] - public void When_not_approximating_two_nullable_floats_with_a_negative_precision_it_should_throw() - { - // Arrange - float? value = 3.1415927F; - float? expected = 3.14F; - - // Act - Action act = () => value.Should().NotBeApproximately(expected, -0.1F); - - // Assert - act.Should().Throw() - .WithMessage("* value of precision must be non-negative*"); - } - - [Fact] - public void When_asserting_not_approximately_and_nullable_float_is_not_approximating_a_value_it_should_not_throw() - { - // Arrange - float? value = 3.1415927F; - - // Act - Action act = () => value.Should().NotBeApproximately(1.0F, 0.1F); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_asserting_not_approximately_and_nullable_float_has_no_value_it_should_throw() - { - // Arrange - float? value = null; - - // Act - Action act = () => value.Should().NotBeApproximately(3.14F, 0.001F); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_asserting_not_approximately_and_nullable_float_is_indeed_approximating_a_value_it_should_throw() - { - // Arrange - float? value = 3.1415927F; - - // Act - Action act = () => value.Should().NotBeApproximately(3.14F, 0.1F); - - // Assert - act - .Should().Throw() - .WithMessage("Expected value to not approximate *3.14F* +/- *0.1F* but 3.14* only differed by*"); - } - - [Fact] - public void When_asserting_not_approximately_and_nullable_float_is_not_approximating_a_nullable_value_it_should_not_throw() - { - // Arrange - float? value = 3.1415927F; - float? expected = 1.0F; - - // Act - Action act = () => value.Should().NotBeApproximately(expected, 0.1F); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_asserting_not_approximately_and_nullable_float_is_not_approximating_a_null_value_it_should_throw() - { - // Arrange - float? value = 3.1415927F; - float? expected = null; - - // Act - Action act = () => value.Should().NotBeApproximately(expected, 0.1F); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_asserting_not_approximately_and_null_float_is_not_approximating_a_nullable_float_value_it_should_throw() - { - // Arrange - float? value = null; - float? expected = 20.0f; - - // Act - Action act = () => value.Should().NotBeApproximately(expected, 0.1F); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_asserting_not_approximately_and_null_float_is_not_approximating_a_null_value_it_should_not_throw() - { - // Arrange - float? value = null; - float? expected = null; - - // Act - Action act = () => value.Should().NotBeApproximately(expected, 0.1F); - - // Assert - act.Should().Throw("Expected**+/-*0.1F**"); - } - - [Fact] - public void When_asserting_not_approximately_and_nullable_float_is_approximating_a_nullable_value_it_should_throw() - { - // Arrange - float? value = 3.1415927F; - float? expected = 3.1F; - - // Act - Action act = () => value.Should().NotBeApproximately(expected, 0.1F); - - // Assert - act.Should().Throw(); - } - - [Fact] - public void When_not_approximating_a_nullable_decimal_with_a_negative_precision_it_should_throw() - { - // Arrange - decimal? value = 3.1415927m; - - // Act - Action act = () => value.Should().NotBeApproximately(3.14m, -0.1m); - - // Assert - act.Should().Throw() - .WithMessage("* value of precision must be non-negative*"); - } - - [Fact] - public void When_not_approximating_two_nullable_decimals_with_a_negative_precision_it_should_throw() - { - // Arrange - decimal? value = 3.1415927m; - decimal? expected = 3.14m; - - // Act - Action act = () => value.Should().NotBeApproximately(expected, -0.1m); - - // Assert - act.Should().Throw() - .WithMessage("* value of precision must be non-negative*"); - } - - [Fact] - public void When_asserting_not_approximately_and_nullable_decimal_is_not_approximating_a_value_it_should_not_throw() - { - // Arrange - decimal? value = 3.1415927m; - - // Act - Action act = () => value.Should().NotBeApproximately(1.0m, 0.1m); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_asserting_not_approximately_and_nullable_decimal_has_no_value_it_should_throw() - { - // Arrange - decimal? value = null; - - // Act - Action act = () => value.Should().NotBeApproximately(3.14m, 0.001m); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_asserting_not_approximately_and_nullable_decimal_is_indeed_approximating_a_value_it_should_throw() - { - // Arrange - decimal? value = 3.1415927m; - - // Act - Action act = () => value.Should().NotBeApproximately(3.14m, 0.1m); - - // Assert - act - .Should().Throw() - .WithMessage("Expected value to not approximate*3.14* +/-*0.1*, but*3.14*only differed by*"); - } - - [Fact] - public void When_asserting_not_approximately_and_nullable_decimal_is_not_approximating_a_nullable_value_it_should_not_throw() - { - // Arrange - decimal? value = 3.1415927m; - decimal? expected = 1.0m; - - // Act - Action act = () => value.Should().NotBeApproximately(expected, 0.1m); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_asserting_not_approximately_and_nullable_decimal_is_not_approximating_a_null_value_it_should_throw() - { - // Arrange - decimal? value = 3.1415927m; - decimal? expected = null; - - // Act - Action act = () => value.Should().NotBeApproximately(expected, 0.1m); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_asserting_not_approximately_and_null_decimal_is_not_approximating_a_nullable_decimal_value_it_should_throw() - { - // Arrange - decimal? value = null; - decimal? expected = 20.0m; - - // Act - Action act = () => value.Should().NotBeApproximately(expected, 0.1m); - - // Assert - act.Should().NotThrow(); - } - - [Fact] - public void When_asserting_not_approximately_and_null_decimal_is_not_approximating_a_null_value_it_should_not_throw() - { - // Arrange - decimal? value = null; - decimal? expected = null; - - // Act - Action act = () => value.Should().NotBeApproximately(expected, 0.1m); - - // Assert - act.Should().Throw() - .WithMessage("Expected**0.1M**"); - } - - [Fact] - public void When_asserting_not_approximately_and_nullable_decimal_is_approximating_a_nullable_value_it_should_throw() - { - // Arrange - decimal? value = 3.1415927m; - decimal? expected = 3.1m; - - // Act - Action act = () => value.Should().NotBeApproximately(expected, 0.1m); - - // Assert - act.Should().Throw(); + public class BeApproximately + { + [Fact] + public void When_approximating_a_nullable_double_with_a_negative_precision_it_should_throw() + { + // Arrange + double? value = 3.1415927; + + // Act + Action act = () => value.Should().BeApproximately(3.14, -0.1); + + // Assert + act.Should().Throw() + .WithMessage("* value of precision must be non-negative*"); + } + + [Fact] + public void When_approximating_two_nullable_doubles_with_a_negative_precision_it_should_throw() + { + // Arrange + double? value = 3.1415927; + double? expected = 3.14; + + // Act + Action act = () => value.Should().BeApproximately(expected, -0.1); + + // Assert + act.Should().Throw() + .WithMessage("* value of precision must be non-negative*"); + } + + [Fact] + public void When_nullable_double_is_indeed_approximating_a_value_it_should_not_throw() + { + // Arrange + double? value = 3.1415927; + + // Act + Action act = () => value.Should().BeApproximately(3.14, 0.1); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_nullable_double_is_indeed_approximating_a_nullable_value_it_should_not_throw() + { + // Arrange + double? value = 3.1415927; + double? expected = 3.142; + + // Act + Action act = () => value.Should().BeApproximately(expected, 0.1); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_nullable_double_is_null_approximating_a_nullable_null_value_it_should_not_throw() + { + // Arrange + double? value = null; + double? expected = null; + + // Act + Action act = () => value.Should().BeApproximately(expected, 0.1); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_nullable_double_with_value_is_not_approximating_a_non_null_nullable_value_it_should_throw() + { + // Arrange + double? value = 13; + double? expected = 12; + + // Act + Action act = () => value.Should().BeApproximately(expected, 0.1); + + // Assert + act.Should().Throw().WithMessage("Expected*12.0*0.1*13.0*"); + } + + [Fact] + public void When_nullable_double_is_null_approximating_a_non_null_nullable_value_it_should_throw() + { + // Arrange + double? value = null; + double? expected = 12; + + // Act + Action act = () => value.Should().BeApproximately(expected, 0.1); + + // Assert + act.Should().Throw().WithMessage( + "Expected value to approximate 12.0 +/- 0.1, but it was ."); + } + + [Fact] + public void When_nullable_double_is_not_null_approximating_a_null_value_it_should_throw() + { + // Arrange + double? value = 12; + double? expected = null; + + // Act + Action act = () => value.Should().BeApproximately(expected, 0.1); + + // Assert + act.Should().Throw().WithMessage( + "Expected value to approximate +/- 0.1, but it was 12.0."); + } + + [Fact] + public void When_nullable_double_has_no_value_it_should_throw() + { + // Arrange + double? value = null; + + // Act + Action act = () => value.Should().BeApproximately(3.14, 0.001); + + // Assert + act.Should().Throw().WithMessage( + "Expected value to approximate 3.14 +/- 0.001, but it was ."); + } + + [Fact] + public void When_nullable_double_is_not_approximating_a_value_it_should_throw() + { + // Arrange + double? value = 3.1415927F; + + // Act + Action act = () => value.Should().BeApproximately(1.0, 0.1); + + // Assert + act + .Should().Throw() + .WithMessage("Expected value to approximate 1.0 +/- 0.1, but 3.14* differed by*"); + } + + [Fact] + public void A_double_cannot_approximate_NaN() + { + // Arrange + double? value = 3.1415927F; + + // Act + Action act = () => value.Should().BeApproximately(double.NaN, 0.1); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } + + [Fact] + public void When_approximating_a_nullable_float_with_a_negative_precision_it_should_throw() + { + // Arrange + float? value = 3.1415927F; + + // Act + Action act = () => value.Should().BeApproximately(3.14F, -0.1F); + + // Assert + act.Should().Throw() + .WithMessage("* value of precision must be non-negative*"); + } + + [Fact] + public void When_approximating_two_nullable_floats_with_a_negative_precision_it_should_throw() + { + // Arrange + float? value = 3.1415927F; + float? expected = 3.14F; + + // Act + Action act = () => value.Should().BeApproximately(expected, -0.1F); + + // Assert + act.Should().Throw() + .WithMessage("* value of precision must be non-negative*"); + } + + [Fact] + public void When_nullable_float_is_indeed_approximating_a_value_it_should_not_throw() + { + // Arrange + float? value = 3.1415927F; + + // Act + Action act = () => value.Should().BeApproximately(3.14F, 0.1F); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_nullable_float_is_indeed_approximating_a_nullable_value_it_should_not_throw() + { + // Arrange + float? value = 3.1415927f; + float? expected = 3.142f; + + // Act + Action act = () => value.Should().BeApproximately(expected, 0.1f); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_nullable_float_is_null_approximating_a_nullable_null_value_it_should_not_throw() + { + // Arrange + float? value = null; + float? expected = null; + + // Act + Action act = () => value.Should().BeApproximately(expected, 0.1f); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_nullable_float_with_value_is_not_approximating_a_non_null_nullable_value_it_should_throw() + { + // Arrange + float? value = 13; + float? expected = 12; + + // Act + Action act = () => value.Should().BeApproximately(expected, 0.1f); + + // Assert + act.Should().Throw().WithMessage("Expected*12*0.1*13*"); + } + + [Fact] + public void When_nullable_float_is_null_approximating_a_non_null_nullable_value_it_should_throw() + { + // Arrange + float? value = null; + float? expected = 12; + + // Act + Action act = () => value.Should().BeApproximately(expected, 0.1f); + + // Assert + act.Should().Throw().WithMessage( + "Expected value to approximate 12F +/- 0.1F, but it was ."); + } + + [Fact] + public void When_nullable_float_is_not_null_approximating_a_null_value_it_should_throw() + { + // Arrange + float? value = 12; + float? expected = null; + + // Act + Action act = () => value.Should().BeApproximately(expected, 0.1f); + + // Assert + act.Should().Throw().WithMessage( + "Expected value to approximate +/- 0.1F, but it was 12F."); + } + + [Fact] + public void When_nullable_float_is_not_approximating_a_value_it_should_throw() + { + // Arrange + float? value = 3.1415927F; + + // Act + Action act = () => value.Should().BeApproximately(1.0F, 0.1F); + + // Assert + act + .Should().Throw() + .WithMessage( + "Expected value to approximate *1* +/- *0.1* but 3.14* differed by*"); + } + + [Fact] + public void A_float_cannot_approximate_NaN() + { + // Arrange + float? value = 3.1415927F; + + // Act + Action act = () => value.Should().BeApproximately(float.NaN, 0.1F); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } + + [Fact] + public void When_approximating_a_nullable_decimal_with_a_negative_precision_it_should_throw() + { + // Arrange + decimal? value = 3.1415927m; + + // Act + Action act = () => value.Should().BeApproximately(3.14m, -0.1m); + + // Assert + act.Should().Throw() + .WithMessage("* value of precision must be non-negative*"); + } + + [Fact] + public void When_approximating_two_nullable_decimals_with_a_negative_precision_it_should_throw() + { + // Arrange + decimal? value = 3.1415927m; + decimal? expected = 3.14m; + + // Act + Action act = () => value.Should().BeApproximately(expected, -0.1m); + + // Assert + act.Should().Throw() + .WithMessage("* value of precision must be non-negative*"); + } + + [Fact] + public void When_nullable_decimal_is_indeed_approximating_a_value_it_should_not_throw() + { + // Arrange + decimal? value = 3.1415927m; + + // Act + Action act = () => value.Should().BeApproximately(3.14m, 0.1m); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_nullable_decimal_is_indeed_approximating_a_nullable_value_it_should_not_throw() + { + // Arrange + decimal? value = 3.1415927m; + decimal? expected = 3.142m; + + // Act + Action act = () => value.Should().BeApproximately(expected, 0.1m); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_nullable_decimal_is_null_approximating_a_nullable_null_value_it_should_not_throw() + { + // Arrange + decimal? value = null; + decimal? expected = null; + + // Act + Action act = () => value.Should().BeApproximately(expected, 0.1m); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_nullable_decimal_with_value_is_not_approximating_a_non_null_nullable_value_it_should_throw() + { + // Arrange + decimal? value = 13; + decimal? expected = 12; + + // Act + Action act = () => value.Should().BeApproximately(expected, 0.1m); + + // Assert + act.Should().Throw().WithMessage("Expected*12*0.1*13*"); + } + + [Fact] + public void When_nullable_decimal_is_null_approximating_a_non_null_nullable_value_it_should_throw() + { + // Arrange + decimal? value = null; + decimal? expected = 12; + + // Act + Action act = () => value.Should().BeApproximately(expected, 0.1m); + + // Assert + act.Should().Throw().WithMessage( + "Expected value to approximate 12M +/- 0.1M, but it was ."); + } + + [Fact] + public void When_nullable_decimal_is_not_null_approximating_a_null_value_it_should_throw() + { + // Arrange + decimal? value = 12; + decimal? expected = null; + + // Act + Action act = () => value.Should().BeApproximately(expected, 0.1m); + + // Assert + act.Should().Throw().WithMessage( + "Expected value to approximate +/- 0.1M, but it was 12M."); + } + + [Fact] + public void When_nullable_decimal_has_no_value_it_should_throw() + { + // Arrange + decimal? value = null; + + // Act + Action act = () => value.Should().BeApproximately(3.14m, 0.001m); + + // Assert + act.Should().Throw() + .WithMessage("Expected value to approximate*3.14* +/-*0.001*, but it was ."); + } + + [Fact] + public void When_nullable_decimal_is_not_approximating_a_value_it_should_throw() + { + // Arrange + decimal? value = 3.1415927m; + + // Act + Action act = () => value.Should().BeApproximately(1.0m, 0.1m); + + // Assert + act + .Should().Throw() + .WithMessage("Expected value to approximate*1.0* +/-*0.1*, but 3.14* differed by*"); + } + } + + public class NotBeApproximately + { + [Fact] + public void When_not_approximating_a_nullable_double_with_a_negative_precision_it_should_throw() + { + // Arrange + double? value = 3.1415927; + + // Act + Action act = () => value.Should().NotBeApproximately(3.14, -0.1); + + // Assert + act.Should().Throw() + .WithMessage("* value of precision must be non-negative*"); + } + + [Fact] + public void When_not_approximating_two_nullable_doubles_with_a_negative_precision_it_should_throw() + { + // Arrange + double? value = 3.1415927; + double? expected = 3.14; + + // Act + Action act = () => value.Should().NotBeApproximately(expected, -0.1); + + // Assert + act.Should().Throw() + .WithMessage("* value of precision must be non-negative*"); + } + + [Fact] + public void When_asserting_not_approximately_and_nullable_double_is_not_approximating_a_value_it_should_not_throw() + { + // Arrange + double? value = 3.1415927; + + // Act + Action act = () => value.Should().NotBeApproximately(1.0, 0.1); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_asserting_not_approximately_and_nullable_double_has_no_value_it_should_throw() + { + // Arrange + double? value = null; + + // Act + Action act = () => value.Should().NotBeApproximately(3.14, 0.001); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_asserting_not_approximately_and_nullable_double_is_indeed_approximating_a_value_it_should_throw() + { + // Arrange + double? value = 3.1415927; + + // Act + Action act = () => value.Should().NotBeApproximately(3.14, 0.1); + + // Assert + act + .Should().Throw() + .WithMessage("Expected value to not approximate 3.14 +/- 0.1, but 3.14*only differed by*"); + } + + [Fact] + public void + When_asserting_not_approximately_and_nullable_double_is_not_approximating_a_nullable_value_it_should_not_throw() + { + // Arrange + double? value = 3.1415927; + double? expected = 1.0; + + // Act + Action act = () => value.Should().NotBeApproximately(expected, 0.1); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_asserting_not_approximately_and_nullable_double_is_not_approximating_a_null_value_it_should_throw() + { + // Arrange + double? value = 3.1415927; + double? expected = null; + + // Act + Action act = () => value.Should().NotBeApproximately(expected, 0.1); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void + When_asserting_not_approximately_and_null_double_is_not_approximating_a_nullable_double_value_it_should_throw() + { + // Arrange + double? value = null; + double? expected = 20.0; + + // Act + Action act = () => value.Should().NotBeApproximately(expected, 0.1); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_asserting_not_approximately_and_null_double_is_not_approximating_a_null_value_it_should_not_throw() + { + // Arrange + double? value = null; + double? expected = null; + + // Act + Action act = () => value.Should().NotBeApproximately(expected, 0.1); + + // Assert + act.Should().Throw() + .WithMessage("Expected*null*0.1*but*null*"); + } + + [Fact] + public void When_asserting_not_approximately_and_nullable_double_is_approximating_a_nullable_value_it_should_throw() + { + // Arrange + double? value = 3.1415927; + double? expected = 3.1; + + // Act + Action act = () => value.Should().NotBeApproximately(expected, 0.1F); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void A_double_cannot_approximate_NaN() + { + // Arrange + double? value = 3.1415927F; + + // Act + Action act = () => value.Should().NotBeApproximately(double.NaN, 0.1); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } + + [Fact] + public void When_not_approximating_a_nullable_float_with_a_negative_precision_it_should_throw() + { + // Arrange + float? value = 3.1415927F; + + // Act + Action act = () => value.Should().NotBeApproximately(3.14F, -0.1F); + + // Assert + act.Should().Throw() + .WithMessage("* value of precision must be non-negative*"); + } + + [Fact] + public void When_not_approximating_two_nullable_floats_with_a_negative_precision_it_should_throw() + { + // Arrange + float? value = 3.1415927F; + float? expected = 3.14F; + + // Act + Action act = () => value.Should().NotBeApproximately(expected, -0.1F); + + // Assert + act.Should().Throw() + .WithMessage("* value of precision must be non-negative*"); + } + + [Fact] + public void When_asserting_not_approximately_and_nullable_float_is_not_approximating_a_value_it_should_not_throw() + { + // Arrange + float? value = 3.1415927F; + + // Act + Action act = () => value.Should().NotBeApproximately(1.0F, 0.1F); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_asserting_not_approximately_and_nullable_float_has_no_value_it_should_throw() + { + // Arrange + float? value = null; + + // Act + Action act = () => value.Should().NotBeApproximately(3.14F, 0.001F); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_asserting_not_approximately_and_nullable_float_is_indeed_approximating_a_value_it_should_throw() + { + // Arrange + float? value = 3.1415927F; + + // Act + Action act = () => value.Should().NotBeApproximately(3.14F, 0.1F); + + // Assert + act + .Should().Throw() + .WithMessage("Expected value to not approximate *3.14F* +/- *0.1F* but 3.14* only differed by*"); + } + + [Fact] + public void + When_asserting_not_approximately_and_nullable_float_is_not_approximating_a_nullable_value_it_should_not_throw() + { + // Arrange + float? value = 3.1415927F; + float? expected = 1.0F; + + // Act + Action act = () => value.Should().NotBeApproximately(expected, 0.1F); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_asserting_not_approximately_and_nullable_float_is_not_approximating_a_null_value_it_should_throw() + { + // Arrange + float? value = 3.1415927F; + float? expected = null; + + // Act + Action act = () => value.Should().NotBeApproximately(expected, 0.1F); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void + When_asserting_not_approximately_and_null_float_is_not_approximating_a_nullable_float_value_it_should_throw() + { + // Arrange + float? value = null; + float? expected = 20.0f; + + // Act + Action act = () => value.Should().NotBeApproximately(expected, 0.1F); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_asserting_not_approximately_and_null_float_is_not_approximating_a_null_value_it_should_not_throw() + { + // Arrange + float? value = null; + float? expected = null; + + // Act + Action act = () => value.Should().NotBeApproximately(expected, 0.1F); + + // Assert + act.Should().Throw("Expected**+/-*0.1F**"); + } + + [Fact] + public void When_asserting_not_approximately_and_nullable_float_is_approximating_a_nullable_value_it_should_throw() + { + // Arrange + float? value = 3.1415927F; + float? expected = 3.1F; + + // Act + Action act = () => value.Should().NotBeApproximately(expected, 0.1F); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void A_float_cannot_approximate_NaN() + { + // Arrange + float? value = 3.1415927F; + + // Act + Action act = () => value.Should().NotBeApproximately(float.NaN, 0.1F); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } + + [Fact] + public void When_not_approximating_a_nullable_decimal_with_a_negative_precision_it_should_throw() + { + // Arrange + decimal? value = 3.1415927m; + + // Act + Action act = () => value.Should().NotBeApproximately(3.14m, -0.1m); + + // Assert + act.Should().Throw() + .WithMessage("* value of precision must be non-negative*"); + } + + [Fact] + public void When_not_approximating_two_nullable_decimals_with_a_negative_precision_it_should_throw() + { + // Arrange + decimal? value = 3.1415927m; + decimal? expected = 3.14m; + + // Act + Action act = () => value.Should().NotBeApproximately(expected, -0.1m); + + // Assert + act.Should().Throw() + .WithMessage("* value of precision must be non-negative*"); + } + + [Fact] + public void When_asserting_not_approximately_and_nullable_decimal_is_not_approximating_a_value_it_should_not_throw() + { + // Arrange + decimal? value = 3.1415927m; + + // Act + Action act = () => value.Should().NotBeApproximately(1.0m, 0.1m); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_asserting_not_approximately_and_nullable_decimal_has_no_value_it_should_throw() + { + // Arrange + decimal? value = null; + + // Act + Action act = () => value.Should().NotBeApproximately(3.14m, 0.001m); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_asserting_not_approximately_and_nullable_decimal_is_indeed_approximating_a_value_it_should_throw() + { + // Arrange + decimal? value = 3.1415927m; + + // Act + Action act = () => value.Should().NotBeApproximately(3.14m, 0.1m); + + // Assert + act + .Should().Throw() + .WithMessage("Expected value to not approximate*3.14* +/-*0.1*, but*3.14*only differed by*"); + } + + [Fact] + public void + When_asserting_not_approximately_and_nullable_decimal_is_not_approximating_a_nullable_value_it_should_not_throw() + { + // Arrange + decimal? value = 3.1415927m; + decimal? expected = 1.0m; + + // Act + Action act = () => value.Should().NotBeApproximately(expected, 0.1m); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_asserting_not_approximately_and_nullable_decimal_is_not_approximating_a_null_value_it_should_throw() + { + // Arrange + decimal? value = 3.1415927m; + decimal? expected = null; + + // Act + Action act = () => value.Should().NotBeApproximately(expected, 0.1m); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void + When_asserting_not_approximately_and_null_decimal_is_not_approximating_a_nullable_decimal_value_it_should_throw() + { + // Arrange + decimal? value = null; + decimal? expected = 20.0m; + + // Act + Action act = () => value.Should().NotBeApproximately(expected, 0.1m); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_asserting_not_approximately_and_null_decimal_is_not_approximating_a_null_value_it_should_not_throw() + { + // Arrange + decimal? value = null; + decimal? expected = null; + + // Act + Action act = () => value.Should().NotBeApproximately(expected, 0.1m); + + // Assert + act.Should().Throw() + .WithMessage("Expected**0.1M**"); + } + + [Fact] + public void When_asserting_not_approximately_and_nullable_decimal_is_approximating_a_nullable_value_it_should_throw() + { + // Arrange + decimal? value = 3.1415927m; + decimal? expected = 3.1m; + + // Act + Action act = () => value.Should().NotBeApproximately(expected, 0.1m); + + // Assert + act.Should().Throw(); + } + } + + public class Match + { + [Fact] + public void When_nullable_value_satisfies_predicate_it_should_not_throw() + { + // Arrange + int? nullableInteger = 1; + + // Act / Assert + nullableInteger.Should().Match(o => o.HasValue); + } + + [Fact] + public void When_nullable_value_does_not_match_the_predicate_it_should_throw() + { + // Arrange + int? nullableInteger = 1; + + // Act + Action act = () => + nullableInteger.Should().Match(o => !o.HasValue, "because we want to test the failure {0}", "message"); + + // Assert + act.Should().Throw() + .WithMessage( + "Expected value to match Not(o.HasValue) because we want to test the failure message, but found 1."); + } + + [Fact] + public void When_nullable_value_is_matched_against_a_null_it_should_throw() + { + // Arrange + int? nullableInteger = 1; + + // Act + Action act = () => nullableInteger.Should().Match(null); + + // Assert + act.Should().ThrowExactly() + .WithParameterName("predicate"); + } } - #endregion - - #region Match - - [Fact] - public void When_nullable_value_satisfies_predicate_it_should_not_throw() - { - // Arrange - int? nullableInteger = 1; - - // Act / Assert - nullableInteger.Should().Match(o => o.HasValue); - } - - [Fact] - public void When_nullable_value_does_not_match_the_predicate_it_should_throw() - { - // Arrange - int? nullableInteger = 1; - - // Act - Action act = () => nullableInteger.Should().Match(o => !o.HasValue, "because we want to test the failure {0}", "message"); - - // Assert - act.Should().Throw() - .WithMessage("Expected value to match Not(o.HasValue) because we want to test the failure message, but found 1."); - } - - [Fact] - public void When_nullable_value_is_matched_against_a_null_it_should_throw() - { - // Arrange - int? nullableInteger = 1; - - // Act - Action act = () => nullableInteger.Should().Match(null); - - // Assert - act.Should().ThrowExactly() - .WithParameterName("predicate"); - } - - #endregion - [Fact] public void Should_support_chaining_constraints_with_and() { diff --git a/Tests/FluentAssertions.Specs/Numeric/NumericAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Numeric/NumericAssertionSpecs.cs index d459dbd701..1b7e7c9bc0 100644 --- a/Tests/FluentAssertions.Specs/Numeric/NumericAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Numeric/NumericAssertionSpecs.cs @@ -47,6 +47,32 @@ public void When_a_zero_value_is_positive_it_should_throw() act.Should().Throw(); } + [Fact] + public void NaN_is_never_a_positive_float() + { + // Arrange + float value = float.NaN; + + // Act + Action act = () => value.Should().BePositive(); + + // Assert + act.Should().Throw().WithMessage("*but found NaN*"); + } + + [Fact] + public void NaN_is_never_a_positive_double() + { + // Arrange + double value = double.NaN; + + // Act + Action act = () => value.Should().BePositive(); + + // Assert + act.Should().Throw().WithMessage("*but found NaN*"); + } + [Fact] public void When_a_negative_value_is_positive_it_should_throw_with_descriptive_message() { @@ -62,6 +88,21 @@ public void When_a_negative_value_is_positive_it_should_throw_with_descriptive_m .WithMessage("Expected value to be positive because we want to test the failure message, but found -1."); } + [Fact] + public void When_a_nullable_numeric_null_value_is_not_positive_it_should_throw() + { + // Arrange + int? value = null; + + // Act + Action act = () => value.Should().BePositive(); + + // Assert + act + .Should().Throw() + .WithMessage("*null*"); + } + [Fact] public void When_a_negative_value_is_negative_it_should_not_throw() { @@ -132,18 +173,29 @@ public void When_a_nullable_numeric_null_value_is_not_negative_it_should_throw() } [Fact] - public void When_a_nullable_numeric_null_value_is_not_positive_it_should_throw() + public void NaN_is_never_a_negative_float() { // Arrange - int? value = null; + float value = float.NaN; // Act - Action act = () => value.Should().BePositive(); + Action act = () => value.Should().BeNegative(); // Assert - act - .Should().Throw() - .WithMessage("*null*"); + act.Should().Throw().WithMessage("*but found NaN*"); + } + + [Fact] + public void NaN_is_never_a_negative_double() + { + // Arrange + double value = double.NaN; + + // Act + Action act = () => value.Should().BeNegative(); + + // Assert + act.Should().Throw().WithMessage("*but found NaN*"); } } @@ -513,6 +565,57 @@ public void When_asserting_that_a_null_decimal_value_is_equal_to_some_value_it_s .Should().Throw() .WithMessage("Expected value to be*3.5*, but found ."); } + + [Fact] + public void Nan_is_never_equal_to_a_normal_float() + { + // Arrange + float value = float.NaN; + + // Act + Action act = () => value.Should().Be(3.4F); + + // Assert + act + .Should().Throw() + .WithMessage( + "Expected value to be *3.4F, but found NaN*"); + } + + [Fact] + public void NaN_can_be_compared_to_NaN_when_its_a_float() + { + // Arrange + float value = float.NaN; + + // Act + value.Should().Be(float.NaN); + } + + [Fact] + public void Nan_is_never_equal_to_a_normal_double() + { + // Arrange + double value = double.NaN; + + // Act + Action act = () => value.Should().Be(3.4D); + + // Assert + act + .Should().Throw() + .WithMessage("Expected value to be *3.4, but found NaN*"); + } + + [Fact] + public void NaN_can_be_compared_to_NaN_when_its_a_double() + { + // Arrange + double value = double.NaN; + + // Act + value.Should().Be(double.NaN); + } } public class BeGreaterThanOrEqualTo @@ -575,6 +678,54 @@ public void When_a_value_is_greater_than_greater_value_it_should_throw_with_desc .Should().Throw() .WithMessage("Expected value to be greater than 3 because we want to test the failure message, but found 2."); } + + [Fact] + public void NaN_is_never_greater_than_another_float() + { + // Act + Action act = () => float.NaN.Should().BeGreaterThan(0); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } + + [Fact] + public void A_float_cannot_be_greater_than_NaN() + { + // Act + Action act = () => 3.4F.Should().BeGreaterThan(float.NaN); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } + + [Fact] + public void NaN_is_never_greater_than_another_double() + { + // Act + Action act = () => double.NaN.Should().BeGreaterThan(0); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } + + [Fact] + public void A_double_can_never_be_greater_than_NaN() + { + // Act + Action act = () => 3.4D.Should().BeGreaterThan(double.NaN); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } [Fact] public void When_a_value_is_greater_than_or_equal_to_smaller_value_it_should_not_throw() @@ -666,6 +817,54 @@ public void When_a_nullable_numeric_null_value_is_not_greater_than_or_equal_to_i .Should().Throw() .WithMessage("*null*"); } + + [Fact] + public void NaN_is_never_greater_than_or_equal_to_another_float() + { + // Act + Action act = () => float.NaN.Should().BeGreaterThanOrEqualTo(0); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } + + [Fact] + public void A_float_cannot_be_greater_than_or_equal_to_NaN() + { + // Act + Action act = () => 3.4F.Should().BeGreaterThanOrEqualTo(float.NaN); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } + + [Fact] + public void NaN_is_never_greater_or_equal_to_another_double() + { + // Act + Action act = () => double.NaN.Should().BeGreaterThanOrEqualTo(0); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } + + [Fact] + public void A_double_can_never_be_greater_or_equal_to_NaN() + { + // Act + Action act = () => 3.4D.Should().BeGreaterThanOrEqualTo(double.NaN); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } } public class LessThanOrEqualTo @@ -728,6 +927,54 @@ public void When_a_value_is_less_than_smaller_value_it_should_throw_with_descrip .WithMessage("Expected value to be less than 1 because we want to test the failure message, but found 2."); } + [Fact] + public void NaN_is_never_less_than_another_float() + { + // Act + Action act = () => float.NaN.Should().BeLessThan(0); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } + + [Fact] + public void A_float_can_never_be_less_than_NaN() + { + // Act + Action act = () => 3.4F.Should().BeLessThan(float.NaN); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } + + [Fact] + public void NaN_is_never_less_than_another_double() + { + // Act + Action act = () => double.NaN.Should().BeLessThan(0); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } + + [Fact] + public void A_double_can_never_be_less_than_NaN() + { + // Act + Action act = () => 3.4D.Should().BeLessThan(double.NaN); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } + [Fact] public void When_a_value_is_less_than_or_equal_to_greater_value_it_should_not_throw() { @@ -817,6 +1064,54 @@ public void When_a_nullable_numeric_null_value_is_not_less_than_or_equal_to_it_s .Should().Throw() .WithMessage("*null*"); } + + [Fact] + public void NaN_is_never_less_than_or_equal_to_another_float() + { + // Act + Action act = () => float.NaN.Should().BeLessThanOrEqualTo(0); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } + + [Fact] + public void A_float_can_never_be_less_than_or_equal_to_NaN() + { + // Act + Action act = () => 3.4F.Should().BeLessThanOrEqualTo(float.NaN); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } + + [Fact] + public void NaN_is_never_less_than_or_equal_to_another_double() + { + // Act + Action act = () => double.NaN.Should().BeLessThanOrEqualTo(0); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } + + [Fact] + public void A_double_can_never_be_less_than_or_equal_to_NaN() + { + // Act + Action act = () => 3.4D.Should().BeLessThanOrEqualTo(double.NaN); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } } public class InRange @@ -864,6 +1159,74 @@ public void When_a_nullable_numeric_null_value_is_not_in_range_it_should_throw() .Should().Throw() .WithMessage("*null*"); } + + [Fact] + public void NaN_is_never_in_range_of_two_floats() + { + // Arrange + float value = float.NaN; + + // Act + Action act = () => value.Should().BeInRange(4, 5); + + // Assert + act + .Should().Throw() + .WithMessage( + "Expected value to be between*4* and*5*, but found*NaN*"); + } + + [Theory] + [InlineData(float.NaN, 5F)] + [InlineData(5F, float.NaN)] + public void A_float_can_never_be_in_a_range_containing_NaN(float minimumValue, float maximumValue) + { + // Arrange + float value = 4.5F; + + // Act + Action act = () => value.Should().BeInRange(minimumValue, maximumValue); + + // Assert + act + .Should().Throw() + .WithMessage( + "*NaN*"); + } + + [Fact] + public void A_NaN_is_never_in_range_of_two_doubles() + { + // Arrange + float value = float.NaN; + + // Act + Action act = () => value.Should().BeInRange(4, 5); + + // Assert + act + .Should().Throw() + .WithMessage( + "Expected value to be between*4* and*5*, but found*NaN*"); + } + + [Theory] + [InlineData(double.NaN, 5)] + [InlineData(5, double.NaN)] + public void A_double_can_never_be_in_a_range_containing_NaN(double minimumValue, double maximumValue) + { + // Arrange + double value = 4.5D; + + // Act + Action act = () => value.Should().BeInRange(minimumValue, maximumValue); + + // Assert + act + .Should().Throw() + .WithMessage( + "*NaN*"); + } } public class NotInRange @@ -911,6 +1274,60 @@ public void When_a_nullable_numeric_null_value_is_not_not_in_range_to_it_should_ .Should().Throw() .WithMessage("*null*"); } + + [Fact] + public void NaN_is_never_inside_any_range_of_floats() + { + // Arrange + float value = float.NaN; + + // Act / Assert + value.Should().NotBeInRange(4, 5); + } + + [Theory] + [InlineData(float.NaN, 1F)] + [InlineData(1F, float.NaN)] + public void Cannot_use_NaN_in_a_range_of_floats(float minimumValue, float maximumValue) + { + // Arrange + float value = 4.5F; + + // Act + Action act = () => value.Should().NotBeInRange(minimumValue, maximumValue); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } + + [Fact] + public void NaN_is_never_inside_any_range_of_doubles() + { + // Arrange + double value = double.NaN; + + // Act / Assert + value.Should().NotBeInRange(4, 5); + } + + [Theory] + [InlineData(double.NaN, 1D)] + [InlineData(1D, double.NaN)] + public void Cannot_use_NaN_in_a_range_of_doubles(double minimumValue, double maximumValue) + { + // Arrange + double value = 4.5D; + + // Act + Action act = () => value.Should().NotBeInRange(minimumValue, maximumValue); + + // Assert + act + .Should().Throw() + .WithMessage("*NaN*"); + } } public class BeOneOf @@ -972,6 +1389,56 @@ public void When_a_nullable_numeric_null_value_is_not_one_of_to_it_should_throw( .Should().Throw() .WithMessage("*null*"); } + + [Fact] + public void Two_floats_that_are_NaN_can_be_compared() + { + // Arrange + float value = float.NaN; + + // Act / Assert + value.Should().BeOneOf(float.NaN, 4.5F); + } + + [Fact] + public void Floats_are_never_equal_to_NaN() + { + // Arrange + float value = float.NaN; + + // Act + Action act = () => value.Should().BeOneOf(1.5F, 4.5F); + + // Assert + act + .Should().Throw() + .WithMessage("Expected*1.5F*found*NaN*"); + } + + [Fact] + public void Two_doubles_that_are_NaN_can_be_compared() + { + // Arrange + double value = double.NaN; + + // Act / Assert + value.Should().BeOneOf(double.NaN, 4.5F); + } + + [Fact] + public void Doubles_are_never_equal_to_NaN() + { + // Arrange + double value = double.NaN; + + // Act + Action act = () => value.Should().BeOneOf(1.5D, 4.5D); + + // Assert + act + .Should().Throw() + .WithMessage("Expected*1.5*found NaN*"); + } } public class Bytes @@ -1296,6 +1763,32 @@ public void When_float_is_not_approximating_negative_infinity_it_should_throw() act.Should().Throw(); } + [Fact] + public void NaN_can_never_be_close_to_any_float() + { + // Arrange + float value = float.NaN; + + // Act + Action act = () => value.Should().BeApproximately(float.MinValue, 0.1F); + + // Assert + act.Should().Throw().WithMessage("*NaN*"); + } + + [Fact] + public void A_float_can_never_be_close_to_NaN() + { + // Arrange + float value = float.MinValue; + + // Act + Action act = () => value.Should().BeApproximately(float.NaN, 0.1F); + + // Assert + act.Should().Throw().WithMessage("*NaN*"); + } + [Fact] public void When_a_nullable_float_has_no_value_it_should_throw() { @@ -1444,7 +1937,33 @@ public void When_double_is_not_approximating_a_value_on_boundaries_it_should_thr } [Fact] - public void When_approximating_a_decimale_with_a_negative_precision_it_should_throw() + public void NaN_can_never_be_close_to_any_double() + { + // Arrange + double value = double.NaN; + + // Act + Action act = () => value.Should().BeApproximately(double.MinValue, 0.1F); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void A_double_can_never_be_close_to_NaN() + { + // Arrange + double value = double.MinValue; + + // Act + Action act = () => value.Should().BeApproximately(double.NaN, 0.1F); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void When_approximating_a_decimal_with_a_negative_precision_it_should_throw() { // Arrange decimal value = 3.1415927M; @@ -1686,6 +2205,32 @@ public void When_a_nullable_float_has_no_value_and_should_not_approximate_it_sho act.Should().NotThrow(); } + [Fact] + public void NaN_can_never_be_close_to_any_float() + { + // Arrange + float value = float.NaN; + + // Act + Action act = () => value.Should().NotBeApproximately(float.MinValue, 0.1F); + + // Assert + act.Should().Throw().WithMessage("*NaN*"); + } + + [Fact] + public void A_float_can_never_be_close_to_NaN() + { + // Arrange + float value = float.MinValue; + + // Act + Action act = () => value.Should().NotBeApproximately(float.NaN, 0.1F); + + // Assert + act.Should().Throw().WithMessage("*NaN*"); + } + [Fact] public void When_not_approximating_a_double_with_a_negative_precision_it_should_throw() { @@ -1833,6 +2378,32 @@ public void When_double_is_approximating_a_value_on_boundaries_it_should_throw(d act.Should().Throw(); } + [Fact] + public void NaN_can_never_be_close_to_any_double() + { + // Arrange + double value = double.NaN; + + // Act + Action act = () => value.Should().NotBeApproximately(double.MinValue, 0.1F); + + // Assert + act.Should().Throw().WithMessage("*NaN*"); + } + + [Fact] + public void A_double_can_never_be_close_to_NaN() + { + // Arrange + double value = double.MinValue; + + // Act + Action act = () => value.Should().NotBeApproximately(double.NaN, 0.1F); + + // Assert + act.Should().Throw().WithMessage("*NaN*"); + } + [Fact] public void When_not_approximating_a_decimal_with_a_negative_precision_it_should_throw() { diff --git a/docs/_pages/releases.md b/docs/_pages/releases.md index 9cc588475f..bb10f3a580 100644 --- a/docs/_pages/releases.md +++ b/docs/_pages/releases.md @@ -16,6 +16,7 @@ sidebar: ### Fixes * `EnumAssertions.Be` did not determine the caller name - [#1835](https://github.com/fluentassertions/fluentassertions/pull/1835) * Ensure `ExcludingMissingMembers` doesn't undo usage of `WithMapping` in `BeEquivalentTo` - [#1838](https://github.com/fluentassertions/fluentassertions/pull/1838) +* Better handling of NaN in various numeric assertions - [#1822](https://github.com/fluentassertions/fluentassertions/pull/1822) ### Fixes (Extensibility)