-
Notifications
You must be signed in to change notification settings - Fork 731
Description
Background and motivation
The IComparable<T> interface offers a single method CompareTo(...) that accepts a nullable T (T?).
When we want to write a test for the case, where we check, if an object of class X is greater than null, then we need to use the null-forgiving operator (!) to avoid warnings. The class X can be implemented as following:
public class X : IComparable<X>
{
public override int CompareTo(X? other)
{
if (ReferenceEquals(this, other))
{
return 0;
}
if (other is null)
{
return 1;
}
return this.value.CompareTo(other.value);
}
public int CompareTo(object? obj)
{
if (obj is null)
{
return 1;
}
if (ReferenceEquals(this, obj))
{
return 0;
}
return obj is X other
? this.CompareTo(other)
: throw new ArgumentException($"Object must be of type {nameof(X)}");
}
}An associated test using the current version of FluentAssertions must be implemented as following, to avoid warnings by the compiler:
public class XTest
{
public void Is_greater_than_null()
{
// Arrange
var x = new X(1);
// Assert
x.Should().BeGreaterThan(null!); // The ! (null-forgiving) operator avoids the warning
}
}Since the CompareTo(...) method of IComparable<T> accepts a nullable T, with T the type to compare, it would be a better fit to support nullable values in the following methods:
- BeGreaterThan(...) / BeGreaterThanOrEqualTo(...)
- BeLessThan(...) / BeLessThanOrEqualTo(...)
- BeRankedEquallyTo(...) / NotBeRankedEquallyTo(...)
- BeInRange(...) / NotBeInRange(...)
This change enables to write assertions without using the null-forgiving operator (!) and doesn't change the functionality of existing assertions based on IComparable<T>. So the code within the unit test is more 'cleaner'.
API Proposal
public class ComparableTypeAssertions<T, TAssertions> : ReferenceTypeAssertions<IComparable<T>, TAssertions>
where TAssertions : ComparableTypeAssertions<T, TAssertions>
{
- public AndConstraint<TAssertions> BeRankedEquallyTo(T expected, string because = "", params object[] becauseArgs);
+ public AndConstraint<TAssertions> BeRankedEquallyTo(T? expected, string because = "", params object[] becauseArgs);
- public AndConstraint<TAssertions> NotBeRankedEquallyTo(T expected, string because = "", params object[] becauseArgs);
+ public AndConstraint<TAssertions> NotBeRankedEquallyTo(T? expected, string because = "", params object[] becauseArgs);
- public AndConstraint<TAssertions> BeLessThan(T expected, string because = "", params object[] becauseArgs);
+ public AndConstraint<TAssertions> BeLessThan(T? expected, string because = "", params object[] becauseArgs);
- public AndConstraint<TAssertions> BeLessThanOrEqualTo(T expected, string because = "", params object[] becauseArgs);
+ public AndConstraint<TAssertions> BeLessThanOrEqualTo(T? expected, string because = "", params object[] becauseArgs);
- public AndConstraint<TAssertions> BeGreaterThan(T expected, string because = "", params object[] becauseArgs);
+ public AndConstraint<TAssertions> BeGreaterThan(T? expected, string because = "", params object[] becauseArgs);
- public AndConstraint<TAssertions> BeGreaterThanOrEqualTo(T expected, string because = "", params object[] becauseArgs);
+ public AndConstraint<TAssertions> BeGreaterThanOrEqualTo(T? expected, string because = "", params object[] becauseArgs);
- public AndConstraint<TAssertions> BeInRange(T minimumValue, T maximumValue, string because = "", params object[] becauseArgs);
+ public AndConstraint<TAssertions> BeInRange(T? minimumValue, T? maximumValue, string because = "", params object[] becauseArgs);
- public AndConstraint<TAssertions> NotBeInRange(T minimumValue, T maximumValue, string because = "", params object[] becauseArgs);
+ public AndConstraint<TAssertions> NotBeInRange(T? minimumValue, T? maximumValue, string because = "", params object[] becauseArgs);
}API Usage
var one = 1;
one.Should().BeGreaterThan(null);
one.Should().NotBeLessThan(null);
one.Should().BeGreaterThanOrEqualTo(null);
one.Should().NotBeLessThanOrEqualTo(null);
one.Should().NotBeRankedEquallyTo(null);
one.Should().NotBeInRange(null, null);Alternative Designs
No response
Risks
None. Should work with legacy code, where nullable reference types are not enabled explicit.
Are you willing to help with a proof-of-concept (as PR in that or a separate repo) first and as pull-request later on?
Yes, please assign this issue to me.