From 42ef7d9374c7490c4fafcc53f413f93f0acadfa7 Mon Sep 17 00:00:00 2001 From: Artur Krajewski Date: Tue, 2 Oct 2018 22:16:04 +0200 Subject: [PATCH] Add `BeApproximately` version for both subject and expected nullable (#934) * Add `BeApproximately` for both subject and expected of type `double?` * Add `BeApproximately` for both subject and expected of type `float?` * Add `BeApproximately` for both subject and expected of type `decimal?` --- .../NumericAssertionsExtensions.cs | 123 +++++++ .../NullableNumericAssertionSpecs.cs | 306 ++++++++++++++++++ 2 files changed, 429 insertions(+) diff --git a/Src/FluentAssertions/NumericAssertionsExtensions.cs b/Src/FluentAssertions/NumericAssertionsExtensions.cs index 3dd20af3e9..1ad7accfb9 100644 --- a/Src/FluentAssertions/NumericAssertionsExtensions.cs +++ b/Src/FluentAssertions/NumericAssertionsExtensions.cs @@ -711,6 +711,47 @@ public static class NumericAssertionsExtensions return new AndConstraint>(parent); } + /// + /// Asserts a floating point value approximates another value as close as possible. + /// Does not throw if null subject value approximates null value. + /// + /// The object that is being extended. + /// + /// The expected value to compare the actual value with. + /// + /// + /// The maximum amount of which the two values may differ. + /// + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public static AndConstraint> BeApproximately(this NullableNumericAssertions parent, + float? expectedValue, float precision, string because = "", + params object[] becauseArgs) + { + if (parent.Subject == null && expectedValue == null) + { + return new AndConstraint>(parent); + } + + bool succeeded = Execute.Assertion + .ForCondition(expectedValue != null) + .BecauseOf(because, becauseArgs) + .FailWith("Expected {context:value} to approximate {0} +/- {1}{reason}, but it was {2}.", expectedValue, precision, parent.Subject); + + if (succeeded) + { + // ReSharper disable once PossibleInvalidOperationException + parent.BeApproximately(expectedValue.Value, precision, because, becauseArgs); + } + + return new AndConstraint>(parent); + } + /// /// Asserts a floating point value approximates another value as close as possible. /// @@ -775,6 +816,47 @@ public static class NumericAssertionsExtensions return new AndConstraint>(parent); } + /// + /// Asserts a double value approximates another value as close as possible. + /// Does not throw if null subject value approximates null value. + /// + /// The object that is being extended. + /// + /// The expected value to compare the actual value with. + /// + /// + /// The maximum amount of which the two values may differ. + /// + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public static AndConstraint> BeApproximately(this NullableNumericAssertions parent, + double? expectedValue, double precision, string because = "", + params object[] becauseArgs) + { + if(parent.Subject == null && expectedValue == null) + { + return new AndConstraint>(parent); + } + + bool succeeded = Execute.Assertion + .ForCondition(expectedValue != null) + .BecauseOf(because, becauseArgs) + .FailWith("Expected {context:value} to approximate {0} +/- {1}{reason}, but it was {2}.", expectedValue, precision, parent.Subject); + + if (succeeded) + { + // ReSharper disable once PossibleInvalidOperationException + parent.BeApproximately(expectedValue.Value, precision, because, becauseArgs); + } + + return new AndConstraint>(parent); + } + /// /// Asserts a double value approximates another value as close as possible. /// @@ -839,6 +921,47 @@ public static class NumericAssertionsExtensions return new AndConstraint>(parent); } + /// + /// Asserts a decimal value approximates another value as close as possible. + /// Does not throw if null subject value approximates null value. + /// + /// The object that is being extended. + /// + /// The expected value to compare the actual value with. + /// + /// + /// The maximum amount of which the two values may differ. + /// + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public static AndConstraint> BeApproximately(this NullableNumericAssertions parent, + decimal? expectedValue, decimal precision, string because = "", + params object[] becauseArgs) + { + if (parent.Subject == null && expectedValue == null) + { + return new AndConstraint>(parent); + } + + bool succeeded = Execute.Assertion + .ForCondition(expectedValue != null) + .BecauseOf(because, becauseArgs) + .FailWith("Expected {context:value} to approximate {0} +/- {1}{reason}, but it was {2}.", expectedValue, precision, parent.Subject); + + if (succeeded) + { + // ReSharper disable once PossibleInvalidOperationException + parent.BeApproximately(expectedValue.Value, precision, because, becauseArgs); + } + + return new AndConstraint>(parent); + } + /// /// Asserts a decimal value approximates another value as close as possible. /// diff --git a/Tests/Shared.Specs/NullableNumericAssertionSpecs.cs b/Tests/Shared.Specs/NullableNumericAssertionSpecs.cs index 1eaf57e231..52d65d23fd 100644 --- a/Tests/Shared.Specs/NullableNumericAssertionSpecs.cs +++ b/Tests/Shared.Specs/NullableNumericAssertionSpecs.cs @@ -314,6 +314,108 @@ public void When_nullable_double_is_indeed_approximating_a_value_it_should_not_t 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() { @@ -374,6 +476,108 @@ public void When_nullable_float_is_indeed_approximating_a_value_it_should_not_th 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() { @@ -415,6 +619,108 @@ public void When_nullable_decimal_is_indeed_approximating_a_value_it_should_not_ 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() {