Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions TUnit.Assertions.Tests/Old/DoubleEqualsToAssertionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public async Task Double_EqualsTo__With_Tolerance_Success()
{
var double1 = 1.1d;
var double2 = 1.2d;

await TUnitAssert.That(double1).IsEqualTo(double2).Within(0.1);
}

Expand All @@ -53,8 +53,34 @@ public async Task Double_EqualsTo__With_Tolerance_Failure()
{
var double1 = 1.1d;
var double2 = 1.3d;

await TUnitAssert.ThrowsAsync<TUnitAssertionException>(async () => await TUnitAssert.That(double1).IsEqualTo(double2).Within(0.1));
}

[Test]
public async Task Double_NaN_EqualsTo_NaN_With_Tolerance_Success()
{
const double tolerance = 0.001;

await TUnitAssert.That(double.NaN).IsEqualTo(double.NaN).Within(tolerance);
}

[Test]
public async Task Double_NaN_EqualsTo_Number_With_Tolerance_Failure()
{
const double tolerance = 0.001;

await TUnitAssert.ThrowsAsync<TUnitAssertionException>(async () =>
await TUnitAssert.That(double.NaN).IsEqualTo(1.0).Within(tolerance));
}

[Test]
public async Task Double_Number_EqualsTo_NaN_With_Tolerance_Failure()
{
const double tolerance = 0.001;

await TUnitAssert.ThrowsAsync<TUnitAssertionException>(async () =>
await TUnitAssert.That(1.0).IsEqualTo(double.NaN).Within(tolerance));
}
#endif
}
86 changes: 86 additions & 0 deletions TUnit.Assertions.Tests/Old/FloatEqualsToAssertionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
namespace TUnit.Assertions.Tests.Old;

public class FloatEqualsToAssertionTests
{
[Test]
public async Task Float_EqualsTo_Success()
{
var float1 = 1.1f;
var float2 = 1.1f;

await TUnitAssert.That(float1).IsEqualTo(float2);
}

[Test]
public async Task Float_EqualsTo_Failure()
{
var float1 = 1.1f;
var float2 = 1.2f;

await TUnitAssert.ThrowsAsync<TUnitAssertionException>(async () => await TUnitAssert.That(float1).IsEqualTo(float2));
}

[Test]
public async Task Float_NaN_EqualsTo_NaN_Success()
{
await TUnitAssert.That(float.NaN).IsEqualTo(float.NaN);
}

[Test]
public async Task Float_PositiveInfinity_EqualsTo_PositiveInfinity_Success()
{
await TUnitAssert.That(float.PositiveInfinity).IsEqualTo(float.PositiveInfinity);
}

[Test]
public async Task Float_NegativeInfinity_EqualsTo_NegativeInfinity_Success()
{
await TUnitAssert.That(float.NegativeInfinity).IsEqualTo(float.NegativeInfinity);
}

#if NET
[Test]
public async Task Float_EqualsTo__With_Tolerance_Success()
{
var float1 = 1.1f;
var float2 = 1.2f;

await TUnitAssert.That(float1).IsEqualTo(float2).Within(0.2f);
}

[Test]
public async Task Float_EqualsTo__With_Tolerance_Failure()
{
var float1 = 1.1f;
var float2 = 1.3f;

await TUnitAssert.ThrowsAsync<TUnitAssertionException>(async () => await TUnitAssert.That(float1).IsEqualTo(float2).Within(0.1f));
}

[Test]
public async Task Float_NaN_EqualsTo_NaN_With_Tolerance_Success()
{
const float tolerance = 0.001f;

await TUnitAssert.That(float.NaN).IsEqualTo(float.NaN).Within(tolerance);
}

[Test]
public async Task Float_NaN_EqualsTo_Number_With_Tolerance_Failure()
{
const float tolerance = 0.001f;

await TUnitAssert.ThrowsAsync<TUnitAssertionException>(async () =>
await TUnitAssert.That(float.NaN).IsEqualTo(1.0f).Within(tolerance));
}

[Test]
public async Task Float_Number_EqualsTo_NaN_With_Tolerance_Failure()
{
const float tolerance = 0.001f;

await TUnitAssert.ThrowsAsync<TUnitAssertionException>(async () =>
await TUnitAssert.That(1.0f).IsEqualTo(float.NaN).Within(tolerance));
}
#endif
}
46 changes: 46 additions & 0 deletions TUnit.Assertions/Conditions/EqualsAssertion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class EqualsAssertion<TValue> : Assertion<TValue>
#endif
[typeof(int)] = new ToleranceComparer<int>(CompareInt),
[typeof(long)] = new ToleranceComparer<long>(CompareLong),
[typeof(float)] = new ToleranceComparer<float>(CompareFloat),
[typeof(double)] = new ToleranceComparer<double>(CompareDouble),
[typeof(decimal)] = new ToleranceComparer<decimal>(CompareDecimal)
};
Expand Down Expand Up @@ -156,6 +157,38 @@ private static bool CompareLong(long actual, long expected, object tolerance, ou
return false;
}

private static bool CompareFloat(float actual, float expected, object tolerance, out string? errorMessage)
{
if (tolerance is not float floatTolerance)
{
errorMessage = null;
return false;
}

// Handle NaN comparisons: NaN is only equal to NaN
if (float.IsNaN(actual) && float.IsNaN(expected))
{
errorMessage = null;
return true;
}

if (float.IsNaN(actual) || float.IsNaN(expected))
{
errorMessage = $"found {actual}";
return false;
}

var difference = actual > expected ? actual - expected : expected - actual;
if (difference <= floatTolerance)
{
errorMessage = null;
return true;
}

errorMessage = $"found {actual}, difference {difference} exceeds tolerance {floatTolerance}";
return false;
}

private static bool CompareDouble(double actual, double expected, object tolerance, out string? errorMessage)
{
if (tolerance is not double doubleTolerance)
Expand All @@ -164,6 +197,19 @@ private static bool CompareDouble(double actual, double expected, object toleran
return false;
}

// Handle NaN comparisons: NaN is only equal to NaN
if (double.IsNaN(actual) && double.IsNaN(expected))
{
errorMessage = null;
return true;
}

if (double.IsNaN(actual) || double.IsNaN(expected))
{
errorMessage = $"found {actual}";
return false;
}

var difference = actual > expected ? actual - expected : expected - actual;
if (difference <= doubleTolerance)
{
Expand Down
80 changes: 80 additions & 0 deletions TUnit.Assertions/Conditions/SpecializedEqualityAssertions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,17 @@ protected override Task<AssertionResult> CheckAsync(EvaluationMetadata<double> m

if (_tolerance.HasValue)
{
// Handle NaN comparisons: NaN is only equal to NaN
if (double.IsNaN(value) && double.IsNaN(_expected))
{
return Task.FromResult(AssertionResult.Passed);
}

if (double.IsNaN(value) || double.IsNaN(_expected))
{
return Task.FromResult(AssertionResult.Failed($"found {value}"));
}

var diff = Math.Abs(value - _expected);
if (diff <= _tolerance.Value)
{
Expand All @@ -181,6 +192,75 @@ protected override string GetExpectation() =>
: $"to be {_expected}";
}

/// <summary>
/// Asserts that a float value is equal to another, with optional tolerance.
/// </summary>
public class FloatEqualsAssertion : Assertion<float>
{
private readonly float _expected;
private float? _tolerance;

public FloatEqualsAssertion(
AssertionContext<float> context,
float expected)
: base(context)
{
_expected = expected;
}

public FloatEqualsAssertion Within(float tolerance)
{
_tolerance = tolerance;
Context.ExpressionBuilder.Append($".Within({tolerance})");
return this;
}

protected override Task<AssertionResult> CheckAsync(EvaluationMetadata<float> metadata)
{
var value = metadata.Value;
var exception = metadata.Exception;

if (exception != null)
{
return Task.FromResult(AssertionResult.Failed($"threw {exception.GetType().Name}"));
}

if (_tolerance.HasValue)
{
// Handle NaN comparisons: NaN is only equal to NaN
if (float.IsNaN(value) && float.IsNaN(_expected))
{
return Task.FromResult(AssertionResult.Passed);
}

if (float.IsNaN(value) || float.IsNaN(_expected))
{
return Task.FromResult(AssertionResult.Failed($"found {value}"));
}

var diff = Math.Abs(value - _expected);
if (diff <= _tolerance.Value)
{
return Task.FromResult(AssertionResult.Passed);
}

return Task.FromResult(AssertionResult.Failed($"found {value}, which differs by {diff}"));
}

if (float.Equals(value, _expected))
{
return Task.FromResult(AssertionResult.Passed);
}

return Task.FromResult(AssertionResult.Failed($"found {value}"));
}

protected override string GetExpectation() =>
_tolerance.HasValue
? $"to be within {_tolerance} of {_expected}"
: $"to be {_expected}";
}

/// <summary>
/// Asserts that a long value is equal to another, with optional tolerance.
/// </summary>
Expand Down
15 changes: 15 additions & 0 deletions TUnit.Assertions/Extensions/AssertionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,21 @@ public static DoubleEqualsAssertion IsEqualTo(
return new DoubleEqualsAssertion(source.Context, expected);
}

/// <summary>
/// Asserts that the float is equal to the expected value.
/// Returns FloatEqualsAssertion which has .Within() method!
/// Priority 2: Highest priority for specialized type.
/// </summary>
[OverloadResolutionPriority(2)]
public static FloatEqualsAssertion IsEqualTo(
this IAssertionSource<float> source,
float expected,
[CallerArgumentExpression(nameof(expected))] string? expression = null)
{
source.Context.ExpressionBuilder.Append($".IsEqualTo({expression})");
return new FloatEqualsAssertion(source.Context, expected);
}

/// <summary>
/// Asserts that the long is equal to the expected value.
/// Returns LongEqualsAssertion which has .Within() method!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,13 @@ namespace .Conditions
protected override .<.> CheckAsync(.<.FileInfo> metadata) { }
protected override string GetExpectation() { }
}
public class FloatEqualsAssertion : .<float>
{
public FloatEqualsAssertion(.<float> context, float expected) { }
protected override .<.> CheckAsync(.<float> metadata) { }
protected override string GetExpectation() { }
public . Within(float tolerance) { }
}
[.("IsGreaterThan")]
public class GreaterThanAssertion<TValue> : .<TValue>
where TValue : <TValue>
Expand Down Expand Up @@ -1702,6 +1709,8 @@ namespace .Extensions
[.(2)]
public static . IsEqualTo(this .<double> source, double expected, [.("expected")] string? expression = null) { }
[.(2)]
public static . IsEqualTo(this .<float> source, float expected, [.("expected")] string? expression = null) { }
[.(2)]
public static .<int> IsEqualTo(this .<int> source, int expected, [.("expected")] string? expression = null) { }
[.(2)]
public static . IsEqualTo(this .<long> source, long expected, [.("expected")] string? expression = null) { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,13 @@ namespace .Conditions
protected override .<.> CheckAsync(.<.FileInfo> metadata) { }
protected override string GetExpectation() { }
}
public class FloatEqualsAssertion : .<float>
{
public FloatEqualsAssertion(.<float> context, float expected) { }
protected override .<.> CheckAsync(.<float> metadata) { }
protected override string GetExpectation() { }
public . Within(float tolerance) { }
}
[.("IsGreaterThan")]
public class GreaterThanAssertion<TValue> : .<TValue>
where TValue : <TValue>
Expand Down Expand Up @@ -1695,6 +1702,7 @@ namespace .Extensions
public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { }
public static .<> IsEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { }
public static . IsEqualTo(this .<double> source, double expected, [.("expected")] string? expression = null) { }
public static . IsEqualTo(this .<float> source, float expected, [.("expected")] string? expression = null) { }
public static .<int> IsEqualTo(this .<int> source, int expected, [.("expected")] string? expression = null) { }
public static . IsEqualTo(this .<long> source, long expected, [.("expected")] string? expression = null) { }
public static . IsEqualTo(this .<string> source, string? expected, [.("expected")] string? expression = null) { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,13 @@ namespace .Conditions
protected override .<.> CheckAsync(.<.FileInfo> metadata) { }
protected override string GetExpectation() { }
}
public class FloatEqualsAssertion : .<float>
{
public FloatEqualsAssertion(.<float> context, float expected) { }
protected override .<.> CheckAsync(.<float> metadata) { }
protected override string GetExpectation() { }
public . Within(float tolerance) { }
}
[.("IsGreaterThan")]
public class GreaterThanAssertion<TValue> : .<TValue>
where TValue : <TValue>
Expand Down Expand Up @@ -1702,6 +1709,8 @@ namespace .Extensions
[.(2)]
public static . IsEqualTo(this .<double> source, double expected, [.("expected")] string? expression = null) { }
[.(2)]
public static . IsEqualTo(this .<float> source, float expected, [.("expected")] string? expression = null) { }
[.(2)]
public static .<int> IsEqualTo(this .<int> source, int expected, [.("expected")] string? expression = null) { }
[.(2)]
public static . IsEqualTo(this .<long> source, long expected, [.("expected")] string? expression = null) { }
Expand Down
Loading
Loading