Skip to content

Commit

Permalink
Fixed a regression in which CompleteWithinAsync treated a canceled ta…
Browse files Browse the repository at this point in the history
…sk as an exception.
  • Loading branch information
dennisdoomen committed Nov 28, 2024
1 parent 4647b6f commit 9004c96
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 7 deletions.
15 changes: 9 additions & 6 deletions Src/FluentAssertions/Specialized/AsyncFunctionAssertions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public async Task<AndConstraint<TAssertions>> CompleteWithinAsync(

if (success)
{
bool completesWithinTimeout = await CompletesWithinTimeoutAsync(task, remainingTime);
bool completesWithinTimeout = await CompletesWithinTimeoutAsync(task, remainingTime, _ => Task.CompletedTask);

Execute.Assertion
.ForCondition(completesWithinTimeout)
Expand Down Expand Up @@ -97,7 +97,7 @@ public async Task<AndConstraint<TAssertions>> NotCompleteWithinAsync(

if (remainingTime >= TimeSpan.Zero)
{
bool completesWithinTimeout = await CompletesWithinTimeoutAsync(task, remainingTime);
bool completesWithinTimeout = await CompletesWithinTimeoutAsync(task, remainingTime, _ => Task.CompletedTask);

Execute.Assertion
.ForCondition(!completesWithinTimeout)
Expand Down Expand Up @@ -271,7 +271,11 @@ private async Task<Exception> InvokeWithInterceptionAsync(TimeSpan timeout)
// Here we do not need to know whether the task completes (successfully) in timeout
// or does not complete. We are only interested in the exception which is thrown, not returned.
// So, we can ignore the result.
_ = await CompletesWithinTimeoutAsync(task, remainingTime);
_ = await CompletesWithinTimeoutAsync(task, remainingTime, async cancelledTask =>
{
// Rethrow the exception causing the task be canceled.
await cancelledTask;
});
}

return null;
Expand Down Expand Up @@ -431,7 +435,7 @@ private protected (TTask result, TimeSpan remainingTime) InvokeWithTimer(TimeSpa
/// <summary>
/// Monitors the specified task whether it completes withing the remaining time span.
/// </summary>
private protected async Task<bool> CompletesWithinTimeoutAsync(Task target, TimeSpan remainingTime)
private protected async Task<bool> CompletesWithinTimeoutAsync(Task target, TimeSpan remainingTime, Func<Task, Task> onTaskCanceled)
{
using var delayCancellationTokenSource = new CancellationTokenSource();

Expand All @@ -452,8 +456,7 @@ private protected async Task<bool> CompletesWithinTimeoutAsync(Task target, Time

if (target.IsCanceled)
{
// Rethrow the exception causing the task be canceled.
await target;
await onTaskCanceled(target);
}

// The monitored task is completed, we shall cancel the clock.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public GenericAsyncFunctionAssertions(Func<Task<TResult>> subject, IExtractExcep

if (success)
{
bool completesWithinTimeout = await CompletesWithinTimeoutAsync(task, remainingTime);
bool completesWithinTimeout = await CompletesWithinTimeoutAsync(task, remainingTime, _ => Task.CompletedTask);

success = Execute.Assertion
.ForCondition(completesWithinTimeout)
Expand Down
20 changes: 20 additions & 0 deletions Tests/FluentAssertions.Specs/Specialized/TaskAssertionSpecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,26 @@ public async Task When_task_completes_late_it_should_fail()
// Assert
await action.Should().ThrowAsync<XunitException>();
}

[Fact]
public async Task Cancelling_a_token_also_means_the_task_is_completed()
{
// Arrange
var timer = new FakeClock();
var taskFactory = new TaskCompletionSource<bool>();

// Act
Func<Task> action = () => taskFactory
.Awaiting(t => (Task)t.Task)
.Should(timer)
.CompleteWithinAsync(100.Milliseconds());

taskFactory.SetCanceled();
timer.Complete();

// Assert
await action.Should().NotThrowAsync();
}
}

public class NotCompleteWithinAsync
Expand Down
4 changes: 4 additions & 0 deletions docs/_pages/releases.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ sidebar:

## 7.0.0

### Fixes

* Fixed a regression in which `CompleteWithinAsync` treated a canceled task as an exception - [#9999](https://github.com/fluentassertions/fluentassertions/pull/9999)

### Breaking Changes

* Dropped direct support for .NET Core 2.x and .NET Core 3.x - [#2302](https://github.com/fluentassertions/fluentassertions/pull/2302)
Expand Down

0 comments on commit 9004c96

Please sign in to comment.