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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .nuget/Cuemon.Extensions.Core/PackageReleaseNotes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Availability: .NET 9, .NET 8 and .NET Standard 2.0
- ADDED FuncFactory class in the Cuemon.Extensions namespace that provides access to factory methods for creating FuncFactory{TTuple, TResult} objects that encapsulate a function delegate with a variable amount of generic arguments
- ADDED MutableTupleFactory class in the Cuemon.Extensions namespace that provides access to factory methods for creating MutableTuple objects
- ADDED TesterFuncFactory class in the Cuemon.Extensions namespace that provides access to factory methods for creating TesterFuncFactory{TTuple, TResult, TSuccess} objects that encapsulate a tester function delegate with a variable amount of generic arguments
- ADDED AsyncDisposable class in the Cuemon.Extensions namespace that provides a mechanism for asynchronously releasing both managed and unmanaged resources with focus on the former

Version 8.3.2
Availability: .NET 8, .NET 6 and .NET Standard 2.0
Expand Down
2 changes: 1 addition & 1 deletion .nuget/Cuemon.Extensions.Text.Json/PackageReleaseNotes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Availability: .NET 9, .NET 8 and .NET Standard 2.0

# Bug Fixes
- FIXED ExceptionConverter class in the Cuemon.Extensions.Text.Json.Converters namespace to use JsonSerializerOptions when converting JSON to Exception
- FIXED the JSON converter that converts a Failure to JSON so it uses the actual key-value from the Data property of an exception instead of always writing key
- FIXED the JSON converter in the Cuemon.Extensions.Text.Json.Converters namespace that converts a Failure to JSON so it uses the actual key-value from the Data property of an exception instead of always writing key

Version 8.3.2
Availability: .NET 8 and .NET 6
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Highlighted features included in this release:
- FuncFactory class in the Cuemon.Extensions namespace that provides access to factory methods for creating FuncFactory{TTuple, TResult} objects that encapsulate a function delegate with a variable amount of generic arguments
- MutableTupleFactory class in the Cuemon.Extensions namespace that provides access to factory methods for creating MutableTuple objects
- TesterFuncFactory class in the Cuemon.Extensions namespace that provides access to factory methods for creating TesterFuncFactory{TTuple, TResult, TSuccess} objects that encapsulate a tester function delegate with a variable amount of generic arguments
- AsyncDisposable class in the Cuemon.Extensions namespace that provides a mechanism for asynchronously releasing both managed and unmanaged resources with focus on the former

### Changed

Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
</ItemGroup>

<ItemGroup Condition="'$(IsTestProject)' == 'true'">
<PackageReference Include="Codebelt.Extensions.Xunit" Version="9.0.0-preview.10" />
<PackageReference Include="Codebelt.Extensions.Xunit" Version="9.0.0-preview.11" />
</ItemGroup>

</Project>
1 change: 0 additions & 1 deletion src/Cuemon.Core/Disposable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ namespace Cuemon
{
/// <summary>
/// Provides a mechanism for releasing both managed and unmanaged resources with focus on the former.
/// Implements the <see cref="IDisposable" />
/// </summary>
/// <seealso cref="IDisposable" />
public abstract class Disposable : IDisposable
Expand Down
2 changes: 1 addition & 1 deletion src/Cuemon.Core/FinalizeDisposable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ protected override void OnDisposeManagedResources()
/// </summary>
protected abstract override void OnDisposeUnmanagedResources();
}
}
}
38 changes: 38 additions & 0 deletions src/Cuemon.Extensions.Core/AsyncDisposable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System;
using System.Threading.Tasks;

namespace Cuemon.Extensions
{
/// <summary>
/// Provides a mechanism for asynchronously releasing both managed and unmanaged resources with focus on the former.
/// </summary>
/// <seealso cref="Disposable" />
/// <seealso cref="IAsyncDisposable" />
public abstract class AsyncDisposable : Disposable, IAsyncDisposable
{
/// <summary>
/// Called when this object is being disposed by either <see cref="Disposable.Dispose()"/> or <see cref="Disposable.Dispose(bool)"/> having <c>disposing</c> set to <c>true</c> and <see cref="Disposable.Disposed"/> is <c>false</c>.
/// </summary>
/// <remarks>You should almost never override this - unless you want to call it from <see cref="OnDisposeManagedResourcesAsync"/>.</remarks>
protected override void OnDisposeManagedResources()
{
}

/// <summary>
/// Called when this object is being disposed by <see cref="DisposeAsync()"/>.
/// </summary>
protected abstract ValueTask OnDisposeManagedResourcesAsync();

/// <summary>
/// Asynchronously releases the resources used by the <see cref="AsyncDisposable"/>.
/// </summary>
/// <returns>A <see cref="ValueTask"/> that represents the asynchronous dispose operation.</returns>
/// <remarks>https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-disposeasync#the-disposeasync-method</remarks>
public async ValueTask DisposeAsync()
{
await OnDisposeManagedResourcesAsync().ConfigureAwait(false);
Dispose(false);
GC.SuppressFinalize(this);
}
}
}
7 changes: 6 additions & 1 deletion src/Cuemon.Extensions.Core/Cuemon.Extensions.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,13 @@
<PackageTags>extension-methods extensions to-byte-array flatten to-encoded-string configure create-instance action-delegate options-pattern</PackageTags>
</PropertyGroup>

<ItemGroup Condition="$(TargetFramework.StartsWith('netstandard2'))">
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Cuemon.Core\Cuemon.Core.csproj" />
</ItemGroup>

</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.10" />
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.11" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<ItemGroup>
<PackageReference Include="Meziantou.Xunit.ParallelTestFramework" Version="2.3.0" />
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.10" />
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.11" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<ItemGroup>
<PackageReference Include="Meziantou.Xunit.ParallelTestFramework" Version="2.3.0" />
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.10" />
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.11" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.10" />
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.11" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.10" />
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.11" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.10" />
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.11" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting" Version="9.0.0-preview.10" />
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting" Version="9.0.0-preview.11" />
</ItemGroup>

</Project>
2 changes: 1 addition & 1 deletion test/Cuemon.Data.Tests/Cuemon.Data.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting" Version="9.0.0-preview.10" />
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting" Version="9.0.0-preview.11" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.10" />
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.11" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.10" />
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.11" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.10" />
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.11" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.10" />
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.11" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.10" />
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.11" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.10" />
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting.AspNetCore" Version="9.0.0-preview.11" />
</ItemGroup>

</Project>
88 changes: 88 additions & 0 deletions test/Cuemon.Extensions.Core.Tests/AsyncDisposableTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System.Diagnostics;
using System.Threading.Tasks;
using Codebelt.Extensions.Xunit;
using Xunit;
using Xunit.Abstractions;

namespace Cuemon.Extensions
{
public class AsyncDisposableTest : Test
{
public AsyncDisposableTest(ITestOutputHelper output) : base(output)
{
}

private class TestAsyncDisposable : AsyncDisposable
{
public bool ManagedResourcesDisposed { get; private set; }

public bool IsAsyncOperationCompleted { get; private set; }

public bool UnmanagedResourcesDisposed { get; private set; }

protected override ValueTask OnDisposeManagedResourcesAsync()
{
ManagedResourcesDisposed = true;
return new ValueTask(Task.Run(async () =>
{
await Task.Delay(100); // Simulate async work
IsAsyncOperationCompleted = true;
}));
}

protected override void OnDisposeUnmanagedResources()
{
UnmanagedResourcesDisposed = true;
}
}

[Fact]
public async Task DisposeAsync_ShouldCallOnDisposeManagedResourcesAsync()
{
// Arrange
var disposable = new TestAsyncDisposable();

// Act
await disposable.DisposeAsync();

// Assert
Assert.True(disposable.ManagedResourcesDisposed);
}

[Fact]
public async Task DisposeAsync_ShouldSuppressFinalize()
{
// Arrange
var disposable = new TestAsyncDisposable();

// Act
await disposable.DisposeAsync();

// Assert
Assert.True(disposable.Disposed);
}
Comment on lines +39 to +63
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add more comprehensive async disposal tests.

While the current tests cover basic scenarios, consider adding:

  1. Theory tests with different disposal scenarios
  2. Verification of async context
  3. Order of disposal operations

Here's a suggested additional test:

[Theory]
[InlineData(100)]  // Fast disposal
[InlineData(1000)] // Slower disposal
public async Task DisposeAsync_ShouldHandleVariousAsyncScenarios(int delayMs)
{
    // Arrange
    var disposable = new TestAsyncDisposable();
    var sw = Stopwatch.StartNew();

    // Act
    await using (disposable)
    {
        await Task.Delay(delayMs);
    }

    // Assert
    Assert.True(disposable.ManagedResourcesDisposed);
    Assert.True(disposable.IsAsyncOperationCompleted);
    Assert.True(sw.ElapsedMilliseconds >= delayMs);
}


[Theory]
[InlineData(100)] // Fast disposal
[InlineData(1000)] // Slower disposal
public async Task DisposeAsync_ShouldHandleVariousAsyncScenarios(int delayMs)
{
// Arrange
var disposable = new TestAsyncDisposable();
var sw = Stopwatch.StartNew();

// Act
await using (disposable)
{
await Task.Delay(delayMs);
}

sw.Stop();

// Assert
Assert.True(disposable.ManagedResourcesDisposed);
Assert.True(disposable.IsAsyncOperationCompleted);
Assert.True(sw.ElapsedMilliseconds >= delayMs);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting" Version="9.0.0-preview.10" />
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting" Version="9.0.0-preview.11" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting" Version="9.0.0-preview.10" />
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting" Version="9.0.0-preview.11" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting" Version="9.0.0-preview.10" />
<PackageReference Include="Codebelt.Extensions.Xunit.Hosting" Version="9.0.0-preview.11" />
</ItemGroup>

</Project>