From 25e76eecc21ec34b8875b93afe4e7414452031b9 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Wed, 15 Oct 2025 18:05:22 +0100 Subject: [PATCH 1/2] fix: update assertion methods to accept nullable types for improved flexibility --- .../Conditions/StringEqualsAssertion.cs | 4 ++-- TUnit.Assertions/Extensions/Assert.cs | 6 +++--- .../Extensions/AssertionExtensions.cs | 4 ++-- .../Sources/AsyncFuncAssertion.cs | 2 +- TUnit.Assertions/Sources/FuncAssertion.cs | 2 +- TUnit.Assertions/Sources/TaskAssertion.cs | 15 +++++++------- ...Has_No_API_Changes.DotNet10_0.verified.txt | 20 +++++++++---------- ..._Has_No_API_Changes.DotNet8_0.verified.txt | 20 +++++++++---------- ..._Has_No_API_Changes.DotNet9_0.verified.txt | 20 +++++++++---------- ...ary_Has_No_API_Changes.Net4_7.verified.txt | 20 +++++++++---------- 10 files changed, 57 insertions(+), 56 deletions(-) diff --git a/TUnit.Assertions/Conditions/StringEqualsAssertion.cs b/TUnit.Assertions/Conditions/StringEqualsAssertion.cs index 03a02ec21e..50f39ae81a 100644 --- a/TUnit.Assertions/Conditions/StringEqualsAssertion.cs +++ b/TUnit.Assertions/Conditions/StringEqualsAssertion.cs @@ -9,7 +9,7 @@ namespace TUnit.Assertions.Conditions; /// public class StringEqualsAssertion : Assertion { - private readonly string _expected; + private readonly string? _expected; private StringComparison _comparison = StringComparison.Ordinal; private bool _trimming = false; private bool _nullAndEmptyEquality = false; @@ -17,7 +17,7 @@ public class StringEqualsAssertion : Assertion public StringEqualsAssertion( AssertionContext context, - string expected) + string? expected) : base(context) { _expected = expected; diff --git a/TUnit.Assertions/Extensions/Assert.cs b/TUnit.Assertions/Extensions/Assert.cs index b53a4e6bd1..afa8c7c06e 100644 --- a/TUnit.Assertions/Extensions/Assert.cs +++ b/TUnit.Assertions/Extensions/Assert.cs @@ -127,7 +127,7 @@ public static ValueAssertion That( /// Example: await Assert.That(() => GetValue()).IsGreaterThan(10); /// public static FuncAssertion That( - Func func, + Func func, [CallerArgumentExpression(nameof(func))] string? expression = null) { return new FuncAssertion(func, expression); @@ -138,7 +138,7 @@ public static FuncAssertion That( /// Example: await Assert.That(async () => await GetValueAsync()).IsEqualTo(expected); /// public static AsyncFuncAssertion That( - Func> func, + Func> func, [CallerArgumentExpression(nameof(func))] string? expression = null) { return new AsyncFuncAssertion(func, expression); @@ -151,7 +151,7 @@ public static AsyncFuncAssertion That( /// Example: await Assert.That(GetValueAsync()).IsCompleted(); /// public static TaskAssertion That( - Task task, + Task task, [CallerArgumentExpression(nameof(task))] string? expression = null) { return new TaskAssertion(task, expression); diff --git a/TUnit.Assertions/Extensions/AssertionExtensions.cs b/TUnit.Assertions/Extensions/AssertionExtensions.cs index a845e9a273..908fa9dc9f 100644 --- a/TUnit.Assertions/Extensions/AssertionExtensions.cs +++ b/TUnit.Assertions/Extensions/AssertionExtensions.cs @@ -76,7 +76,7 @@ public static DateTimeEqualsAssertion IsEqualTo( [OverloadResolutionPriority(2)] public static StringEqualsAssertion IsEqualTo( this IAssertionSource source, - string expected, + string? expected, [CallerArgumentExpression(nameof(expected))] string? expression = null) { source.Context.ExpressionBuilder.Append($".IsEqualTo({expression})"); @@ -88,7 +88,7 @@ public static StringEqualsAssertion IsEqualTo( /// public static StringEqualsAssertion IsEqualTo( this IAssertionSource source, - string expected, + string? expected, StringComparison comparison, [CallerArgumentExpression(nameof(expected))] string? expression = null) { diff --git a/TUnit.Assertions/Sources/AsyncFuncAssertion.cs b/TUnit.Assertions/Sources/AsyncFuncAssertion.cs index 23b1353176..fe5db4f47a 100644 --- a/TUnit.Assertions/Sources/AsyncFuncAssertion.cs +++ b/TUnit.Assertions/Sources/AsyncFuncAssertion.cs @@ -14,7 +14,7 @@ public class AsyncFuncAssertion : IAssertionSource, IDelegateAss { public AssertionContext Context { get; } - public AsyncFuncAssertion(Func> func, string? expression) + public AsyncFuncAssertion(Func> func, string? expression) { var expressionBuilder = new StringBuilder(); expressionBuilder.Append($"Assert.That({expression ?? "?"})"); diff --git a/TUnit.Assertions/Sources/FuncAssertion.cs b/TUnit.Assertions/Sources/FuncAssertion.cs index c62bbf9df4..83f961e36a 100644 --- a/TUnit.Assertions/Sources/FuncAssertion.cs +++ b/TUnit.Assertions/Sources/FuncAssertion.cs @@ -14,7 +14,7 @@ public class FuncAssertion : IAssertionSource, IDelegateAssertio { public AssertionContext Context { get; } - public FuncAssertion(Func func, string? expression) + public FuncAssertion(Func func, string? expression) { var expressionBuilder = new StringBuilder(); expressionBuilder.Append($"Assert.That({expression ?? "?"})"); diff --git a/TUnit.Assertions/Sources/TaskAssertion.cs b/TUnit.Assertions/Sources/TaskAssertion.cs index 2249b5309f..88507253ef 100644 --- a/TUnit.Assertions/Sources/TaskAssertion.cs +++ b/TUnit.Assertions/Sources/TaskAssertion.cs @@ -12,14 +12,14 @@ namespace TUnit.Assertions.Sources; /// Implements IDelegateAssertionSource to enable Throws() extension methods. /// Does not inherit from Assertion to prevent premature awaiting. /// -public class TaskAssertion : IAssertionSource, IDelegateAssertionSource, IAssertionSource> +public class TaskAssertion : IAssertionSource, IDelegateAssertionSource, IAssertionSource> { public AssertionContext Context { get; } - AssertionContext> IAssertionSource>.Context => TaskContext; + AssertionContext> IAssertionSource>.Context => TaskContext; - private AssertionContext> TaskContext { get; } + private AssertionContext> TaskContext { get; } - public TaskAssertion(Task task, string? expression) + public TaskAssertion(Task task, string? expression) { var expressionBuilder = new StringBuilder(); expressionBuilder.Append($"Assert.That({expression ?? "?"})"); @@ -43,13 +43,14 @@ public TaskAssertion(Task task, string? expression) // DO NOT await the task here - we want to check its state synchronously var taskExpressionBuilder = new StringBuilder(); taskExpressionBuilder.Append(expressionBuilder.ToString()); - var taskEvaluationContext = new EvaluationContext>(() => + var taskEvaluationContext = new EvaluationContext>(() => { // Return the task object itself without awaiting it // This allows IsCompleted, IsCanceled, IsFaulted, etc. to check task properties synchronously - return Task.FromResult<(Task?, Exception?)>((task, null)); + return Task.FromResult<(Task?, Exception?)>((task, null)); }); - TaskContext = new AssertionContext>(taskEvaluationContext, taskExpressionBuilder); + + TaskContext = new AssertionContext>(taskEvaluationContext, taskExpressionBuilder); } /// 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 6dc804c66b..3fd7308b08 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 @@ -11,9 +11,9 @@ namespace public static . That(. task, [.("task")] string? expression = null) { } public static . That(.? value, [.("value")] string? expression = null) { } public static . That(.? value, [.("value")] string? expression = null) { } - public static . That(<.> func, [.("func")] string? expression = null) { } - public static . That( func, [.("func")] string? expression = null) { } - public static . That(. task, [.("task")] string? expression = null) { } + public static . That(<.> func, [.("func")] string? expression = null) { } + public static . That( func, [.("func")] string? expression = null) { } + public static . That(. task, [.("task")] string? expression = null) { } public static . That(TItem[]? value, [.("value")] string? expression = null) { } public static . That(TValue? value, [.("value")] string? expression = null) { } public static . That(. value, [.("value")] string? expression = null) @@ -1134,7 +1134,7 @@ namespace .Conditions } public class StringEqualsAssertion : . { - public StringEqualsAssertion(. context, string expected) { } + public StringEqualsAssertion(. context, string? expected) { } protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } public . IgnoringCase() { } @@ -1681,8 +1681,8 @@ namespace .Extensions [.(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) { } + 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)] @@ -3534,7 +3534,7 @@ namespace .Sources } public class AsyncFuncAssertion : ., . { - public AsyncFuncAssertion(<.> func, string? expression) { } + public AsyncFuncAssertion(<.> func, string? expression) { } public . Context { get; } public . Throws() where TException : { } @@ -3558,16 +3558,16 @@ namespace .Sources } public class FuncAssertion : ., . { - public FuncAssertion( func, string? expression) { } + public FuncAssertion( func, string? expression) { } public . Context { get; } public . Throws() where TException : { } public . ThrowsExactly() where TException : { } } - public class TaskAssertion : .<.>, ., . + public class TaskAssertion : .<.>, ., . { - public TaskAssertion(. task, string? expression) { } + public TaskAssertion(. task, string? expression) { } public . Context { get; } public .<.> IsCanceled() { } public .<.> IsCompleted() { } 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 5dd524912a..4edd515145 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 @@ -11,9 +11,9 @@ namespace public static . That(. task, [.("task")] string? expression = null) { } public static . That(.? value, [.("value")] string? expression = null) { } public static . That(.? value, [.("value")] string? expression = null) { } - public static . That(<.> func, [.("func")] string? expression = null) { } - public static . That( func, [.("func")] string? expression = null) { } - public static . That(. task, [.("task")] string? expression = null) { } + public static . That(<.> func, [.("func")] string? expression = null) { } + public static . That( func, [.("func")] string? expression = null) { } + public static . That(. task, [.("task")] string? expression = null) { } public static . That(TItem[]? value, [.("value")] string? expression = null) { } public static . That(TValue? value, [.("value")] string? expression = null) { } public static . That(. value, [.("value")] string? expression = null) @@ -1134,7 +1134,7 @@ namespace .Conditions } public class StringEqualsAssertion : . { - public StringEqualsAssertion(. context, string expected) { } + public StringEqualsAssertion(. context, string? expected) { } protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } public . IgnoringCase() { } @@ -1672,8 +1672,8 @@ namespace .Extensions public static . IsEqualTo(this . source, double 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, 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, { } @@ -3522,7 +3522,7 @@ namespace .Sources } public class AsyncFuncAssertion : ., . { - public AsyncFuncAssertion(<.> func, string? expression) { } + public AsyncFuncAssertion(<.> func, string? expression) { } public . Context { get; } public . Throws() where TException : { } @@ -3546,16 +3546,16 @@ namespace .Sources } public class FuncAssertion : ., . { - public FuncAssertion( func, string? expression) { } + public FuncAssertion( func, string? expression) { } public . Context { get; } public . Throws() where TException : { } public . ThrowsExactly() where TException : { } } - public class TaskAssertion : .<.>, ., . + public class TaskAssertion : .<.>, ., . { - public TaskAssertion(. task, string? expression) { } + public TaskAssertion(. task, string? expression) { } public . Context { get; } public .<.> IsCanceled() { } public .<.> IsCompleted() { } 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 c1e61d2657..cf3bec615d 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 @@ -11,9 +11,9 @@ namespace public static . That(. task, [.("task")] string? expression = null) { } public static . That(.? value, [.("value")] string? expression = null) { } public static . That(.? value, [.("value")] string? expression = null) { } - public static . That(<.> func, [.("func")] string? expression = null) { } - public static . That( func, [.("func")] string? expression = null) { } - public static . That(. task, [.("task")] string? expression = null) { } + public static . That(<.> func, [.("func")] string? expression = null) { } + public static . That( func, [.("func")] string? expression = null) { } + public static . That(. task, [.("task")] string? expression = null) { } public static . That(TItem[]? value, [.("value")] string? expression = null) { } public static . That(TValue? value, [.("value")] string? expression = null) { } public static . That(. value, [.("value")] string? expression = null) @@ -1134,7 +1134,7 @@ namespace .Conditions } public class StringEqualsAssertion : . { - public StringEqualsAssertion(. context, string expected) { } + public StringEqualsAssertion(. context, string? expected) { } protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } public . IgnoringCase() { } @@ -1681,8 +1681,8 @@ namespace .Extensions [.(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) { } + 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)] @@ -3534,7 +3534,7 @@ namespace .Sources } public class AsyncFuncAssertion : ., . { - public AsyncFuncAssertion(<.> func, string? expression) { } + public AsyncFuncAssertion(<.> func, string? expression) { } public . Context { get; } public . Throws() where TException : { } @@ -3558,16 +3558,16 @@ namespace .Sources } public class FuncAssertion : ., . { - public FuncAssertion( func, string? expression) { } + public FuncAssertion( func, string? expression) { } public . Context { get; } public . Throws() where TException : { } public . ThrowsExactly() where TException : { } } - public class TaskAssertion : .<.>, ., . + public class TaskAssertion : .<.>, ., . { - public TaskAssertion(. task, string? expression) { } + public TaskAssertion(. task, string? expression) { } public . Context { get; } public .<.> IsCanceled() { } public .<.> IsCompleted() { } 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 e0d1430edd..789796c1e0 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 @@ -11,9 +11,9 @@ namespace public static . That(. task, [.("task")] string? expression = null) { } public static . That(.? value, [.("value")] string? expression = null) { } public static . That(.? value, [.("value")] string? expression = null) { } - public static . That(<.> func, [.("func")] string? expression = null) { } - public static . That( func, [.("func")] string? expression = null) { } - public static . That(. task, [.("task")] string? expression = null) { } + public static . That(<.> func, [.("func")] string? expression = null) { } + public static . That( func, [.("func")] string? expression = null) { } + public static . That(. task, [.("task")] string? expression = null) { } public static . That(TItem[]? value, [.("value")] string? expression = null) { } public static . That(TValue? value, [.("value")] string? expression = null) { } public static . That(. value, [.("value")] string? expression = null) @@ -1081,7 +1081,7 @@ namespace .Conditions } public class StringEqualsAssertion : . { - public StringEqualsAssertion(. context, string expected) { } + public StringEqualsAssertion(. context, string? expected) { } protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } public . IgnoringCase() { } @@ -1575,8 +1575,8 @@ namespace .Extensions public static . IsEqualTo(this . source, double 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, 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, { } @@ -3227,7 +3227,7 @@ namespace .Sources } public class AsyncFuncAssertion : ., . { - public AsyncFuncAssertion(<.> func, string? expression) { } + public AsyncFuncAssertion(<.> func, string? expression) { } public . Context { get; } public . Throws() where TException : { } @@ -3251,16 +3251,16 @@ namespace .Sources } public class FuncAssertion : ., . { - public FuncAssertion( func, string? expression) { } + public FuncAssertion( func, string? expression) { } public . Context { get; } public . Throws() where TException : { } public . ThrowsExactly() where TException : { } } - public class TaskAssertion : .<.>, ., . + public class TaskAssertion : .<.>, ., . { - public TaskAssertion(. task, string? expression) { } + public TaskAssertion(. task, string? expression) { } public . Context { get; } public .<.> IsCanceled() { } public .<.> IsCompleted() { } From bccc2125c6c978cca0a57537ef0f23c96dc3b804 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Wed, 15 Oct 2025 18:06:09 +0100 Subject: [PATCH 2/2] refactor: remove redundant custom method comments from assertion classes --- TUnit.Assertions/Conditions/DateTimeEqualsAssertion.cs | 1 - TUnit.Assertions/Conditions/StringEqualsAssertion.cs | 5 ----- 2 files changed, 6 deletions(-) diff --git a/TUnit.Assertions/Conditions/DateTimeEqualsAssertion.cs b/TUnit.Assertions/Conditions/DateTimeEqualsAssertion.cs index f5197ec048..c4a0e2d4fb 100644 --- a/TUnit.Assertions/Conditions/DateTimeEqualsAssertion.cs +++ b/TUnit.Assertions/Conditions/DateTimeEqualsAssertion.cs @@ -21,7 +21,6 @@ public DateTimeEqualsAssertion( } /// - /// ⚡ CUSTOM METHOD - No wrapper needed! /// Specifies the acceptable tolerance for the comparison. /// public DateTimeEqualsAssertion Within(TimeSpan tolerance) diff --git a/TUnit.Assertions/Conditions/StringEqualsAssertion.cs b/TUnit.Assertions/Conditions/StringEqualsAssertion.cs index 50f39ae81a..8e72dca209 100644 --- a/TUnit.Assertions/Conditions/StringEqualsAssertion.cs +++ b/TUnit.Assertions/Conditions/StringEqualsAssertion.cs @@ -24,7 +24,6 @@ public StringEqualsAssertion( } /// - /// ⚡ CUSTOM METHOD - No wrapper needed! /// Makes the comparison case-insensitive. /// public StringEqualsAssertion IgnoringCase() @@ -35,7 +34,6 @@ public StringEqualsAssertion IgnoringCase() } /// - /// ⚡ CUSTOM METHOD - No wrapper needed! /// Specifies a custom string comparison type. /// public StringEqualsAssertion WithComparison(StringComparison comparison) @@ -46,7 +44,6 @@ public StringEqualsAssertion WithComparison(StringComparison comparison) } /// - /// ⚡ CUSTOM METHOD - No wrapper needed! /// Trims both strings before comparing. /// public StringEqualsAssertion WithTrimming() @@ -57,7 +54,6 @@ public StringEqualsAssertion WithTrimming() } /// - /// ⚡ CUSTOM METHOD - No wrapper needed! /// Treats null and empty string as equal. /// public StringEqualsAssertion WithNullAndEmptyEquality() @@ -68,7 +64,6 @@ public StringEqualsAssertion WithNullAndEmptyEquality() } /// - /// ⚡ CUSTOM METHOD - No wrapper needed! /// Removes all whitespace from both strings before comparing. /// public StringEqualsAssertion IgnoringWhitespace()