diff --git a/TUnit.Assertions.SourceGenerator/Generators/AssertionExtensionGenerator.cs b/TUnit.Assertions.SourceGenerator/Generators/AssertionExtensionGenerator.cs index 6d0f6001b3..ffd047654a 100644 --- a/TUnit.Assertions.SourceGenerator/Generators/AssertionExtensionGenerator.cs +++ b/TUnit.Assertions.SourceGenerator/Generators/AssertionExtensionGenerator.cs @@ -59,14 +59,19 @@ public void Initialize(IncrementalGeneratorInitializationContext context) return null; } - // Extract optional negated method name + // Extract optional negated method name and overload resolution priority string? negatedMethodName = null; + int overloadPriority = 0; // Default to 0 foreach (var namedArg in attributeData.NamedArguments) { if (namedArg.Key == "NegatedMethodName") { negatedMethodName = namedArg.Value.Value?.ToString(); } + else if (namedArg.Key == "OverloadResolutionPriority" && namedArg.Value.Value is int priority) + { + overloadPriority = priority; + } } // Find the base Assertion type to extract the type parameter @@ -92,7 +97,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context) methodName!, negatedMethodName, assertionBaseType, - constructors + constructors, + overloadPriority ); } @@ -288,6 +294,12 @@ private static void GenerateExtensionMethod( sourceBuilder.AppendLine($" /// Extension method for {assertionType.Name}."); sourceBuilder.AppendLine(" /// "); + // Add OverloadResolutionPriority attribute only if priority > 0 + if (data.OverloadResolutionPriority > 0) + { + sourceBuilder.AppendLine($" [global::System.Runtime.CompilerServices.OverloadResolutionPriority({data.OverloadResolutionPriority})]"); + } + // Method declaration var returnType = assertionType.IsGenericType ? $"{assertionType.Name}{genericParamsString}" @@ -393,6 +405,7 @@ private record AssertionExtensionData( string MethodName, string? NegatedMethodName, INamedTypeSymbol AssertionBaseType, - ImmutableArray Constructors + ImmutableArray Constructors, + int OverloadResolutionPriority ); } diff --git a/TUnit.Assertions.Tests/AssertMultipleTests.cs b/TUnit.Assertions.Tests/AssertMultipleTests.cs index 6bfc1f0643..822c4209b4 100644 --- a/TUnit.Assertions.Tests/AssertMultipleTests.cs +++ b/TUnit.Assertions.Tests/AssertMultipleTests.cs @@ -21,7 +21,7 @@ await Assert.That(async () => await Assert.That(3).IsEqualTo(6); } - }).Throws().And.HasMessageContaining("Expected to be equal to 2"); + }).Throws().And.HasMessageContaining("Expected to be 2"); } [Test] @@ -51,7 +51,7 @@ public async Task Caught_Exception_In_Scope_Is_Not_Captured() }).Throws(); await Assert.That(exception!.Message) - .Contains("Expected to be equal to 2"); + .Contains("Expected to be 2"); } [Test] diff --git a/TUnit.Assertions.Tests/EquatableTests.cs b/TUnit.Assertions.Tests/EquatableTests.cs index fc47129ad3..33b896e9e5 100644 --- a/TUnit.Assertions.Tests/EquatableTests.cs +++ b/TUnit.Assertions.Tests/EquatableTests.cs @@ -76,7 +76,7 @@ public async Task Wrapper_IsEqualTo_Long_Success() Wrapper wrapper = new() { Value = 42 }; // Act & Assert - await Assert.That(wrapper).IsEqualTo(42L); + await Assert.That(wrapper).IsEquatableTo(42L); } [Test] @@ -88,7 +88,7 @@ public async Task Wrapper_IsEqualTo_Long_Failure() // Act & Assert await Assert.ThrowsAsync(async () => { - await Assert.That(wrapper).IsEqualTo(99L); + await Assert.That(wrapper).IsEquatableTo(99L); }); } @@ -110,7 +110,7 @@ public async Task NullableWrapper_IsEqualTo_Long_Success() Wrapper? wrapper = new Wrapper { Value = 42 }; // Act & Assert - await Assert.That(wrapper).IsEqualTo(42L); + await Assert.That(wrapper).IsEquatableTo(42L); } [Test] @@ -122,7 +122,7 @@ public async Task NullableWrapper_IsEqualTo_Long_NullFailure() // Act & Assert await Assert.ThrowsAsync(async () => { - await Assert.That(wrapper).IsEqualTo(42L); + await Assert.That(wrapper).IsEquatableTo(42L); }); } @@ -133,7 +133,7 @@ public async Task MultiEquatable_IsEqualTo_Int_Success() MultiEquatable value = new() { IntValue = 100, StringValue = "test" }; // Act & Assert - await Assert.That(value).IsEqualTo(100); + await Assert.That(value).IsEquatableTo(100); } [Test] @@ -143,7 +143,7 @@ public async Task MultiEquatable_IsEqualTo_String_Success() MultiEquatable value = new() { IntValue = 100, StringValue = "test" }; // Act & Assert - await Assert.That(value).IsEqualTo("test"); + await Assert.That(value).IsEquatableTo("test"); } [Test] @@ -153,7 +153,7 @@ public async Task IntWrapper_IsEqualTo_Int_Success() IntWrapper wrapper = new() { Value = 123 }; // Act & Assert - await Assert.That(wrapper).IsEqualTo(123); + await Assert.That(wrapper).IsEquatableTo(123); } [Test] @@ -165,7 +165,7 @@ public async Task IntWrapper_IsEqualTo_Int_Failure() // Act & Assert await Assert.ThrowsAsync(async () => { - await Assert.That(wrapper).IsEqualTo(456); + await Assert.That(wrapper).IsEquatableTo(456); }); } @@ -176,7 +176,7 @@ public async Task EquatableAssertion_WithAnd_Success() Wrapper wrapper = new() { Value = 42 }; // Act & Assert - await Assert.That(wrapper).IsEqualTo(42L).And.IsEqualTo(new Wrapper { Value = 42 }); + await Assert.That(wrapper).IsEquatableTo(42L).And.IsEqualTo(new Wrapper { Value = 42 }); } [Test] @@ -186,7 +186,7 @@ public async Task EquatableAssertion_WithOr_Success() Wrapper wrapper = new() { Value = 42 }; // Act & Assert - should pass because first condition is true - await Assert.That(wrapper).IsEqualTo(42L).Or.IsEqualTo(new Wrapper { Value = 99 }); + await Assert.That(wrapper).IsEquatableTo(42L).Or.IsEqualTo(new Wrapper { Value = 99 }); } [Test] @@ -198,7 +198,7 @@ public async Task EquatableAssertion_WithAnd_Failure() // Act & Assert await Assert.ThrowsAsync(async () => { - await Assert.That(wrapper).IsEqualTo(42L).And.IsEqualTo(new Wrapper { Value = 99 }); + await Assert.That(wrapper).IsEquatableTo(42L).And.IsEqualTo(new Wrapper { Value = 99 }); }); } @@ -209,7 +209,7 @@ public async Task EquatableAssertion_ChainedWithAndContinuation() Wrapper wrapper = new() { Value = 42 }; // Act & Assert - test that And continuation works - await Assert.That(wrapper).IsEqualTo(42L).And.IsEqualTo(42L); + await Assert.That(wrapper).IsEquatableTo(42L).And.IsEquatableTo(42L); } [Test] @@ -219,7 +219,7 @@ public async Task EquatableAssertion_ChainedWithOrContinuation() Wrapper wrapper = new() { Value = 42 }; // Act & Assert - test that Or continuation works - await Assert.That(wrapper).IsEqualTo(99L).Or.IsEqualTo(42L); + await Assert.That(wrapper).IsEquatableTo(99L).Or.IsEquatableTo(42L); } [Test] @@ -229,7 +229,7 @@ public async Task NullableIntWrapper_IsEqualTo_Int_Success() IntWrapper? wrapper = new IntWrapper { Value = 789 }; // Act & Assert - await Assert.That(wrapper).IsEqualTo(789); + await Assert.That(wrapper).IsEquatableTo(789); } [Test] @@ -241,7 +241,7 @@ public async Task NullableIntWrapper_IsEqualTo_Int_NullFailure() // Act & Assert await Assert.ThrowsAsync(async () => { - await Assert.That(wrapper).IsEqualTo(789); + await Assert.That(wrapper).IsEquatableTo(789); }); } @@ -262,7 +262,7 @@ public async Task GitHubIssue2972_Example() { // This is the exact example from the GitHub issue Wrapper value = new() { Value = 1 }; - await Assert.That(value).IsEqualTo(1L); + await Assert.That(value).IsEquatableTo(1L); } } #endif diff --git a/TUnit.Assertions.Tests/Old/AssertMultipleTests.cs b/TUnit.Assertions.Tests/Old/AssertMultipleTests.cs index ceb0eef84c..e1fcd0b335 100644 --- a/TUnit.Assertions.Tests/Old/AssertMultipleTests.cs +++ b/TUnit.Assertions.Tests/Old/AssertMultipleTests.cs @@ -29,35 +29,35 @@ public async Task MultipleFailures() var exception5 = (TUnitAssertionException) aggregateException.InnerExceptions[4]; await TUnitAssert.That(exception1.Message).IsEqualTo(""" - Expected to be equal to 2 + Expected to be 2 but found 1 at Assert.That(1).IsEqualTo(2) """); await TUnitAssert.That(exception2.Message).IsEqualTo(""" - Expected to be equal to 3 + Expected to be 3 but found 2 at Assert.That(2).IsEqualTo(3) """); await TUnitAssert.That(exception3.Message).IsEqualTo(""" - Expected to be equal to 4 + Expected to be 4 but found 3 at Assert.That(3).IsEqualTo(4) """); await TUnitAssert.That(exception4.Message).IsEqualTo(""" - Expected to be equal to 5 + Expected to be 5 but found 4 at Assert.That(4).IsEqualTo(5) """); await TUnitAssert.That(exception5.Message).IsEqualTo(""" - Expected to be equal to 6 + Expected to be 6 but found 5 at Assert.That(5).IsEqualTo(6) @@ -88,40 +88,40 @@ public async Task MultipleFailures_With_Connectors() var exception5 = (TUnitAssertionException) aggregateException.InnerExceptions[4]; await TUnitAssert.That(exception1.Message).IsEqualTo(""" - Expected to be equal to 2 - or to be equal to 3 + Expected to be 2 + or to be 3 but found 1 at Assert.That(1).IsEqualTo(2).Or.IsEqualTo(3) """); await TUnitAssert.That(exception2.Message).IsEqualTo(""" - Expected to be equal to 3 - and to be equal to 4 + Expected to be 3 + and to be 4 but found 2 at Assert.That(2).IsEqualTo(3).And.IsEqualTo(4) """); await TUnitAssert.That(exception3.Message).IsEqualTo(""" - Expected to be equal to 4 - or to be equal to 5 + Expected to be 4 + or to be 5 but found 3 at Assert.That(3).IsEqualTo(4).Or.IsEqualTo(5) """); await TUnitAssert.That(exception4.Message).IsEqualTo(""" - Expected to be equal to 5 - and to be equal to 6 + Expected to be 5 + and to be 6 but found 4 at Assert.That(4).IsEqualTo(5).And.IsEqualTo(6) """); await TUnitAssert.That(exception5.Message).IsEqualTo(""" - Expected to be equal to 6 - or to be equal to 7 + Expected to be 6 + or to be 7 but found 5 at Assert.That(5).IsEqualTo(6).Or.IsEqualTo(7) @@ -172,49 +172,49 @@ public async Task Nested_Multiples() var assertionException7 = (TUnitAssertionException) aggregateException.InnerExceptions[6]; await TUnitAssert.That(assertionException1.Message).IsEqualTo(""" - Expected to be equal to 2 + Expected to be 2 but found 1 at Assert.That(1).IsEqualTo(2) """); await TUnitAssert.That(assertionException2.Message).IsEqualTo(""" - Expected to be equal to 3 + Expected to be 3 but found 2 at Assert.That(2).IsEqualTo(3) """); await TUnitAssert.That(assertionException3.Message).IsEqualTo(""" - Expected to be equal to 4 + Expected to be 4 but found 3 at Assert.That(3).IsEqualTo(4) """); await TUnitAssert.That(assertionException4.Message).IsEqualTo(""" - Expected to be equal to 5 + Expected to be 5 but found 4 at Assert.That(4).IsEqualTo(5) """); await TUnitAssert.That(assertionException5.Message).IsEqualTo(""" - Expected to be equal to 6 + Expected to be 6 but found 5 at Assert.That(5).IsEqualTo(6) """); await TUnitAssert.That(assertionException6.Message).IsEqualTo(""" - Expected to be equal to 7 + Expected to be 7 but found 6 at Assert.That(6).IsEqualTo(7) """); await TUnitAssert.That(assertionException7.Message).IsEqualTo(""" - Expected to be equal to 8 + Expected to be 8 but found 7 at Assert.That(7).IsEqualTo(8) diff --git a/TUnit.Assertions.Tests/Old/EqualityComparerTests.cs b/TUnit.Assertions.Tests/Old/EqualityComparerTests.cs index 5aa81f04b5..6f9c7e6c74 100644 --- a/TUnit.Assertions.Tests/Old/EqualityComparerTests.cs +++ b/TUnit.Assertions.Tests/Old/EqualityComparerTests.cs @@ -19,8 +19,8 @@ public async Task ComparerTestFailureAsync() { const double a = 10; const double b = 0; - // Old API used to accept IEqualityComparer, new API requires using the comparer directly - await TUnitAssert.That(new Comparer().Equals(a, b)).IsTrue(); + // With IEqualityComparer support restored, we can use it directly + await TUnitAssert.That(a).IsEqualTo(b, new Comparer()); } [Test] @@ -28,6 +28,6 @@ public async Task ComparerTestSuccessAsync() { const double a = 10; const double b = 0; - await TUnitAssert.That(new Comparer().Equals(a, b)).IsTrue(); + await TUnitAssert.That(a).IsEqualTo(b, new Comparer()); } } diff --git a/TUnit.Assertions.Tests/Old/MemberTests.cs b/TUnit.Assertions.Tests/Old/MemberTests.cs index c20251b751..534067b626 100644 --- a/TUnit.Assertions.Tests/Old/MemberTests.cs +++ b/TUnit.Assertions.Tests/Old/MemberTests.cs @@ -29,7 +29,7 @@ public async Task Number_Falsey() var exception = await TUnitAssert.ThrowsAsync(async () => await TUnitAssert.That(myClass).Member(x => x.Number, num => num.IsEqualTo(1))); - await TUnitAssert.That(exception.Message).Contains("to be equal to 1"); + await TUnitAssert.That(exception.Message).Contains("to be 1"); await TUnitAssert.That(exception.Message).Contains("but found 123"); } @@ -46,7 +46,7 @@ public async Task Number_Nested_Falsey() var exception = await TUnitAssert.ThrowsAsync(async () => await TUnitAssert.That(myClass).Member(x => x.Nested.Nested.Nested.Number, num => num.IsEqualTo(1))); - await TUnitAssert.That(exception.Message).Contains("to be equal to 1"); + await TUnitAssert.That(exception.Message).Contains("to be 1"); await TUnitAssert.That(exception.Message).Contains("but found 123"); } @@ -110,7 +110,7 @@ await TUnitAssert.That(myClass) .Member(x => x.Number, num => num.IsEqualTo(999)) .And.Member(x => x.Text, text => text.IsEqualTo("Blah"))); - await TUnitAssert.That(exception.Message).Contains("to be equal to 999"); + await TUnitAssert.That(exception.Message).Contains("to be 999"); } [Test] diff --git a/TUnit.Assertions/Attributes/AssertionExtensionAttribute.cs b/TUnit.Assertions/Attributes/AssertionExtensionAttribute.cs index e6cc850b22..6ab4983cdb 100644 --- a/TUnit.Assertions/Attributes/AssertionExtensionAttribute.cs +++ b/TUnit.Assertions/Attributes/AssertionExtensionAttribute.cs @@ -51,4 +51,15 @@ public AssertionExtensionAttribute(string methodName) /// [AssertionExtension("Contains", NegatedMethodName = "DoesNotContain")] /// public string? NegatedMethodName { get; set; } + + /// + /// Optional: The overload resolution priority for the generated extension methods. + /// Higher values are preferred over lower values during overload resolution. + /// Default is 0. When 0, no OverloadResolutionPriority attribute is generated. + /// Use higher values (e.g., 2) for specialized overloads that should take precedence. + /// + /// + /// [AssertionExtension("IsEqualTo", OverloadResolutionPriority = 2)] + /// + public int OverloadResolutionPriority { get; set; } = 0; } diff --git a/TUnit.Assertions/Conditions/DateTimeEqualsAssertion.cs b/TUnit.Assertions/Conditions/DateTimeEqualsAssertion.cs index c4a0e2d4fb..39cb1cf8b7 100644 --- a/TUnit.Assertions/Conditions/DateTimeEqualsAssertion.cs +++ b/TUnit.Assertions/Conditions/DateTimeEqualsAssertion.cs @@ -1,4 +1,5 @@ using System.Text; +using TUnit.Assertions.Attributes; using TUnit.Assertions.Core; namespace TUnit.Assertions.Conditions; @@ -7,6 +8,7 @@ namespace TUnit.Assertions.Conditions; /// Asserts that a DateTime is equal to an expected value. /// Demonstrates custom methods WITHOUT wrappers: .Within() is directly on this class! /// +[AssertionExtension("IsEqualTo", OverloadResolutionPriority = 2)] public class DateTimeEqualsAssertion : Assertion { private readonly DateTime _expected; diff --git a/TUnit.Assertions/Conditions/EqualsAssertion.cs b/TUnit.Assertions/Conditions/EqualsAssertion.cs index 4fd54bb749..8c845236d2 100644 --- a/TUnit.Assertions/Conditions/EqualsAssertion.cs +++ b/TUnit.Assertions/Conditions/EqualsAssertion.cs @@ -2,6 +2,7 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Text; +using TUnit.Assertions.Attributes; using TUnit.Assertions.Core; namespace TUnit.Assertions.Conditions; @@ -10,271 +11,41 @@ namespace TUnit.Assertions.Conditions; /// Asserts that a value is equal to an expected value. /// Generic implementation that works for all types. /// +[AssertionExtension("IsEqualTo")] public class EqualsAssertion : Assertion { private readonly TValue? _expected; private readonly IEqualityComparer? _comparer; - private object? _tolerance; private readonly HashSet _ignoredTypes = new(); - // Delegate for tolerance comparison strategies - private delegate bool ToleranceComparer(T actual, T expected, object tolerance, out string? errorMessage); - - // Static dictionary mapping types to their tolerance comparison strategies - private static readonly Dictionary ToleranceComparers = new() - { - [typeof(TimeSpan)] = new ToleranceComparer(CompareTimeSpan), - [typeof(DateTime)] = new ToleranceComparer(CompareDateTime), - [typeof(DateTimeOffset)] = new ToleranceComparer(CompareDateTimeOffset), -#if NET6_0_OR_GREATER - [typeof(TimeOnly)] = new ToleranceComparer(CompareTimeOnly), -#endif - [typeof(int)] = new ToleranceComparer(CompareInt), - [typeof(long)] = new ToleranceComparer(CompareLong), - [typeof(float)] = new ToleranceComparer(CompareFloat), - [typeof(double)] = new ToleranceComparer(CompareDouble), - [typeof(decimal)] = new ToleranceComparer(CompareDecimal) - }; - // Cache reflection results for better performance in deep comparison private static readonly ConcurrentDictionary PropertyCache = new(); private static readonly ConcurrentDictionary FieldCache = new(); - // Tolerance comparison strategies - private static bool CompareTimeSpan(TimeSpan actual, TimeSpan expected, object tolerance, out string? errorMessage) - { - if (tolerance is not TimeSpan timeSpanTolerance) - { - errorMessage = null; - return false; - } - - var difference = actual > expected ? actual - expected : expected - actual; - if (difference <= timeSpanTolerance) - { - errorMessage = null; - return true; - } - - errorMessage = $"found {actual}, difference {difference} exceeds tolerance {timeSpanTolerance}"; - return false; - } - - private static bool CompareDateTime(DateTime actual, DateTime expected, object tolerance, out string? errorMessage) - { - if (tolerance is not TimeSpan dateTimeTolerance) - { - errorMessage = null; - return false; - } - - var difference = actual > expected ? actual - expected : expected - actual; - if (difference <= dateTimeTolerance) - { - errorMessage = null; - return true; - } - - errorMessage = $"found {actual}, difference {difference} exceeds tolerance {dateTimeTolerance}"; - return false; - } - - private static bool CompareDateTimeOffset(DateTimeOffset actual, DateTimeOffset expected, object tolerance, out string? errorMessage) - { - if (tolerance is not TimeSpan dateTimeOffsetTolerance) - { - errorMessage = null; - return false; - } - - var difference = actual > expected ? actual - expected : expected - actual; - if (difference <= dateTimeOffsetTolerance) - { - errorMessage = null; - return true; - } - - errorMessage = $"found {actual}, difference {difference} exceeds tolerance {dateTimeOffsetTolerance}"; - return false; - } - -#if NET6_0_OR_GREATER - private static bool CompareTimeOnly(TimeOnly actual, TimeOnly expected, object tolerance, out string? errorMessage) - { - if (tolerance is not TimeSpan timeOnlyTolerance) - { - errorMessage = null; - return false; - } - - var difference = actual > expected ? actual.ToTimeSpan() - expected.ToTimeSpan() : expected.ToTimeSpan() - actual.ToTimeSpan(); - if (difference <= timeOnlyTolerance) - { - errorMessage = null; - return true; - } - - errorMessage = $"found {actual}, difference {difference} exceeds tolerance {timeOnlyTolerance}"; - return false; - } -#endif - - private static bool CompareInt(int actual, int expected, object tolerance, out string? errorMessage) - { - if (tolerance is not int intTolerance) - { - errorMessage = null; - return false; - } - - var difference = actual > expected ? actual - expected : expected - actual; - if (difference <= intTolerance) - { - errorMessage = null; - return true; - } - - errorMessage = $"found {actual}, difference {difference} exceeds tolerance {intTolerance}"; - return false; - } - - private static bool CompareLong(long actual, long expected, object tolerance, out string? errorMessage) - { - if (tolerance is not long longTolerance) - { - errorMessage = null; - return false; - } - - var difference = actual > expected ? actual - expected : expected - actual; - if (difference <= longTolerance) - { - errorMessage = null; - return true; - } - - errorMessage = $"found {actual}, difference {difference} exceeds tolerance {longTolerance}"; - 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) - { - errorMessage = null; - 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) - { - errorMessage = null; - return true; - } - - errorMessage = $"found {actual}, difference {difference} exceeds tolerance {doubleTolerance}"; - return false; - } - - private static bool CompareDecimal(decimal actual, decimal expected, object tolerance, out string? errorMessage) - { - if (tolerance is not decimal decimalTolerance) - { - errorMessage = null; - return false; - } - - var difference = actual > expected ? actual - expected : expected - actual; - if (difference <= decimalTolerance) - { - errorMessage = null; - return true; - } - - errorMessage = $"found {actual}, difference {difference} exceeds tolerance {decimalTolerance}"; - return false; - } - /// /// Gets the expected value for this equality assertion. - /// Used by extension methods like Within() to create derived assertions. /// public TValue? Expected => _expected; + // Constructor 1: Just expected value public EqualsAssertion( AssertionContext context, - TValue? expected, - IEqualityComparer? comparer = null) + TValue? expected) : base(context) { _expected = expected; - _comparer = comparer; + _comparer = null; } - /// - /// Specifies a tolerance for numeric/temporal comparisons. - /// Supports TimeSpan (for DateTime/DateTimeOffset/TimeOnly), and numeric types (int, long, double, decimal). - /// - public EqualsAssertion Within(object tolerance) - { - _tolerance = tolerance; - Context.ExpressionBuilder.Append($".Within({tolerance})"); - return this; - } - - /// - /// Sets a tolerance for numeric/temporal comparisons. - /// Internal method used by Within(). Most users should call Within() instead. - /// - internal EqualsAssertion WithTolerance(object tolerance) + // Constructor 2: Expected value with comparer + public EqualsAssertion( + AssertionContext context, + TValue? expected, + IEqualityComparer comparer) + : base(context) { - _tolerance = tolerance; - return this; + _expected = expected; + _comparer = comparer; } /// @@ -299,7 +70,6 @@ public EqualsAssertion IgnoringType(Type type) return this; } - [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Tolerance comparison requires dynamic invocation of known comparer delegates")] protected override Task CheckAsync(EvaluationMetadata metadata) { var value = metadata.Value; @@ -310,25 +80,6 @@ protected override Task CheckAsync(EvaluationMetadata m return Task.FromResult(AssertionResult.Failed($"threw {exception.GetType().FullName}")); } - // Handle tolerance-based comparisons using strategy pattern - if (_tolerance != null && value != null && ToleranceComparers.TryGetValue(typeof(TValue), out var toleranceComparer)) - { - // Invoke the appropriate comparer using dynamic invocation - var parameters = new[] { value, _expected, _tolerance, null }; - var result = (bool)toleranceComparer.DynamicInvoke(parameters)!; - var errorMessage = (string?)parameters[3]; - - if (result) - { - return Task.FromResult(AssertionResult.Passed); - } - - if (errorMessage != null) - { - return Task.FromResult(AssertionResult.Failed(errorMessage)); - } - } - // Deep comparison with ignored types if (_ignoredTypes.Count > 0) { @@ -461,10 +212,7 @@ private static (bool IsSuccess, string? Message) DeepEquals(object? actual, obje return (true, null); } - protected override string GetExpectation() => - _tolerance != null - ? $"to equal {_expected} within {_tolerance}" - : $"to be equal to {_expected}"; + protected override string GetExpectation() => $"to be equal to {_expected}"; /// /// Comparer that uses reference equality instead of value equality. diff --git a/TUnit.Assertions/Conditions/EquatableAssertion.cs b/TUnit.Assertions/Conditions/EquatableAssertion.cs index ae1e8a65d8..98b5b42775 100644 --- a/TUnit.Assertions/Conditions/EquatableAssertion.cs +++ b/TUnit.Assertions/Conditions/EquatableAssertion.cs @@ -1,3 +1,4 @@ +using TUnit.Assertions.Attributes; using TUnit.Assertions.Core; namespace TUnit.Assertions.Conditions; @@ -7,6 +8,7 @@ namespace TUnit.Assertions.Conditions; /// This allows comparing types that implement IEquatable with cross-type equality. /// Example: A Wrapper struct implementing IEquatable<long> can be compared directly to a long value. /// +[AssertionExtension("IsEquatableTo")] public class EquatableAssertion : Assertion where TActual : IEquatable { @@ -51,6 +53,7 @@ protected override Task CheckAsync(EvaluationMetadata /// Asserts that a nullable value type implementing IEquatable<TExpected> is equal to an expected value. /// Handles nullable structs that implement IEquatable. /// +[AssertionExtension("IsEquatableTo")] public class NullableEquatableAssertion : Assertion where TActual : struct, IEquatable { diff --git a/TUnit.Assertions/Conditions/SpecializedEqualityAssertions.cs b/TUnit.Assertions/Conditions/SpecializedEqualityAssertions.cs index 469ac353f5..0e1b87de34 100644 --- a/TUnit.Assertions/Conditions/SpecializedEqualityAssertions.cs +++ b/TUnit.Assertions/Conditions/SpecializedEqualityAssertions.cs @@ -1,4 +1,5 @@ using System.Text; +using TUnit.Assertions.Attributes; using TUnit.Assertions.Core; namespace TUnit.Assertions.Conditions; @@ -7,6 +8,7 @@ namespace TUnit.Assertions.Conditions; /// /// Asserts that a DateOnly value is equal to another, with optional tolerance. /// +[AssertionExtension("IsEqualTo", OverloadResolutionPriority = 2)] public class DateOnlyEqualsAssertion : Assertion { private readonly DateOnly _expected; @@ -67,6 +69,7 @@ protected override string GetExpectation() => /// /// Asserts that a TimeOnly value is equal to another, with optional tolerance. /// +[AssertionExtension("IsEqualTo", OverloadResolutionPriority = 2)] public class TimeOnlyEqualsAssertion : Assertion { private readonly TimeOnly _expected; @@ -126,6 +129,7 @@ protected override string GetExpectation() => /// /// Asserts that a double value is equal to another, with optional tolerance. /// +[AssertionExtension("IsEqualTo", OverloadResolutionPriority = 2)] public class DoubleEqualsAssertion : Assertion { private readonly double _expected; @@ -195,6 +199,7 @@ protected override string GetExpectation() => /// /// Asserts that a float value is equal to another, with optional tolerance. /// +[AssertionExtension("IsEqualTo", OverloadResolutionPriority = 2)] public class FloatEqualsAssertion : Assertion { private readonly float _expected; @@ -261,9 +266,69 @@ protected override string GetExpectation() => : $"to be {_expected}"; } +/// +/// Asserts that an int value is equal to another, with optional tolerance. +/// +[AssertionExtension("IsEqualTo", OverloadResolutionPriority = 2)] +public class IntEqualsAssertion : Assertion +{ + private readonly int _expected; + private int? _tolerance; + + public IntEqualsAssertion( + AssertionContext context, + int expected) + : base(context) + { + _expected = expected; + } + + public IntEqualsAssertion Within(int tolerance) + { + _tolerance = tolerance; + Context.ExpressionBuilder.Append($".Within({tolerance})"); + return this; + } + + protected override Task CheckAsync(EvaluationMetadata metadata) + { + var value = metadata.Value; + var exception = metadata.Exception; + + if (exception != null) + { + return Task.FromResult(AssertionResult.Failed($"threw {exception.GetType().Name}")); + } + + if (_tolerance.HasValue) + { + 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 (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}"; +} + /// /// Asserts that a long value is equal to another, with optional tolerance. /// +[AssertionExtension("IsEqualTo", OverloadResolutionPriority = 2)] public class LongEqualsAssertion : Assertion { private readonly long _expected; @@ -322,6 +387,7 @@ protected override string GetExpectation() => /// /// Asserts that a DateTimeOffset value is equal to another, with optional tolerance. /// +[AssertionExtension("IsEqualTo", OverloadResolutionPriority = 2)] public class DateTimeOffsetEqualsAssertion : Assertion { private readonly DateTimeOffset _expected; @@ -376,3 +442,62 @@ protected override string GetExpectation() => ? $"to be within {_tolerance} of {_expected}" : $"to be {_expected}"; } + +/// +/// Asserts that a TimeSpan value is equal to another, with optional tolerance. +/// +[AssertionExtension("IsEqualTo", OverloadResolutionPriority = 2)] +public class TimeSpanEqualsAssertion : Assertion +{ + private readonly TimeSpan _expected; + private TimeSpan? _tolerance; + + public TimeSpanEqualsAssertion( + AssertionContext context, + TimeSpan expected) + : base(context) + { + _expected = expected; + } + + public TimeSpanEqualsAssertion Within(TimeSpan tolerance) + { + _tolerance = tolerance; + Context.ExpressionBuilder.Append($".Within({tolerance})"); + return this; + } + + protected override Task CheckAsync(EvaluationMetadata metadata) + { + var value = metadata.Value; + var exception = metadata.Exception; + + if (exception != null) + { + return Task.FromResult(AssertionResult.Failed($"threw {exception.GetType().Name}")); + } + + if (_tolerance.HasValue) + { + var diff = value > _expected ? value - _expected : _expected - value; + if (diff <= _tolerance.Value) + { + return Task.FromResult(AssertionResult.Passed); + } + + return Task.FromResult(AssertionResult.Failed($"found {value}, which differs by {diff}")); + } + + if (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}"; +} diff --git a/TUnit.Assertions/Conditions/StringEqualsAssertion.cs b/TUnit.Assertions/Conditions/StringEqualsAssertion.cs index 8e72dca209..973e69f6a6 100644 --- a/TUnit.Assertions/Conditions/StringEqualsAssertion.cs +++ b/TUnit.Assertions/Conditions/StringEqualsAssertion.cs @@ -1,4 +1,5 @@ using System.Text; +using TUnit.Assertions.Attributes; using TUnit.Assertions.Core; namespace TUnit.Assertions.Conditions; @@ -7,6 +8,7 @@ namespace TUnit.Assertions.Conditions; /// Asserts that a string is equal to an expected value. /// Demonstrates multiple custom methods WITHOUT wrappers! /// +[AssertionExtension("IsEqualTo", OverloadResolutionPriority = 2)] public class StringEqualsAssertion : Assertion { private readonly string? _expected; diff --git a/TUnit.Assertions/Extensions/AssertionExtensions.cs b/TUnit.Assertions/Extensions/AssertionExtensions.cs index 4146841441..59d8a4cbb0 100644 --- a/TUnit.Assertions/Extensions/AssertionExtensions.cs +++ b/TUnit.Assertions/Extensions/AssertionExtensions.cs @@ -22,21 +22,7 @@ public static class AssertionExtensions // IsNull and IsNotNull are now generated by AssertionExtensionGenerator // ============ EQUALITY ============ - - /// - /// Asserts that the value is equal to the expected value. - /// Generic method that works for all types. - /// Priority 0: Fallback for types without specialized overloads. - /// - [OverloadResolutionPriority(0)] - public static EqualsAssertion IsEqualTo( - this IAssertionSource source, - TValue? expected, - [CallerArgumentExpression(nameof(expected))] string? expression = null) - { - source.Context.ExpressionBuilder.Append($".IsEqualTo({expression})"); - return new EqualsAssertion(source.Context, expected); - } + // IsEqualTo methods are now generated by AssertionExtensionGenerator for all assertion types /// /// Alias for IsEqualTo - asserts that the value is equal to the expected value. @@ -53,38 +39,9 @@ public static EqualsAssertion EqualTo( // IsNotEqualTo is now generated by AssertionExtensionGenerator - /// - /// Asserts that the DateTime is equal to the expected value. - /// Returns DateTimeEqualsAssertion which has .Within() method! - /// Priority 2: Highest priority for specialized type. - /// - [OverloadResolutionPriority(2)] - public static DateTimeEqualsAssertion IsEqualTo( - this IAssertionSource source, - DateTime expected, - [CallerArgumentExpression(nameof(expected))] string? expression = null) - { - source.Context.ExpressionBuilder.Append($".IsEqualTo({expression})"); - return new DateTimeEqualsAssertion(source.Context, expected); - } - - /// - /// Asserts that the string is equal to the expected value. - /// Returns StringEqualsAssertion which has .IgnoringCase() and .WithComparison() methods! - /// Priority 2: Highest priority for specialized type. - /// - [OverloadResolutionPriority(2)] - public static StringEqualsAssertion IsEqualTo( - this IAssertionSource source, - string? expected, - [CallerArgumentExpression(nameof(expected))] string? expression = null) - { - source.Context.ExpressionBuilder.Append($".IsEqualTo({expression})"); - return new StringEqualsAssertion(source.Context, expected); - } - /// /// Asserts that the string is equal to the expected value using the specified comparison. + /// Uses .WithComparison() since StringEqualsAssertion doesn't have a constructor for this. /// public static StringEqualsAssertion IsEqualTo( this IAssertionSource source, @@ -97,158 +54,6 @@ public static StringEqualsAssertion IsEqualTo( return assertion.WithComparison(comparison); } -#if NET6_0_OR_GREATER - /// - /// Asserts that the DateOnly is equal to the expected value. - /// Returns DateOnlyEqualsAssertion which has .WithinDays() method! - /// Priority 2: Highest priority for specialized type. - /// - [OverloadResolutionPriority(2)] - public static DateOnlyEqualsAssertion IsEqualTo( - this IAssertionSource source, - DateOnly expected, - [CallerArgumentExpression(nameof(expected))] string? expression = null) - { - source.Context.ExpressionBuilder.Append($".IsEqualTo({expression})"); - return new DateOnlyEqualsAssertion(source.Context, expected); - } - - /// - /// Asserts that the TimeOnly is equal to the expected value. - /// Returns TimeOnlyEqualsAssertion which has .Within() method! - /// Priority 2: Highest priority for specialized type. - /// - [OverloadResolutionPriority(2)] - public static TimeOnlyEqualsAssertion IsEqualTo( - this IAssertionSource source, - TimeOnly expected, - [CallerArgumentExpression(nameof(expected))] string? expression = null) - { - source.Context.ExpressionBuilder.Append($".IsEqualTo({expression})"); - return new TimeOnlyEqualsAssertion(source.Context, expected); - } -#endif - - /// - /// Asserts that the double is equal to the expected value. - /// Returns DoubleEqualsAssertion which has .Within() method! - /// Priority 2: Highest priority for specialized type. - /// - [OverloadResolutionPriority(2)] - public static DoubleEqualsAssertion IsEqualTo( - this IAssertionSource source, - double expected, - [CallerArgumentExpression(nameof(expected))] string? expression = null) - { - source.Context.ExpressionBuilder.Append($".IsEqualTo({expression})"); - return new DoubleEqualsAssertion(source.Context, expected); - } - - /// - /// Asserts that the float is equal to the expected value. - /// Returns FloatEqualsAssertion which has .Within() method! - /// Priority 2: Highest priority for specialized type. - /// - [OverloadResolutionPriority(2)] - public static FloatEqualsAssertion IsEqualTo( - this IAssertionSource source, - float expected, - [CallerArgumentExpression(nameof(expected))] string? expression = null) - { - source.Context.ExpressionBuilder.Append($".IsEqualTo({expression})"); - return new FloatEqualsAssertion(source.Context, expected); - } - - /// - /// Asserts that the long is equal to the expected value. - /// Returns LongEqualsAssertion which has .Within() method! - /// Priority 2: Highest priority for specialized type. - /// - [OverloadResolutionPriority(2)] - public static LongEqualsAssertion IsEqualTo( - this IAssertionSource source, - long expected, - [CallerArgumentExpression(nameof(expected))] string? expression = null) - { - source.Context.ExpressionBuilder.Append($".IsEqualTo({expression})"); - return new LongEqualsAssertion(source.Context, expected); - } - - /// - /// Asserts that the DateTimeOffset is equal to the expected value. - /// Returns DateTimeOffsetEqualsAssertion which has .Within() method! - /// Priority 2: Highest priority for specialized type. - /// - [OverloadResolutionPriority(2)] - public static DateTimeOffsetEqualsAssertion IsEqualTo( - this IAssertionSource source, - DateTimeOffset expected, - [CallerArgumentExpression(nameof(expected))] string? expression = null) - { - source.Context.ExpressionBuilder.Append($".IsEqualTo({expression})"); - return new DateTimeOffsetEqualsAssertion(source.Context, expected); - } - - /// - /// Asserts that the int is equal to the expected value. - /// Priority 2: Takes precedence over IEquatable overload to provide .Within() support. - /// - [OverloadResolutionPriority(2)] - public static EqualsAssertion IsEqualTo( - this IAssertionSource source, - int expected, - [CallerArgumentExpression(nameof(expected))] string? expression = null) - { - source.Context.ExpressionBuilder.Append($".IsEqualTo({expression})"); - return new EqualsAssertion(source.Context, expected); - } - - /// - /// Asserts that the TimeSpan is equal to the expected value. - /// Priority 2: Takes precedence over IEquatable overload to provide .Within() support. - /// - [OverloadResolutionPriority(2)] - public static EqualsAssertion IsEqualTo( - this IAssertionSource source, - TimeSpan expected, - [CallerArgumentExpression(nameof(expected))] string? expression = null) - { - source.Context.ExpressionBuilder.Append($".IsEqualTo({expression})"); - return new EqualsAssertion(source.Context, expected); - } - - /// - /// Asserts that a struct implementing IEquatable<TExpected> is equal to the expected value. - /// This enables direct equality comparisons for structs with cross-type IEquatable implementations. - /// Example: A Wrapper struct implementing IEquatable<long> can be compared directly to a long value. - /// Priority -1: Lower than generic fallback; only used for cross-type IEquatable scenarios (TActual != TExpected). - /// - [OverloadResolutionPriority(-1)] - public static EquatableAssertion IsEqualTo( - this IAssertionSource source, - TExpected expected, - [CallerArgumentExpression(nameof(expected))] string? expression = null) - where TActual : struct, IEquatable - { - source.Context.ExpressionBuilder.Append($".IsEqualTo({expression})"); - return new EquatableAssertion(source.Context, expected); - } - - /// - /// Asserts that a nullable struct implementing IEquatable<TExpected> is equal to the expected value. - /// Handles nullable structs with cross-type IEquatable implementations. - /// Priority -1: Lower than generic fallback; only used for cross-type IEquatable scenarios (TActual != TExpected). - /// - [OverloadResolutionPriority(-1)] - public static NullableEquatableAssertion IsEqualTo( - this IAssertionSource source, - TExpected expected, - [CallerArgumentExpression(nameof(expected))] string? expression = null) - where TActual : struct, IEquatable - { - source.Context.ExpressionBuilder.Append($".IsEqualTo({expression})"); - return new NullableEquatableAssertion(source.Context, expected); - } // ============ COMPARISONS ============ // IsGreaterThan, IsGreaterThanOrEqualTo, IsLessThan, IsLessThanOrEqualTo, and IsBetween diff --git a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet10_0.verified.txt b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet10_0.verified.txt index 4cf0af00b7..74781e60ec 100644 --- a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet10_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet10_0.verified.txt @@ -151,6 +151,7 @@ namespace .Attributes public AssertionExtensionAttribute(string methodName) { } public string MethodName { get; } public string? NegatedMethodName { get; set; } + public int OverloadResolutionPriority { get; set; } } [(.Class, AllowMultiple=true, Inherited=false)] public class AssertionFromAttribute : @@ -510,6 +511,7 @@ namespace .Conditions [.(ExpectationMessage="to be today")] public static bool IsToday(this value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class DateOnlyEqualsAssertion : .<> { public DateOnlyEqualsAssertion(.<> context, expected) { } @@ -546,6 +548,7 @@ namespace .Conditions [.(ExpectationMessage="to be UTC")] public static bool IsUtc(this value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class DateTimeEqualsAssertion : .<> { public DateTimeEqualsAssertion(.<> context, expected) { } @@ -587,6 +590,7 @@ namespace .Conditions [.(ExpectationMessage="to be UTC")] public static bool IsUtc(this value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class DateTimeOffsetEqualsAssertion : .<> { public DateTimeOffsetEqualsAssertion(.<> context, expected) { } @@ -650,6 +654,7 @@ namespace .Conditions [.(ExpectationMessage="to be a system directory")] public static bool IsSystemDirectory(this .DirectoryInfo value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class DoubleEqualsAssertion : . { public DoubleEqualsAssertion(. context, double expected) { } @@ -674,17 +679,18 @@ namespace .Conditions [.(ExpectationMessage="to be Unicode encoding")] public static bool IsUnicode(this .Encoding value) { } } + [.("IsEqualTo")] public class EqualsAssertion : . { - public EqualsAssertion(. context, TValue? expected, .? comparer = null) { } + public EqualsAssertion(. context, TValue? expected) { } + public EqualsAssertion(. context, TValue? expected, . comparer) { } public TValue Expected { get; } - [.("Trimming", "IL2075", Justification="Tolerance comparison requires dynamic invocation of known comparer delegates")] protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } public . IgnoringType( type) { } public . IgnoringType() { } - public . Within(object tolerance) { } } + [.("IsEquatableTo")] public class EquatableAssertion : . where TActual : { @@ -798,6 +804,7 @@ namespace .Conditions protected override .<.> CheckAsync(.<.FileInfo> metadata) { } protected override string GetExpectation() { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class FloatEqualsAssertion : . { public FloatEqualsAssertion(. context, float expected) { } @@ -892,6 +899,14 @@ namespace .Conditions [.<>("IsFromEnd", CustomName="IsNotFromEnd", ExpectationMessage="be from the end", NegateLogic=true)] [.<>("IsFromEnd", ExpectationMessage="be from the end")] public static class IndexAssertionExtensions { } + [.("IsEqualTo", OverloadResolutionPriority=2)] + public class IntEqualsAssertion : . + { + public IntEqualsAssertion(. context, int expected) { } + protected override .<.> CheckAsync(. metadata) { } + protected override string GetExpectation() { } + public . Within(int tolerance) { } + } [.("IsAssignableTo")] public class IsAssignableToAssertion : . { @@ -983,6 +998,7 @@ namespace .Conditions protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class LongEqualsAssertion : . { public LongEqualsAssertion(. context, long expected) { } @@ -1050,6 +1066,7 @@ namespace .Conditions protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } + [.("IsEquatableTo")] public class NullableEquatableAssertion : . where TActual : struct, { @@ -1158,6 +1175,7 @@ namespace .Conditions public . IgnoringCase() { } public . WithComparison( comparison) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class StringEqualsAssertion : . { public StringEqualsAssertion(. context, string? expected) { } @@ -1295,6 +1313,7 @@ namespace .Conditions [.(ExpectationMessage="to be at the start of the hour")] public static bool IsStartOfHour(this value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class TimeOnlyEqualsAssertion : .<> { public TimeOnlyEqualsAssertion(.<> context, expected) { } @@ -1317,6 +1336,14 @@ namespace .Conditions [.(ExpectationMessage="to be zero")] public static bool IsZero(this value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] + public class TimeSpanEqualsAssertion : .<> + { + public TimeSpanEqualsAssertion(.<> context, expected) { } + protected override .<.> CheckAsync(.<> metadata) { } + protected override string GetExpectation() { } + public . Within( tolerance) { } + } [.<>("HasIanaId", CustomName="DoesNotHaveIanaId", ExpectationMessage="have an IANA ID", NegateLogic=true)] [.<>("HasIanaId", ExpectationMessage="have an IANA ID")] [.<>("SupportsDaylightSavingTime", CustomName="DoesNotSupportDaylightSavingTime", ExpectationMessage="support daylight saving time", NegateLogic=true)] @@ -1719,35 +1746,7 @@ namespace .Extensions where TEnum : struct, { } public static . IsEmpty(this . source) where TValue : .IEnumerable { } - [.(2)] - public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - [.(2)] - public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - [.(2)] - public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - [.(2)] - public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - [.(2)] - public static .<> IsEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - [.(2)] - public static . IsEqualTo(this . source, double expected, [.("expected")] string? expression = null) { } - [.(2)] - public static . IsEqualTo(this . source, float expected, [.("expected")] string? expression = null) { } - [.(2)] - public static . IsEqualTo(this . source, int expected, [.("expected")] string? expression = null) { } - [.(2)] - public static . IsEqualTo(this . source, long expected, [.("expected")] string? expression = null) { } - [.(2)] - public static . IsEqualTo(this . source, string? expected, [.("expected")] string? expression = null) { } public static . IsEqualTo(this . source, string? expected, comparison, [.("expected")] string? expression = null) { } - [.(0)] - public static . IsEqualTo(this . source, TValue? expected, [.("expected")] string? expression = null) { } - [.(-1)] - public static . IsEqualTo(this . source, TExpected expected, [.("expected")] string? expression = null) - where TActual : struct, { } - [.(-1)] - public static . IsEqualTo(this . source, TExpected expected, [.("expected")] string? expression = null) - where TActual : struct, { } public static . IsEquivalentTo(this . source, object? expected, [.("expected")] string? expression = null) { } public static . IsEquivalentTo(this . source, . expected, [.("expected")] string? expression = null) where TCollection : . { } @@ -2089,6 +2088,11 @@ namespace .Extensions public static ._IsOnWeekend_Assertion IsOnWeekend(this .<> source) { } public static ._IsToday_Assertion IsToday(this .<> source) { } } + public static class DateOnlyEqualsAssertionExtensions + { + [.(2)] + public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } + } public sealed class DateOnly_IsFirstDayOfMonth_Assertion : .<> { public DateOnly_IsFirstDayOfMonth_Assertion(.<> context) { } @@ -2166,6 +2170,11 @@ namespace .Extensions public static ._IsToday_Assertion IsToday(this .<> source) { } public static ._IsUtc_Assertion IsUtc(this .<> source) { } } + public static class DateTimeEqualsAssertionExtensions + { + [.(2)] + public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } + } public static class DateTimeEqualsExactAssertionExtensions { public static . EqualsExact(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } @@ -2191,6 +2200,11 @@ namespace .Extensions public static ._IsToday_Assertion IsToday(this .<> source) { } public static ._IsUtc_Assertion IsUtc(this .<> source) { } } + public static class DateTimeOffsetEqualsAssertionExtensions + { + [.(2)] + public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } + } public sealed class DateTimeOffset_IsInFutureUtc_Assertion : .<> { public DateTimeOffset_IsInFutureUtc_Assertion(.<> context) { } @@ -2434,6 +2448,11 @@ namespace .Extensions protected override .<.> CheckAsync(.<.DirectoryInfo> metadata) { } protected override string GetExpectation() { } } + public static class DoubleEqualsAssertionExtensions + { + [.(2)] + public static . IsEqualTo(this . source, double expected, [.("expected")] string? expectedExpression = null) { } + } public static class EncodingAssertionExtensions { public static ._IsASCII_Assertion IsASCII(this .<.Encoding> source) { } @@ -2487,6 +2506,16 @@ namespace .Extensions protected override .<.> CheckAsync(.<.Encoding> metadata) { } protected override string GetExpectation() { } } + public static class EqualsAssertionExtensions + { + public static . IsEqualTo(this . source, TValue? expected, [.("expected")] string? expectedExpression = null) { } + public static . IsEqualTo(this . source, TValue? expected, . comparer, [.("expected")] string? expectedExpression = null, [.("comparer")] string? comparerExpression = null) { } + } + public static class EquatableAssertionExtensions + { + public static . IsEquatableTo(this . source, TExpected expected, [.("expected")] string? expectedExpression = null) + where TActual : { } + } public static class ExceptionAssertionExtensions { public static ._HasHelpLink_Assertion HasHelpLink(this .<> source) { } @@ -2643,6 +2672,11 @@ namespace .Extensions { public static . IsNotSystem(this .<.FileInfo> source) { } } + public static class FloatEqualsAssertionExtensions + { + [.(2)] + public static . IsEqualTo(this . source, float expected, [.("expected")] string? expectedExpression = null) { } + } public static class GreaterThanAssertionExtensions { public static . IsGreaterThan(this . source, TValue minimum, [.("minimum")] string? minimumExpression = null) @@ -2790,6 +2824,11 @@ namespace .Extensions protected override .<.> CheckAsync(.<> metadata) { } protected override string GetExpectation() { } } + public static class IntEqualsAssertionExtensions + { + [.(2)] + public static . IsEqualTo(this . source, int expected, [.("expected")] string? expectedExpression = null) { } + } public static class IsAssignableToAssertionExtensions { public static . IsAssignableTo(this . source) { } @@ -2849,6 +2888,11 @@ namespace .Extensions public static . IsLessThanOrEqualTo(this . source, TValue maximum, [.("maximum")] string? maximumExpression = null) where TValue : { } } + public static class LongEqualsAssertionExtensions + { + [.(2)] + public static . IsEqualTo(this . source, long expected, [.("expected")] string? expectedExpression = null) { } + } public static class NotEqualsAssertionExtensions { public static . IsNotEqualTo(this . source, TValue notExpected, .? comparer = null, [.("notExpected")] string? notExpectedExpression = null, [.("comparer")] string? comparerExpression = null) { } @@ -2865,6 +2909,11 @@ namespace .Extensions { public static . IsNull(this . source) { } } + public static class NullableEquatableAssertionExtensions + { + public static . IsEquatableTo(this . source, TExpected expected, [.("expected")] string? expectedExpression = null) + where TActual : struct, { } + } public static class ProcessAssertionExtensions { public static . DoesNotHaveEventRaisingEnabled(this .<.Process> source) { } @@ -3034,6 +3083,11 @@ namespace .Extensions public static . EndsWith(this . source, string expected, [.("expected")] string? expectedExpression = null) { } public static . EndsWith(this . source, string expected, comparison, [.("expected")] string? expectedExpression = null, [.("comparison")] string? comparisonExpression = null) { } } + public static class StringEqualsAssertionExtensions + { + [.(2)] + public static . IsEqualTo(this . source, string? expected, [.("expected")] string? expectedExpression = null) { } + } public static class StringIsEmptyAssertionExtensions { public static . IsEmpty(this . source) { } @@ -3154,6 +3208,11 @@ namespace .Extensions public static ._IsPM_Assertion IsPM(this .<> source) { } public static ._IsStartOfHour_Assertion IsStartOfHour(this .<> source) { } } + public static class TimeOnlyEqualsAssertionExtensions + { + [.(2)] + public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } + } public sealed class TimeOnly_IsAM_Assertion : .<> { public TimeOnly_IsAM_Assertion(.<> context) { } @@ -3205,6 +3264,11 @@ namespace .Extensions public static ._IsPositive_Assertion IsPositive(this .<> source) { } public static ._IsZero_Assertion IsZero(this .<> source) { } } + public static class TimeSpanEqualsAssertionExtensions + { + [.(2)] + public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } + } public sealed class TimeSpan_IsNegative_Assertion : .<> { public TimeSpan_IsNegative_Assertion(.<> context) { } diff --git a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet8_0.verified.txt b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet8_0.verified.txt index bfc649440c..fee385300b 100644 --- a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet8_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet8_0.verified.txt @@ -151,6 +151,7 @@ namespace .Attributes public AssertionExtensionAttribute(string methodName) { } public string MethodName { get; } public string? NegatedMethodName { get; set; } + public int OverloadResolutionPriority { get; set; } } [(.Class, AllowMultiple=true, Inherited=false)] public class AssertionFromAttribute : @@ -510,6 +511,7 @@ namespace .Conditions [.(ExpectationMessage="to be today")] public static bool IsToday(this value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class DateOnlyEqualsAssertion : .<> { public DateOnlyEqualsAssertion(.<> context, expected) { } @@ -546,6 +548,7 @@ namespace .Conditions [.(ExpectationMessage="to be UTC")] public static bool IsUtc(this value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class DateTimeEqualsAssertion : .<> { public DateTimeEqualsAssertion(.<> context, expected) { } @@ -587,6 +590,7 @@ namespace .Conditions [.(ExpectationMessage="to be UTC")] public static bool IsUtc(this value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class DateTimeOffsetEqualsAssertion : .<> { public DateTimeOffsetEqualsAssertion(.<> context, expected) { } @@ -650,6 +654,7 @@ namespace .Conditions [.(ExpectationMessage="to be a system directory")] public static bool IsSystemDirectory(this .DirectoryInfo value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class DoubleEqualsAssertion : . { public DoubleEqualsAssertion(. context, double expected) { } @@ -674,17 +679,18 @@ namespace .Conditions [.(ExpectationMessage="to be Unicode encoding")] public static bool IsUnicode(this .Encoding value) { } } + [.("IsEqualTo")] public class EqualsAssertion : . { - public EqualsAssertion(. context, TValue? expected, .? comparer = null) { } + public EqualsAssertion(. context, TValue? expected) { } + public EqualsAssertion(. context, TValue? expected, . comparer) { } public TValue Expected { get; } - [.("Trimming", "IL2075", Justification="Tolerance comparison requires dynamic invocation of known comparer delegates")] protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } public . IgnoringType( type) { } public . IgnoringType() { } - public . Within(object tolerance) { } } + [.("IsEquatableTo")] public class EquatableAssertion : . where TActual : { @@ -798,6 +804,7 @@ namespace .Conditions protected override .<.> CheckAsync(.<.FileInfo> metadata) { } protected override string GetExpectation() { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class FloatEqualsAssertion : . { public FloatEqualsAssertion(. context, float expected) { } @@ -892,6 +899,14 @@ namespace .Conditions [.<>("IsFromEnd", CustomName="IsNotFromEnd", ExpectationMessage="be from the end", NegateLogic=true)] [.<>("IsFromEnd", ExpectationMessage="be from the end")] public static class IndexAssertionExtensions { } + [.("IsEqualTo", OverloadResolutionPriority=2)] + public class IntEqualsAssertion : . + { + public IntEqualsAssertion(. context, int expected) { } + protected override .<.> CheckAsync(. metadata) { } + protected override string GetExpectation() { } + public . Within(int tolerance) { } + } [.("IsAssignableTo")] public class IsAssignableToAssertion : . { @@ -983,6 +998,7 @@ namespace .Conditions protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class LongEqualsAssertion : . { public LongEqualsAssertion(. context, long expected) { } @@ -1050,6 +1066,7 @@ namespace .Conditions protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } + [.("IsEquatableTo")] public class NullableEquatableAssertion : . where TActual : struct, { @@ -1158,6 +1175,7 @@ namespace .Conditions public . IgnoringCase() { } public . WithComparison( comparison) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class StringEqualsAssertion : . { public StringEqualsAssertion(. context, string? expected) { } @@ -1295,6 +1313,7 @@ namespace .Conditions [.(ExpectationMessage="to be at the start of the hour")] public static bool IsStartOfHour(this value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class TimeOnlyEqualsAssertion : .<> { public TimeOnlyEqualsAssertion(.<> context, expected) { } @@ -1317,6 +1336,14 @@ namespace .Conditions [.(ExpectationMessage="to be zero")] public static bool IsZero(this value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] + public class TimeSpanEqualsAssertion : .<> + { + public TimeSpanEqualsAssertion(.<> context, expected) { } + protected override .<.> CheckAsync(.<> metadata) { } + protected override string GetExpectation() { } + public . Within( tolerance) { } + } [.<>("HasIanaId", CustomName="DoesNotHaveIanaId", ExpectationMessage="have an IANA ID", NegateLogic=true)] [.<>("HasIanaId", ExpectationMessage="have an IANA ID")] [.<>("SupportsDaylightSavingTime", CustomName="DoesNotSupportDaylightSavingTime", ExpectationMessage="support daylight saving time", NegateLogic=true)] @@ -1719,22 +1746,7 @@ namespace .Extensions where TEnum : struct, { } public static . IsEmpty(this . source) where TValue : .IEnumerable { } - public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - public static .<> IsEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - public static . IsEqualTo(this . source, double expected, [.("expected")] string? expression = null) { } - public static . IsEqualTo(this . source, float expected, [.("expected")] string? expression = null) { } - public static . IsEqualTo(this . source, int expected, [.("expected")] string? expression = null) { } - public static . IsEqualTo(this . source, long expected, [.("expected")] string? expression = null) { } - public static . IsEqualTo(this . source, string? expected, [.("expected")] string? expression = null) { } public static . IsEqualTo(this . source, string? expected, comparison, [.("expected")] string? expression = null) { } - public static . IsEqualTo(this . source, TValue? expected, [.("expected")] string? expression = null) { } - public static . IsEqualTo(this . source, TExpected expected, [.("expected")] string? expression = null) - where TActual : struct, { } - public static . IsEqualTo(this . source, TExpected expected, [.("expected")] string? expression = null) - where TActual : struct, { } public static . IsEquivalentTo(this . source, object? expected, [.("expected")] string? expression = null) { } public static . IsEquivalentTo(this . source, . expected, [.("expected")] string? expression = null) where TCollection : . { } @@ -2076,6 +2088,10 @@ namespace .Extensions public static ._IsOnWeekend_Assertion IsOnWeekend(this .<> source) { } public static ._IsToday_Assertion IsToday(this .<> source) { } } + public static class DateOnlyEqualsAssertionExtensions + { + public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } + } public sealed class DateOnly_IsFirstDayOfMonth_Assertion : .<> { public DateOnly_IsFirstDayOfMonth_Assertion(.<> context) { } @@ -2153,6 +2169,10 @@ namespace .Extensions public static ._IsToday_Assertion IsToday(this .<> source) { } public static ._IsUtc_Assertion IsUtc(this .<> source) { } } + public static class DateTimeEqualsAssertionExtensions + { + public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } + } public static class DateTimeEqualsExactAssertionExtensions { public static . EqualsExact(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } @@ -2178,6 +2198,10 @@ namespace .Extensions public static ._IsToday_Assertion IsToday(this .<> source) { } public static ._IsUtc_Assertion IsUtc(this .<> source) { } } + public static class DateTimeOffsetEqualsAssertionExtensions + { + public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } + } public sealed class DateTimeOffset_IsInFutureUtc_Assertion : .<> { public DateTimeOffset_IsInFutureUtc_Assertion(.<> context) { } @@ -2421,6 +2445,10 @@ namespace .Extensions protected override .<.> CheckAsync(.<.DirectoryInfo> metadata) { } protected override string GetExpectation() { } } + public static class DoubleEqualsAssertionExtensions + { + public static . IsEqualTo(this . source, double expected, [.("expected")] string? expectedExpression = null) { } + } public static class EncodingAssertionExtensions { public static ._IsASCII_Assertion IsASCII(this .<.Encoding> source) { } @@ -2474,6 +2502,16 @@ namespace .Extensions protected override .<.> CheckAsync(.<.Encoding> metadata) { } protected override string GetExpectation() { } } + public static class EqualsAssertionExtensions + { + public static . IsEqualTo(this . source, TValue? expected, [.("expected")] string? expectedExpression = null) { } + public static . IsEqualTo(this . source, TValue? expected, . comparer, [.("expected")] string? expectedExpression = null, [.("comparer")] string? comparerExpression = null) { } + } + public static class EquatableAssertionExtensions + { + public static . IsEquatableTo(this . source, TExpected expected, [.("expected")] string? expectedExpression = null) + where TActual : { } + } public static class ExceptionAssertionExtensions { public static ._HasHelpLink_Assertion HasHelpLink(this .<> source) { } @@ -2630,6 +2668,10 @@ namespace .Extensions { public static . IsNotSystem(this .<.FileInfo> source) { } } + public static class FloatEqualsAssertionExtensions + { + public static . IsEqualTo(this . source, float expected, [.("expected")] string? expectedExpression = null) { } + } public static class GreaterThanAssertionExtensions { public static . IsGreaterThan(this . source, TValue minimum, [.("minimum")] string? minimumExpression = null) @@ -2777,6 +2819,10 @@ namespace .Extensions protected override .<.> CheckAsync(.<> metadata) { } protected override string GetExpectation() { } } + public static class IntEqualsAssertionExtensions + { + public static . IsEqualTo(this . source, int expected, [.("expected")] string? expectedExpression = null) { } + } public static class IsAssignableToAssertionExtensions { public static . IsAssignableTo(this . source) { } @@ -2836,6 +2882,10 @@ namespace .Extensions public static . IsLessThanOrEqualTo(this . source, TValue maximum, [.("maximum")] string? maximumExpression = null) where TValue : { } } + public static class LongEqualsAssertionExtensions + { + public static . IsEqualTo(this . source, long expected, [.("expected")] string? expectedExpression = null) { } + } public static class NotEqualsAssertionExtensions { public static . IsNotEqualTo(this . source, TValue notExpected, .? comparer = null, [.("notExpected")] string? notExpectedExpression = null, [.("comparer")] string? comparerExpression = null) { } @@ -2852,6 +2902,11 @@ namespace .Extensions { public static . IsNull(this . source) { } } + public static class NullableEquatableAssertionExtensions + { + public static . IsEquatableTo(this . source, TExpected expected, [.("expected")] string? expectedExpression = null) + where TActual : struct, { } + } public static class ProcessAssertionExtensions { public static . DoesNotHaveEventRaisingEnabled(this .<.Process> source) { } @@ -3021,6 +3076,10 @@ namespace .Extensions public static . EndsWith(this . source, string expected, [.("expected")] string? expectedExpression = null) { } public static . EndsWith(this . source, string expected, comparison, [.("expected")] string? expectedExpression = null, [.("comparison")] string? comparisonExpression = null) { } } + public static class StringEqualsAssertionExtensions + { + public static . IsEqualTo(this . source, string? expected, [.("expected")] string? expectedExpression = null) { } + } public static class StringIsEmptyAssertionExtensions { public static . IsEmpty(this . source) { } @@ -3141,6 +3200,10 @@ namespace .Extensions public static ._IsPM_Assertion IsPM(this .<> source) { } public static ._IsStartOfHour_Assertion IsStartOfHour(this .<> source) { } } + public static class TimeOnlyEqualsAssertionExtensions + { + public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } + } public sealed class TimeOnly_IsAM_Assertion : .<> { public TimeOnly_IsAM_Assertion(.<> context) { } @@ -3192,6 +3255,10 @@ namespace .Extensions public static ._IsPositive_Assertion IsPositive(this .<> source) { } public static ._IsZero_Assertion IsZero(this .<> source) { } } + public static class TimeSpanEqualsAssertionExtensions + { + public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } + } public sealed class TimeSpan_IsNegative_Assertion : .<> { public TimeSpan_IsNegative_Assertion(.<> context) { } diff --git a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet9_0.verified.txt b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet9_0.verified.txt index 8837dd000e..3fd84cfc14 100644 --- a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet9_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet9_0.verified.txt @@ -151,6 +151,7 @@ namespace .Attributes public AssertionExtensionAttribute(string methodName) { } public string MethodName { get; } public string? NegatedMethodName { get; set; } + public int OverloadResolutionPriority { get; set; } } [(.Class, AllowMultiple=true, Inherited=false)] public class AssertionFromAttribute : @@ -510,6 +511,7 @@ namespace .Conditions [.(ExpectationMessage="to be today")] public static bool IsToday(this value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class DateOnlyEqualsAssertion : .<> { public DateOnlyEqualsAssertion(.<> context, expected) { } @@ -546,6 +548,7 @@ namespace .Conditions [.(ExpectationMessage="to be UTC")] public static bool IsUtc(this value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class DateTimeEqualsAssertion : .<> { public DateTimeEqualsAssertion(.<> context, expected) { } @@ -587,6 +590,7 @@ namespace .Conditions [.(ExpectationMessage="to be UTC")] public static bool IsUtc(this value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class DateTimeOffsetEqualsAssertion : .<> { public DateTimeOffsetEqualsAssertion(.<> context, expected) { } @@ -650,6 +654,7 @@ namespace .Conditions [.(ExpectationMessage="to be a system directory")] public static bool IsSystemDirectory(this .DirectoryInfo value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class DoubleEqualsAssertion : . { public DoubleEqualsAssertion(. context, double expected) { } @@ -674,17 +679,18 @@ namespace .Conditions [.(ExpectationMessage="to be Unicode encoding")] public static bool IsUnicode(this .Encoding value) { } } + [.("IsEqualTo")] public class EqualsAssertion : . { - public EqualsAssertion(. context, TValue? expected, .? comparer = null) { } + public EqualsAssertion(. context, TValue? expected) { } + public EqualsAssertion(. context, TValue? expected, . comparer) { } public TValue Expected { get; } - [.("Trimming", "IL2075", Justification="Tolerance comparison requires dynamic invocation of known comparer delegates")] protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } public . IgnoringType( type) { } public . IgnoringType() { } - public . Within(object tolerance) { } } + [.("IsEquatableTo")] public class EquatableAssertion : . where TActual : { @@ -798,6 +804,7 @@ namespace .Conditions protected override .<.> CheckAsync(.<.FileInfo> metadata) { } protected override string GetExpectation() { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class FloatEqualsAssertion : . { public FloatEqualsAssertion(. context, float expected) { } @@ -892,6 +899,14 @@ namespace .Conditions [.<>("IsFromEnd", CustomName="IsNotFromEnd", ExpectationMessage="be from the end", NegateLogic=true)] [.<>("IsFromEnd", ExpectationMessage="be from the end")] public static class IndexAssertionExtensions { } + [.("IsEqualTo", OverloadResolutionPriority=2)] + public class IntEqualsAssertion : . + { + public IntEqualsAssertion(. context, int expected) { } + protected override .<.> CheckAsync(. metadata) { } + protected override string GetExpectation() { } + public . Within(int tolerance) { } + } [.("IsAssignableTo")] public class IsAssignableToAssertion : . { @@ -983,6 +998,7 @@ namespace .Conditions protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class LongEqualsAssertion : . { public LongEqualsAssertion(. context, long expected) { } @@ -1050,6 +1066,7 @@ namespace .Conditions protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } + [.("IsEquatableTo")] public class NullableEquatableAssertion : . where TActual : struct, { @@ -1158,6 +1175,7 @@ namespace .Conditions public . IgnoringCase() { } public . WithComparison( comparison) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class StringEqualsAssertion : . { public StringEqualsAssertion(. context, string? expected) { } @@ -1295,6 +1313,7 @@ namespace .Conditions [.(ExpectationMessage="to be at the start of the hour")] public static bool IsStartOfHour(this value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class TimeOnlyEqualsAssertion : .<> { public TimeOnlyEqualsAssertion(.<> context, expected) { } @@ -1317,6 +1336,14 @@ namespace .Conditions [.(ExpectationMessage="to be zero")] public static bool IsZero(this value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] + public class TimeSpanEqualsAssertion : .<> + { + public TimeSpanEqualsAssertion(.<> context, expected) { } + protected override .<.> CheckAsync(.<> metadata) { } + protected override string GetExpectation() { } + public . Within( tolerance) { } + } [.<>("HasIanaId", CustomName="DoesNotHaveIanaId", ExpectationMessage="have an IANA ID", NegateLogic=true)] [.<>("HasIanaId", ExpectationMessage="have an IANA ID")] [.<>("SupportsDaylightSavingTime", CustomName="DoesNotSupportDaylightSavingTime", ExpectationMessage="support daylight saving time", NegateLogic=true)] @@ -1719,35 +1746,7 @@ namespace .Extensions where TEnum : struct, { } public static . IsEmpty(this . source) where TValue : .IEnumerable { } - [.(2)] - public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - [.(2)] - public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - [.(2)] - public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - [.(2)] - public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - [.(2)] - public static .<> IsEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - [.(2)] - public static . IsEqualTo(this . source, double expected, [.("expected")] string? expression = null) { } - [.(2)] - public static . IsEqualTo(this . source, float expected, [.("expected")] string? expression = null) { } - [.(2)] - public static . IsEqualTo(this . source, int expected, [.("expected")] string? expression = null) { } - [.(2)] - public static . IsEqualTo(this . source, long expected, [.("expected")] string? expression = null) { } - [.(2)] - public static . IsEqualTo(this . source, string? expected, [.("expected")] string? expression = null) { } public static . IsEqualTo(this . source, string? expected, comparison, [.("expected")] string? expression = null) { } - [.(0)] - public static . IsEqualTo(this . source, TValue? expected, [.("expected")] string? expression = null) { } - [.(-1)] - public static . IsEqualTo(this . source, TExpected expected, [.("expected")] string? expression = null) - where TActual : struct, { } - [.(-1)] - public static . IsEqualTo(this . source, TExpected expected, [.("expected")] string? expression = null) - where TActual : struct, { } public static . IsEquivalentTo(this . source, object? expected, [.("expected")] string? expression = null) { } public static . IsEquivalentTo(this . source, . expected, [.("expected")] string? expression = null) where TCollection : . { } @@ -2089,6 +2088,11 @@ namespace .Extensions public static ._IsOnWeekend_Assertion IsOnWeekend(this .<> source) { } public static ._IsToday_Assertion IsToday(this .<> source) { } } + public static class DateOnlyEqualsAssertionExtensions + { + [.(2)] + public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } + } public sealed class DateOnly_IsFirstDayOfMonth_Assertion : .<> { public DateOnly_IsFirstDayOfMonth_Assertion(.<> context) { } @@ -2166,6 +2170,11 @@ namespace .Extensions public static ._IsToday_Assertion IsToday(this .<> source) { } public static ._IsUtc_Assertion IsUtc(this .<> source) { } } + public static class DateTimeEqualsAssertionExtensions + { + [.(2)] + public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } + } public static class DateTimeEqualsExactAssertionExtensions { public static . EqualsExact(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } @@ -2191,6 +2200,11 @@ namespace .Extensions public static ._IsToday_Assertion IsToday(this .<> source) { } public static ._IsUtc_Assertion IsUtc(this .<> source) { } } + public static class DateTimeOffsetEqualsAssertionExtensions + { + [.(2)] + public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } + } public sealed class DateTimeOffset_IsInFutureUtc_Assertion : .<> { public DateTimeOffset_IsInFutureUtc_Assertion(.<> context) { } @@ -2434,6 +2448,11 @@ namespace .Extensions protected override .<.> CheckAsync(.<.DirectoryInfo> metadata) { } protected override string GetExpectation() { } } + public static class DoubleEqualsAssertionExtensions + { + [.(2)] + public static . IsEqualTo(this . source, double expected, [.("expected")] string? expectedExpression = null) { } + } public static class EncodingAssertionExtensions { public static ._IsASCII_Assertion IsASCII(this .<.Encoding> source) { } @@ -2487,6 +2506,16 @@ namespace .Extensions protected override .<.> CheckAsync(.<.Encoding> metadata) { } protected override string GetExpectation() { } } + public static class EqualsAssertionExtensions + { + public static . IsEqualTo(this . source, TValue? expected, [.("expected")] string? expectedExpression = null) { } + public static . IsEqualTo(this . source, TValue? expected, . comparer, [.("expected")] string? expectedExpression = null, [.("comparer")] string? comparerExpression = null) { } + } + public static class EquatableAssertionExtensions + { + public static . IsEquatableTo(this . source, TExpected expected, [.("expected")] string? expectedExpression = null) + where TActual : { } + } public static class ExceptionAssertionExtensions { public static ._HasHelpLink_Assertion HasHelpLink(this .<> source) { } @@ -2643,6 +2672,11 @@ namespace .Extensions { public static . IsNotSystem(this .<.FileInfo> source) { } } + public static class FloatEqualsAssertionExtensions + { + [.(2)] + public static . IsEqualTo(this . source, float expected, [.("expected")] string? expectedExpression = null) { } + } public static class GreaterThanAssertionExtensions { public static . IsGreaterThan(this . source, TValue minimum, [.("minimum")] string? minimumExpression = null) @@ -2790,6 +2824,11 @@ namespace .Extensions protected override .<.> CheckAsync(.<> metadata) { } protected override string GetExpectation() { } } + public static class IntEqualsAssertionExtensions + { + [.(2)] + public static . IsEqualTo(this . source, int expected, [.("expected")] string? expectedExpression = null) { } + } public static class IsAssignableToAssertionExtensions { public static . IsAssignableTo(this . source) { } @@ -2849,6 +2888,11 @@ namespace .Extensions public static . IsLessThanOrEqualTo(this . source, TValue maximum, [.("maximum")] string? maximumExpression = null) where TValue : { } } + public static class LongEqualsAssertionExtensions + { + [.(2)] + public static . IsEqualTo(this . source, long expected, [.("expected")] string? expectedExpression = null) { } + } public static class NotEqualsAssertionExtensions { public static . IsNotEqualTo(this . source, TValue notExpected, .? comparer = null, [.("notExpected")] string? notExpectedExpression = null, [.("comparer")] string? comparerExpression = null) { } @@ -2865,6 +2909,11 @@ namespace .Extensions { public static . IsNull(this . source) { } } + public static class NullableEquatableAssertionExtensions + { + public static . IsEquatableTo(this . source, TExpected expected, [.("expected")] string? expectedExpression = null) + where TActual : struct, { } + } public static class ProcessAssertionExtensions { public static . DoesNotHaveEventRaisingEnabled(this .<.Process> source) { } @@ -3034,6 +3083,11 @@ namespace .Extensions public static . EndsWith(this . source, string expected, [.("expected")] string? expectedExpression = null) { } public static . EndsWith(this . source, string expected, comparison, [.("expected")] string? expectedExpression = null, [.("comparison")] string? comparisonExpression = null) { } } + public static class StringEqualsAssertionExtensions + { + [.(2)] + public static . IsEqualTo(this . source, string? expected, [.("expected")] string? expectedExpression = null) { } + } public static class StringIsEmptyAssertionExtensions { public static . IsEmpty(this . source) { } @@ -3154,6 +3208,11 @@ namespace .Extensions public static ._IsPM_Assertion IsPM(this .<> source) { } public static ._IsStartOfHour_Assertion IsStartOfHour(this .<> source) { } } + public static class TimeOnlyEqualsAssertionExtensions + { + [.(2)] + public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } + } public sealed class TimeOnly_IsAM_Assertion : .<> { public TimeOnly_IsAM_Assertion(.<> context) { } @@ -3205,6 +3264,11 @@ namespace .Extensions public static ._IsPositive_Assertion IsPositive(this .<> source) { } public static ._IsZero_Assertion IsZero(this .<> source) { } } + public static class TimeSpanEqualsAssertionExtensions + { + [.(2)] + public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } + } public sealed class TimeSpan_IsNegative_Assertion : .<> { public TimeSpan_IsNegative_Assertion(.<> context) { } diff --git a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.Net4_7.verified.txt b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.Net4_7.verified.txt index 2a24fafdb3..44c52a7960 100644 --- a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.Net4_7.verified.txt +++ b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.Net4_7.verified.txt @@ -151,6 +151,7 @@ namespace .Attributes public AssertionExtensionAttribute(string methodName) { } public string MethodName { get; } public string? NegatedMethodName { get; set; } + public int OverloadResolutionPriority { get; set; } } [(.Class, AllowMultiple=true, Inherited=false)] public class AssertionFromAttribute : @@ -514,6 +515,7 @@ namespace .Conditions [.(ExpectationMessage="to be UTC")] public static bool IsUtc(this value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class DateTimeEqualsAssertion : .<> { public DateTimeEqualsAssertion(.<> context, expected) { } @@ -555,6 +557,7 @@ namespace .Conditions [.(ExpectationMessage="to be UTC")] public static bool IsUtc(this value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class DateTimeOffsetEqualsAssertion : .<> { public DateTimeOffsetEqualsAssertion(.<> context, expected) { } @@ -618,6 +621,7 @@ namespace .Conditions [.(ExpectationMessage="to be a system directory")] public static bool IsSystemDirectory(this .DirectoryInfo value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class DoubleEqualsAssertion : . { public DoubleEqualsAssertion(. context, double expected) { } @@ -642,16 +646,18 @@ namespace .Conditions [.(ExpectationMessage="to be Unicode encoding")] public static bool IsUnicode(this .Encoding value) { } } + [.("IsEqualTo")] public class EqualsAssertion : . { - public EqualsAssertion(. context, TValue? expected, .? comparer = null) { } + public EqualsAssertion(. context, TValue? expected) { } + public EqualsAssertion(. context, TValue? expected, . comparer) { } public TValue Expected { get; } protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } public . IgnoringType( type) { } public . IgnoringType() { } - public . Within(object tolerance) { } } + [.("IsEquatableTo")] public class EquatableAssertion : . where TActual : { @@ -761,6 +767,7 @@ namespace .Conditions protected override .<.> CheckAsync(.<.FileInfo> metadata) { } protected override string GetExpectation() { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class FloatEqualsAssertion : . { public FloatEqualsAssertion(. context, float expected) { } @@ -852,6 +859,14 @@ namespace .Conditions [.<.IPAddress>("IsIPv6Teredo", CustomName="IsNotIPv6Teredo", ExpectationMessage="be an IPv6 Teredo address", NegateLogic=true)] [.<.IPAddress>("IsIPv6Teredo", ExpectationMessage="be an IPv6 Teredo address")] public static class IPAddressAssertionExtensions { } + [.("IsEqualTo", OverloadResolutionPriority=2)] + public class IntEqualsAssertion : . + { + public IntEqualsAssertion(. context, int expected) { } + protected override .<.> CheckAsync(. metadata) { } + protected override string GetExpectation() { } + public . Within(int tolerance) { } + } [.("IsAssignableTo")] public class IsAssignableToAssertion : . { @@ -941,6 +956,7 @@ namespace .Conditions protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class LongEqualsAssertion : . { public LongEqualsAssertion(. context, long expected) { } @@ -1008,6 +1024,7 @@ namespace .Conditions protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } } + [.("IsEquatableTo")] public class NullableEquatableAssertion : . where TActual : struct, { @@ -1105,6 +1122,7 @@ namespace .Conditions public . IgnoringCase() { } public . WithComparison( comparison) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] public class StringEqualsAssertion : . { public StringEqualsAssertion(. context, string? expected) { } @@ -1238,6 +1256,14 @@ namespace .Conditions [.(ExpectationMessage="to be zero")] public static bool IsZero(this value) { } } + [.("IsEqualTo", OverloadResolutionPriority=2)] + public class TimeSpanEqualsAssertion : .<> + { + public TimeSpanEqualsAssertion(.<> context, expected) { } + protected override .<.> CheckAsync(.<> metadata) { } + protected override string GetExpectation() { } + public . Within( tolerance) { } + } [.<>("SupportsDaylightSavingTime", CustomName="DoesNotSupportDaylightSavingTime", ExpectationMessage="support daylight saving time", NegateLogic=true)] [.<>("SupportsDaylightSavingTime", ExpectationMessage="support daylight saving time")] public static class TimeZoneInfoAssertionExtensions { } @@ -1616,20 +1642,7 @@ namespace .Extensions where TEnum : struct, { } public static . IsEmpty(this . source) where TValue : .IEnumerable { } - public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - public static .<> IsEqualTo(this .<> source, expected, [.("expected")] string? expression = null) { } - public static . IsEqualTo(this . source, double expected, [.("expected")] string? expression = null) { } - public static . IsEqualTo(this . source, float expected, [.("expected")] string? expression = null) { } - public static . IsEqualTo(this . source, int expected, [.("expected")] string? expression = null) { } - public static . IsEqualTo(this . source, long expected, [.("expected")] string? expression = null) { } - public static . IsEqualTo(this . source, string? expected, [.("expected")] string? expression = null) { } public static . IsEqualTo(this . source, string? expected, comparison, [.("expected")] string? expression = null) { } - public static . IsEqualTo(this . source, TValue? expected, [.("expected")] string? expression = null) { } - public static . IsEqualTo(this . source, TExpected expected, [.("expected")] string? expression = null) - where TActual : struct, { } - public static . IsEqualTo(this . source, TExpected expected, [.("expected")] string? expression = null) - where TActual : struct, { } public static . IsEquivalentTo(this . source, object? expected, [.("expected")] string? expression = null) { } public static . IsEquivalentTo(this . source, . expected, [.("expected")] string? expression = null) where TCollection : . { } @@ -1975,6 +1988,10 @@ namespace .Extensions public static ._IsToday_Assertion IsToday(this .<> source) { } public static ._IsUtc_Assertion IsUtc(this .<> source) { } } + public static class DateTimeEqualsAssertionExtensions + { + public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } + } public static class DateTimeEqualsExactAssertionExtensions { public static . EqualsExact(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } @@ -2000,6 +2017,10 @@ namespace .Extensions public static ._IsToday_Assertion IsToday(this .<> source) { } public static ._IsUtc_Assertion IsUtc(this .<> source) { } } + public static class DateTimeOffsetEqualsAssertionExtensions + { + public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } + } public sealed class DateTimeOffset_IsInFutureUtc_Assertion : .<> { public DateTimeOffset_IsInFutureUtc_Assertion(.<> context) { } @@ -2243,6 +2264,10 @@ namespace .Extensions protected override .<.> CheckAsync(.<.DirectoryInfo> metadata) { } protected override string GetExpectation() { } } + public static class DoubleEqualsAssertionExtensions + { + public static . IsEqualTo(this . source, double expected, [.("expected")] string? expectedExpression = null) { } + } public static class EncodingAssertionExtensions { public static ._IsASCII_Assertion IsASCII(this .<.Encoding> source) { } @@ -2296,6 +2321,16 @@ namespace .Extensions protected override .<.> CheckAsync(.<.Encoding> metadata) { } protected override string GetExpectation() { } } + public static class EqualsAssertionExtensions + { + public static . IsEqualTo(this . source, TValue? expected, [.("expected")] string? expectedExpression = null) { } + public static . IsEqualTo(this . source, TValue? expected, . comparer, [.("expected")] string? expectedExpression = null, [.("comparer")] string? comparerExpression = null) { } + } + public static class EquatableAssertionExtensions + { + public static . IsEquatableTo(this . source, TExpected expected, [.("expected")] string? expectedExpression = null) + where TActual : { } + } public static class ExceptionAssertionExtensions { public static ._HasHelpLink_Assertion HasHelpLink(this .<> source) { } @@ -2452,6 +2487,10 @@ namespace .Extensions { public static . IsNotSystem(this .<.FileInfo> source) { } } + public static class FloatEqualsAssertionExtensions + { + public static . IsEqualTo(this . source, float expected, [.("expected")] string? expectedExpression = null) { } + } public static class GreaterThanAssertionExtensions { public static . IsGreaterThan(this . source, TValue minimum, [.("minimum")] string? minimumExpression = null) @@ -2586,6 +2625,10 @@ namespace .Extensions protected override .<.> CheckAsync(.<.IPAddress> metadata) { } protected override string GetExpectation() { } } + public static class IntEqualsAssertionExtensions + { + public static . IsEqualTo(this . source, int expected, [.("expected")] string? expectedExpression = null) { } + } public static class IsAssignableToAssertionExtensions { public static . IsAssignableTo(this . source) { } @@ -2641,6 +2684,10 @@ namespace .Extensions public static . IsLessThanOrEqualTo(this . source, TValue maximum, [.("maximum")] string? maximumExpression = null) where TValue : { } } + public static class LongEqualsAssertionExtensions + { + public static . IsEqualTo(this . source, long expected, [.("expected")] string? expectedExpression = null) { } + } public static class NotEqualsAssertionExtensions { public static . IsNotEqualTo(this . source, TValue notExpected, .? comparer = null, [.("notExpected")] string? notExpectedExpression = null, [.("comparer")] string? comparerExpression = null) { } @@ -2657,6 +2704,11 @@ namespace .Extensions { public static . IsNull(this . source) { } } + public static class NullableEquatableAssertionExtensions + { + public static . IsEquatableTo(this . source, TExpected expected, [.("expected")] string? expectedExpression = null) + where TActual : struct, { } + } public static class ProcessAssertionExtensions { public static . DoesNotHaveEventRaisingEnabled(this .<.Process> source) { } @@ -2795,6 +2847,10 @@ namespace .Extensions public static . EndsWith(this . source, string expected, [.("expected")] string? expectedExpression = null) { } public static . EndsWith(this . source, string expected, comparison, [.("expected")] string? expectedExpression = null, [.("comparison")] string? comparisonExpression = null) { } } + public static class StringEqualsAssertionExtensions + { + public static . IsEqualTo(this . source, string? expected, [.("expected")] string? expectedExpression = null) { } + } public static class StringIsEmptyAssertionExtensions { public static . IsEmpty(this . source) { } @@ -2903,6 +2959,10 @@ namespace .Extensions public static ._IsPositive_Assertion IsPositive(this .<> source) { } public static ._IsZero_Assertion IsZero(this .<> source) { } } + public static class TimeSpanEqualsAssertionExtensions + { + public static . IsEqualTo(this .<> source, expected, [.("expected")] string? expectedExpression = null) { } + } public sealed class TimeSpan_IsNegative_Assertion : .<> { public TimeSpan_IsNegative_Assertion(.<> context) { }