From b7d844e3707e9f14657f577fba8e4e0a17fa48fc Mon Sep 17 00:00:00 2001 From: "codebelt-aicia[bot]" Date: Wed, 20 May 2026 20:31:17 +0000 Subject: [PATCH 01/16] V11.0.10/service update --- .../PackageReleaseNotes.txt | 6 ++ .../PackageReleaseNotes.txt | 6 ++ .../PackageReleaseNotes.txt | 6 ++ .../PackageReleaseNotes.txt | 6 ++ CHANGELOG.md | 4 + Directory.Packages.props | 88 +++++++++---------- 6 files changed, 72 insertions(+), 44 deletions(-) diff --git a/.nuget/Codebelt.Extensions.Xunit.App/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Xunit.App/PackageReleaseNotes.txt index e550068..5ca77c6 100644 --- a/.nuget/Codebelt.Extensions.Xunit.App/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Xunit.App/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 11.0.10 +Availability: .NET 10 and .NET 9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 11.0.9 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/PackageReleaseNotes.txt index d8ca9ad..f40a6bb 100644 --- a/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 11.0.10 +Availability: .NET 10 and .NET 9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 11.0.9 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt index 3819706..8bc1a78 100644 --- a/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 11.0.10 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 11.0.9 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Codebelt.Extensions.Xunit/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Xunit/PackageReleaseNotes.txt index 28be718..d54e860 100644 --- a/.nuget/Codebelt.Extensions.Xunit/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Xunit/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 11.0.10 +Availability: .NET 10 and .NET 9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 11.0.9 Availability: .NET 10 and .NET 9 diff --git a/CHANGELOG.md b/CHANGELOG.md index 0705687..4610d1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ For more details, please refer to `PackageReleaseNotes.txt` on a per assembly ba > [!NOTE] > Changelog entries prior to version 8.4.0 was migrated from previous versions of Cuemon.Extensions.Xunit, Cuemon.Extensions.Xunit.Hosting, and Cuemon.Extensions.Xunit.Hosting.AspNetCore. +## [11.0.10] - 2026-05-20 + +This is a service update that focuses on package dependencies. + ## [11.0.9] - 2026-04-16 This is a service update that focuses on package dependencies. diff --git a/Directory.Packages.props b/Directory.Packages.props index 148d8e3..10bf0a2 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,45 +1,45 @@ - - - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From aafb51cbf69d8cb7237681ac78d3abff28596034 Mon Sep 17 00:00:00 2001 From: gimlichael Date: Thu, 21 May 2026 21:46:09 +0200 Subject: [PATCH 02/16] =?UTF-8?q?=F0=9F=8E=A8=20normalize=20whitespace=20a?= =?UTF-8?q?cross=20dependency=20and=20package=20metadata=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Standardized line endings and whitespace formatting across Directory.Packages.props and all PackageReleaseNotes.txt files for consistency. --- .../PackageReleaseNotes.txt | 20 ++--- .../PackageReleaseNotes.txt | 20 ++--- .../PackageReleaseNotes.txt | 20 ++--- .../PackageReleaseNotes.txt | 20 ++--- Directory.Packages.props | 88 +++++++++---------- 5 files changed, 84 insertions(+), 84 deletions(-) diff --git a/.nuget/Codebelt.Extensions.Xunit.App/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Xunit.App/PackageReleaseNotes.txt index 5ca77c6..cc50285 100644 --- a/.nuget/Codebelt.Extensions.Xunit.App/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Xunit.App/PackageReleaseNotes.txt @@ -1,15 +1,15 @@ -Version: 11.0.10 +Version: 11.0.10 Availability: .NET 10 and .NET 9 - -# ALM -- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) - -Version: 11.0.9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + +Version: 11.0.9 Availability: .NET 10 and .NET 9 - -# ALM -- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) - + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 11.0.8 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/PackageReleaseNotes.txt index f40a6bb..6f1f329 100644 --- a/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/PackageReleaseNotes.txt @@ -1,15 +1,15 @@ -Version: 11.0.10 +Version: 11.0.10 Availability: .NET 10 and .NET 9 - -# ALM -- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) - -Version: 11.0.9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + +Version: 11.0.9 Availability: .NET 10 and .NET 9 - -# ALM -- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) - + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 11.0.8 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt index 8bc1a78..0c1dcc2 100644 --- a/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Xunit.Hosting/PackageReleaseNotes.txt @@ -1,15 +1,15 @@ -Version: 11.0.10 +Version: 11.0.10 Availability: .NET 10, .NET 9 and .NET Standard 2.0 - -# ALM -- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) - -Version: 11.0.9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + +Version: 11.0.9 Availability: .NET 10, .NET 9 and .NET Standard 2.0 - -# ALM -- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) - + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 11.0.8 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Codebelt.Extensions.Xunit/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Xunit/PackageReleaseNotes.txt index d54e860..5a4e24c 100644 --- a/.nuget/Codebelt.Extensions.Xunit/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Xunit/PackageReleaseNotes.txt @@ -1,15 +1,15 @@ -Version: 11.0.10 +Version: 11.0.10 Availability: .NET 10 and .NET 9 - -# ALM -- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) - -Version: 11.0.9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + +Version: 11.0.9 Availability: .NET 10 and .NET 9 - -# ALM -- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) - + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 11.0.8 Availability: .NET 10 and .NET 9 diff --git a/Directory.Packages.props b/Directory.Packages.props index 10bf0a2..4494ab0 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,45 +1,45 @@ - - - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 8a86d18b2034278e29af1004b1e613cb6365b235 Mon Sep 17 00:00:00 2001 From: gimlichael Date: Thu, 21 May 2026 21:46:15 +0200 Subject: [PATCH 03/16] =?UTF-8?q?=F0=9F=92=AC=20update=20release=20date=20?= =?UTF-8?q?in=20changelog=20to=202026-05-21?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated the release date for version 11.0.10 to reflect current date. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4610d1c..5549d44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ For more details, please refer to `PackageReleaseNotes.txt` on a per assembly ba > [!NOTE] > Changelog entries prior to version 8.4.0 was migrated from previous versions of Cuemon.Extensions.Xunit, Cuemon.Extensions.Xunit.Hosting, and Cuemon.Extensions.Xunit.Hosting.AspNetCore. -## [11.0.10] - 2026-05-20 +## [11.0.10] - 2026-05-21 This is a service update that focuses on package dependencies. From a0f57f6e9be8552d46284452689f424075b16eea Mon Sep 17 00:00:00 2001 From: gimlichael Date: Thu, 21 May 2026 21:46:20 +0200 Subject: [PATCH 04/16] =?UTF-8?q?=F0=9F=93=9D=20update=20hosting=20readme?= =?UTF-8?q?=20with=20current=20api=20examples?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated example code in the README to use ManagedHostFixture and correct service provider access pattern. Also fixed reference link to a real test example. --- .nuget/Codebelt.Extensions.Xunit.Hosting/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.nuget/Codebelt.Extensions.Xunit.Hosting/README.md b/.nuget/Codebelt.Extensions.Xunit.Hosting/README.md index 795d2c0..6b87a9b 100644 --- a/.nuget/Codebelt.Extensions.Xunit.Hosting/README.md +++ b/.nuget/Codebelt.Extensions.Xunit.Hosting/README.md @@ -27,13 +27,13 @@ More documentation available at our documentation site: ### CSharp Example ```csharp -public class HostTestTest : HostTest +public class HostTestTest : HostTest { private readonly IServiceProvider _provider; public HostTestTest(HostFixture hostFixture, ITestOutputHelper output) : base(hostFixture, output) { - _provider = hostFixture.ServiceProvider; + _provider = hostFixture.Host?.Services; _provider.GetRequiredService().TestOutput = output; } @@ -47,4 +47,4 @@ public class HostTestTest : HostTest } ``` -A similar but real life example can be found here: [AspNetCoreHostTestTest.cs](https://github.com/codebeltnet/xunit/tree/main/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/AspNetCoreHostTestTest.cs) +A similar but real life example can be found here: [WebHostTestTest.cs](https://github.com/codebeltnet/xunit/blob/main/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/WebHostTestTest.cs) From e88d1c70dbf6461cba0b20ab36c83c14606bfe70 Mon Sep 17 00:00:00 2001 From: gimlichael Date: Thu, 21 May 2026 21:46:25 +0200 Subject: [PATCH 05/16] =?UTF-8?q?=F0=9F=94=A7=20upgrade=20nginx=20base=20i?= =?UTF-8?q?mage=20to=201.31.0-alpine?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated the NGINX version used in the documentation build Dockerfile to the latest stable Alpine-based version. --- .docfx/Dockerfile.docfx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.docfx/Dockerfile.docfx b/.docfx/Dockerfile.docfx index 69153cc..aa53eba 100644 --- a/.docfx/Dockerfile.docfx +++ b/.docfx/Dockerfile.docfx @@ -1,4 +1,4 @@ -ARG NGINX_VERSION=1.30.0-alpine +ARG NGINX_VERSION=1.31.0-alpine FROM --platform=$BUILDPLATFORM nginx:${NGINX_VERSION} AS base RUN rm -rf /usr/share/nginx/html/* From 59a06c788404c69b8cabad7f801919db0db7a211 Mon Sep 17 00:00:00 2001 From: gimlichael Date: Thu, 21 May 2026 21:48:26 +0200 Subject: [PATCH 06/16] =?UTF-8?q?=F0=9F=93=9D=20update=20cuemon=20reposito?= =?UTF-8?q?ry=20references=20to=20codebeltnet=20organization?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated GitHub links in package READMEs to point to the codebeltnet organization namespace instead of the personal gimlichael account. --- .nuget/Codebelt.Extensions.Xunit.App/README.md | 2 +- .nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.nuget/Codebelt.Extensions.Xunit.App/README.md b/.nuget/Codebelt.Extensions.Xunit.App/README.md index 349338c..cb86185 100644 --- a/.nuget/Codebelt.Extensions.Xunit.App/README.md +++ b/.nuget/Codebelt.Extensions.Xunit.App/README.md @@ -11,7 +11,7 @@ It is, by heart, free, flexible and built to extend and boost your agile codebel ## **Codebelt.Extensions.Xunit.App** for .NET -`Codebelt.Extensions.Xunit.App`, aka `Extensions for xUnit API by Codebelt`, is a toolbelt of assemblies designed to extend upon [xUnit.net](https://xunit.net/) for more advanced unit test scenarios while also being the preferred unit test platform of [Cuemon for .NET](https://github.com/gimlichael/Cuemon). +`Codebelt.Extensions.Xunit.App`, aka `Extensions for xUnit API by Codebelt`, is a toolbelt of assemblies designed to extend upon [xUnit.net](https://xunit.net/) for more advanced unit test scenarios while also being the preferred unit test platform of [Cuemon for .NET](https://github.com/codebeltnet/cuemon). More documentation available at our documentation site: diff --git a/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/README.md b/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/README.md index 46ff128..688a810 100644 --- a/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/README.md +++ b/.nuget/Codebelt.Extensions.Xunit.Hosting.AspNetCore/README.md @@ -30,7 +30,7 @@ More documentation available at our documentation site: ### CSharp Example -Source: [ServerTimingMiddlewareTest.cs](https://github.com/gimlichael/Cuemon/blob/main/test/Cuemon.AspNetCore.Tests/Diagnostics/ServerTimingMiddlewareTest.cs) +Source: [ServerTimingMiddlewareTest.cs](https://github.com/codebeltnet/cuemon/blob/main/test/Cuemon.AspNetCore.Tests/Diagnostics/ServerTimingMiddlewareTest.cs) ```csharp [Fact] From 36cfc970f1fd528c7ff6633405d3b3346b484d25 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Thu, 21 May 2026 22:16:01 +0200 Subject: [PATCH 07/16] =?UTF-8?q?=E2=9C=85=20add=20aspnetcore=20hosting=20?= =?UTF-8?q?fixture=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added comprehensive unit tests for BlockingManagedWebHostFixture, SelfManagedWebHostFixture, SelfManagedWebMinimalHostFixture, HostBuilderApplicationExtensions, and FakeHttpResponseFeature to ensure correct hosting behavior and configuration. --- .../BlockingManagedWebHostFixtureTest.cs | 19 +++++++ .../HostBuilderApplicationExtensionsTest.cs | 32 ++++++++++++ .../Features/FakeHttpResponseFeatureTest.cs | 49 +++++++++++++++++++ .../SelfManagedWebHostFixtureTest.cs | 19 +++++++ .../SelfManagedWebMinimalHostFixtureTest.cs | 23 +++++++++ 5 files changed, 142 insertions(+) create mode 100644 test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/BlockingManagedWebHostFixtureTest.cs create mode 100644 test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/HostBuilderApplicationExtensionsTest.cs create mode 100644 test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Http/Features/FakeHttpResponseFeatureTest.cs create mode 100644 test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/SelfManagedWebHostFixtureTest.cs create mode 100644 test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/SelfManagedWebMinimalHostFixtureTest.cs diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/BlockingManagedWebHostFixtureTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/BlockingManagedWebHostFixtureTest.cs new file mode 100644 index 0000000..48d0dc7 --- /dev/null +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/BlockingManagedWebHostFixtureTest.cs @@ -0,0 +1,19 @@ +using Xunit; + +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +{ + public class BlockingManagedWebHostFixtureTest : Test + { + public BlockingManagedWebHostFixtureTest(ITestOutputHelper output) : base(output) + { + } + + [Fact] + public void Create_ShouldSucceed_WhenBlockingManagedWebHostFixtureIsUsed() + { + using var startup = WebHostTestFactory.Create(hostFixture: new BlockingManagedWebHostFixture()); + + Assert.NotNull(startup.Host); + } + } +} diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/HostBuilderApplicationExtensionsTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/HostBuilderApplicationExtensionsTest.cs new file mode 100644 index 0000000..1f90b4a --- /dev/null +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/HostBuilderApplicationExtensionsTest.cs @@ -0,0 +1,32 @@ +using System; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Hosting; +using Xunit; + +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +{ + public class HostBuilderApplicationExtensionsTest : Test + { + public HostBuilderApplicationExtensionsTest(ITestOutputHelper output) : base(output) + { + } + + [Fact] + public void ToHostBuilder_ShouldReturnHostBuilder_WhenWebApplicationBuilderIsProvided() + { + IHostApplicationBuilder builder = WebApplication.CreateBuilder(); + + var hostBuilder = builder.ToHostBuilder(); + + Assert.NotNull(hostBuilder); + } + + [Fact] + public void ToHostBuilder_ShouldThrowArgumentException_WhenNotWebApplicationBuilder() + { + IHostApplicationBuilder builder = Host.CreateApplicationBuilder(); + + Assert.Throws(() => builder.ToHostBuilder()); + } + } +} diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Http/Features/FakeHttpResponseFeatureTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Http/Features/FakeHttpResponseFeatureTest.cs new file mode 100644 index 0000000..4da6593 --- /dev/null +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Http/Features/FakeHttpResponseFeatureTest.cs @@ -0,0 +1,49 @@ +using System.Threading.Tasks; +using Codebelt.Extensions.Xunit.Hosting.AspNetCore.Http.Features; +using Xunit; + +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Http.Features +{ + public class FakeHttpResponseFeatureTest : Test + { + public FakeHttpResponseFeatureTest(ITestOutputHelper output) : base(output) + { + } + + [Fact] + public void OnStarting_ShouldInvokeCallback_OnFirstCall() + { + var feature = new FakeHttpResponseFeature(); + var invoked = false; + + feature.OnStarting(_ => { invoked = true; return Task.CompletedTask; }, null); + + Assert.True(invoked); + Assert.True(feature.HasStarted); + } + + [Fact] + public void OnStarting_ShouldNotInvokeCallback_OnSubsequentCalls() + { + var feature = new FakeHttpResponseFeature(); + var count = 0; + + feature.OnStarting(_ => { count++; return Task.CompletedTask; }, null); + feature.OnStarting(_ => { count++; return Task.CompletedTask; }, null); + + Assert.Equal(1, count); + Assert.True(feature.HasStarted); + } + + [Fact] + public void OnStarting_ShouldNotThrow_WhenCallbackIsNull() + { + var feature = new FakeHttpResponseFeature(); + + var ex = Record.Exception(() => feature.OnStarting(null, null)); + + Assert.Null(ex); + Assert.True(feature.HasStarted); + } + } +} diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/SelfManagedWebHostFixtureTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/SelfManagedWebHostFixtureTest.cs new file mode 100644 index 0000000..f9abec3 --- /dev/null +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/SelfManagedWebHostFixtureTest.cs @@ -0,0 +1,19 @@ +using Xunit; + +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +{ + public class SelfManagedWebHostFixtureTest : Test + { + public SelfManagedWebHostFixtureTest(ITestOutputHelper output) : base(output) + { + } + + [Fact] + public void Create_ShouldSucceed_WhenSelfManagedWebHostFixtureIsUsed() + { + using var startup = WebHostTestFactory.Create(hostFixture: new SelfManagedWebHostFixture()); + + Assert.NotNull(startup.Host); + } + } +} diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/SelfManagedWebMinimalHostFixtureTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/SelfManagedWebMinimalHostFixtureTest.cs new file mode 100644 index 0000000..79e03b9 --- /dev/null +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/SelfManagedWebMinimalHostFixtureTest.cs @@ -0,0 +1,23 @@ +using Microsoft.AspNetCore.Builder; +using Xunit; + +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +{ + public class SelfManagedWebMinimalHostFixtureTest : MinimalWebHostTest + { + public SelfManagedWebMinimalHostFixtureTest(SelfManagedWebMinimalHostFixture hostFixture, ITestOutputHelper output) : base(hostFixture, output) + { + } + + [Fact] + public void Host_ShouldNotBeNull_WhenNoOpRunnerIsUsed() + { + Assert.NotNull(Host); + Assert.NotNull(Application); + } + + public override void ConfigureApplication(IApplicationBuilder app) + { + } + } +} From b7bcee7375c5bb7682c2599b8fa6c71f961b3bd9 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Thu, 21 May 2026 23:29:21 +0200 Subject: [PATCH 08/16] =?UTF-8?q?=F0=9F=8E=A8=20refactor=20core=20xunit=20?= =?UTF-8?q?assembly=20to=20file-scoped=20namespaces?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Converted all source files in Codebelt.Extensions.Xunit from block-scoped to file-scoped namespace declarations (namespace Foo;). Pure structural change — no behavior or API modifications. --- .../DelimitedString.cs | 38 ++- .../GlobalSuppressions.cs | 7 +- src/Codebelt.Extensions.Xunit/ITest.cs | 21 +- .../ITestOutputHelperAccessor.cs | 19 +- src/Codebelt.Extensions.Xunit/ITestStore.cs | 55 ++- .../InMemoryTestStore.cs | 101 +++--- .../StringExtensions.cs | 63 ++-- src/Codebelt.Extensions.Xunit/Test.cs | 312 +++++++++--------- .../TestOutputHelperAccessor.cs | 43 ++- .../TestOutputHelperExtensions.cs | 91 ++--- .../WildcardOptions.cs | 89 +++-- 11 files changed, 423 insertions(+), 416 deletions(-) diff --git a/src/Codebelt.Extensions.Xunit/DelimitedString.cs b/src/Codebelt.Extensions.Xunit/DelimitedString.cs index d20d2f7..3925e69 100644 --- a/src/Codebelt.Extensions.Xunit/DelimitedString.cs +++ b/src/Codebelt.Extensions.Xunit/DelimitedString.cs @@ -1,25 +1,29 @@ -using System; +using System; using System.Collections.Generic; using System.Text; -namespace Codebelt.Extensions.Xunit +namespace Codebelt.Extensions.Xunit; + +internal static class DelimitedString { - internal static class DelimitedString - { - internal static string Create(IEnumerable source, string delimiter) - { - if (source == null) { throw new ArgumentNullException(nameof(source)); } - if (delimiter == null) { throw new ArgumentNullException(nameof(delimiter)); } + internal static string Create(IEnumerable source, string delimiter) + { +#if NETSTANDARD2_0 + if (source == null) { throw new ArgumentNullException(nameof(source)); } + if (delimiter == null) { throw new ArgumentNullException(nameof(delimiter)); } +#else + ArgumentNullException.ThrowIfNull(source); + ArgumentNullException.ThrowIfNull(delimiter); +#endif - var sb = new StringBuilder(); - var first = true; - foreach (var item in source) - { - if (!first) { sb.Append(delimiter); } - first = false; - sb.Append(item); - } - return sb.ToString(); + var sb = new StringBuilder(); + var first = true; + foreach (var item in source) + { + if (!first) { sb.Append(delimiter); } + first = false; + sb.Append(item); } + return sb.ToString(); } } diff --git a/src/Codebelt.Extensions.Xunit/GlobalSuppressions.cs b/src/Codebelt.Extensions.Xunit/GlobalSuppressions.cs index 83d5071..1a58ddf 100644 --- a/src/Codebelt.Extensions.Xunit/GlobalSuppressions.cs +++ b/src/Codebelt.Extensions.Xunit/GlobalSuppressions.cs @@ -1,4 +1,4 @@ -// This file is used by Code Analysis to maintain SuppressMessage +// This file is used by Code Analysis to maintain SuppressMessage // attributes that are applied to this project. // Project-level suppressions either have no target or are given // a specific target and scoped to a namespace, type, member, etc. @@ -7,6 +7,5 @@ [assembly: SuppressMessage("Major Code Smell", "S3881:\"IDisposable\" should be implemented correctly", Justification = "This is a base class implementation of the IDisposable interface tailored to avoid wrong implementations.", Scope = "type", Target = "~T:Codebelt.Extensions.Xunit.Test")] [assembly: SuppressMessage("Major Code Smell", "S3971:\"GC.SuppressFinalize\" should not be called", Justification = "False-Positive due to IAsyncDisposable living side-by-side with IDisposable.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Test.DisposeAsync~System.Threading.Tasks.ValueTask")] -[assembly: SuppressMessage("Maintainability", "CA1510:Use ArgumentNullException throw helper", Justification = "Wont fix. Multi-TFMs. Only supported with >= .NET 7.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.DelimitedString.Create``1(System.Collections.Generic.IEnumerable{``0},System.Action{Codebelt.Extensions.Xunit.DelimitedStringOptions{``0}})~System.String")] -[assembly: SuppressMessage("Maintainability", "CA1510:Use ArgumentNullException throw helper", Justification = "Wont fix. Multi-TFMs. Only supported with >= .NET 7.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.TestOutputHelperExtensions.WriteLines(Xunit.Abstractions.ITestOutputHelper,System.Object[])")] -[assembly: SuppressMessage("Maintainability", "CA1510:Use ArgumentNullException throw helper", Justification = "Wont fix. Multi-TFMs. Only supported with >= .NET 7.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.TestOutputHelperExtensions.WriteLines``1(Xunit.Abstractions.ITestOutputHelper,System.Collections.Generic.IEnumerable{``0})")] +[assembly: SuppressMessage("Maintainability", "CA1510:Use ArgumentNullException throw helper", Justification = "Wont fix. Multi-TFMs. Only supported with >= .NET 7.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.TestOutputHelperExtensions.WriteLines(Xunit.ITestOutputHelper,System.Object[])")] +[assembly: SuppressMessage("Maintainability", "CA1510:Use ArgumentNullException throw helper", Justification = "Wont fix. Multi-TFMs. Only supported with >= .NET 7.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.TestOutputHelperExtensions.WriteLines``1(Xunit.ITestOutputHelper,System.Collections.Generic.IEnumerable{``0})")] diff --git a/src/Codebelt.Extensions.Xunit/ITest.cs b/src/Codebelt.Extensions.Xunit/ITest.cs index b08272a..042e389 100644 --- a/src/Codebelt.Extensions.Xunit/ITest.cs +++ b/src/Codebelt.Extensions.Xunit/ITest.cs @@ -1,17 +1,16 @@ using System; -namespace Codebelt.Extensions.Xunit +namespace Codebelt.Extensions.Xunit; + +/// +/// Represents the members needed for vanilla testing. +/// +/// +public interface ITest : IDisposable, IAsyncDisposable { /// - /// Represents the members needed for vanilla testing. + /// Gets the type of caller for this instance. Default is . /// - /// - public interface ITest : IDisposable, IAsyncDisposable - { - /// - /// Gets the type of caller for this instance. Default is . - /// - /// The type of caller for this instance. - Type CallerType { get; } - } + /// The type of caller for this instance. + Type CallerType { get; } } diff --git a/src/Codebelt.Extensions.Xunit/ITestOutputHelperAccessor.cs b/src/Codebelt.Extensions.Xunit/ITestOutputHelperAccessor.cs index 71aff75..a41cc05 100644 --- a/src/Codebelt.Extensions.Xunit/ITestOutputHelperAccessor.cs +++ b/src/Codebelt.Extensions.Xunit/ITestOutputHelperAccessor.cs @@ -1,16 +1,15 @@ using Xunit; -namespace Codebelt.Extensions.Xunit +namespace Codebelt.Extensions.Xunit; + +/// +/// Provides an interface for accessing the instance. +/// +public interface ITestOutputHelperAccessor { /// - /// Provides an interface for accessing the instance. + /// Gets or sets the instance used for outputting test results. /// - public interface ITestOutputHelperAccessor - { - /// - /// Gets or sets the instance used for outputting test results. - /// - /// The instance. - ITestOutputHelper TestOutput { get; set; } - } + /// The instance. + ITestOutputHelper TestOutput { get; set; } } diff --git a/src/Codebelt.Extensions.Xunit/ITestStore.cs b/src/Codebelt.Extensions.Xunit/ITestStore.cs index 0750610..88fe9fd 100644 --- a/src/Codebelt.Extensions.Xunit/ITestStore.cs +++ b/src/Codebelt.Extensions.Xunit/ITestStore.cs @@ -1,38 +1,37 @@ using System; using System.Collections.Generic; -namespace Codebelt.Extensions.Xunit +namespace Codebelt.Extensions.Xunit; + +/// +/// Represents the members needed for adding and querying a store tailored for unit testing. +/// +/// The type of the object to reference in the store. +public interface ITestStore { /// - /// Represents the members needed for adding and querying a store tailored for unit testing. + /// Gets the number of elements contained in the . /// - /// The type of the object to reference in the store. - public interface ITestStore - { - /// - /// Gets the number of elements contained in the . - /// - /// The number of elements contained in the . - int Count { get; } + /// The number of elements contained in the . + int Count { get; } - /// - /// Adds an item to the . - /// - /// The object to add to the . - void Add(T item); + /// + /// Adds an item to the . + /// + /// The object to add to the . + void Add(T item); - /// - /// Filters the elements contained in the based on an optional . - /// - /// The function delegate to test each element for a condition. - /// An that satisfies the condition. - IEnumerable Query(Func predicate = null); + /// + /// Filters the elements contained in the based on an optional . + /// + /// The function delegate to test each element for a condition. + /// An that satisfies the condition. + IEnumerable Query(Func predicate = null); - /// - /// Filters the elements contained in the based on the type . - /// - /// The concrete type that implements . - /// An that satisfies the condition. - IEnumerable QueryFor() where TResult : T; - } + /// + /// Filters the elements contained in the based on the type . + /// + /// The concrete type that implements . + /// An that satisfies the condition. + IEnumerable QueryFor() where TResult : T; } diff --git a/src/Codebelt.Extensions.Xunit/InMemoryTestStore.cs b/src/Codebelt.Extensions.Xunit/InMemoryTestStore.cs index 1cb367c..5820fbd 100644 --- a/src/Codebelt.Extensions.Xunit/InMemoryTestStore.cs +++ b/src/Codebelt.Extensions.Xunit/InMemoryTestStore.cs @@ -2,65 +2,64 @@ using System.Collections.Generic; using System.Linq; -namespace Codebelt.Extensions.Xunit +namespace Codebelt.Extensions.Xunit; + +/// +/// Provides a default base implementation of the interface. +/// +/// The type of the object to reference in the memory store. +/// +public class InMemoryTestStore : ITestStore { + private readonly List _store = new(); + /// - /// Provides a default base implementation of the interface. + /// Initializes a new instance of the class. /// - /// The type of the object to reference in the memory store. - /// - public class InMemoryTestStore : ITestStore + public InMemoryTestStore() { - private readonly List _store = new(); - - /// - /// Initializes a new instance of the class. - /// - public InMemoryTestStore() - { - } + } - /// - /// Gets the reference to the encapsulated store. - /// - /// The reference to the encapsulated store. - protected IList InnerStore => _store; + /// + /// Gets the reference to the encapsulated store. + /// + /// The reference to the encapsulated store. + protected IList InnerStore => _store; - /// - /// Gets the number of elements contained in the . - /// - /// The number of elements contained in the . - public int Count => _store.Count; + /// + /// Gets the number of elements contained in the . + /// + /// The number of elements contained in the . + public int Count => _store.Count; - /// - /// Adds an item to the . - /// - /// The object to add to the . - public void Add(T item) - { - _store.Add(item); - } + /// + /// Adds an item to the . + /// + /// The object to add to the . + public void Add(T item) + { + _store.Add(item); + } - /// - /// Filters the elements contained in the based on an optional . - /// - /// The function delegate to test each element for a condition. - /// An that satisfies the condition. - public virtual IEnumerable Query(Func predicate = null) - { - return predicate == null - ? _store - : _store.Where(predicate!); - } + /// + /// Filters the elements contained in the based on an optional . + /// + /// The function delegate to test each element for a condition. + /// An that satisfies the condition. + public virtual IEnumerable Query(Func predicate = null) + { + return predicate == null + ? _store + : _store.Where(predicate!); + } - /// - /// Filters the elements contained in the based on the type . - /// - /// The concrete type that implements . - /// An that satisfies the condition. - public IEnumerable QueryFor() where TResult : T - { - return Query(item => item.GetType() == typeof(TResult)).Cast(); - } + /// + /// Filters the elements contained in the based on the type . + /// + /// The concrete type that implements . + /// An that satisfies the condition. + public IEnumerable QueryFor() where TResult : T + { + return Query(item => item.GetType() == typeof(TResult)).Cast(); } } diff --git a/src/Codebelt.Extensions.Xunit/StringExtensions.cs b/src/Codebelt.Extensions.Xunit/StringExtensions.cs index e607cdc..d9569c1 100644 --- a/src/Codebelt.Extensions.Xunit/StringExtensions.cs +++ b/src/Codebelt.Extensions.Xunit/StringExtensions.cs @@ -2,43 +2,42 @@ using System; using System.Text.RegularExpressions; -namespace Codebelt.Extensions.Xunit +namespace Codebelt.Extensions.Xunit; + +/// +/// Extension methods for the class. +/// +public static class StringExtensions { + private static readonly Regex NewLineRegex = new(@"\r\n|\r|\n", RegexOptions.Compiled); + /// - /// Extension methods for the class. + /// Replaces all newline sequences in the current string with . /// - public static class StringExtensions + /// The to extend. + /// A string whose contents match the current string, but with all newline sequences replaced with . + /// Shamefully stolen from https://github.com/WebFormsCore/WebFormsCore/blob/main/src/WebFormsCore/Util/StringExtensions.cs to support .NET Standard 2.0. + public static string ReplaceLineEndings(this string input) { - private static readonly Regex NewLineRegex = new(@"\r\n|\r|\n", RegexOptions.Compiled); - - /// - /// Replaces all newline sequences in the current string with . - /// - /// The to extend. - /// A string whose contents match the current string, but with all newline sequences replaced with . - /// Shamefully stolen from https://github.com/WebFormsCore/WebFormsCore/blob/main/src/WebFormsCore/Util/StringExtensions.cs to support .NET Standard 2.0. - public static string ReplaceLineEndings(this string input) - { - return ReplaceLineEndings(input, Environment.NewLine); - } + return ReplaceLineEndings(input, Environment.NewLine); + } - /// - /// Replaces all newline sequences in the current string with . - /// - /// The to extend. - /// The text to use as replacement. - /// A string whose contents match the current string, but with all newline sequences replaced with . - /// Shamefully stolen from https://github.com/WebFormsCore/WebFormsCore/blob/main/src/WebFormsCore/Util/StringExtensions.cs to support .NET Standard 2.0. - /// - /// cannot be null -or- - /// cannot be null. - /// - public static string ReplaceLineEndings(this string input, string replacementText) - { - if (input == null) { throw new ArgumentNullException(nameof(input)); } - if (replacementText == null) { throw new ArgumentNullException(nameof(replacementText)); } - return NewLineRegex.Replace(input, replacementText); - } + /// + /// Replaces all newline sequences in the current string with . + /// + /// The to extend. + /// The text to use as replacement. + /// A string whose contents match the current string, but with all newline sequences replaced with . + /// Shamefully stolen from https://github.com/WebFormsCore/WebFormsCore/blob/main/src/WebFormsCore/Util/StringExtensions.cs to support .NET Standard 2.0. + /// + /// cannot be null -or- + /// cannot be null. + /// + public static string ReplaceLineEndings(this string input, string replacementText) + { + if (input == null) { throw new ArgumentNullException(nameof(input)); } + if (replacementText == null) { throw new ArgumentNullException(nameof(replacementText)); } + return NewLineRegex.Replace(input, replacementText); } } #endif diff --git a/src/Codebelt.Extensions.Xunit/Test.cs b/src/Codebelt.Extensions.Xunit/Test.cs index 8ad0ad9..fc173f9 100644 --- a/src/Codebelt.Extensions.Xunit/Test.cs +++ b/src/Codebelt.Extensions.Xunit/Test.cs @@ -1,69 +1,59 @@ -using System; +using System; using System.Linq; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Xunit; -namespace Codebelt.Extensions.Xunit +namespace Codebelt.Extensions.Xunit; + +/// +/// Represents the base class from which all implementations of unit testing should derive. +/// +/// +public abstract class Test : ITest, IAsyncLifetime { +#if NET9_0_OR_GREATER + private readonly Lock _lock = new(); +#else + private readonly object _lock = new(); +#endif + /// - /// Represents the base class from which all implementations of unit testing should derive. + /// Provides a way, with wildcard support, to determine if matches . /// - /// - public abstract class Test : ITest, IAsyncLifetime + /// The expected string value. + /// The actual string value. + /// The which may be configured. + /// true if matches , false otherwise. + /// Credits for inspiration goes to this SO answer: https://stackoverflow.com/questions/30299671/matching-strings-with-wildcard/30300521#30300521 + /// + /// cannot be matched with . Includes the non-matched string(s) in . + /// + /// + /// is null -or- + /// is null. + /// + public static bool Match(string expected, string actual, Action setup = null) { -#if NET9_0_OR_GREATER - private readonly Lock _lock = new(); + #if NETSTANDARD2_0 + if (expected == null) { throw new ArgumentNullException(nameof(expected)); } + if (actual == null) { throw new ArgumentNullException(nameof(actual)); } #else - private readonly object _lock = new(); + ArgumentNullException.ThrowIfNull(expected); + ArgumentNullException.ThrowIfNull(actual); #endif - /// - /// Provides a way, with wildcard support, to determine if matches . - /// - /// The expected string value. - /// The actual string value. - /// The which may be configured. - /// true if matches , false otherwise. - /// Credits for inspiration goes to this SO answer: https://stackoverflow.com/questions/30299671/matching-strings-with-wildcard/30300521#30300521 - /// - /// cannot be matched with . Includes the non-matched string(s) in . - /// - /// - /// is null -or- - /// is null. - /// - public static bool Match(string expected, string actual, Action setup = null) - { - if (expected == null) { throw new ArgumentNullException(nameof(expected)); } - if (actual == null) { throw new ArgumentNullException(nameof(actual)); } - - var options = new WildcardOptions(); - setup?.Invoke(options); - - var escapedExpected = Regex.Escape(expected); - - var hasWildcards = escapedExpected.IndexOf(options.SingleCharacter, StringComparison.Ordinal) >= 0 || escapedExpected.IndexOf(options.GroupOfCharacters, StringComparison.Ordinal) >= 0; + var options = new WildcardOptions(); + setup?.Invoke(options); - if (!hasWildcards) - { - if (string.Equals(expected, actual, StringComparison.Ordinal)) - { - return true; - } - - if (options.ThrowOnNoMatch) - { - var diff = ComputeNonMatchingLines(expected, actual, options); - throw new ArgumentOutOfRangeException(nameof(expected), $"'{diff}'", "The expected value does not match the actual value."); - } - return false; - } + var escapedExpected = Regex.Escape(expected); - var pattern = $"^{escapedExpected.Replace(options.SingleCharacter, ".").Replace(options.GroupOfCharacters, ".*")}$"; + var hasWildcards = escapedExpected.IndexOf(options.SingleCharacter, StringComparison.Ordinal) >= 0 || escapedExpected.IndexOf(options.GroupOfCharacters, StringComparison.Ordinal) >= 0; - if (Regex.IsMatch(actual, pattern, RegexOptions.None, TimeSpan.FromSeconds(2))) + if (!hasWildcards) + { + if (string.Equals(expected, actual, StringComparison.Ordinal)) { return true; } @@ -73,131 +63,145 @@ public static bool Match(string expected, string actual, Action var diff = ComputeNonMatchingLines(expected, actual, options); throw new ArgumentOutOfRangeException(nameof(expected), $"'{diff}'", "The expected value does not match the actual value."); } - return false; - - static string ComputeNonMatchingLines(string expectedText, string actualText, WildcardOptions o) - { - var e = expectedText.Split(Environment.NewLine.ToCharArray()); - var a = actualText.Split(Environment.NewLine.ToCharArray()); - var d = e.Except(a).Where(s => s.IndexOf(o.GroupOfCharacters, StringComparison.InvariantCulture) < 0 && s.IndexOf(o.SingleCharacter, StringComparison.InvariantCulture) < 0); - return string.Join(Environment.NewLine, d); - } } - /// - /// Initializes a new instance of the class. - /// - /// An implementation of the interface. - /// The of caller that ends up invoking this instance. - /// is initialized automatically in an xUnit project. - protected Test(ITestOutputHelper output = null, Type callerType = null) - { - TestOutput = output; - CallerType = callerType ?? GetType(); + var pattern = $"^{escapedExpected.Replace(options.SingleCharacter, ".").Replace(options.GroupOfCharacters, ".*")}$"; - if (output == null) { return; } - - AppDomain.CurrentDomain.UnhandledException += (_, e) => - { - var exception = e.ExceptionObject as Exception; - output.WriteLine($"Unhandled exception captured: {exception?.Message}"); - }; - } - - /// - /// Gets the type of caller for this instance. Default is . - /// - /// The type of caller for this instance. - public Type CallerType { get; } - - /// - /// Gets the console substitute to write out unit test information. - /// - /// The console substitute to write out unit test information. - protected ITestOutputHelper TestOutput { get; } - - /// - /// Gets a value indicating whether has a reference to an implementation of . - /// - /// true if this instance has a reference to an implementation of ; otherwise, false. - protected bool HasTestOutput => TestOutput != null; - - /// - /// Gets a value indicating whether this object is disposed. - /// - /// true if this object is disposed; otherwise, false. - public bool Disposed { get; private set; } - - /// - /// Called when this object is being disposed by either or having disposing set to true and is false. - /// - protected virtual void OnDisposeManagedResources() + if (Regex.IsMatch(actual, pattern, RegexOptions.None, TimeSpan.FromSeconds(2))) { + return true; } - /// - /// Called when this object is being disposed by . - /// - protected virtual ValueTask OnDisposeManagedResourcesAsync() + if (options.ThrowOnNoMatch) { - return default; + var diff = ComputeNonMatchingLines(expected, actual, options); + throw new ArgumentOutOfRangeException(nameof(expected), $"'{diff}'", "The expected value does not match the actual value."); } - /// - /// Called when this object is being disposed by either or and is false. - /// - protected virtual void OnDisposeUnmanagedResources() + return false; + + static string ComputeNonMatchingLines(string expectedText, string actualText, WildcardOptions o) { + var e = expectedText.Split(Environment.NewLine.ToCharArray()); + var a = actualText.Split(Environment.NewLine.ToCharArray()); + var d = e.Except(a).Where(s => s.IndexOf(o.GroupOfCharacters, StringComparison.InvariantCulture) < 0 && s.IndexOf(o.SingleCharacter, StringComparison.InvariantCulture) < 0); + return string.Join(Environment.NewLine, d); } + } + + /// + /// Initializes a new instance of the class. + /// + /// An implementation of the interface. + /// The of caller that ends up invoking this instance. + /// is initialized automatically in an xUnit project. + protected Test(ITestOutputHelper output = null, Type callerType = null) + { + TestOutput = output; + CallerType = callerType ?? GetType(); - /// - /// Releases all resources used by the object. - /// - public void Dispose() + if (output == null) { return; } + + AppDomain.CurrentDomain.UnhandledException += (_, e) => { - Dispose(true); - GC.SuppressFinalize(this); - } + var exception = e.ExceptionObject as Exception; + output.WriteLine($"Unhandled exception captured: {exception?.Message}"); + }; + } + + /// + /// Gets the type of caller for this instance. Default is . + /// + /// The type of caller for this instance. + public Type CallerType { get; } + + /// + /// Gets the console substitute to write out unit test information. + /// + /// The console substitute to write out unit test information. + protected ITestOutputHelper TestOutput { get; } + + /// + /// Gets a value indicating whether has a reference to an implementation of . + /// + /// true if this instance has a reference to an implementation of ; otherwise, false. + protected bool HasTestOutput => TestOutput != null; + + /// + /// Gets a value indicating whether this object is disposed. + /// + /// true if this object is disposed; otherwise, false. + public bool Disposed { get; private set; } + + /// + /// Called when this object is being disposed by either or having disposing set to true and is false. + /// + protected virtual void OnDisposeManagedResources() + { + } + + /// + /// Called when this object is being disposed by . + /// + protected virtual ValueTask OnDisposeManagedResourcesAsync() + { + return default; + } + + /// + /// Called when this object is being disposed by either or and is false. + /// + protected virtual void OnDisposeUnmanagedResources() + { + } - /// - /// Releases the unmanaged resources used by the object and optionally releases the managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected void Dispose(bool disposing) + /// + /// Releases all resources used by the object. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases the unmanaged resources used by the object and optionally releases the managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected void Dispose(bool disposing) + { + if (Disposed) { return; } + lock (_lock) { if (Disposed) { return; } - lock (_lock) + if (disposing) { - if (Disposed) { return; } - if (disposing) - { - OnDisposeManagedResources(); - } - OnDisposeUnmanagedResources(); - Disposed = true; + OnDisposeManagedResources(); } + OnDisposeUnmanagedResources(); + Disposed = true; } + } - /// - /// Asynchronously releases the resources used by the . - /// - /// A that represents the asynchronous dispose operation. - /// https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-disposeasync#the-disposeasync-method - public async ValueTask DisposeAsync() - { - await OnDisposeManagedResourcesAsync().ConfigureAwait(false); - Dispose(false); - GC.SuppressFinalize(this); - } + /// + /// Asynchronously releases the resources used by the . + /// + /// A that represents the asynchronous dispose operation. + /// https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-disposeasync#the-disposeasync-method + public async ValueTask DisposeAsync() + { + await OnDisposeManagedResourcesAsync().ConfigureAwait(false); + Dispose(false); + GC.SuppressFinalize(this); + } - /// - /// Called immediately after the class has been created, before it is used. - /// - /// A that represents the asynchronous operation. - public virtual ValueTask InitializeAsync() - { - return default; - } + /// + /// Called immediately after the class has been created, before it is used. + /// + /// A that represents the asynchronous operation. + public virtual ValueTask InitializeAsync() + { + return default; } } diff --git a/src/Codebelt.Extensions.Xunit/TestOutputHelperAccessor.cs b/src/Codebelt.Extensions.Xunit/TestOutputHelperAccessor.cs index 6cef970..a65fc77 100644 --- a/src/Codebelt.Extensions.Xunit/TestOutputHelperAccessor.cs +++ b/src/Codebelt.Extensions.Xunit/TestOutputHelperAccessor.cs @@ -1,32 +1,31 @@ using System.Threading; using Xunit; -namespace Codebelt.Extensions.Xunit +namespace Codebelt.Extensions.Xunit; + +/// +/// Provides a default implementation of the interface. +/// +public class TestOutputHelperAccessor : ITestOutputHelperAccessor { + private static readonly AsyncLocal Current = new(); + /// - /// Provides a default implementation of the interface. + /// Initializes a new instance of the class with the specified instance. /// - public class TestOutputHelperAccessor : ITestOutputHelperAccessor + /// The instance to be used for outputting test results. + public TestOutputHelperAccessor(ITestOutputHelper output = null) { - private static readonly AsyncLocal Current = new(); - - /// - /// Initializes a new instance of the class with the specified instance. - /// - /// The instance to be used for outputting test results. - public TestOutputHelperAccessor(ITestOutputHelper output = null) - { - Current.Value = output; - } + Current.Value = output; + } - /// - /// Gets or sets the instance used for outputting test results. - /// - /// The instance. - public ITestOutputHelper TestOutput - { - get => Current.Value; - set => Current.Value = value; - } + /// + /// Gets or sets the instance used for outputting test results. + /// + /// The instance. + public ITestOutputHelper TestOutput + { + get => Current.Value; + set => Current.Value = value; } } diff --git a/src/Codebelt.Extensions.Xunit/TestOutputHelperExtensions.cs b/src/Codebelt.Extensions.Xunit/TestOutputHelperExtensions.cs index 9cf25e8..b3c67c7 100644 --- a/src/Codebelt.Extensions.Xunit/TestOutputHelperExtensions.cs +++ b/src/Codebelt.Extensions.Xunit/TestOutputHelperExtensions.cs @@ -1,53 +1,60 @@ -using System; +using System; using System.Collections.Generic; using Xunit; -namespace Codebelt.Extensions.Xunit +namespace Codebelt.Extensions.Xunit; + +/// +/// Extension methods for the . +/// +public static class TestOutputHelperExtensions { /// - /// Extension methods for the . + /// Adds a line of text per object in to the output. /// - public static class TestOutputHelperExtensions + /// The to extend. + /// The values to write, per line, to the output. + /// + /// cannot be null. + /// + public static void WriteLines(this ITestOutputHelper helper, params object[] values) { - /// - /// Adds a line of text per object in to the output. - /// - /// The to extend. - /// The values to write, per line, to the output. - /// - /// cannot be null. - /// - public static void WriteLines(this ITestOutputHelper helper, params object[] values) - { - if (helper == null) { throw new ArgumentNullException(nameof(helper)); } - helper.WriteLine(DelimitedString.Create(values, Environment.NewLine)); - } +#if NETSTANDARD2_0 + if (helper == null) { throw new ArgumentNullException(nameof(helper)); } +#else + ArgumentNullException.ThrowIfNull(helper); +#endif + helper.WriteLine(DelimitedString.Create(values, Environment.NewLine)); + } - /// - /// Adds a line of text per item in to the output. - /// - /// The to extend. - /// The values to write, per line, to the output. - /// - /// cannot be null. - /// - public static void WriteLines(this ITestOutputHelper helper, T[] values) - { - WriteLines(helper, (IEnumerable)values); - } + /// + /// Adds a line of text per item in to the output. + /// + /// The to extend. + /// The values to write, per line, to the output. + /// + /// cannot be null. + /// + public static void WriteLines(this ITestOutputHelper helper, T[] values) + { + WriteLines(helper, (IEnumerable)values); + } - /// - /// Adds a line of text per item in to the output. - /// - /// The to extend. - /// The values to write, per line, to the output. - /// - /// cannot be null. - /// - public static void WriteLines(this ITestOutputHelper helper, IEnumerable values) - { - if (helper == null) { throw new ArgumentNullException(nameof(helper)); } - helper.WriteLine(DelimitedString.Create(values, Environment.NewLine)); - } + /// + /// Adds a line of text per item in to the output. + /// + /// The to extend. + /// The values to write, per line, to the output. + /// + /// cannot be null. + /// + public static void WriteLines(this ITestOutputHelper helper, IEnumerable values) + { +#if NETSTANDARD2_0 + if (helper == null) { throw new ArgumentNullException(nameof(helper)); } +#else + ArgumentNullException.ThrowIfNull(helper); +#endif + helper.WriteLine(DelimitedString.Create(values, Environment.NewLine)); } } diff --git a/src/Codebelt.Extensions.Xunit/WildcardOptions.cs b/src/Codebelt.Extensions.Xunit/WildcardOptions.cs index a67f8f1..68286d0 100644 --- a/src/Codebelt.Extensions.Xunit/WildcardOptions.cs +++ b/src/Codebelt.Extensions.Xunit/WildcardOptions.cs @@ -1,55 +1,54 @@ using System; -namespace Codebelt.Extensions.Xunit +namespace Codebelt.Extensions.Xunit; + +/// +/// Configuration options for . +/// +public class WildcardOptions { /// - /// Configuration options for . + /// Initializes a new instance of the class. /// - public class WildcardOptions + /// + /// The following table shows the initial property values for an instance of . + /// + /// + /// Property + /// Initial Value + /// + /// + /// + /// \\* + /// + /// + /// + /// \\? + /// + /// + /// + public WildcardOptions() { - /// - /// Initializes a new instance of the class. - /// - /// - /// The following table shows the initial property values for an instance of . - /// - /// - /// Property - /// Initial Value - /// - /// - /// - /// \\* - /// - /// - /// - /// \\? - /// - /// - /// - public WildcardOptions() - { - GroupOfCharacters = "\\*"; - SingleCharacter = "\\?"; - ThrowOnNoMatch = false; - } + GroupOfCharacters = "\\*"; + SingleCharacter = "\\?"; + ThrowOnNoMatch = false; + } - /// - /// Gets or sets the symbol used to represents any group of characters, including no character. The default value is \\*. - /// - /// The symbol used to represents any group of characters, including no character. - public string GroupOfCharacters { get; set; } + /// + /// Gets or sets the symbol used to represents any group of characters, including no character. The default value is \\*. + /// + /// The symbol used to represents any group of characters, including no character. + public string GroupOfCharacters { get; set; } - /// - /// Gets or sets the symbol used to represents any single character. The default value is \\?. - /// - /// The symbol used to represents any single character. - public string SingleCharacter { get; set; } + /// + /// Gets or sets the symbol used to represents any single character. The default value is \\?. + /// + /// The symbol used to represents any single character. + public string SingleCharacter { get; set; } - /// - /// Gets or sets a value indicating whether a is thrown when no match is found. The default value is false. - /// - /// true if a is thrown when no match is found; otherwise, false. - public bool ThrowOnNoMatch { get; set; } - } + /// + /// Gets or sets a value indicating whether a is thrown when no match is found. The default value is false. + /// + /// true if a is thrown when no match is found; otherwise, false. + public bool ThrowOnNoMatch { get; set; } } From 6c4a150887ae5b18f96515640a5d81f0237740f9 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Thu, 21 May 2026 23:29:32 +0200 Subject: [PATCH 09/16] =?UTF-8?q?=F0=9F=8E=A8=20refactor=20hosting=20assem?= =?UTF-8?q?bly=20to=20file-scoped=20namespaces?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Converted all source files in Codebelt.Extensions.Xunit.Hosting from block-scoped to file-scoped namespace declarations (namespace Foo;). Pure structural change — no behavior or API modifications. --- .../GenericHostFixtureExtensions.cs | 33 +- .../GlobalSuppressions.cs | 12 +- .../HostFixture.cs | 309 +++++++++--------- .../HostTest.cs | 193 +++++------ .../HostTestFactory.cs | 49 ++- .../IConfigurationTest.cs | 19 +- .../IEnvironmentTest.cs | 19 +- .../IGenericHostFixture.cs | 43 ++- .../IHostFixture.cs | 37 +-- .../IHostTest.cs | 25 +- .../IMinimalHostFixture.cs | 37 +-- .../Internal/HostTest.cs | 85 +++-- .../Internal/MinimalHostTest.cs | 77 +++-- .../LoggerExtensions.cs | 128 ++++---- .../ManagedHostFixture.cs | 137 ++++---- .../ManagedMinimalHostFixture.cs | 89 +++-- .../MinimalHostFixtureExtensions.cs | 35 +- .../MinimalHostTest.cs | 125 +++---- .../MinimalHostTestFactory.cs | 49 ++- .../SelfManagedHostFixture.cs | 25 +- .../SelfManagedMinimalHostFixture.cs | 25 +- .../ServiceCollectionExtensions.cs | 178 +++++----- .../ServiceProviderExtensions.cs | 29 +- .../Tweaker.cs | 11 +- .../XunitTestLogger.cs | 105 +++--- .../XunitTestLoggerEntry.cs | 75 +++-- .../XunitTestLoggerProvider.cs | 75 +++-- 27 files changed, 1012 insertions(+), 1012 deletions(-) diff --git a/src/Codebelt.Extensions.Xunit.Hosting/GenericHostFixtureExtensions.cs b/src/Codebelt.Extensions.Xunit.Hosting/GenericHostFixtureExtensions.cs index 373f8ef..32f110a 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/GenericHostFixtureExtensions.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/GenericHostFixtureExtensions.cs @@ -1,23 +1,22 @@ -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +/// +/// Extension methods for the interface. +/// +public static class GenericHostFixtureExtensions { /// - /// Extension methods for the interface. + /// Determines whether the specified has a valid state. /// - public static class GenericHostFixtureExtensions + /// The to check. + /// true if the specified has a valid state; otherwise, false. + /// + /// A valid state is defined as having non-null values for the following properties: + /// and . + /// + public static bool HasValidState(this IGenericHostFixture hostFixture) { - /// - /// Determines whether the specified has a valid state. - /// - /// The to check. - /// true if the specified has a valid state; otherwise, false. - /// - /// A valid state is defined as having non-null values for the following properties: - /// and . - /// - public static bool HasValidState(this IGenericHostFixture hostFixture) - { - return hostFixture.ConfigureServicesCallback != null && - hostFixture.ConfigureHostCallback != null; - } + return hostFixture.ConfigureServicesCallback != null && + hostFixture.ConfigureHostCallback != null; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/GlobalSuppressions.cs b/src/Codebelt.Extensions.Xunit.Hosting/GlobalSuppressions.cs index c2de754..a73e32e 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/GlobalSuppressions.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/GlobalSuppressions.cs @@ -1,4 +1,4 @@ -// This file is used by Code Analysis to maintain SuppressMessage +// This file is used by Code Analysis to maintain SuppressMessage // attributes that are applied to this project. // Project-level suppressions either have no target or are given // a specific target and scoped to a namespace, type, member, etc. @@ -7,13 +7,13 @@ [assembly: SuppressMessage("Major Code Smell", "S3881:\"IDisposable\" should be implemented correctly", Justification = "This is an implementation of the IDisposable interface tailored to avoid wrong implementations.", Scope = "type", Target = "~T:Codebelt.Extensions.Xunit.Hosting.HostFixture")] [assembly: SuppressMessage("Major Code Smell", "S3971:\"GC.SuppressFinalize\" should not be called", Justification = "False-Positive due to IAsyncDisposable living side-by-side with IDisposable.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.HostFixture.DisposeAsync~System.Threading.Tasks.ValueTask")] -[assembly: SuppressMessage("Blocker Code Smell", "S3427:Method overloads with default parameter values should not overlap", Justification = "Avoid bumping major version by providing an extra overloaded member as optional argument.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.GenericHostTestFactory.Create(System.Action{Microsoft.Extensions.DependencyInjection.IServiceCollection},System.Action{Microsoft.Extensions.Hosting.IHostBuilder},Codebelt.Extensions.Xunit.Hosting.IHostFixture)~Codebelt.Extensions.Xunit.Hosting.IGenericHostTest")] -[assembly: SuppressMessage("Blocker Code Smell", "S3427:Method overloads with default parameter values should not overlap", Justification = "Avoid bumping major version by providing an extra overloaded member as optional argument.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.GenericHostTestFactory.CreateWithHostBuilderContext(System.Action{Microsoft.Extensions.Hosting.HostBuilderContext,Microsoft.Extensions.DependencyInjection.IServiceCollection},System.Action{Microsoft.Extensions.Hosting.IHostBuilder},Codebelt.Extensions.Xunit.Hosting.IHostFixture)~Codebelt.Extensions.Xunit.Hosting.IGenericHostTest")] -[assembly: SuppressMessage("Maintainability", "CA1510:Use ArgumentNullException throw helper", Justification = "Wont fix. Multi-TFMs. Only supported with >= .NET 7.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.HostTest`1.#ctor(System.Boolean,`0,Xunit.Abstractions.ITestOutputHelper,System.Type)")] +[assembly: SuppressMessage("Blocker Code Smell", "S3427:Method overloads with default parameter values should not overlap", Justification = "Avoid bumping major version by providing an extra overloaded member as optional argument.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.HostTestFactory.Create(System.Action{Microsoft.Extensions.DependencyInjection.IServiceCollection},System.Action{Microsoft.Extensions.Hosting.IHostBuilder},Codebelt.Extensions.Xunit.Hosting.IGenericHostFixture)~Codebelt.Extensions.Xunit.Hosting.IHostTest")] +[assembly: SuppressMessage("Blocker Code Smell", "S3427:Method overloads with default parameter values should not overlap", Justification = "Avoid bumping major version by providing an extra overloaded member as optional argument.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.HostTestFactory.CreateWithHostBuilderContext(System.Action{Microsoft.Extensions.Hosting.HostBuilderContext,Microsoft.Extensions.DependencyInjection.IServiceCollection},System.Action{Microsoft.Extensions.Hosting.IHostBuilder},Codebelt.Extensions.Xunit.Hosting.IGenericHostFixture)~Codebelt.Extensions.Xunit.Hosting.IHostTest")] +[assembly: SuppressMessage("Maintainability", "CA1510:Use ArgumentNullException throw helper", Justification = "Wont fix. Multi-TFMs. Only supported with >= .NET 7.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.HostTest`1.#ctor(System.Boolean,`0,Xunit.ITestOutputHelper,System.Type)")] [assembly: SuppressMessage("Maintainability", "CA1510:Use ArgumentNullException throw helper", Justification = "Wont fix. Multi-TFMs. Only supported with >= .NET 7.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.LoggerExtensions.GetTestStore(Microsoft.Extensions.Logging.ILogger,System.String)~Codebelt.Extensions.Xunit.ITestStore{Codebelt.Extensions.Xunit.Hosting.XunitTestLoggerEntry}")] [assembly: SuppressMessage("Maintainability", "CA1510:Use ArgumentNullException throw helper", Justification = "Wont fix. Multi-TFMs. Only supported with >= .NET 7.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.ManagedHostFixture.ConfigureHost(Codebelt.Extensions.Xunit.Test)")] [assembly: SuppressMessage("Maintainability", "CA1510:Use ArgumentNullException throw helper", Justification = "Wont fix. Multi-TFMs. Only supported with >= .NET 7.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.ManagedMinimalHostFixture.ConfigureHost(Codebelt.Extensions.Xunit.Test)")] -[assembly: SuppressMessage("Maintainability", "CA1510:Use ArgumentNullException throw helper", Justification = "Wont fix. Multi-TFMs. Only supported with >= .NET 7.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.MinimalHostTest`1.#ctor(System.Boolean,`0,Xunit.Abstractions.ITestOutputHelper,System.Type)")] +[assembly: SuppressMessage("Maintainability", "CA1510:Use ArgumentNullException throw helper", Justification = "Wont fix. Multi-TFMs. Only supported with >= .NET 7.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.MinimalHostTest`1.#ctor(System.Boolean,`0,Xunit.ITestOutputHelper,System.Type)")] [assembly: SuppressMessage("Maintainability", "CA1510:Use ArgumentNullException throw helper", Justification = "Wont fix. Multi-TFMs. Only supported with >= .NET 7.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.ServiceCollectionExtensions.AddXunitTestLogging(Microsoft.Extensions.DependencyInjection.IServiceCollection,Microsoft.Extensions.Logging.LogLevel)~Microsoft.Extensions.DependencyInjection.IServiceCollection")] -[assembly: SuppressMessage("Maintainability", "CA1510:Use ArgumentNullException throw helper", Justification = "Wont fix. Multi-TFMs. Only supported with >= .NET 7.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.ServiceCollectionExtensions.AddXunitTestLogging(Microsoft.Extensions.DependencyInjection.IServiceCollection,Xunit.Abstractions.ITestOutputHelper,Microsoft.Extensions.Logging.LogLevel)~Microsoft.Extensions.DependencyInjection.IServiceCollection")] +[assembly: SuppressMessage("Maintainability", "CA1510:Use ArgumentNullException throw helper", Justification = "Wont fix. Multi-TFMs. Only supported with >= .NET 7.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.ServiceCollectionExtensions.AddXunitTestLogging(Microsoft.Extensions.DependencyInjection.IServiceCollection,Xunit.ITestOutputHelper,Microsoft.Extensions.Logging.LogLevel)~Microsoft.Extensions.DependencyInjection.IServiceCollection")] [assembly: SuppressMessage("Maintainability", "CA1510:Use ArgumentNullException throw helper", Justification = "Wont fix. Multi-TFMs. Only supported with >= .NET 7.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.ServiceCollectionExtensions.AddXunitTestLoggingOutputHelperAccessor``1(Microsoft.Extensions.DependencyInjection.IServiceCollection)~Microsoft.Extensions.DependencyInjection.IServiceCollection")] diff --git a/src/Codebelt.Extensions.Xunit.Hosting/HostFixture.cs b/src/Codebelt.Extensions.Xunit.Hosting/HostFixture.cs index 461917b..0abf8f9 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/HostFixture.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/HostFixture.cs @@ -5,194 +5,193 @@ using Microsoft.Extensions.Hosting; using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +/// +/// Represents the base class from which all implementations of xUnit fixture concept should derive. +/// +/// +public abstract class HostFixture : IHostFixture, IAsyncLifetime { - /// - /// Represents the base class from which all implementations of xUnit fixture concept should derive. - /// - /// - public abstract class HostFixture : IHostFixture, IAsyncLifetime - { #if NET9_0_OR_GREATER - private readonly Lock _lock = new(); + private readonly Lock _lock = new(); #else - private readonly object _lock = new(); + private readonly object _lock = new(); #endif - private Func _asyncHostRunnerCallback = async (host, cancellationToken) => + private Func _asyncHostRunnerCallback = async (host, cancellationToken) => + { + if (SynchronizationContext.Current == null) + { + await host.StartAsync(cancellationToken).ConfigureAwait(false); + } + else { - if (SynchronizationContext.Current == null) + Task.Run(async () => { await host.StartAsync(cancellationToken).ConfigureAwait(false); - } - else - { - Task.Run(async () => - { - await host.StartAsync(cancellationToken).ConfigureAwait(false); - }).GetAwaiter().GetResult(); - } + }).GetAwaiter().GetResult(); + } - // this was done to reduce the risk of deadlocks (https://stackoverflow.com/questions/50918647/why-does-this-xunit-test-deadlock-on-a-single-cpu-vm/50953607#50953607) - }; + // this was done to reduce the risk of deadlocks (https://stackoverflow.com/questions/50918647/why-does-this-xunit-test-deadlock-on-a-single-cpu-vm/50953607#50953607) + }; - /// - /// Initializes a new instance of the class. - /// - protected HostFixture() - { - } + /// + /// Initializes a new instance of the class. + /// + protected HostFixture() + { + } - /// - /// Determines whether the specified contains one or more of the specified target . - /// - /// The to validate. - /// The target types to be matched against. - /// true if the contains one or more of the specified target types; otherwise, false. - protected static bool HasTypes(Type type, params Type[] types) + /// + /// Determines whether the specified contains one or more of the specified target . + /// + /// The to validate. + /// The target types to be matched against. + /// true if the contains one or more of the specified target types; otherwise, false. + protected static bool HasTypes(Type type, params Type[] types) + { + foreach (var tt in types) { - foreach (var tt in types) + var st = type; + while (st != null) { - var st = type; - while (st != null) - { - if (st.IsGenericType && tt == st.GetGenericTypeDefinition()) { return true; } - if (st == tt) { return true; } - st = st.BaseType; - } + if (st.IsGenericType && tt == st.GetGenericTypeDefinition()) { return true; } + if (st == tt) { return true; } + st = st.BaseType; } - return false; } + return false; + } - /// - /// Gets or sets the delegate responsible for running the . - /// - /// The delegate responsible for running the . - /// - /// cannot be null. - /// - protected Func AsyncHostRunnerCallback + /// + /// Gets or sets the delegate responsible for running the . + /// + /// The delegate responsible for running the . + /// + /// cannot be null. + /// + protected Func AsyncHostRunnerCallback + { + get => _asyncHostRunnerCallback; + set => _asyncHostRunnerCallback = value ?? throw new ArgumentNullException(nameof(value), "The host runner delegate cannot be null."); + } + + /// + /// Gets or sets the delegate that initializes the test class. + /// + /// The delegate that initializes the test class. + /// Mimics the Startup convention. + public Action ConfigureCallback { get; set; } + + /// + /// Gets or sets the initialized by this instance. + /// + /// The initialized by this instance. + public IHost Host { get; protected set; } + + /// + /// Gets the initialized by this instance. + /// + /// The initialized by this instance. + public IConfiguration Configuration { get; protected set; } + + /// + /// Gets the initialized by this instance. + /// + /// The initialized by this instance. + public IHostEnvironment Environment { get; protected set; } + + /// + /// Gets a value indicating whether this object is disposed. + /// + /// true if this object is disposed; otherwise, false. + public bool Disposed { get; private set; } + + /// + /// Called when this object is being disposed by either or having disposing set to true and is false. + /// + protected virtual void OnDisposeManagedResources() + { + Host?.Dispose(); + } + + /// + /// Called when this object is being disposed by . + /// +#if NET8_0_OR_GREATER + protected virtual async ValueTask OnDisposeManagedResourcesAsync() + { + if (Host is IAsyncDisposable asyncDisposable) { - get => _asyncHostRunnerCallback; - set => _asyncHostRunnerCallback = value ?? throw new ArgumentNullException(nameof(value), "The host runner delegate cannot be null."); + await asyncDisposable.DisposeAsync(); } - - /// - /// Gets or sets the delegate that initializes the test class. - /// - /// The delegate that initializes the test class. - /// Mimics the Startup convention. - public Action ConfigureCallback { get; set; } - - /// - /// Gets or sets the initialized by this instance. - /// - /// The initialized by this instance. - public IHost Host { get; protected set; } - - /// - /// Gets the initialized by this instance. - /// - /// The initialized by this instance. - public IConfiguration Configuration { get; protected set; } - - /// - /// Gets the initialized by this instance. - /// - /// The initialized by this instance. - public IHostEnvironment Environment { get; protected set; } - - /// - /// Gets a value indicating whether this object is disposed. - /// - /// true if this object is disposed; otherwise, false. - public bool Disposed { get; private set; } - - /// - /// Called when this object is being disposed by either or having disposing set to true and is false. - /// - protected virtual void OnDisposeManagedResources() + else { Host?.Dispose(); } - - /// - /// Called when this object is being disposed by . - /// -#if NET8_0_OR_GREATER - protected virtual async ValueTask OnDisposeManagedResourcesAsync() + } +#else + protected virtual ValueTask OnDisposeManagedResourcesAsync() { - if (Host is IAsyncDisposable asyncDisposable) - { - await asyncDisposable.DisposeAsync(); - } - else - { - Host?.Dispose(); - } + OnDisposeManagedResources(); + return default; } -#else - protected virtual ValueTask OnDisposeManagedResourcesAsync() - { - OnDisposeManagedResources(); - return default; - } #endif - /// - /// Called when this object is being disposed by either or and is false. - /// - protected virtual void OnDisposeUnmanagedResources() - { - } + /// + /// Called when this object is being disposed by either or and is false. + /// + protected virtual void OnDisposeUnmanagedResources() + { + } - /// - /// Releases all resources used by the object. - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } + /// + /// Releases all resources used by the object. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - /// - /// Releases the unmanaged resources used by the object and optionally releases the managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected void Dispose(bool disposing) + /// + /// Releases the unmanaged resources used by the object and optionally releases the managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected void Dispose(bool disposing) + { + if (Disposed) { return; } + lock (_lock) { if (Disposed) { return; } - lock (_lock) + if (disposing) { - if (Disposed) { return; } - if (disposing) - { - OnDisposeManagedResources(); - } - OnDisposeUnmanagedResources(); - Disposed = true; + OnDisposeManagedResources(); } + OnDisposeUnmanagedResources(); + Disposed = true; } + } - /// - /// Asynchronously releases the resources used by the . - /// - /// A that represents the asynchronous dispose operation. - /// https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-disposeasync#the-disposeasync-method - public async ValueTask DisposeAsync() - { - await OnDisposeManagedResourcesAsync().ConfigureAwait(false); - Dispose(false); - GC.SuppressFinalize(this); - } + /// + /// Asynchronously releases the resources used by the . + /// + /// A that represents the asynchronous dispose operation. + /// https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-disposeasync#the-disposeasync-method + public async ValueTask DisposeAsync() + { + await OnDisposeManagedResourcesAsync().ConfigureAwait(false); + Dispose(false); + GC.SuppressFinalize(this); + } - /// - /// Called immediately after the class has been created, before it is used. - /// - /// A that represents the asynchronous operation. - public virtual ValueTask InitializeAsync() - { - return default; - } + /// + /// Called immediately after the class has been created, before it is used. + /// + /// A that represents the asynchronous operation. + public virtual ValueTask InitializeAsync() + { + return default; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/HostTest.cs b/src/Codebelt.Extensions.Xunit.Hosting/HostTest.cs index 3e2cf9f..18b7f19 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/HostTest.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/HostTest.cs @@ -1,118 +1,121 @@ -using System; +using System; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +/// +/// Represents the non-generic base class from where its generic equivalent should derive. +/// +/// +/// +/// +public abstract class HostTest : Test, IHostTest { /// - /// Represents the non-generic base class from where its generic equivalent should derive. + /// Initializes a new instance of the class. /// - /// - /// - /// - public abstract class HostTest : Test, IHostTest + /// An implementation of the interface. + /// The of caller that ends up invoking this instance. + protected HostTest(ITestOutputHelper output = null, Type callerType = null) : base(output, callerType) { - /// - /// Initializes a new instance of the class. - /// - /// An implementation of the interface. - /// The of caller that ends up invoking this instance. - protected HostTest(ITestOutputHelper output = null, Type callerType = null) : base(output, callerType) - { - } + } - /// - /// Adds and to this instance. - /// - /// The initialized by the . - /// The initialized by the . - public virtual void Configure(IConfiguration configuration, IHostEnvironment environment) - { - Configuration = configuration; - Environment = environment; - } + /// + /// Adds and to this instance. + /// + /// The initialized by the . + /// The initialized by the . + public virtual void Configure(IConfiguration configuration, IHostEnvironment environment) + { + Configuration = configuration; + Environment = environment; + } - /// - /// Gets the initialized by the . - /// - /// The initialized by the . - public IHost Host { get; protected set; } + /// + /// Gets the initialized by the . + /// + /// The initialized by the . + public IHost Host { get; protected set; } - /// - /// Gets the initialized by the . - /// - /// The initialized by the . - public IConfiguration Configuration { get; protected set; } + /// + /// Gets the initialized by the . + /// + /// The initialized by the . + public IConfiguration Configuration { get; protected set; } - /// - /// Gets the initialized by the . - /// - /// The initialized by the . - public IHostEnvironment Environment { get; protected set; } - } + /// + /// Gets the initialized by the . + /// + /// The initialized by the . + public IHostEnvironment Environment { get; protected set; } +} +/// +/// Represents a base class from which all implementations of unit testing, that uses Microsoft Dependency Injection, should derive. +/// +/// The type of the object that implements the interface. +/// +/// +/// +/// The class needed to be designed in this rather complex way, as this is the only way that xUnit supports a shared context. The need for shared context is theoretical at best, but it does opt-in for Scoped instances. +public abstract class HostTest : HostTest, IClassFixture where T : class, IGenericHostFixture +{ /// - /// Represents a base class from which all implementations of unit testing, that uses Microsoft Dependency Injection, should derive. + /// Initializes a new instance of the class. /// - /// The type of the object that implements the interface. - /// - /// - /// - /// The class needed to be designed in this rather complex way, as this is the only way that xUnit supports a shared context. The need for shared context is theoretical at best, but it does opt-in for Scoped instances. - public abstract class HostTest : HostTest, IClassFixture where T : class, IGenericHostFixture + /// An implementation of the interface. + /// An implementation of the interface. + /// The of caller that ends up invoking this instance. + /// + /// is null. + /// + protected HostTest(T hostFixture, ITestOutputHelper output = null, Type callerType = null) : this(false, hostFixture, output, callerType) { - /// - /// Initializes a new instance of the class. - /// - /// An implementation of the interface. - /// An implementation of the interface. - /// The of caller that ends up invoking this instance. - /// - /// is null. - /// - protected HostTest(T hostFixture, ITestOutputHelper output = null, Type callerType = null) : this(false, hostFixture, output, callerType) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// A value indicating whether to skip the host fixture initialization. - /// An implementation of the interface. - /// An implementation of the interface. - /// The of caller that ends up invoking this instance. - /// - /// is null. - /// - protected HostTest(bool skipHostFixtureInitialization, T hostFixture, ITestOutputHelper output = null, Type callerType = null) : base(output, callerType) - { - if (hostFixture == null) { throw new ArgumentNullException(nameof(hostFixture)); } - if (skipHostFixtureInitialization) { return; } - if (!hostFixture.HasValidState()) - { - hostFixture.ConfigureHostCallback = ConfigureHost; - hostFixture.ConfigureCallback = Configure; - hostFixture.ConfigureServicesCallback = ConfigureServices; - hostFixture.ConfigureHost(this); - } - Host = hostFixture.Host; - Configure(hostFixture.Configuration, hostFixture.Environment); - } + } - /// - /// Provides a way to override the defaults set up by . - /// - /// The that initializes an instance of . - protected virtual void ConfigureHost(IHostBuilder hb) + /// + /// Initializes a new instance of the class. + /// + /// A value indicating whether to skip the host fixture initialization. + /// An implementation of the interface. + /// An implementation of the interface. + /// The of caller that ends up invoking this instance. + /// + /// is null. + /// + protected HostTest(bool skipHostFixtureInitialization, T hostFixture, ITestOutputHelper output = null, Type callerType = null) : base(output, callerType) + { +#if NETSTANDARD2_0 + if (hostFixture == null) { throw new ArgumentNullException(nameof(hostFixture)); } +#else + ArgumentNullException.ThrowIfNull(hostFixture); +#endif + if (skipHostFixtureInitialization) { return; } + if (!hostFixture.HasValidState()) { + hostFixture.ConfigureHostCallback = ConfigureHost; + hostFixture.ConfigureCallback = Configure; + hostFixture.ConfigureServicesCallback = ConfigureServices; + hostFixture.ConfigureHost(this); } + Host = hostFixture.Host; + Configure(hostFixture.Configuration, hostFixture.Environment); + } - /// - /// Adds services to the container. - /// - /// The collection of service descriptors. - public abstract void ConfigureServices(IServiceCollection services); + /// + /// Provides a way to override the defaults set up by . + /// + /// The that initializes an instance of . + protected virtual void ConfigureHost(IHostBuilder hb) + { } + + /// + /// Adds services to the container. + /// + /// The collection of service descriptors. + public abstract void ConfigureServices(IServiceCollection services); } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/HostTestFactory.cs b/src/Codebelt.Extensions.Xunit.Hosting/HostTestFactory.cs index 0962eea..fb4dd21 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/HostTestFactory.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/HostTestFactory.cs @@ -2,35 +2,34 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +/// +/// Provides a set of static methods for unit testing. +/// +public static class HostTestFactory { /// - /// Provides a set of static methods for unit testing. + /// Creates and returns an implementation. /// - public static class HostTestFactory + /// The which may be configured. + /// The which may be configured. + /// An optional implementation to use instead of the default instance. + /// An instance of an implementation. + public static IHostTest Create(Action serviceSetup = null, Action hostSetup = null, IGenericHostFixture hostFixture = null) { - /// - /// Creates and returns an implementation. - /// - /// The which may be configured. - /// The which may be configured. - /// An optional implementation to use instead of the default instance. - /// An instance of an implementation. - public static IHostTest Create(Action serviceSetup = null, Action hostSetup = null, IGenericHostFixture hostFixture = null) - { - return new Internal.HostTest(serviceSetup, hostSetup, hostFixture ?? new ManagedHostFixture()); - } + return new Internal.HostTest(serviceSetup, hostSetup, hostFixture ?? new ManagedHostFixture()); + } - /// - /// Creates and returns an implementation. - /// - /// The which may be configured. - /// The which may be configured. - /// An optional implementation to use instead of the default instance. - /// An instance of an implementation. - public static IHostTest CreateWithHostBuilderContext(Action serviceSetup = null, Action hostSetup = null, IGenericHostFixture hostFixture = null) - { - return new Internal.HostTest(serviceSetup, hostSetup, hostFixture ?? new ManagedHostFixture()); - } + /// + /// Creates and returns an implementation. + /// + /// The which may be configured. + /// The which may be configured. + /// An optional implementation to use instead of the default instance. + /// An instance of an implementation. + public static IHostTest CreateWithHostBuilderContext(Action serviceSetup = null, Action hostSetup = null, IGenericHostFixture hostFixture = null) + { + return new Internal.HostTest(serviceSetup, hostSetup, hostFixture ?? new ManagedHostFixture()); } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/IConfigurationTest.cs b/src/Codebelt.Extensions.Xunit.Hosting/IConfigurationTest.cs index 6a63ae6..e925a28 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/IConfigurationTest.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/IConfigurationTest.cs @@ -1,17 +1,16 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +/// +/// Represents the members needed for DI testing with support for Configuration. +/// +public interface IConfigurationTest { /// - /// Represents the members needed for DI testing with support for Configuration. + /// Gets the initialized by the . /// - public interface IConfigurationTest - { - /// - /// Gets the initialized by the . - /// - /// The initialized by the . - IConfiguration Configuration { get; } - } + /// The initialized by the . + IConfiguration Configuration { get; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/IEnvironmentTest.cs b/src/Codebelt.Extensions.Xunit.Hosting/IEnvironmentTest.cs index 95c3a22..6801a74 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/IEnvironmentTest.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/IEnvironmentTest.cs @@ -1,16 +1,15 @@ using Microsoft.Extensions.Hosting; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +/// +/// Represents the members needed for DI testing with support for . +/// +public interface IEnvironmentTest { /// - /// Represents the members needed for DI testing with support for . + /// Gets the initialized by the . /// - public interface IEnvironmentTest - { - /// - /// Gets the initialized by the . - /// - /// The initialized by the . - IHostEnvironment Environment { get; } - } + /// The initialized by the . + IHostEnvironment Environment { get; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/IGenericHostFixture.cs b/src/Codebelt.Extensions.Xunit.Hosting/IGenericHostFixture.cs index 92ce0d8..457c579 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/IGenericHostFixture.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/IGenericHostFixture.cs @@ -2,31 +2,30 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +/// +/// Provides a way to use Microsoft Dependency Injection in unit tests. +/// +/// +public interface IGenericHostFixture : IHostFixture { /// - /// Provides a way to use Microsoft Dependency Injection in unit tests. + /// Gets or sets the delegate that adds services to the container. /// - /// - public interface IGenericHostFixture : IHostFixture - { - /// - /// Gets or sets the delegate that adds services to the container. - /// - /// The delegate that adds services to the container. - Action ConfigureServicesCallback { get; set; } + /// The delegate that adds services to the container. + Action ConfigureServicesCallback { get; set; } - /// - /// Gets or sets the delegate that provides a way to override the defaults set up by . - /// - /// The delegate that provides a way to override the . - Action ConfigureHostCallback { get; set; } + /// + /// Gets or sets the delegate that provides a way to override the defaults set up by . + /// + /// The delegate that provides a way to override the . + Action ConfigureHostCallback { get; set; } - /// - /// Creates and configures the of this . - /// - /// The object that inherits from . - /// was added to support those cases where the caller is required in the host configuration. - void ConfigureHost(Test hostTest); - } + /// + /// Creates and configures the of this . + /// + /// The object that inherits from . + /// was added to support those cases where the caller is required in the host configuration. + void ConfigureHost(Test hostTest); } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/IHostFixture.cs b/src/Codebelt.Extensions.Xunit.Hosting/IHostFixture.cs index b97e197..92b247f 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/IHostFixture.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/IHostFixture.cs @@ -2,27 +2,26 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +/// +/// Provides a way to support app and lifetime management in unit tests. +/// +/// +/// +/// +/// +public interface IHostFixture : IConfigurationTest, IEnvironmentTest, IDisposable, IAsyncDisposable { /// - /// Provides a way to support app and lifetime management in unit tests. + /// Gets the initialized by either the or . /// - /// - /// - /// - /// - public interface IHostFixture : IConfigurationTest, IEnvironmentTest, IDisposable, IAsyncDisposable - { - /// - /// Gets the initialized by either the or . - /// - /// The initialized by the or . - IHost Host { get; } + /// The initialized by the or . + IHost Host { get; } - /// - /// Gets or sets the delegate that adds configuration and environment information to a . - /// - /// The delegate that adds configuration and environment information to a . - Action ConfigureCallback { get; set; } - } + /// + /// Gets or sets the delegate that adds configuration and environment information to a . + /// + /// The delegate that adds configuration and environment information to a . + Action ConfigureCallback { get; set; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/IHostTest.cs b/src/Codebelt.Extensions.Xunit.Hosting/IHostTest.cs index 0314a75..64e48f9 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/IHostTest.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/IHostTest.cs @@ -1,19 +1,18 @@ using Microsoft.Extensions.Hosting; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +/// +/// Represents the members needed for bare-bone DI testing with support for . +/// +/// +/// +/// +public interface IHostTest : IConfigurationTest, IEnvironmentTest, ITest { /// - /// Represents the members needed for bare-bone DI testing with support for . + /// Gets the initialized by the . /// - /// - /// - /// - public interface IHostTest : IConfigurationTest, IEnvironmentTest, ITest - { - /// - /// Gets the initialized by the . - /// - /// The initialized by the . - IHost Host { get; } - } + /// The initialized by the . + IHost Host { get; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/IMinimalHostFixture.cs b/src/Codebelt.Extensions.Xunit.Hosting/IMinimalHostFixture.cs index bafe994..1c95f83 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/IMinimalHostFixture.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/IMinimalHostFixture.cs @@ -1,27 +1,26 @@ using Microsoft.Extensions.Hosting; using System; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +/// +/// Provides a way to use Microsoft Dependency Injection in unit tests (minimal style). +/// +/// +/// +/// +public interface IMinimalHostFixture : IHostFixture { /// - /// Provides a way to use Microsoft Dependency Injection in unit tests (minimal style). + /// Gets or sets the delegate that provides a way to override the defaults set up by . /// - /// - /// - /// - public interface IMinimalHostFixture : IHostFixture - { - /// - /// Gets or sets the delegate that provides a way to override the defaults set up by . - /// - /// The delegate that provides a way to override the . - Action ConfigureHostCallback { get; set; } + /// The delegate that provides a way to override the . + Action ConfigureHostCallback { get; set; } - /// - /// Creates and configures the of this . - /// - /// The object that inherits from . - /// was added to support those cases where the caller is required in the host configuration. - void ConfigureHost(Test hostTest); - } + /// + /// Creates and configures the of this . + /// + /// The object that inherits from . + /// was added to support those cases where the caller is required in the host configuration. + void ConfigureHost(Test hostTest); } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/Internal/HostTest.cs b/src/Codebelt.Extensions.Xunit.Hosting/Internal/HostTest.cs index 6857372..87268ba 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/Internal/HostTest.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/Internal/HostTest.cs @@ -2,57 +2,56 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Codebelt.Extensions.Xunit.Hosting.Internal +namespace Codebelt.Extensions.Xunit.Hosting.Internal; + +internal sealed class HostTest : HostTest { - internal sealed class HostTest : HostTest - { - private readonly Action _serviceConfigurator; - private readonly Action _serviceConfiguratorWithContext; - private readonly Action _hostConfigurator; - private HostBuilderContext _hostBuilderContext; + private readonly Action _serviceConfigurator; + private readonly Action _serviceConfiguratorWithContext; + private readonly Action _hostConfigurator; + private HostBuilderContext _hostBuilderContext; - internal HostTest(Action serviceConfigurator, Action hostConfigurator, IGenericHostFixture hostFixture) : base(true, hostFixture, callerType: serviceConfigurator?.Target?.GetType() ?? hostConfigurator?.Target?.GetType()) - { - _serviceConfigurator = serviceConfigurator; - _hostConfigurator = hostConfigurator; - InitializeHostFixture(hostFixture); - } + internal HostTest(Action serviceConfigurator, Action hostConfigurator, IGenericHostFixture hostFixture) : base(true, hostFixture, callerType: serviceConfigurator?.Target?.GetType() ?? hostConfigurator?.Target?.GetType()) + { + _serviceConfigurator = serviceConfigurator; + _hostConfigurator = hostConfigurator; + InitializeHostFixture(hostFixture); + } - internal HostTest(Action serviceConfigurator, Action hostConfigurator, IGenericHostFixture hostFixture) : base(true, hostFixture, callerType: serviceConfigurator?.Target?.GetType() ?? hostConfigurator?.Target?.GetType()) - { - _serviceConfiguratorWithContext = serviceConfigurator; - _hostConfigurator = hostConfigurator; - InitializeHostFixture(hostFixture); - } + internal HostTest(Action serviceConfigurator, Action hostConfigurator, IGenericHostFixture hostFixture) : base(true, hostFixture, callerType: serviceConfigurator?.Target?.GetType() ?? hostConfigurator?.Target?.GetType()) + { + _serviceConfiguratorWithContext = serviceConfigurator; + _hostConfigurator = hostConfigurator; + InitializeHostFixture(hostFixture); + } - private void InitializeHostFixture(IGenericHostFixture hostFixture) + private void InitializeHostFixture(IGenericHostFixture hostFixture) + { + if (!hostFixture.HasValidState()) { - if (!hostFixture.HasValidState()) - { - hostFixture.ConfigureHostCallback = ConfigureHost; - hostFixture.ConfigureCallback = Configure; - hostFixture.ConfigureServicesCallback = ConfigureServices; - hostFixture.ConfigureHost(this); - } - Host = hostFixture.Host; - Configure(hostFixture.Configuration, hostFixture.Environment); + hostFixture.ConfigureHostCallback = ConfigureHost; + hostFixture.ConfigureCallback = Configure; + hostFixture.ConfigureServicesCallback = ConfigureServices; + hostFixture.ConfigureHost(this); } + Host = hostFixture.Host; + Configure(hostFixture.Configuration, hostFixture.Environment); + } - protected override void ConfigureHost(IHostBuilder hb) - { - _hostBuilderContext = new HostBuilderContext(hb.Properties); - _hostConfigurator?.Invoke(hb); - } + protected override void ConfigureHost(IHostBuilder hb) + { + _hostBuilderContext = new HostBuilderContext(hb.Properties); + _hostConfigurator?.Invoke(hb); + } - public override void ConfigureServices(IServiceCollection services) + public override void ConfigureServices(IServiceCollection services) + { + _serviceConfigurator?.Invoke(services); + _serviceConfiguratorWithContext?.Invoke(Tweaker.Adjust(_hostBuilderContext, hbc => { - _serviceConfigurator?.Invoke(services); - _serviceConfiguratorWithContext?.Invoke(Tweaker.Adjust(_hostBuilderContext, hbc => - { - hbc.Configuration = Configuration; - hbc.HostingEnvironment = Environment; - return hbc; - }), services); - } + hbc.Configuration = Configuration; + hbc.HostingEnvironment = Environment; + return hbc; + }), services); } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/Internal/MinimalHostTest.cs b/src/Codebelt.Extensions.Xunit.Hosting/Internal/MinimalHostTest.cs index e6233b8..b920ed8 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/Internal/MinimalHostTest.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/Internal/MinimalHostTest.cs @@ -2,52 +2,51 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Codebelt.Extensions.Xunit.Hosting.Internal +namespace Codebelt.Extensions.Xunit.Hosting.Internal; + +internal sealed class MinimalHostTest : MinimalHostTest { - internal sealed class MinimalHostTest : MinimalHostTest - { - private readonly Action _serviceConfigurator; - private readonly Action _serviceConfiguratorWithContext; - private readonly Action _hostConfigurator; - private HostBuilderContext _hostBuilderContext; + private readonly Action _serviceConfigurator; + private readonly Action _serviceConfiguratorWithContext; + private readonly Action _hostConfigurator; + private HostBuilderContext _hostBuilderContext; - internal MinimalHostTest(Action serviceConfigurator, Action hostConfigurator, IMinimalHostFixture hostFixture) : base(true, hostFixture, callerType: serviceConfigurator?.Target?.GetType() ?? hostConfigurator?.Target?.GetType()) - { - _serviceConfigurator = serviceConfigurator; - _hostConfigurator = hostConfigurator; - InitializeHostFixture(hostFixture); - } + internal MinimalHostTest(Action serviceConfigurator, Action hostConfigurator, IMinimalHostFixture hostFixture) : base(true, hostFixture, callerType: serviceConfigurator?.Target?.GetType() ?? hostConfigurator?.Target?.GetType()) + { + _serviceConfigurator = serviceConfigurator; + _hostConfigurator = hostConfigurator; + InitializeHostFixture(hostFixture); + } - internal MinimalHostTest(Action serviceConfigurator, Action hostConfigurator, IMinimalHostFixture hostFixture) : base(true, hostFixture, callerType: serviceConfigurator?.Target?.GetType() ?? hostConfigurator?.Target?.GetType()) - { - _serviceConfiguratorWithContext = serviceConfigurator; - _hostConfigurator = hostConfigurator; - InitializeHostFixture(hostFixture); - } + internal MinimalHostTest(Action serviceConfigurator, Action hostConfigurator, IMinimalHostFixture hostFixture) : base(true, hostFixture, callerType: serviceConfigurator?.Target?.GetType() ?? hostConfigurator?.Target?.GetType()) + { + _serviceConfiguratorWithContext = serviceConfigurator; + _hostConfigurator = hostConfigurator; + InitializeHostFixture(hostFixture); + } - private void InitializeHostFixture(IMinimalHostFixture hostFixture) + private void InitializeHostFixture(IMinimalHostFixture hostFixture) + { + if (!hostFixture.HasValidState()) { - if (!hostFixture.HasValidState()) - { - hostFixture.ConfigureCallback = Configure; - hostFixture.ConfigureHostCallback = ConfigureHost; - hostFixture.ConfigureHost(this); - } - Host = hostFixture.Host; - Configure(hostFixture.Configuration, hostFixture.Environment); + hostFixture.ConfigureCallback = Configure; + hostFixture.ConfigureHostCallback = ConfigureHost; + hostFixture.ConfigureHost(this); } + Host = hostFixture.Host; + Configure(hostFixture.Configuration, hostFixture.Environment); + } - protected override void ConfigureHost(IHostApplicationBuilder hb) + protected override void ConfigureHost(IHostApplicationBuilder hb) + { + _hostBuilderContext = new HostBuilderContext(hb.Properties); + _hostConfigurator?.Invoke(hb); + _serviceConfigurator?.Invoke(hb.Services); + _serviceConfiguratorWithContext?.Invoke(Tweaker.Adjust(_hostBuilderContext, hbc => { - _hostBuilderContext = new HostBuilderContext(hb.Properties); - _hostConfigurator?.Invoke(hb); - _serviceConfigurator?.Invoke(hb.Services); - _serviceConfiguratorWithContext?.Invoke(Tweaker.Adjust(_hostBuilderContext, hbc => - { - hbc.Configuration = hb.Configuration; - hbc.HostingEnvironment = hb.Environment; - return hbc; - }), hb.Services); - } + hbc.Configuration = hb.Configuration; + hbc.HostingEnvironment = hb.Environment; + return hbc; + }), hb.Services); } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/LoggerExtensions.cs b/src/Codebelt.Extensions.Xunit.Hosting/LoggerExtensions.cs index c85e32e..da04953 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/LoggerExtensions.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/LoggerExtensions.cs @@ -1,75 +1,87 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using Microsoft.Extensions.Logging; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +/// +/// Extension methods for the interface. +/// +public static class LoggerExtensions { /// - /// Extension methods for the interface. + /// Returns the associated that is provided when settings up services from or related. /// - public static class LoggerExtensions + /// The from which to retrieve the . + /// The category name for messages produced by the -or- null for messages produced by all loggers. + /// Returns an implementation of with all logged entries expressed as . + /// + /// cannot be null. + /// + /// + /// does not contain a test store. + /// + /// + /// does not contain a test store for the specified . + /// + public static ITestStore GetTestStore(this ILogger logger, string categoryName = null) { - /// - /// Returns the associated that is provided when settings up services from or related. - /// - /// The from which to retrieve the . - /// The category name for messages produced by the -or- null for messages produced by all loggers. - /// Returns an implementation of with all logged entries expressed as . - /// - /// cannot be null. - /// - /// - /// does not contain a test store. - /// - /// - /// does not contain a test store for the specified . - /// - public static ITestStore GetTestStore(this ILogger logger, string categoryName = null) + if (logger == null) { throw new ArgumentNullException(nameof(logger)); } + var internalLogger = GetInternalLogger(logger); + if (internalLogger != null) { - if (logger == null) { throw new ArgumentNullException(nameof(logger)); } - var loggerType = logger.GetType(); - var internalLogger = loggerType.GetRuntimeFields().SingleOrDefault(fi => fi.Name == "_logger")?.GetValue(logger); - if (internalLogger != null) - { - var internalLoggerType = internalLogger.GetType(); - var internalLoggers = internalLoggerType.GetRuntimeProperties().SingleOrDefault(pi => pi.Name == "Loggers")?.GetValue(internalLogger); - if (internalLoggers != null) - { - foreach (var loggerInformation in (IEnumerable)internalLoggers) - { - var loggerInformationType = loggerInformation.GetType(); - var providerType = loggerInformationType.GetProperty("ProviderType")?.GetValue(loggerInformation) as Type; - if (providerType == typeof(XunitTestLoggerProvider)) - { - var xunitTestLogger = loggerInformationType.GetProperty("Logger")?.GetValue(loggerInformation) as XunitTestLogger; - if (xunitTestLogger == null) { continue; } - return categoryName == null - ? xunitTestLogger.Provider - : xunitTestLogger.Provider[categoryName]; - } - } - } - } - throw new ArgumentException($"Logger does not contain a test store; did you remember to call {nameof(ServiceCollectionExtensions.AddXunitTestLogging)} before calling this method?", nameof(logger)); + var store = FindTestStore(internalLogger, categoryName); + if (store != null) { return store; } } + throw new ArgumentException($"Logger does not contain a test store; did you remember to call {nameof(ServiceCollectionExtensions.AddXunitTestLogging)} before calling this method?", nameof(logger)); + } - /// - /// Returns the associated that is provided when settings up services from or related. - /// - /// The from which to retrieve the . - /// Returns an implementation of with all logged entries expressed as . - /// - /// cannot be null. - /// - /// - /// does not contain a test store. - /// - public static ITestStore GetTestStore(this ILogger logger) + private static object GetInternalLogger(ILogger logger) + { + var loggerType = logger.GetType(); + return loggerType.GetRuntimeFields().SingleOrDefault(fi => fi.Name == "_logger")?.GetValue(logger); + } + + private static ITestStore FindTestStore(object internalLogger, string categoryName) + { + var internalLoggerType = internalLogger.GetType(); + var internalLoggers = internalLoggerType.GetRuntimeProperties().SingleOrDefault(pi => pi.Name == "Loggers")?.GetValue(internalLogger); + if (internalLoggers == null) { return null; } + foreach (var loggerInformation in (IEnumerable)internalLoggers) { - return GetTestStore(logger, typeof(T).FullName); + var store = TryGetTestStore(loggerInformation, categoryName); + if (store != null) { return store; } } + return null; + } + + private static ITestStore TryGetTestStore(object loggerInformation, string categoryName) + { + var loggerInformationType = loggerInformation.GetType(); + var providerType = loggerInformationType.GetProperty("ProviderType")?.GetValue(loggerInformation) as Type; + if (providerType != typeof(XunitTestLoggerProvider)) { return null; } + if (loggerInformationType.GetProperty("Logger")?.GetValue(loggerInformation) is not XunitTestLogger xunitTestLogger) { return null; } + return categoryName == null + ? xunitTestLogger.Provider + : xunitTestLogger.Provider[categoryName]; + } + + /// + /// Returns the associated that is provided when settings up services from or related. + /// + /// The from which to retrieve the . + /// Returns an implementation of with all logged entries expressed as . + /// + /// cannot be null. + /// + /// + /// does not contain a test store. + /// + public static ITestStore GetTestStore(this ILogger logger) + { + return GetTestStore(logger, typeof(T).FullName); } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/ManagedHostFixture.cs b/src/Codebelt.Extensions.Xunit.Hosting/ManagedHostFixture.cs index 7a593c7..5aa7bd1 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/ManagedHostFixture.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/ManagedHostFixture.cs @@ -6,90 +6,89 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +/// +/// Provides a default implementation of the interface. +/// +/// +/// +public class ManagedHostFixture : HostFixture, IGenericHostFixture { /// - /// Provides a default implementation of the interface. + /// Initializes a new instance of the class. /// - /// - /// - public class ManagedHostFixture : HostFixture, IGenericHostFixture + public ManagedHostFixture() { - /// - /// Initializes a new instance of the class. - /// - public ManagedHostFixture() - { - } + } - /// - /// Creates and configures the of this instance. - /// - /// The object that inherits from . - /// was added to support those cases where the caller is required in the host configuration. - /// - /// is null. - /// - /// - /// is not assignable from . - /// - public virtual void ConfigureHost(Test hostTest) - { - if (hostTest == null) { throw new ArgumentNullException(nameof(hostTest)); } - if (!HasTypes(hostTest.GetType(), typeof(HostTest<>))) { throw new ArgumentOutOfRangeException(nameof(hostTest), typeof(HostTest<>), $"{nameof(hostTest)} is not assignable from HostTest."); } - if (!this.HasValidState()) { return; } // had to include this due to dual-call this method (one uncontrolled from xUnit library reflection magic; second controlled from this library) + /// + /// Creates and configures the of this instance. + /// + /// The object that inherits from . + /// was added to support those cases where the caller is required in the host configuration. + /// + /// is null. + /// + /// + /// is not assignable from . + /// + public virtual void ConfigureHost(Test hostTest) + { + if (hostTest == null) { throw new ArgumentNullException(nameof(hostTest)); } + if (!HasTypes(hostTest.GetType(), typeof(HostTest<>))) { throw new ArgumentOutOfRangeException(nameof(hostTest), typeof(HostTest<>), $"{nameof(hostTest)} is not assignable from HostTest."); } + if (!this.HasValidState()) { return; } // had to include this due to dual-call this method (one uncontrolled from xUnit library reflection magic; second controlled from this library) - var hb = new HostBuilder() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseEnvironment("Development") - .ConfigureAppConfiguration((context, config) => - { - config - .AddJsonFile("appsettings.json", true, true) - .AddJsonFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.json", true, true) - .AddEnvironmentVariables(); + var hb = new HostBuilder() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseEnvironment("Development") + .ConfigureAppConfiguration((context, config) => + { + config + .AddJsonFile("appsettings.json", true, true) + .AddJsonFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.json", true, true) + .AddEnvironmentVariables(); - ConfigureCallback(config.Build(), context.HostingEnvironment); - }) - .ConfigureServices((context, services) => - { - Configuration = context.Configuration; - Environment = context.HostingEnvironment; - ConfigureServicesCallback(services); - }) - .ConfigureHostConfiguration(builder => + ConfigureCallback(config.Build(), context.HostingEnvironment); + }) + .ConfigureServices((context, services) => + { + Configuration = context.Configuration; + Environment = context.HostingEnvironment; + ConfigureServicesCallback(services); + }) + .ConfigureHostConfiguration(builder => + { + builder.AddInMemoryCollection(new Dictionary { - builder.AddInMemoryCollection(new Dictionary - { - { HostDefaults.ApplicationKey, hostTest.CallerType.Assembly.GetName().Name } - }); + { HostDefaults.ApplicationKey, hostTest.CallerType.Assembly.GetName().Name } }); + }); #if NET9_0_OR_GREATER - hb.UseDefaultServiceProvider(o => - { - o.ValidateOnBuild = true; - o.ValidateScopes = true; - }); + hb.UseDefaultServiceProvider(o => + { + o.ValidateOnBuild = true; + o.ValidateScopes = true; + }); #endif - ConfigureHostCallback(hb); + ConfigureHostCallback(hb); - Host = hb.Build(); + Host = hb.Build(); - AsyncHostRunnerCallback(Host, CancellationToken.None); - } + AsyncHostRunnerCallback(Host, CancellationToken.None); + } - /// - /// Gets or sets the delegate that initializes the host builder. - /// - /// The delegate that initializes the host builder. - public Action ConfigureHostCallback { get; set; } + /// + /// Gets or sets the delegate that initializes the host builder. + /// + /// The delegate that initializes the host builder. + public Action ConfigureHostCallback { get; set; } - /// - /// Gets or sets the delegate that adds services to the container. - /// - /// The delegate that adds services to the container. - public Action ConfigureServicesCallback { get; set; } - } + /// + /// Gets or sets the delegate that adds services to the container. + /// + /// The delegate that adds services to the container. + public Action ConfigureServicesCallback { get; set; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/ManagedMinimalHostFixture.cs b/src/Codebelt.Extensions.Xunit.Hosting/ManagedMinimalHostFixture.cs index bf01d9a..b6319d2 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/ManagedMinimalHostFixture.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/ManagedMinimalHostFixture.cs @@ -2,61 +2,60 @@ using System.Threading; using Microsoft.Extensions.Hosting; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +/// +/// Provides a default implementation of the interface. +/// +/// +/// +/// This is the "modern" minimal style implementation of . +public class ManagedMinimalHostFixture : HostFixture, IMinimalHostFixture { /// - /// Provides a default implementation of the interface. + /// Initializes a new instance of the class. /// - /// - /// - /// This is the "modern" minimal style implementation of . - public class ManagedMinimalHostFixture : HostFixture, IMinimalHostFixture + public ManagedMinimalHostFixture() { - /// - /// Initializes a new instance of the class. - /// - public ManagedMinimalHostFixture() - { - } - - /// - /// Creates and configures the of this instance. - /// - /// The object that inherits from . - /// was added to support those cases where the caller is required in the host configuration. - /// - /// is null. - /// - /// - /// is not assignable from . - /// - public virtual void ConfigureHost(Test hostTest) - { - if (hostTest == null) { throw new ArgumentNullException(nameof(hostTest)); } - if (!HasTypes(hostTest.GetType(), typeof(MinimalHostTest<>))) { throw new ArgumentOutOfRangeException(nameof(hostTest), typeof(MinimalHostTest<>), $"{nameof(hostTest)} is not assignable from MinimalHostTest."); } + } - var hb = Microsoft.Extensions.Hosting.Host.CreateApplicationBuilder(new HostApplicationBuilderSettings() - { - EnvironmentName = "Development", - ApplicationName = hostTest.CallerType.Assembly.GetName().Name, - }); + /// + /// Creates and configures the of this instance. + /// + /// The object that inherits from . + /// was added to support those cases where the caller is required in the host configuration. + /// + /// is null. + /// + /// + /// is not assignable from . + /// + public virtual void ConfigureHost(Test hostTest) + { + if (hostTest == null) { throw new ArgumentNullException(nameof(hostTest)); } + if (!HasTypes(hostTest.GetType(), typeof(MinimalHostTest<>))) { throw new ArgumentOutOfRangeException(nameof(hostTest), typeof(MinimalHostTest<>), $"{nameof(hostTest)} is not assignable from MinimalHostTest."); } - Configuration = hb.Configuration; - Environment = hb.Environment; + var hb = Microsoft.Extensions.Hosting.Host.CreateApplicationBuilder(new HostApplicationBuilderSettings() + { + EnvironmentName = "Development", + ApplicationName = hostTest.CallerType.Assembly.GetName().Name, + }); - ConfigureCallback(Configuration, Environment); + Configuration = hb.Configuration; + Environment = hb.Environment; - ConfigureHostCallback(hb); + ConfigureCallback(Configuration, Environment); - Host = hb.Build(); + ConfigureHostCallback(hb); - AsyncHostRunnerCallback(Host, CancellationToken.None); - } + Host = hb.Build(); - /// - /// Gets or sets the delegate that initializes the host application builder. - /// - /// The delegate that initializes the host application builder. - public Action ConfigureHostCallback { get; set; } + AsyncHostRunnerCallback(Host, CancellationToken.None); } + + /// + /// Gets or sets the delegate that initializes the host application builder. + /// + /// The delegate that initializes the host application builder. + public Action ConfigureHostCallback { get; set; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/MinimalHostFixtureExtensions.cs b/src/Codebelt.Extensions.Xunit.Hosting/MinimalHostFixtureExtensions.cs index c9a1543..b27a293 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/MinimalHostFixtureExtensions.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/MinimalHostFixtureExtensions.cs @@ -1,24 +1,23 @@ -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +/// +/// Extension methods for the interface. +/// +public static class MinimalHostFixtureExtensions { /// - /// Extension methods for the interface. + /// Determines whether the specified has a valid state. /// - public static class MinimalHostFixtureExtensions + /// The to check. + /// true if the specified has a valid state; otherwise, false. + /// + /// A valid state is defined as having non-null values for the following properties: + /// , and . + /// + public static bool HasValidState(this IMinimalHostFixture hostFixture) { - /// - /// Determines whether the specified has a valid state. - /// - /// The to check. - /// true if the specified has a valid state; otherwise, false. - /// - /// A valid state is defined as having non-null values for the following properties: - /// , and . - /// - public static bool HasValidState(this IMinimalHostFixture hostFixture) - { - return hostFixture.Host != null && - hostFixture.ConfigureHostCallback != null && - hostFixture.ConfigureCallback != null; - } + return hostFixture.Host != null && + hostFixture.ConfigureHostCallback != null && + hostFixture.ConfigureCallback != null; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/MinimalHostTest.cs b/src/Codebelt.Extensions.Xunit.Hosting/MinimalHostTest.cs index bc76807..6a4d73b 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/MinimalHostTest.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/MinimalHostTest.cs @@ -1,78 +1,81 @@ -using System; +using System; using Microsoft.Extensions.Hosting; using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +/// +/// Represents the non-generic base class from where its generic equivalent should derive. +/// +/// +public abstract class MinimalHostTest : HostTest { /// - /// Represents the non-generic base class from where its generic equivalent should derive. + /// Initializes a new instance of the class. /// - /// - public abstract class MinimalHostTest : HostTest + /// An implementation of the interface. + /// The of caller that ends up invoking this instance. + protected MinimalHostTest(ITestOutputHelper output = null, Type callerType = null) : base(output, callerType) + { + } + + + /// + /// Provides a way to override the defaults. + /// + /// The that initializes an instance of . + protected virtual void ConfigureHost(IHostApplicationBuilder hb) { - /// - /// Initializes a new instance of the class. - /// - /// An implementation of the interface. - /// The of caller that ends up invoking this instance. - protected MinimalHostTest(ITestOutputHelper output = null, Type callerType = null) : base(output, callerType) - { - } - - - /// - /// Provides a way to override the defaults. - /// - /// The that initializes an instance of . - protected virtual void ConfigureHost(IHostApplicationBuilder hb) - { - } } +} +/// +/// Represents a base class from which all implementations of unit testing, that uses Microsoft Dependency Injection (minimal style), should derive. +/// +/// The type of the object that implements the interface. +/// +/// +/// The class needed to be designed in this rather complex way, as this is the only way that xUnit supports a shared context. The need for shared context is theoretical at best, but it does opt-in for Scoped instances. +public abstract class MinimalHostTest : MinimalHostTest, IClassFixture where T : class, IMinimalHostFixture +{ /// - /// Represents a base class from which all implementations of unit testing, that uses Microsoft Dependency Injection (minimal style), should derive. + /// Initializes a new instance of the class. /// - /// The type of the object that implements the interface. - /// - /// - /// The class needed to be designed in this rather complex way, as this is the only way that xUnit supports a shared context. The need for shared context is theoretical at best, but it does opt-in for Scoped instances. - public abstract class MinimalHostTest : MinimalHostTest, IClassFixture where T : class, IMinimalHostFixture + /// An implementation of the interface. + /// An implementation of the interface. + /// The of caller that ends up invoking this instance. + /// + /// is null. + /// + protected MinimalHostTest(T hostFixture, ITestOutputHelper output = null, Type callerType = null) : this(false, hostFixture, output, callerType) { - /// - /// Initializes a new instance of the class. - /// - /// An implementation of the interface. - /// An implementation of the interface. - /// The of caller that ends up invoking this instance. - /// - /// is null. - /// - protected MinimalHostTest(T hostFixture, ITestOutputHelper output = null, Type callerType = null) : this(false, hostFixture, output, callerType) - { - } + } - /// - /// Initializes a new instance of the class. - /// - /// A value indicating whether to skip the host fixture initialization. - /// An implementation of the interface. - /// An implementation of the interface. - /// The of caller that ends up invoking this instance. - /// - /// is null. - /// - protected MinimalHostTest(bool skipHostFixtureInitialization, T hostFixture, ITestOutputHelper output = null, Type callerType = null) : base(output, callerType) + /// + /// Initializes a new instance of the class. + /// + /// A value indicating whether to skip the host fixture initialization. + /// An implementation of the interface. + /// An implementation of the interface. + /// The of caller that ends up invoking this instance. + /// + /// is null. + /// + protected MinimalHostTest(bool skipHostFixtureInitialization, T hostFixture, ITestOutputHelper output = null, Type callerType = null) : base(output, callerType) + { +#if NETSTANDARD2_0 + if (hostFixture == null) { throw new ArgumentNullException(nameof(hostFixture)); } +#else + ArgumentNullException.ThrowIfNull(hostFixture); +#endif + if (skipHostFixtureInitialization) { return; } + if (!hostFixture.HasValidState()) { - if (hostFixture == null) { throw new ArgumentNullException(nameof(hostFixture)); } - if (skipHostFixtureInitialization) { return; } - if (!hostFixture.HasValidState()) - { - hostFixture.ConfigureCallback = Configure; - hostFixture.ConfigureHostCallback = ConfigureHost; - hostFixture.ConfigureHost(this); - } - Host = hostFixture.Host; - Configure(hostFixture.Configuration, hostFixture.Environment); + hostFixture.ConfigureCallback = Configure; + hostFixture.ConfigureHostCallback = ConfigureHost; + hostFixture.ConfigureHost(this); } + Host = hostFixture.Host; + Configure(hostFixture.Configuration, hostFixture.Environment); } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/MinimalHostTestFactory.cs b/src/Codebelt.Extensions.Xunit.Hosting/MinimalHostTestFactory.cs index 340993a..b81903a 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/MinimalHostTestFactory.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/MinimalHostTestFactory.cs @@ -2,35 +2,34 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +/// +/// Provides a set of static methods for unit testing (minimal style). +/// +public static class MinimalHostTestFactory { /// - /// Provides a set of static methods for unit testing (minimal style). + /// Creates and returns an implementation. /// - public static class MinimalHostTestFactory + /// The which may be configured. + /// The which may be configured. + /// An optional implementation to use instead of the default instance. + /// An instance of an implementation. + public static IHostTest Create(Action serviceSetup = null, Action hostSetup = null, IMinimalHostFixture hostFixture = null) { - /// - /// Creates and returns an implementation. - /// - /// The which may be configured. - /// The which may be configured. - /// An optional implementation to use instead of the default instance. - /// An instance of an implementation. - public static IHostTest Create(Action serviceSetup = null, Action hostSetup = null, IMinimalHostFixture hostFixture = null) - { - return new Internal.MinimalHostTest(serviceSetup, hostSetup, hostFixture ?? new ManagedMinimalHostFixture()); - } + return new Internal.MinimalHostTest(serviceSetup, hostSetup, hostFixture ?? new ManagedMinimalHostFixture()); + } - /// - /// Creates and returns an implementation. - /// - /// The which may be configured. - /// The which may be configured. - /// An optional implementation to use instead of the default instance. - /// An instance of an implementation. - public static IHostTest CreateWithHostBuilderContext(Action serviceSetup = null, Action hostSetup = null, IMinimalHostFixture hostFixture = null) - { - return new Internal.MinimalHostTest(serviceSetup, hostSetup, hostFixture ?? new ManagedMinimalHostFixture()); - } + /// + /// Creates and returns an implementation. + /// + /// The which may be configured. + /// The which may be configured. + /// An optional implementation to use instead of the default instance. + /// An instance of an implementation. + public static IHostTest CreateWithHostBuilderContext(Action serviceSetup = null, Action hostSetup = null, IMinimalHostFixture hostFixture = null) + { + return new Internal.MinimalHostTest(serviceSetup, hostSetup, hostFixture ?? new ManagedMinimalHostFixture()); } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/SelfManagedHostFixture.cs b/src/Codebelt.Extensions.Xunit.Hosting/SelfManagedHostFixture.cs index d68cbdf..17e31bd 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/SelfManagedHostFixture.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/SelfManagedHostFixture.cs @@ -1,21 +1,20 @@ using System.Threading.Tasks; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +/// +/// Represents a self-managed implementation of the class. +/// +public sealed class SelfManagedHostFixture : ManagedHostFixture { /// - /// Represents a self-managed implementation of the class. + /// Initializes a new instance of the class. /// - public sealed class SelfManagedHostFixture : ManagedHostFixture + /// + /// This constructor sets the to a no-op asynchronous delegate. + /// + public SelfManagedHostFixture() { - /// - /// Initializes a new instance of the class. - /// - /// - /// This constructor sets the to a no-op asynchronous delegate. - /// - public SelfManagedHostFixture() - { - AsyncHostRunnerCallback = (_, __) => Task.CompletedTask; - } + AsyncHostRunnerCallback = (_, __) => Task.CompletedTask; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/SelfManagedMinimalHostFixture.cs b/src/Codebelt.Extensions.Xunit.Hosting/SelfManagedMinimalHostFixture.cs index 8090797..ebe8a30 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/SelfManagedMinimalHostFixture.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/SelfManagedMinimalHostFixture.cs @@ -1,21 +1,20 @@ using System.Threading.Tasks; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +/// +/// Represents a self-managed implementation of the class. +/// +public sealed class SelfManagedMinimalHostFixture : ManagedMinimalHostFixture { /// - /// Represents a self-managed implementation of the class. + /// Initializes a new instance of the class. /// - public sealed class SelfManagedMinimalHostFixture : ManagedMinimalHostFixture + /// + /// This constructor sets the to a no-op asynchronous delegate. + /// + public SelfManagedMinimalHostFixture() { - /// - /// Initializes a new instance of the class. - /// - /// - /// This constructor sets the to a no-op asynchronous delegate. - /// - public SelfManagedMinimalHostFixture() - { - AsyncHostRunnerCallback = (_, __) => Task.CompletedTask; - } + AsyncHostRunnerCallback = (_, __) => Task.CompletedTask; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/ServiceCollectionExtensions.cs b/src/Codebelt.Extensions.Xunit.Hosting/ServiceCollectionExtensions.cs index 727897c..8967546 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/ServiceCollectionExtensions.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/ServiceCollectionExtensions.cs @@ -1,111 +1,115 @@ -using System; +using System; using System.Linq; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +/// +/// Extension methods for the interface. +/// +public static class ServiceCollectionExtensions { - /// - /// Extension methods for the interface. - /// - public static class ServiceCollectionExtensions + /// + /// Adds a unit test optimized implementation of logging to the collection. + /// + /// The to extend. + /// The that specifies the minimum level to include for the logging. + /// A reference to so that additional configuration calls can be chained. + /// + /// cannot be null. + /// + public static IServiceCollection AddXunitTestLogging(this IServiceCollection services, LogLevel minimumLevel = LogLevel.Trace) { - /// - /// Adds a unit test optimized implementation of logging to the collection. - /// - /// The to extend. - /// The that specifies the minimum level to include for the logging. - /// A reference to so that additional configuration calls can be chained. - /// - /// cannot be null. - /// - public static IServiceCollection AddXunitTestLogging(this IServiceCollection services, LogLevel minimumLevel = LogLevel.Trace) + if (services == null) { throw new ArgumentNullException(nameof(services)); } + if (services.Any(sd => sd.ServiceType == typeof(ITestOutputHelperAccessor))) { - if (services == null) { throw new ArgumentNullException(nameof(services)); } - if (services.Any(sd => sd.ServiceType == typeof(ITestOutputHelperAccessor))) - { - AddTestOutputHelperAccessor(services, minimumLevel); - } - else - { - services.AddLogging(builder => - { - builder.SetMinimumLevel(minimumLevel); - builder.AddProvider(new XunitTestLoggerProvider()); - }); - } - return services; + AddTestOutputHelperAccessor(services, minimumLevel); } - - /// - /// Adds a unit test optimized implementation of output logging to the collection. - /// - /// The to extend. - /// The that provides the output for the logging. - /// The that specifies the minimum level to include for the logging. - /// A reference to so that additional configuration calls can be chained. - /// - /// cannot be null -or- - /// cannot be null. - /// - public static IServiceCollection AddXunitTestLogging(this IServiceCollection services, ITestOutputHelper output, LogLevel minimumLevel = LogLevel.Trace) + else { - if (services == null) { throw new ArgumentNullException(nameof(services)); } - if (output == null) { throw new ArgumentNullException(nameof(output)); } - if (services.Any(sd => sd.ServiceType == typeof(ITestOutputHelperAccessor))) - { - AddTestOutputHelperAccessor(services, minimumLevel); - } - else + services.AddLogging(builder => { - services.AddLogging(builder => - { - builder.SetMinimumLevel(minimumLevel); - builder.AddProvider(new XunitTestLoggerProvider(output)); - }); - } - return services; + builder.SetMinimumLevel(minimumLevel); + builder.AddProvider(new XunitTestLoggerProvider()); + }); } + return services; + } - private static void AddTestOutputHelperAccessor(IServiceCollection services, LogLevel minimumLevel) + /// + /// Adds a unit test optimized implementation of output logging to the collection. + /// + /// The to extend. + /// The that provides the output for the logging. + /// The that specifies the minimum level to include for the logging. + /// A reference to so that additional configuration calls can be chained. + /// + /// cannot be null -or- + /// cannot be null. + /// + public static IServiceCollection AddXunitTestLogging(this IServiceCollection services, ITestOutputHelper output, LogLevel minimumLevel = LogLevel.Trace) + { +#if NETSTANDARD2_0 + if (services == null) { throw new ArgumentNullException(nameof(services)); } + if (output == null) { throw new ArgumentNullException(nameof(output)); } +#else + ArgumentNullException.ThrowIfNull(services); + ArgumentNullException.ThrowIfNull(output); +#endif + if (services.Any(sd => sd.ServiceType == typeof(ITestOutputHelperAccessor))) + { + AddTestOutputHelperAccessor(services, minimumLevel); + } + else { services.AddLogging(builder => { builder.SetMinimumLevel(minimumLevel); - builder.Services.AddSingleton(provider => - { - var accessor = provider.GetRequiredService(); - return new XunitTestLoggerProvider(accessor); - }); + builder.AddProvider(new XunitTestLoggerProvider(output)); }); } + return services; + } - /// - /// Adds a default implementation of to the collection. - /// - /// The to extend. - /// A reference to so that additional configuration calls can be chained. - public static IServiceCollection AddXunitTestLoggingOutputHelperAccessor(this IServiceCollection services) + private static void AddTestOutputHelperAccessor(IServiceCollection services, LogLevel minimumLevel) + { + services.AddLogging(builder => { - services.AddXunitTestLoggingOutputHelperAccessor(); - return services; - } + builder.SetMinimumLevel(minimumLevel); + builder.Services.AddSingleton(provider => + { + var accessor = provider.GetRequiredService(); + return new XunitTestLoggerProvider(accessor); + }); + }); + } - /// - /// Adds a specified implementation of to the collection. - /// - /// The type of the implementation of . - /// The to extend. - /// A reference to so that additional configuration calls can be chained. - /// - /// cannot be null. - /// - public static IServiceCollection AddXunitTestLoggingOutputHelperAccessor(this IServiceCollection services) where T : class, ITestOutputHelperAccessor - { - if (services == null) { throw new ArgumentNullException(nameof(services)); } - services.AddSingleton(); - return services; - } + /// + /// Adds a default implementation of to the collection. + /// + /// The to extend. + /// A reference to so that additional configuration calls can be chained. + public static IServiceCollection AddXunitTestLoggingOutputHelperAccessor(this IServiceCollection services) + { + services.AddXunitTestLoggingOutputHelperAccessor(); + return services; + } + + /// + /// Adds a specified implementation of to the collection. + /// + /// The type of the implementation of . + /// The to extend. + /// A reference to so that additional configuration calls can be chained. + /// + /// cannot be null. + /// + public static IServiceCollection AddXunitTestLoggingOutputHelperAccessor(this IServiceCollection services) where T : class, ITestOutputHelperAccessor + { + if (services == null) { throw new ArgumentNullException(nameof(services)); } + services.AddSingleton(); + return services; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/ServiceProviderExtensions.cs b/src/Codebelt.Extensions.Xunit.Hosting/ServiceProviderExtensions.cs index 6926955..e18b2a9 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/ServiceProviderExtensions.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/ServiceProviderExtensions.cs @@ -1,24 +1,23 @@ using System; using Microsoft.Extensions.DependencyInjection; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +/// +/// Provides extension methods for the interface. +/// +public static class ServiceProviderExtensions { /// - /// Provides extension methods for the interface. + /// Gets a required scoped service of type from the . /// - public static class ServiceProviderExtensions + /// The type of the service to retrieve. + /// The to retrieve the service from. + /// The required service of type . + /// There is no service of type . + public static T GetRequiredScopedService(this IServiceProvider provider) { - /// - /// Gets a required scoped service of type from the . - /// - /// The type of the service to retrieve. - /// The to retrieve the service from. - /// The required service of type . - /// There is no service of type . - public static T GetRequiredScopedService(this IServiceProvider provider) - { - using var scope = provider.CreateScope(); - return scope.ServiceProvider.GetRequiredService(); - } + using var scope = provider.CreateScope(); + return scope.ServiceProvider.GetRequiredService(); } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/Tweaker.cs b/src/Codebelt.Extensions.Xunit.Hosting/Tweaker.cs index 5e84692..f2f741a 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/Tweaker.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/Tweaker.cs @@ -1,12 +1,11 @@ using System; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +internal static class Tweaker { - internal static class Tweaker + internal static T Adjust(T value, Func converter) { - internal static T Adjust(T value, Func converter) - { - return converter == null ? value : converter.Invoke(value); - } + return converter == null ? value : converter.Invoke(value); } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/XunitTestLogger.cs b/src/Codebelt.Extensions.Xunit.Hosting/XunitTestLogger.cs index 5ea6aa2..837771e 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/XunitTestLogger.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/XunitTestLogger.cs @@ -3,75 +3,74 @@ using Microsoft.Extensions.Logging; using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +internal sealed class XunitTestLogger : InMemoryTestStore, ILogger, IDisposable { - internal sealed class XunitTestLogger : InMemoryTestStore, ILogger, IDisposable - { - private readonly ITestOutputHelperAccessor _accessor; - private readonly ITestOutputHelper _output; - private readonly XunitTestLoggerProvider _provider; + private readonly ITestOutputHelperAccessor _accessor; + private readonly ITestOutputHelper _output; + private readonly XunitTestLoggerProvider _provider; - public XunitTestLogger(XunitTestLoggerProvider provider, ITestOutputHelper output) - { - _provider = provider; - _output = output; - } + public XunitTestLogger(XunitTestLoggerProvider provider, ITestOutputHelper output) + { + _provider = provider; + _output = output; + } - public XunitTestLogger(XunitTestLoggerProvider provider, ITestOutputHelperAccessor accessor) - { - _provider = provider; - _accessor = accessor; - } + public XunitTestLogger(XunitTestLoggerProvider provider, ITestOutputHelperAccessor accessor) + { + _provider = provider; + _accessor = accessor; + } - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) - { - var builder = new StringBuilder($"{logLevel}: {formatter(state, exception)}"); - if (exception != null) { builder.AppendLine().Append(exception).AppendLine(); } + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + { + var builder = new StringBuilder($"{logLevel}: {formatter(state, exception)}"); + if (exception != null) { builder.AppendLine().Append(exception).AppendLine(); } - var message = builder.ToString(); + var message = builder.ToString(); - _provider.WriteLoggerEntry(logLevel, eventId, message); + _provider.WriteLoggerEntry(logLevel, eventId, message); - Add(new XunitTestLoggerEntry(logLevel, eventId, message)); + Add(new XunitTestLoggerEntry(logLevel, eventId, message)); - if (_accessor != null) + if (_accessor != null) + { + try { - try - { - _accessor.TestOutput?.WriteLine(message); - } - catch (InvalidOperationException) - { - // can happen when there is no currently active test - } + _accessor.TestOutput?.WriteLine(message); } - else + catch (InvalidOperationException) { - try - { - _output?.WriteLine(message); - } - catch (InvalidOperationException) - { - // can happen when there is no currently active test (e.g., you should use the ITestOutputHelperAccessor capability) - } + // can happen when there is no currently active test } } - - public XunitTestLoggerProvider Provider => _provider; - - public bool IsEnabled(LogLevel logLevel) + else { - return logLevel != LogLevel.None; + try + { + _output?.WriteLine(message); + } + catch (InvalidOperationException) + { + // can happen when there is no currently active test (e.g., you should use the ITestOutputHelperAccessor capability) + } } + } - public IDisposable BeginScope(TState state) where TState : notnull - { - return this; - } + public XunitTestLoggerProvider Provider => _provider; - public void Dispose() - { - } + public bool IsEnabled(LogLevel logLevel) + { + return logLevel != LogLevel.None; + } + + public IDisposable BeginScope(TState state) where TState : notnull + { + return this; + } + + public void Dispose() + { } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/XunitTestLoggerEntry.cs b/src/Codebelt.Extensions.Xunit.Hosting/XunitTestLoggerEntry.cs index dea478b..ca7c73a 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/XunitTestLoggerEntry.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/XunitTestLoggerEntry.cs @@ -1,50 +1,49 @@ using Microsoft.Extensions.Logging; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +/// +/// Represents a captured log-entry for testing purposes. This record encapsulates the , and message. +/// +public record XunitTestLoggerEntry { /// - /// Represents a captured log-entry for testing purposes. This record encapsulates the , and message. + /// Initializes a new instance of the class. /// - public record XunitTestLoggerEntry + /// The for this entry. + /// The of this entry. + /// The message of this entry. + public XunitTestLoggerEntry(LogLevel severity, EventId id, string message) { - /// - /// Initializes a new instance of the class. - /// - /// The for this entry. - /// The of this entry. - /// The message of this entry. - public XunitTestLoggerEntry(LogLevel severity, EventId id, string message) - { - Severity = severity; - Id = id; - Message = message; - } + Severity = severity; + Id = id; + Message = message; + } - /// - /// Gets the event identifier. - /// - /// The event identifier. - public EventId Id { get; } + /// + /// Gets the event identifier. + /// + /// The event identifier. + public EventId Id { get; } - /// - /// Gets the log level. - /// - /// The log level. - public LogLevel Severity { get; } + /// + /// Gets the log level. + /// + /// The log level. + public LogLevel Severity { get; } - /// - /// Gets the value of the message. - /// - /// The value of the message. - public string Message { get; } + /// + /// Gets the value of the message. + /// + /// The value of the message. + public string Message { get; } - /// - /// Returns a that represents this instance. - /// - /// A that represents this instance. - public override string ToString() - { - return Message; - } + /// + /// Returns a that represents this instance. + /// + /// A that represents this instance. + public override string ToString() + { + return Message; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting/XunitTestLoggerProvider.cs b/src/Codebelt.Extensions.Xunit.Hosting/XunitTestLoggerProvider.cs index 41e7849..e1bbb0f 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/XunitTestLoggerProvider.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/XunitTestLoggerProvider.cs @@ -4,54 +4,53 @@ using System.Collections.Generic; using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +internal sealed class XunitTestLoggerProvider : InMemoryTestStore, ILoggerProvider { - internal sealed class XunitTestLoggerProvider : InMemoryTestStore, ILoggerProvider - { - private readonly ConcurrentDictionary _loggers = new(StringComparer.OrdinalIgnoreCase); - private readonly ITestOutputHelperAccessor _accessor; - private readonly ITestOutputHelper _output; + private readonly ConcurrentDictionary _loggers = new(StringComparer.OrdinalIgnoreCase); + private readonly ITestOutputHelperAccessor _accessor; + private readonly ITestOutputHelper _output; - public XunitTestLoggerProvider() - { - } + public XunitTestLoggerProvider() + { + } - public XunitTestLoggerProvider(ITestOutputHelper output) - { - _output = output; - } + public XunitTestLoggerProvider(ITestOutputHelper output) + { + _output = output; + } - public XunitTestLoggerProvider(ITestOutputHelperAccessor accessor) - { - _accessor = accessor; - } + public XunitTestLoggerProvider(ITestOutputHelperAccessor accessor) + { + _accessor = accessor; + } - public ILogger CreateLogger(string categoryName) - { - return _loggers.GetOrAdd(categoryName, _ => _accessor != null - ? new XunitTestLogger(this, _accessor) - : new XunitTestLogger(this, _output)); - } - - public void WriteLoggerEntry(LogLevel logLevel, EventId eventId, string message) - { - Add(new XunitTestLoggerEntry(logLevel, eventId, message)); - } + public ILogger CreateLogger(string categoryName) + { + return _loggers.GetOrAdd(categoryName, _ => _accessor != null + ? new XunitTestLogger(this, _accessor) + : new XunitTestLogger(this, _output)); + } + + public void WriteLoggerEntry(LogLevel logLevel, EventId eventId, string message) + { + Add(new XunitTestLoggerEntry(logLevel, eventId, message)); + } - public ITestStore this[string categoryName] + public ITestStore this[string categoryName] + { + get { - get + if (_loggers.TryGetValue(categoryName, out var logger)) { - if (_loggers.TryGetValue(categoryName, out var logger)) - { - return logger; - } - throw new KeyNotFoundException($"Logger for category '{categoryName}' not found."); + return logger; } + throw new KeyNotFoundException($"Logger for category '{categoryName}' not found."); } + } - public void Dispose() - { - } + public void Dispose() + { } } From 580d4f60eb45bd35ccf0db64affe29a609d88efc Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Thu, 21 May 2026 23:29:40 +0200 Subject: [PATCH 10/16] =?UTF-8?q?=F0=9F=8E=A8=20refactor=20aspnetcore=20ho?= =?UTF-8?q?sting=20assembly=20to=20file-scoped=20namespaces?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Converted all source files in Codebelt.Extensions.Xunit.Hosting.AspNetCore from block-scoped to file-scoped namespace declarations (namespace Foo;). Includes files under Http/ and Http/Features/ subdirectories and both Internal/ types. Pure structural change — no behavior or API modifications. --- .../BlockingManagedWebHostFixture.cs | 27 ++- .../GlobalSuppressions.cs | 10 +- .../HostBuilderApplicationExtensions.cs | 31 ++-- .../Http/FakeHttpContextAccessor.cs | 101 ++++++----- .../Http/Features/FakeHttpRequestFeature.cs | 27 ++- .../Http/Features/FakeHttpResponseFeature.cs | 63 ++++--- .../HttpClientExtensions.cs | 37 ++-- .../IPipelineTest.cs | 19 +- .../IWebHostFixture.cs | 21 ++- .../IWebHostTest.cs | 17 +- .../IWebMinimalHostFixture.cs | 23 ++- .../Internal/MinimalWebHostTest.cs | 109 ++++++------ .../Internal/WebHostTest.cs | 117 +++++++------ .../ManagedWebHostFixture.cs | 163 +++++++++--------- .../ManagedWebMinimalHostFixture.cs | 109 ++++++------ .../MinimalWebHostTest.cs | 101 ++++++----- .../MinimalWebHostTestFactory.cs | 111 ++++++------ .../SelfManagedWebHostFixture.cs | 25 ++- .../SelfManagedWebMinimalHostFixture.cs | 25 ++- .../ServiceCollectionExtensions.cs | 57 +++--- .../Tweaker.cs | 11 +- .../WebHostFixtureExtensions.cs | 33 ++-- .../WebHostTest.cs | 93 +++++----- .../WebHostTestFactory.cs | 111 ++++++------ .../WebMinimalHostFixtureExtensions.cs | 35 ++-- 25 files changed, 726 insertions(+), 750 deletions(-) diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/BlockingManagedWebHostFixture.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/BlockingManagedWebHostFixture.cs index d4b2c1b..303adb4 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/BlockingManagedWebHostFixture.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/BlockingManagedWebHostFixture.cs @@ -1,24 +1,23 @@ using System.Threading.Tasks; using Microsoft.Extensions.Hosting; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +/// +/// Extends the default implementation of the interface to be synchronous e.g., blocking where exceptions can be captured. +/// +/// +public sealed class BlockingManagedWebHostFixture : ManagedWebHostFixture { /// - /// Extends the default implementation of the interface to be synchronous e.g., blocking where exceptions can be captured. + /// Initializes a new instance of the class. /// - /// - public sealed class BlockingManagedWebHostFixture : ManagedWebHostFixture + public BlockingManagedWebHostFixture() { - /// - /// Initializes a new instance of the class. - /// - public BlockingManagedWebHostFixture() + AsyncHostRunnerCallback = (host, _) => { - AsyncHostRunnerCallback = (host, _) => - { - host.Start(); - return Task.CompletedTask; - }; - } + host.Start(); + return Task.CompletedTask; + }; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/GlobalSuppressions.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/GlobalSuppressions.cs index 72b8b95..97a14ca 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/GlobalSuppressions.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/GlobalSuppressions.cs @@ -1,12 +1,12 @@ -// This file is used by Code Analysis to maintain SuppressMessage +// This file is used by Code Analysis to maintain SuppressMessage // attributes that are applied to this project. // Project-level suppressions either have no target or are given // a specific target and scoped to a namespace, type, member, etc. using System.Diagnostics.CodeAnalysis; -[assembly: SuppressMessage("Blocker Code Smell", "S3427:Method overloads with default parameter values should not overlap", Justification = "Avoid bumping major version by providing an extra overloaded member as optional argument.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.AspNetCore.WebHostTestFactory.Create(System.Action{Microsoft.Extensions.DependencyInjection.IServiceCollection},System.Action{Microsoft.AspNetCore.Builder.IApplicationBuilder},System.Action{Microsoft.Extensions.Hosting.IHostBuilder},Codebelt.Extensions.Xunit.Hosting.AspNetCore.IAspNetCoreHostFixture)~Codebelt.Extensions.Xunit.Hosting.AspNetCore.IWebHostTest")] -[assembly: SuppressMessage("Blocker Code Smell", "S3427:Method overloads with default parameter values should not overlap", Justification = "Avoid bumping major version by providing an extra overloaded member as optional argument.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.AspNetCore.WebHostTestFactory.CreateWithHostBuilderContext(System.Action{Microsoft.Extensions.Hosting.HostBuilderContext,Microsoft.Extensions.DependencyInjection.IServiceCollection},System.Action{Microsoft.Extensions.Hosting.HostBuilderContext,Microsoft.AspNetCore.Builder.IApplicationBuilder},System.Action{Microsoft.Extensions.Hosting.IHostBuilder},Codebelt.Extensions.Xunit.Hosting.AspNetCore.IAspNetCoreHostFixture)~Codebelt.Extensions.Xunit.Hosting.AspNetCore.IWebHostTest")] -[assembly: SuppressMessage("Blocker Code Smell", "S3427:Method overloads with default parameter values should not overlap", Justification = "Avoid bumping major version by providing an extra overloaded member as optional argument.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.AspNetCore.WebHostTestFactory.RunAsync(System.Action{Microsoft.Extensions.DependencyInjection.IServiceCollection},System.Action{Microsoft.AspNetCore.Builder.IApplicationBuilder},System.Action{Microsoft.Extensions.Hosting.IHostBuilder},System.Func{System.Net.Http.HttpClient,System.Threading.Tasks.Task{System.Net.Http.HttpResponseMessage}},Codebelt.Extensions.Xunit.Hosting.AspNetCore.IAspNetCoreHostFixture)~System.Threading.Tasks.Task{System.Net.Http.HttpResponseMessage}")] -[assembly: SuppressMessage("Blocker Code Smell", "S3427:Method overloads with default parameter values should not overlap", Justification = "Avoid bumping major version by providing an extra overloaded member as optional argument.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.AspNetCore.WebHostTestFactory.RunWithHostBuilderContextAsync(System.Action{Microsoft.Extensions.Hosting.HostBuilderContext,Microsoft.Extensions.DependencyInjection.IServiceCollection},System.Action{Microsoft.Extensions.Hosting.HostBuilderContext,Microsoft.AspNetCore.Builder.IApplicationBuilder},System.Action{Microsoft.Extensions.Hosting.IHostBuilder},System.Func{System.Net.Http.HttpClient,System.Threading.Tasks.Task{System.Net.Http.HttpResponseMessage}},Codebelt.Extensions.Xunit.Hosting.AspNetCore.IAspNetCoreHostFixture)~System.Threading.Tasks.Task{System.Net.Http.HttpResponseMessage}")] +[assembly: SuppressMessage("Blocker Code Smell", "S3427:Method overloads with default parameter values should not overlap", Justification = "Avoid bumping major version by providing an extra overloaded member as optional argument.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.AspNetCore.WebHostTestFactory.Create(System.Action{Microsoft.Extensions.DependencyInjection.IServiceCollection},System.Action{Microsoft.AspNetCore.Builder.IApplicationBuilder},System.Action{Microsoft.Extensions.Hosting.IHostBuilder},Codebelt.Extensions.Xunit.Hosting.AspNetCore.IWebHostFixture)~Codebelt.Extensions.Xunit.Hosting.AspNetCore.IWebHostTest")] +[assembly: SuppressMessage("Blocker Code Smell", "S3427:Method overloads with default parameter values should not overlap", Justification = "Avoid bumping major version by providing an extra overloaded member as optional argument.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.AspNetCore.WebHostTestFactory.CreateWithHostBuilderContext(System.Action{Microsoft.Extensions.Hosting.HostBuilderContext,Microsoft.Extensions.DependencyInjection.IServiceCollection},System.Action{Microsoft.Extensions.Hosting.HostBuilderContext,Microsoft.AspNetCore.Builder.IApplicationBuilder},System.Action{Microsoft.Extensions.Hosting.IHostBuilder},Codebelt.Extensions.Xunit.Hosting.AspNetCore.IWebHostFixture)~Codebelt.Extensions.Xunit.Hosting.AspNetCore.IWebHostTest")] +[assembly: SuppressMessage("Blocker Code Smell", "S3427:Method overloads with default parameter values should not overlap", Justification = "Avoid bumping major version by providing an extra overloaded member as optional argument.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.AspNetCore.WebHostTestFactory.RunAsync(System.Action{Microsoft.Extensions.DependencyInjection.IServiceCollection},System.Action{Microsoft.AspNetCore.Builder.IApplicationBuilder},System.Action{Microsoft.Extensions.Hosting.IHostBuilder},System.Func{System.Net.Http.HttpClient,System.Threading.Tasks.Task{System.Net.Http.HttpResponseMessage}},Codebelt.Extensions.Xunit.Hosting.AspNetCore.IWebHostFixture)~System.Threading.Tasks.Task{System.Net.Http.HttpResponseMessage}")] +[assembly: SuppressMessage("Blocker Code Smell", "S3427:Method overloads with default parameter values should not overlap", Justification = "Avoid bumping major version by providing an extra overloaded member as optional argument.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.AspNetCore.WebHostTestFactory.RunWithHostBuilderContextAsync(System.Action{Microsoft.Extensions.Hosting.HostBuilderContext,Microsoft.Extensions.DependencyInjection.IServiceCollection},System.Action{Microsoft.Extensions.Hosting.HostBuilderContext,Microsoft.AspNetCore.Builder.IApplicationBuilder},System.Action{Microsoft.Extensions.Hosting.IHostBuilder},System.Func{System.Net.Http.HttpClient,System.Threading.Tasks.Task{System.Net.Http.HttpResponseMessage}},Codebelt.Extensions.Xunit.Hosting.AspNetCore.IWebHostFixture)~System.Threading.Tasks.Task{System.Net.Http.HttpResponseMessage}")] [assembly: SuppressMessage("Performance", "CA1859:Use concrete types when possible for improved performance", Justification = "Nitpick.", Scope = "member", Target = "~M:Codebelt.Extensions.Xunit.Hosting.AspNetCore.Http.FakeHttpContextAccessor.MakeGreeting(System.String)~System.IO.Stream")] diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/HostBuilderApplicationExtensions.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/HostBuilderApplicationExtensions.cs index 338f1ba..a1aa158 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/HostBuilderApplicationExtensions.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/HostBuilderApplicationExtensions.cs @@ -2,25 +2,24 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Hosting; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +/// +/// Provides extension methods for . +/// +public static class HostBuilderApplicationExtensions { /// - /// Provides extension methods for . + /// Converts an to an . /// - public static class HostBuilderApplicationExtensions + /// The to convert. + /// The instance. + /// + /// is not a . + /// + public static IHostBuilder ToHostBuilder(this IHostApplicationBuilder builder) { - /// - /// Converts an to an . - /// - /// The to convert. - /// The instance. - /// - /// is not a . - /// - public static IHostBuilder ToHostBuilder(this IHostApplicationBuilder builder) - { - if (builder is WebApplicationBuilder webAppBuilder) { return webAppBuilder.Host; } - throw new ArgumentException($"The provided IHostApplicationBuilder is not a {nameof(WebApplicationBuilder)}.", nameof(builder)); - } + if (builder is WebApplicationBuilder webAppBuilder) { return webAppBuilder.Host; } + throw new ArgumentException($"The provided IHostApplicationBuilder is not a {nameof(WebApplicationBuilder)}.", nameof(builder)); } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Http/FakeHttpContextAccessor.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Http/FakeHttpContextAccessor.cs index a6c7cb1..49fd808 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Http/FakeHttpContextAccessor.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Http/FakeHttpContextAccessor.cs @@ -6,66 +6,65 @@ using Microsoft.AspNetCore.Http.Features; using Microsoft.Extensions.DependencyInjection; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Http +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Http; + +/// +/// Provides a unit test implementation of . +/// +/// +public class FakeHttpContextAccessor : IHttpContextAccessor { /// - /// Provides a unit test implementation of . + /// Initializes a new instance of the class. /// - /// - public class FakeHttpContextAccessor : IHttpContextAccessor + /// An optional for resolving services. + public FakeHttpContextAccessor(IServiceScopeFactory factory = null) { - /// - /// Initializes a new instance of the class. - /// - /// An optional for resolving services. - public FakeHttpContextAccessor(IServiceScopeFactory factory = null) - { - var context = new DefaultHttpContext(); - var fc = new FeatureCollection(); - fc.Set(new RequestServicesFeature(context, factory)); - fc.Set(new FakeHttpResponseFeature()); - fc.Set(new FakeHttpRequestFeature()); - fc.Set(new StreamResponseBodyFeature(MakeGreeting("Hello awesome developers!"))); - context.Uninitialize(); - context.Initialize(fc); - HttpContext = context; - } + var context = new DefaultHttpContext(); + var fc = new FeatureCollection(); + fc.Set(new RequestServicesFeature(context, factory)); + fc.Set(new FakeHttpResponseFeature()); + fc.Set(new FakeHttpRequestFeature()); + fc.Set(new StreamResponseBodyFeature(MakeGreeting("Hello awesome developers!"))); + context.Uninitialize(); + context.Initialize(fc); + HttpContext = context; + } - private static Stream MakeGreeting(string greeting) + private static Stream MakeGreeting(string greeting) + { + Stream interim = null; + Stream result = null; + try { - Stream interim = null; - Stream result = null; - try - { - interim = new MemoryStream(); + interim = new MemoryStream(); - using (var sw = new StreamWriter(interim, Encoding.UTF8, leaveOpen: true)) - { - sw.Write(greeting); - sw.Flush(); - } - - interim.Flush(); - interim.Position = 0; - - result = interim; - interim = null; - } - catch (Exception ex) - { - throw new InvalidOperationException("There is an error in the Stream being written.", ex); - } - finally + using (var sw = new StreamWriter(interim, Encoding.UTF8, leaveOpen: true)) { - interim?.Dispose(); + sw.Write(greeting); + sw.Flush(); } - return result; - } - /// - /// Gets or sets the HTTP context. - /// - /// The HTTP context. - public HttpContext HttpContext { get; set; } + interim.Flush(); + interim.Position = 0; + + result = interim; + interim = null; + } + catch (Exception ex) + { + throw new InvalidOperationException("There is an error in the Stream being written.", ex); + } + finally + { + interim?.Dispose(); + } + return result; } + + /// + /// Gets or sets the HTTP context. + /// + /// The HTTP context. + public HttpContext HttpContext { get; set; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Http/Features/FakeHttpRequestFeature.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Http/Features/FakeHttpRequestFeature.cs index 56a0ace..1698a7c 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Http/Features/FakeHttpRequestFeature.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Http/Features/FakeHttpRequestFeature.cs @@ -1,23 +1,22 @@ using System.Net.Http; using Microsoft.AspNetCore.Http.Features; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Http.Features +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Http.Features; + +/// +/// Represents a way to support some default values for Request context.. +/// +/// +public class FakeHttpRequestFeature : HttpRequestFeature { /// - /// Represents a way to support some default values for Request context.. + /// Initializes a new instance of the class. /// - /// - public class FakeHttpRequestFeature : HttpRequestFeature + public FakeHttpRequestFeature() { - /// - /// Initializes a new instance of the class. - /// - public FakeHttpRequestFeature() - { - Method = HttpMethod.Get.ToString(); - Path = "/"; - Scheme = "http"; - Protocol = "HTTP/1.1"; - } + Method = HttpMethod.Get.ToString(); + Path = "/"; + Scheme = "http"; + Protocol = "HTTP/1.1"; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Http/Features/FakeHttpResponseFeature.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Http/Features/FakeHttpResponseFeature.cs index 721e8b1..e0469ce 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Http/Features/FakeHttpResponseFeature.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Http/Features/FakeHttpResponseFeature.cs @@ -4,42 +4,41 @@ using Microsoft.AspNetCore.Http.Features; using Microsoft.Net.Http.Headers; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Http.Features +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Http.Features; + +/// +/// Represents a way to trigger . +/// +/// +public class FakeHttpResponseFeature : HttpResponseFeature { + private bool _hasStarted; + /// - /// Represents a way to trigger . + /// Initializes a new instance of the class. /// - /// - public class FakeHttpResponseFeature : HttpResponseFeature + public FakeHttpResponseFeature() { - private bool _hasStarted; - - /// - /// Initializes a new instance of the class. - /// - public FakeHttpResponseFeature() - { - Headers.Append(HeaderNames.Date, DateTime.UtcNow.ToString("R")); - } - - /// - /// Registers a callback to be invoked just before the response starts. This is the last chance to modify the , , or . - /// - /// The callback to invoke when starting the response. - /// The state to pass into the callback. - public override void OnStarting(Func callback, object state) - { - if (_hasStarted) { return; } - _hasStarted = true; - callback?.Invoke(state); - } + Headers.Append(HeaderNames.Date, DateTime.UtcNow.ToString("R")); + } - /// - /// Indicates if the response has started. If true, the , - /// , and are now immutable, and - /// OnStarting should no longer be called. - /// - /// true if this instance has started; otherwise, false. - public override bool HasStarted => _hasStarted; + /// + /// Registers a callback to be invoked just before the response starts. This is the last chance to modify the , , or . + /// + /// The callback to invoke when starting the response. + /// The state to pass into the callback. + public override void OnStarting(Func callback, object state) + { + if (_hasStarted) { return; } + _hasStarted = true; + callback?.Invoke(state); } + + /// + /// Indicates if the response has started. If true, the , + /// , and are now immutable, and + /// OnStarting should no longer be called. + /// + /// true if this instance has started; otherwise, false. + public override bool HasStarted => _hasStarted; } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/HttpClientExtensions.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/HttpClientExtensions.cs index 888561c..74cb697 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/HttpClientExtensions.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/HttpClientExtensions.cs @@ -2,28 +2,27 @@ using System.Net.Http; using System.Threading.Tasks; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +/// +/// Provides extension methods for the class. +/// +public static class HttpClientExtensions { /// - /// Provides extension methods for the class. + /// Provides a convenient way to return a from a using the specified . /// - public static class HttpClientExtensions + /// The to extend. + /// The function delegate that creates a from the . Default is a GET request to the root URL ("/"). + /// A that represents the asynchronous operation. The task result contains the generated by the . + /// + /// cannot be null. + /// + /// Designed to be used in conjunction with and . + public static async Task ToHttpResponseMessageAsync(this HttpClient client, Func> responseFactory = null) { - /// - /// Provides a convenient way to return a from a using the specified . - /// - /// The to extend. - /// The function delegate that creates a from the . Default is a GET request to the root URL ("/"). - /// A that represents the asynchronous operation. The task result contains the generated by the . - /// - /// cannot be null. - /// - /// Designed to be used in conjunction with and . - public static async Task ToHttpResponseMessageAsync(this HttpClient client, Func> responseFactory = null) - { - ArgumentNullException.ThrowIfNull(client); - responseFactory ??= c => c.GetAsync("/"); - return await responseFactory(client).ConfigureAwait(false); - } + ArgumentNullException.ThrowIfNull(client); + responseFactory ??= c => c.GetAsync("/"); + return await responseFactory(client).ConfigureAwait(false); } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/IPipelineTest.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/IPipelineTest.cs index d051cf4..163dcb7 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/IPipelineTest.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/IPipelineTest.cs @@ -1,17 +1,16 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Hosting; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +/// +/// Represents the members needed for ASP.NET Core pipeline testing. +/// +public interface IPipelineTest { /// - /// Represents the members needed for ASP.NET Core pipeline testing. + /// Gets the initialized by the . /// - public interface IPipelineTest - { - /// - /// Gets the initialized by the . - /// - /// The initialized by the . - IApplicationBuilder Application { get; } - } + /// The initialized by the . + IApplicationBuilder Application { get; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/IWebHostFixture.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/IWebHostFixture.cs index 23abfde..fa0131a 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/IWebHostFixture.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/IWebHostFixture.cs @@ -1,18 +1,17 @@ using System; using Microsoft.AspNetCore.Builder; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +/// +/// Provides a way to use Microsoft Dependency Injection in unit tests tailored for ASP.NET Core. +/// +/// +public interface IWebHostFixture : IGenericHostFixture, IPipelineTest { /// - /// Provides a way to use Microsoft Dependency Injection in unit tests tailored for ASP.NET Core. + /// Gets or sets the delegate that configures the HTTP request pipeline. /// - /// - public interface IWebHostFixture : IGenericHostFixture, IPipelineTest - { - /// - /// Gets or sets the delegate that configures the HTTP request pipeline. - /// - /// The delegate that configures the HTTP request pipeline. - Action ConfigureApplicationCallback { get; set; } - } + /// The delegate that configures the HTTP request pipeline. + Action ConfigureApplicationCallback { get; set; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/IWebHostTest.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/IWebHostTest.cs index eb540e6..fca9af9 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/IWebHostTest.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/IWebHostTest.cs @@ -1,11 +1,10 @@ -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +/// +/// Represents the members needed for ASP.NET Core (including but not limited to MVC, Razor and related) testing. +/// +/// +/// +public interface IWebHostTest : IHostTest, IPipelineTest { - /// - /// Represents the members needed for ASP.NET Core (including but not limited to MVC, Razor and related) testing. - /// - /// - /// - public interface IWebHostTest : IHostTest, IPipelineTest - { - } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/IWebMinimalHostFixture.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/IWebMinimalHostFixture.cs index 1845af0..23ae0b5 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/IWebMinimalHostFixture.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/IWebMinimalHostFixture.cs @@ -1,19 +1,18 @@ using System; using Microsoft.AspNetCore.Builder; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +/// +/// Provides a way to use Microsoft Dependency Injection in unit tests (minimal style). +/// +/// +/// +public interface IWebMinimalHostFixture : IMinimalHostFixture, IPipelineTest { /// - /// Provides a way to use Microsoft Dependency Injection in unit tests (minimal style). + /// Gets or sets the delegate that configures the HTTP request pipeline. /// - /// - /// - public interface IWebMinimalHostFixture : IMinimalHostFixture, IPipelineTest - { - /// - /// Gets or sets the delegate that configures the HTTP request pipeline. - /// - /// The delegate that configures the HTTP request pipeline. - Action ConfigureApplicationCallback { get; set; } - } + /// The delegate that configures the HTTP request pipeline. + Action ConfigureApplicationCallback { get; set; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Internal/MinimalWebHostTest.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Internal/MinimalWebHostTest.cs index 3c1dbbe..f8287cf 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Internal/MinimalWebHostTest.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Internal/MinimalWebHostTest.cs @@ -3,70 +3,69 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Internal +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Internal; + +internal sealed class MinimalWebHostTest : MinimalWebHostTest { - internal sealed class MinimalWebHostTest : MinimalWebHostTest - { - private readonly Action _pipelineConfigurator; - private readonly Action _serviceConfigurator; - private readonly Action _pipelineConfiguratorWithContext; - private readonly Action _serviceConfiguratorWithContext; - private readonly Action _hostConfigurator; - private HostBuilderContext _hostBuilderContext; + private readonly Action _pipelineConfigurator; + private readonly Action _serviceConfigurator; + private readonly Action _pipelineConfiguratorWithContext; + private readonly Action _serviceConfiguratorWithContext; + private readonly Action _hostConfigurator; + private HostBuilderContext _hostBuilderContext; - internal MinimalWebHostTest(Action serviceConfigurator, Action pipelineConfigurator, Action hostConfigurator, IWebMinimalHostFixture hostFixture) : base(true, hostFixture, callerType: pipelineConfigurator?.Target?.GetType() ?? serviceConfigurator?.Target?.GetType() ?? hostConfigurator?.Target?.GetType()) - { - _serviceConfigurator = serviceConfigurator; - _pipelineConfigurator = pipelineConfigurator; - _hostConfigurator = hostConfigurator; - InitializeHostFixture(hostFixture); - } + internal MinimalWebHostTest(Action serviceConfigurator, Action pipelineConfigurator, Action hostConfigurator, IWebMinimalHostFixture hostFixture) : base(true, hostFixture, callerType: pipelineConfigurator?.Target?.GetType() ?? serviceConfigurator?.Target?.GetType() ?? hostConfigurator?.Target?.GetType()) + { + _serviceConfigurator = serviceConfigurator; + _pipelineConfigurator = pipelineConfigurator; + _hostConfigurator = hostConfigurator; + InitializeHostFixture(hostFixture); + } - internal MinimalWebHostTest(Action serviceConfigurator, Action pipelineConfigurator, Action hostConfigurator, IWebMinimalHostFixture hostFixture) : base(true, hostFixture, callerType: pipelineConfigurator?.Target?.GetType() ?? serviceConfigurator?.Target?.GetType() ?? hostConfigurator?.Target?.GetType()) - { - _serviceConfiguratorWithContext = serviceConfigurator; - _pipelineConfiguratorWithContext = pipelineConfigurator; - _hostConfigurator = hostConfigurator; - InitializeHostFixture(hostFixture); - } + internal MinimalWebHostTest(Action serviceConfigurator, Action pipelineConfigurator, Action hostConfigurator, IWebMinimalHostFixture hostFixture) : base(true, hostFixture, callerType: pipelineConfigurator?.Target?.GetType() ?? serviceConfigurator?.Target?.GetType() ?? hostConfigurator?.Target?.GetType()) + { + _serviceConfiguratorWithContext = serviceConfigurator; + _pipelineConfiguratorWithContext = pipelineConfigurator; + _hostConfigurator = hostConfigurator; + InitializeHostFixture(hostFixture); + } - private void InitializeHostFixture(IWebMinimalHostFixture hostFixture) + private void InitializeHostFixture(IWebMinimalHostFixture hostFixture) + { + if (!hostFixture.HasValidState()) { - if (!hostFixture.HasValidState()) - { - hostFixture.ConfigureHostCallback = ConfigureHost; - hostFixture.ConfigureCallback = Configure; - hostFixture.ConfigureApplicationCallback = ConfigureApplication; - hostFixture.ConfigureHost(this); - } - Host = hostFixture.Host; - Application = hostFixture.Application; - Configure(hostFixture.Configuration, hostFixture.Environment); + hostFixture.ConfigureHostCallback = ConfigureHost; + hostFixture.ConfigureCallback = Configure; + hostFixture.ConfigureApplicationCallback = ConfigureApplication; + hostFixture.ConfigureHost(this); } + Host = hostFixture.Host; + Application = hostFixture.Application; + Configure(hostFixture.Configuration, hostFixture.Environment); + } - public override void ConfigureApplication(IApplicationBuilder app) + public override void ConfigureApplication(IApplicationBuilder app) + { + _pipelineConfigurator?.Invoke(app); + _pipelineConfiguratorWithContext?.Invoke(Tweaker.Adjust(_hostBuilderContext, hbc => { - _pipelineConfigurator?.Invoke(app); - _pipelineConfiguratorWithContext?.Invoke(Tweaker.Adjust(_hostBuilderContext, hbc => - { - hbc.Configuration = Configuration; - hbc.HostingEnvironment = Environment; - return hbc; - }), app); - } + hbc.Configuration = Configuration; + hbc.HostingEnvironment = Environment; + return hbc; + }), app); + } - protected override void ConfigureHost(IHostApplicationBuilder hb) + protected override void ConfigureHost(IHostApplicationBuilder hb) + { + _hostBuilderContext = new HostBuilderContext(hb.Properties); + _hostConfigurator?.Invoke(hb); + _serviceConfigurator?.Invoke(hb.Services); + _serviceConfiguratorWithContext?.Invoke(Tweaker.Adjust(_hostBuilderContext, hbc => { - _hostBuilderContext = new HostBuilderContext(hb.Properties); - _hostConfigurator?.Invoke(hb); - _serviceConfigurator?.Invoke(hb.Services); - _serviceConfiguratorWithContext?.Invoke(Tweaker.Adjust(_hostBuilderContext, hbc => - { - hbc.Configuration = hb.Configuration; - hbc.HostingEnvironment = hb.Environment; - return hbc; - }), hb.Services); - hb.Services.AddFakeHttpContextAccessor(); - } + hbc.Configuration = hb.Configuration; + hbc.HostingEnvironment = hb.Environment; + return hbc; + }), hb.Services); + hb.Services.AddFakeHttpContextAccessor(); } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Internal/WebHostTest.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Internal/WebHostTest.cs index 8494f1b..7b56f5f 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Internal/WebHostTest.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Internal/WebHostTest.cs @@ -3,75 +3,74 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Internal +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Internal; + +internal sealed class WebHostTest : WebHostTest { - internal sealed class WebHostTest : WebHostTest - { - private readonly Action _pipelineConfigurator; - private readonly Action _serviceConfigurator; - private readonly Action _pipelineConfiguratorWithContext; - private readonly Action _serviceConfiguratorWithContext; - private readonly Action _hostConfigurator; - private HostBuilderContext _hostBuilderContext; + private readonly Action _pipelineConfigurator; + private readonly Action _serviceConfigurator; + private readonly Action _pipelineConfiguratorWithContext; + private readonly Action _serviceConfiguratorWithContext; + private readonly Action _hostConfigurator; + private HostBuilderContext _hostBuilderContext; - internal WebHostTest(Action serviceConfigurator, Action pipelineConfigurator, Action hostConfigurator, IWebHostFixture hostFixture) : base(true, hostFixture, callerType: pipelineConfigurator?.Target?.GetType() ?? serviceConfigurator?.Target?.GetType() ?? hostConfigurator?.Target?.GetType()) - { - _serviceConfigurator = serviceConfigurator; - _pipelineConfigurator = pipelineConfigurator; - _hostConfigurator = hostConfigurator; - InitializeHostFixture(hostFixture); - } + internal WebHostTest(Action serviceConfigurator, Action pipelineConfigurator, Action hostConfigurator, IWebHostFixture hostFixture) : base(true, hostFixture, callerType: pipelineConfigurator?.Target?.GetType() ?? serviceConfigurator?.Target?.GetType() ?? hostConfigurator?.Target?.GetType()) + { + _serviceConfigurator = serviceConfigurator; + _pipelineConfigurator = pipelineConfigurator; + _hostConfigurator = hostConfigurator; + InitializeHostFixture(hostFixture); + } - internal WebHostTest(Action serviceConfigurator, Action pipelineConfigurator, Action hostConfigurator, IWebHostFixture hostFixture) : base(true, hostFixture, callerType: pipelineConfigurator?.Target?.GetType() ?? serviceConfigurator?.Target?.GetType() ?? hostConfigurator?.Target?.GetType()) - { - _serviceConfiguratorWithContext = serviceConfigurator; - _pipelineConfiguratorWithContext = pipelineConfigurator; - _hostConfigurator = hostConfigurator; - InitializeHostFixture(hostFixture); - } + internal WebHostTest(Action serviceConfigurator, Action pipelineConfigurator, Action hostConfigurator, IWebHostFixture hostFixture) : base(true, hostFixture, callerType: pipelineConfigurator?.Target?.GetType() ?? serviceConfigurator?.Target?.GetType() ?? hostConfigurator?.Target?.GetType()) + { + _serviceConfiguratorWithContext = serviceConfigurator; + _pipelineConfiguratorWithContext = pipelineConfigurator; + _hostConfigurator = hostConfigurator; + InitializeHostFixture(hostFixture); + } - private void InitializeHostFixture(IWebHostFixture hostFixture) + private void InitializeHostFixture(IWebHostFixture hostFixture) + { + if (!hostFixture.HasValidState()) { - if (!hostFixture.HasValidState()) - { - hostFixture.ConfigureHostCallback = ConfigureHost; - hostFixture.ConfigureCallback = Configure; - hostFixture.ConfigureServicesCallback = ConfigureServices; - hostFixture.ConfigureApplicationCallback = ConfigureApplication; - hostFixture.ConfigureHost(this); - } - Host = hostFixture.Host; - Application = hostFixture.Application; - Configure(hostFixture.Configuration, hostFixture.Environment); + hostFixture.ConfigureHostCallback = ConfigureHost; + hostFixture.ConfigureCallback = Configure; + hostFixture.ConfigureServicesCallback = ConfigureServices; + hostFixture.ConfigureApplicationCallback = ConfigureApplication; + hostFixture.ConfigureHost(this); } + Host = hostFixture.Host; + Application = hostFixture.Application; + Configure(hostFixture.Configuration, hostFixture.Environment); + } - public override void ConfigureApplication(IApplicationBuilder app) + public override void ConfigureApplication(IApplicationBuilder app) + { + _pipelineConfigurator?.Invoke(app); + _pipelineConfiguratorWithContext?.Invoke(Tweaker.Adjust(_hostBuilderContext, hbc => { - _pipelineConfigurator?.Invoke(app); - _pipelineConfiguratorWithContext?.Invoke(Tweaker.Adjust(_hostBuilderContext, hbc => - { - hbc.Configuration = Configuration; - hbc.HostingEnvironment = Environment; - return hbc; - }), app); - } + hbc.Configuration = Configuration; + hbc.HostingEnvironment = Environment; + return hbc; + }), app); + } - protected override void ConfigureHost(IHostBuilder hb) - { - _hostBuilderContext = new HostBuilderContext(hb.Properties); - _hostConfigurator?.Invoke(hb); - } + protected override void ConfigureHost(IHostBuilder hb) + { + _hostBuilderContext = new HostBuilderContext(hb.Properties); + _hostConfigurator?.Invoke(hb); + } - public override void ConfigureServices(IServiceCollection services) + public override void ConfigureServices(IServiceCollection services) + { + _serviceConfigurator?.Invoke(services); + _serviceConfiguratorWithContext?.Invoke(Tweaker.Adjust(_hostBuilderContext, hbc => { - _serviceConfigurator?.Invoke(services); - _serviceConfiguratorWithContext?.Invoke(Tweaker.Adjust(_hostBuilderContext, hbc => - { - hbc.Configuration = Configuration; - hbc.HostingEnvironment = Environment; - return hbc; - }), services); - services.AddFakeHttpContextAccessor(); - } + hbc.Configuration = Configuration; + hbc.HostingEnvironment = Environment; + return hbc; + }), services); + services.AddFakeHttpContextAccessor(); } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/ManagedWebHostFixture.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/ManagedWebHostFixture.cs index af5ce7c..c7c8332 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/ManagedWebHostFixture.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/ManagedWebHostFixture.cs @@ -9,103 +9,102 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +/// +/// Provides a default implementation of the interface. +/// +/// +/// +public class ManagedWebHostFixture : ManagedHostFixture, IWebHostFixture { /// - /// Provides a default implementation of the interface. + /// Initializes a new instance of the class. /// - /// - /// - public class ManagedWebHostFixture : ManagedHostFixture, IWebHostFixture + public ManagedWebHostFixture() { - /// - /// Initializes a new instance of the class. - /// - public ManagedWebHostFixture() - { - } + } - /// - /// Creates and configures the of this instance. - /// - /// The object that inherits from . - /// was added to support those cases where the caller is required in the host configuration. - /// - /// is null. - /// - /// - /// is not assignable from . - /// - public override void ConfigureHost(Test hostTest) - { - ArgumentNullException.ThrowIfNull(hostTest); - if (!HasTypes(hostTest.GetType(), typeof(WebHostTest<>))) { throw new ArgumentOutOfRangeException(nameof(hostTest), typeof(WebHostTest<>), $"{nameof(hostTest)} is not assignable from WebHostTest."); } - if (!this.HasValidState()) { return; } // had to include this due to dual-call this method (one uncontrolled from xUnit library reflection magic; second controlled from this library) + /// + /// Creates and configures the of this instance. + /// + /// The object that inherits from . + /// was added to support those cases where the caller is required in the host configuration. + /// + /// is null. + /// + /// + /// is not assignable from . + /// + public override void ConfigureHost(Test hostTest) + { + ArgumentNullException.ThrowIfNull(hostTest); + if (!HasTypes(hostTest.GetType(), typeof(WebHostTest<>))) { throw new ArgumentOutOfRangeException(nameof(hostTest), typeof(WebHostTest<>), $"{nameof(hostTest)} is not assignable from WebHostTest."); } + if (!this.HasValidState()) { return; } // had to include this due to dual-call this method (one uncontrolled from xUnit library reflection magic; second controlled from this library) - var hb = new HostBuilder() - .ConfigureWebHost(webBuilder => - { - webBuilder - .UseTestServer(o => o.PreserveExecutionContext = true) - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseEnvironment("Development") - .ConfigureAppConfiguration((context, config) => - { - config.AddJsonFile("appsettings.json", true, true) - .AddJsonFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.json", true, true) - .AddEnvironmentVariables(); + var hb = new HostBuilder() + .ConfigureWebHost(webBuilder => + { + webBuilder + .UseTestServer(o => o.PreserveExecutionContext = true) + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseEnvironment("Development") + .ConfigureAppConfiguration((context, config) => + { + config.AddJsonFile("appsettings.json", true, true) + .AddJsonFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.json", true, true) + .AddEnvironmentVariables(); - StaticWebAssetsLoader.UseStaticWebAssets(context.HostingEnvironment, context.Configuration); + StaticWebAssetsLoader.UseStaticWebAssets(context.HostingEnvironment, context.Configuration); - ConfigureCallback(config.Build(), context.HostingEnvironment); - }) - .ConfigureLogging((context, logging) => - { - logging.AddConfiguration(context.Configuration.GetSection("Logging")); - logging.AddConsole(); - logging.AddDebug(); - logging.AddEventSourceLogger(); - }) - .ConfigureServices((context, services) => + ConfigureCallback(config.Build(), context.HostingEnvironment); + }) + .ConfigureLogging((context, logging) => + { + logging.AddConfiguration(context.Configuration.GetSection("Logging")); + logging.AddConsole(); + logging.AddDebug(); + logging.AddEventSourceLogger(); + }) + .ConfigureServices((context, services) => + { + Configuration = context.Configuration; + Environment = context.HostingEnvironment; + ConfigureServicesCallback(services); + }) + .Configure(app => { - Configuration = context.Configuration; - Environment = context.HostingEnvironment; - ConfigureServicesCallback(services); - }) - .Configure(app => - { - ConfigureApplicationCallback.Invoke(app); - Application = app; - } - ) - .UseSetting(HostDefaults.ApplicationKey, hostTest.CallerType.Assembly.GetName().Name); - }); + ConfigureApplicationCallback.Invoke(app); + Application = app; + } + ) + .UseSetting(HostDefaults.ApplicationKey, hostTest.CallerType.Assembly.GetName().Name); + }); #if NET9_0_OR_GREATER - hb.UseDefaultServiceProvider(o => - { - o.ValidateOnBuild = true; - o.ValidateScopes = true; - }); + hb.UseDefaultServiceProvider(o => + { + o.ValidateOnBuild = true; + o.ValidateScopes = true; + }); #endif - ConfigureHostCallback(hb); + ConfigureHostCallback(hb); - Host = hb.Build(); + Host = hb.Build(); - AsyncHostRunnerCallback(Host, CancellationToken.None); - } + AsyncHostRunnerCallback(Host, CancellationToken.None); + } - /// - /// Gets or sets the delegate that configures the HTTP request pipeline. - /// - /// The delegate that configures the HTTP request pipeline. - public Action ConfigureApplicationCallback { get; set; } + /// + /// Gets or sets the delegate that configures the HTTP request pipeline. + /// + /// The delegate that configures the HTTP request pipeline. + public Action ConfigureApplicationCallback { get; set; } - /// - /// Gets the initialized by the . - /// - /// The initialized by the . - public IApplicationBuilder Application { get; protected set; } - } + /// + /// Gets the initialized by the . + /// + /// The initialized by the . + public IApplicationBuilder Application { get; protected set; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/ManagedWebMinimalHostFixture.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/ManagedWebMinimalHostFixture.cs index 2f1b1e7..29c14f8 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/ManagedWebMinimalHostFixture.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/ManagedWebMinimalHostFixture.cs @@ -4,74 +4,73 @@ using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.Hosting; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +/// +/// Provides a default implementation of the interface. +/// +/// +/// +/// This is the "modern" minimal style implementation of . +public class ManagedWebMinimalHostFixture : ManagedMinimalHostFixture, IWebMinimalHostFixture { /// - /// Provides a default implementation of the interface. + /// Initializes a new instance of the class. /// - /// - /// - /// This is the "modern" minimal style implementation of . - public class ManagedWebMinimalHostFixture : ManagedMinimalHostFixture, IWebMinimalHostFixture + public ManagedWebMinimalHostFixture() { - /// - /// Initializes a new instance of the class. - /// - public ManagedWebMinimalHostFixture() - { - } + } - /// - /// Creates and configures the of this instance. - /// - /// The object that inherits from . - /// was added to support those cases where the caller is required in the host configuration. - /// - /// is null. - /// - /// - /// is not assignable from . - /// - public override void ConfigureHost(Test hostTest) - { - ArgumentNullException.ThrowIfNull(hostTest); - if (!HasTypes(hostTest.GetType(), typeof(MinimalWebHostTest<>))) { throw new ArgumentOutOfRangeException(nameof(hostTest), typeof(MinimalWebHostTest<>), $"{nameof(hostTest)} is not assignable from MinimalWebHostTest."); } + /// + /// Creates and configures the of this instance. + /// + /// The object that inherits from . + /// was added to support those cases where the caller is required in the host configuration. + /// + /// is null. + /// + /// + /// is not assignable from . + /// + public override void ConfigureHost(Test hostTest) + { + ArgumentNullException.ThrowIfNull(hostTest); + if (!HasTypes(hostTest.GetType(), typeof(MinimalWebHostTest<>))) { throw new ArgumentOutOfRangeException(nameof(hostTest), typeof(MinimalWebHostTest<>), $"{nameof(hostTest)} is not assignable from MinimalWebHostTest."); } - var hb = WebApplication.CreateBuilder(new WebApplicationOptions() - { - EnvironmentName = "Development", - ApplicationName = hostTest.CallerType.Assembly.GetName().Name - }); + var hb = WebApplication.CreateBuilder(new WebApplicationOptions() + { + EnvironmentName = "Development", + ApplicationName = hostTest.CallerType.Assembly.GetName().Name + }); - hb.WebHost.UseTestServer(o => o.PreserveExecutionContext = true); + hb.WebHost.UseTestServer(o => o.PreserveExecutionContext = true); - Configuration = hb.Configuration; - Environment = hb.Environment; + Configuration = hb.Configuration; + Environment = hb.Environment; - ConfigureCallback(Configuration, Environment); + ConfigureCallback(Configuration, Environment); - ConfigureHostCallback(hb); + ConfigureHostCallback(hb); - var webApplication = hb.Build(); + var webApplication = hb.Build(); - ConfigureApplicationCallback(webApplication); - Application = webApplication; - - Host = webApplication; + ConfigureApplicationCallback(webApplication); + Application = webApplication; + + Host = webApplication; - AsyncHostRunnerCallback(Host, CancellationToken.None); - } + AsyncHostRunnerCallback(Host, CancellationToken.None); + } - /// - /// Gets or sets the delegate that configures the HTTP request pipeline. - /// - /// The delegate that configures the HTTP request pipeline. - public Action ConfigureApplicationCallback { get; set; } + /// + /// Gets or sets the delegate that configures the HTTP request pipeline. + /// + /// The delegate that configures the HTTP request pipeline. + public Action ConfigureApplicationCallback { get; set; } - /// - /// Gets the initialized by the . - /// - /// The initialized by the . - public IApplicationBuilder Application { get; protected set; } - } + /// + /// Gets the initialized by the . + /// + /// The initialized by the . + public IApplicationBuilder Application { get; protected set; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/MinimalWebHostTest.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/MinimalWebHostTest.cs index 49474c7..c08b789 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/MinimalWebHostTest.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/MinimalWebHostTest.cs @@ -3,64 +3,63 @@ using Microsoft.Extensions.Hosting; using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +/// +/// Represents a base class from which all implementations of unit testing, that uses Microsoft Dependency Injection and depends on ASP.NET Core (minimal style), should derive. +/// +/// The type of the object that implements the interface. +/// +/// +/// +/// The class needed to be designed in this rather complex way, as this is the only way that xUnit supports a shared context. The need for shared context is theoretical at best, but it does opt-in for Scoped instances. +public abstract class MinimalWebHostTest : MinimalHostTest, IWebHostTest, IClassFixture where T : class, IWebMinimalHostFixture { /// - /// Represents a base class from which all implementations of unit testing, that uses Microsoft Dependency Injection and depends on ASP.NET Core (minimal style), should derive. + /// Initializes a new instance of the class. /// - /// The type of the object that implements the interface. - /// - /// - /// - /// The class needed to be designed in this rather complex way, as this is the only way that xUnit supports a shared context. The need for shared context is theoretical at best, but it does opt-in for Scoped instances. - public abstract class MinimalWebHostTest : MinimalHostTest, IWebHostTest, IClassFixture where T : class, IWebMinimalHostFixture + /// An implementation of the interface. + /// An implementation of the interface. + /// The of caller that ends up invoking this instance. + protected MinimalWebHostTest(T hostFixture, ITestOutputHelper output = null, Type callerType = null) : this(false, hostFixture, output, callerType) { - /// - /// Initializes a new instance of the class. - /// - /// An implementation of the interface. - /// An implementation of the interface. - /// The of caller that ends up invoking this instance. - protected MinimalWebHostTest(T hostFixture, ITestOutputHelper output = null, Type callerType = null) : this(false, hostFixture, output, callerType) - { - } + } - /// - /// Initializes a new instance of the class. - /// - /// A value indicating whether to skip the host fixture initialization. - /// An implementation of the interface. - /// An implementation of the interface. - /// The of caller that ends up invoking this instance. - /// - /// is null. - /// - protected MinimalWebHostTest(bool skipHostFixtureInitialization, T hostFixture, ITestOutputHelper output = null, Type callerType = null) : base(output, callerType) + /// + /// Initializes a new instance of the class. + /// + /// A value indicating whether to skip the host fixture initialization. + /// An implementation of the interface. + /// An implementation of the interface. + /// The of caller that ends up invoking this instance. + /// + /// is null. + /// + protected MinimalWebHostTest(bool skipHostFixtureInitialization, T hostFixture, ITestOutputHelper output = null, Type callerType = null) : base(output, callerType) + { + ArgumentNullException.ThrowIfNull(hostFixture); + if (skipHostFixtureInitialization) { return; } + if (!hostFixture.HasValidState()) { - ArgumentNullException.ThrowIfNull(hostFixture); - if (skipHostFixtureInitialization) { return; } - if (!hostFixture.HasValidState()) - { - hostFixture.ConfigureCallback = Configure; - hostFixture.ConfigureHostCallback = ConfigureHost; - hostFixture.ConfigureApplicationCallback = ConfigureApplication; - hostFixture.ConfigureHost(this); - } - Host = hostFixture.Host; - Application = hostFixture.Application; - Configure(hostFixture.Configuration, hostFixture.Environment); + hostFixture.ConfigureCallback = Configure; + hostFixture.ConfigureHostCallback = ConfigureHost; + hostFixture.ConfigureApplicationCallback = ConfigureApplication; + hostFixture.ConfigureHost(this); } + Host = hostFixture.Host; + Application = hostFixture.Application; + Configure(hostFixture.Configuration, hostFixture.Environment); + } - /// - /// Gets the initialized by the . - /// - /// The initialized by the . - public IApplicationBuilder Application { get; protected set; } + /// + /// Gets the initialized by the . + /// + /// The initialized by the . + public IApplicationBuilder Application { get; protected set; } - /// - /// Configures the HTTP request pipeline. - /// - /// The type that provides the mechanisms to configure the HTTP request pipeline. - public abstract void ConfigureApplication(IApplicationBuilder app); - } + /// + /// Configures the HTTP request pipeline. + /// + /// The type that provides the mechanisms to configure the HTTP request pipeline. + public abstract void ConfigureApplication(IApplicationBuilder app); } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/MinimalWebHostTestFactory.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/MinimalWebHostTestFactory.cs index 05780f8..ee843b1 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/MinimalWebHostTestFactory.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/MinimalWebHostTestFactory.cs @@ -7,68 +7,67 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +/// +/// Provides a set of static methods for ASP.NET Core (including, but not limited to MVC, Razor and related) unit testing (minimal style). +/// +/// . +public static class MinimalWebHostTestFactory { /// - /// Provides a set of static methods for ASP.NET Core (including, but not limited to MVC, Razor and related) unit testing (minimal style). + /// Creates and returns an implementation. /// - /// . - public static class MinimalWebHostTestFactory + /// The which may be configured. + /// The which may be configured. + /// The which may be configured. + /// An optional implementation to use instead of the default instance. + /// An instance of an implementation. + public static IWebHostTest Create(Action serviceSetup = null, Action pipelineSetup = null, Action hostSetup = null, IWebMinimalHostFixture hostFixture = null) { - /// - /// Creates and returns an implementation. - /// - /// The which may be configured. - /// The which may be configured. - /// The which may be configured. - /// An optional implementation to use instead of the default instance. - /// An instance of an implementation. - public static IWebHostTest Create(Action serviceSetup = null, Action pipelineSetup = null, Action hostSetup = null, IWebMinimalHostFixture hostFixture = null) - { - return new MinimalWebHostTest(serviceSetup, pipelineSetup, hostSetup, hostFixture ?? new ManagedWebMinimalHostFixture()); - } + return new MinimalWebHostTest(serviceSetup, pipelineSetup, hostSetup, hostFixture ?? new ManagedWebMinimalHostFixture()); + } - /// - /// Creates and returns an implementation. - /// - /// The which may be configured. - /// The which may be configured. - /// The which may be configured. - /// An optional implementation to use instead of the default instance. - /// An instance of an implementation. - public static IWebHostTest CreateWithHostBuilderContext(Action serviceSetup = null, Action pipelineSetup = null, Action hostSetup = null, IWebMinimalHostFixture hostFixture = null) - { - return new MinimalWebHostTest(serviceSetup, pipelineSetup, hostSetup, hostFixture ?? new ManagedWebMinimalHostFixture()); - } + /// + /// Creates and returns an implementation. + /// + /// The which may be configured. + /// The which may be configured. + /// The which may be configured. + /// An optional implementation to use instead of the default instance. + /// An instance of an implementation. + public static IWebHostTest CreateWithHostBuilderContext(Action serviceSetup = null, Action pipelineSetup = null, Action hostSetup = null, IWebMinimalHostFixture hostFixture = null) + { + return new MinimalWebHostTest(serviceSetup, pipelineSetup, hostSetup, hostFixture ?? new ManagedWebMinimalHostFixture()); + } - /// - /// Runs a middleware and returns an for making HTTP requests to the test server. - /// - /// The which may be configured. - /// The which may be configured. - /// The which may be configured. - /// The function delegate that creates a from the . Default is a GET request to the root URL ("/"). - /// An optional implementation to use instead of the default instance. - /// A that represents the asynchronous operation. The task result contains the for the test server. - public static async Task RunAsync(Action serviceSetup = null, Action pipelineSetup = null, Action hostSetup = null, Func> responseFactory = null, IWebMinimalHostFixture hostFixture = null) - { - using var client = Create(serviceSetup, pipelineSetup, hostSetup, hostFixture).Host.GetTestClient(); - return await client.ToHttpResponseMessageAsync(responseFactory).ConfigureAwait(false); - } + /// + /// Runs a middleware and returns an for making HTTP requests to the test server. + /// + /// The which may be configured. + /// The which may be configured. + /// The which may be configured. + /// The function delegate that creates a from the . Default is a GET request to the root URL ("/"). + /// An optional implementation to use instead of the default instance. + /// A that represents the asynchronous operation. The task result contains the for the test server. + public static async Task RunAsync(Action serviceSetup = null, Action pipelineSetup = null, Action hostSetup = null, Func> responseFactory = null, IWebMinimalHostFixture hostFixture = null) + { + using var client = Create(serviceSetup, pipelineSetup, hostSetup, hostFixture).Host.GetTestClient(); + return await client.ToHttpResponseMessageAsync(responseFactory).ConfigureAwait(false); + } - /// - /// Runs a filter/middleware test. - /// - /// The which may be configured. - /// The which may be configured. - /// The which may be configured. - /// The function delegate that creates a from the . Default is a GET request to the root URL ("/"). - /// An optional implementation to use instead of the default instance. - /// A that represents the asynchronous operation. The task result contains the for the test server. - public static async Task RunWithHostBuilderContextAsync(Action serviceSetup = null, Action pipelineSetup = null, Action hostSetup = null, Func> responseFactory = null, IWebMinimalHostFixture hostFixture = null) - { - using var client = CreateWithHostBuilderContext(serviceSetup, pipelineSetup, hostSetup, hostFixture).Host.GetTestClient(); - return await client.ToHttpResponseMessageAsync(responseFactory).ConfigureAwait(false); - } + /// + /// Runs a filter/middleware test. + /// + /// The which may be configured. + /// The which may be configured. + /// The which may be configured. + /// The function delegate that creates a from the . Default is a GET request to the root URL ("/"). + /// An optional implementation to use instead of the default instance. + /// A that represents the asynchronous operation. The task result contains the for the test server. + public static async Task RunWithHostBuilderContextAsync(Action serviceSetup = null, Action pipelineSetup = null, Action hostSetup = null, Func> responseFactory = null, IWebMinimalHostFixture hostFixture = null) + { + using var client = CreateWithHostBuilderContext(serviceSetup, pipelineSetup, hostSetup, hostFixture).Host.GetTestClient(); + return await client.ToHttpResponseMessageAsync(responseFactory).ConfigureAwait(false); } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/SelfManagedWebHostFixture.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/SelfManagedWebHostFixture.cs index 0aa9818..5b90e9a 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/SelfManagedWebHostFixture.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/SelfManagedWebHostFixture.cs @@ -1,21 +1,20 @@ using System.Threading.Tasks; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +/// +/// Represents a self-managed implementation of the class. +/// +public sealed class SelfManagedWebHostFixture : ManagedWebHostFixture { /// - /// Represents a self-managed implementation of the class. + /// Initializes a new instance of the class. /// - public sealed class SelfManagedWebHostFixture : ManagedWebHostFixture + /// + /// This constructor sets the to a no-op asynchronous delegate. + /// + public SelfManagedWebHostFixture() { - /// - /// Initializes a new instance of the class. - /// - /// - /// This constructor sets the to a no-op asynchronous delegate. - /// - public SelfManagedWebHostFixture() - { - AsyncHostRunnerCallback = (_, __) => Task.CompletedTask; - } + AsyncHostRunnerCallback = (_, __) => Task.CompletedTask; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/SelfManagedWebMinimalHostFixture.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/SelfManagedWebMinimalHostFixture.cs index 6b94eb3..8cefce7 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/SelfManagedWebMinimalHostFixture.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/SelfManagedWebMinimalHostFixture.cs @@ -1,21 +1,20 @@ using System.Threading.Tasks; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +/// +/// Represents a self-managed implementation of the class. +/// +public sealed class SelfManagedWebMinimalHostFixture : ManagedWebMinimalHostFixture { /// - /// Represents a self-managed implementation of the class. + /// Initializes a new instance of the class. /// - public sealed class SelfManagedWebMinimalHostFixture : ManagedWebMinimalHostFixture + /// + /// This constructor sets the to a no-op asynchronous delegate. + /// + public SelfManagedWebMinimalHostFixture() { - /// - /// Initializes a new instance of the class. - /// - /// - /// This constructor sets the to a no-op asynchronous delegate. - /// - public SelfManagedWebMinimalHostFixture() - { - AsyncHostRunnerCallback = (_, __) => Task.CompletedTask; - } + AsyncHostRunnerCallback = (_, __) => Task.CompletedTask; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/ServiceCollectionExtensions.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/ServiceCollectionExtensions.cs index c8b6978..9e1db52 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/ServiceCollectionExtensions.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/ServiceCollectionExtensions.cs @@ -5,41 +5,40 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +/// +/// Extension methods for the interface. +/// +public static class ServiceCollectionExtensions { /// - /// Extension methods for the interface. + /// Adds a unit test optimized implementation for the service. /// - public static class ServiceCollectionExtensions + /// The to extend. + /// The lifetime of the service. Default is . + /// A reference to after the operation has completed. + public static IServiceCollection AddFakeHttpContextAccessor(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Singleton) { - /// - /// Adds a unit test optimized implementation for the service. - /// - /// The to extend. - /// The lifetime of the service. Default is . - /// A reference to after the operation has completed. - public static IServiceCollection AddFakeHttpContextAccessor(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Singleton) + switch (lifetime) { - switch (lifetime) - { - case ServiceLifetime.Transient: - services.TryAddTransient(FakeHttpContextAccessorFactory); - break; - case ServiceLifetime.Scoped: - services.TryAddScoped(FakeHttpContextAccessorFactory); - break; - case ServiceLifetime.Singleton: - services.TryAddSingleton(FakeHttpContextAccessorFactory); - break; - default: - throw new InvalidEnumArgumentException(nameof(lifetime), (int)lifetime, typeof(ServiceLifetime)); - } - return services; + case ServiceLifetime.Transient: + services.TryAddTransient(FakeHttpContextAccessorFactory); + break; + case ServiceLifetime.Scoped: + services.TryAddScoped(FakeHttpContextAccessorFactory); + break; + case ServiceLifetime.Singleton: + services.TryAddSingleton(FakeHttpContextAccessorFactory); + break; + default: + throw new InvalidEnumArgumentException(nameof(lifetime), (int)lifetime, typeof(ServiceLifetime)); } + return services; + } - private static IHttpContextAccessor FakeHttpContextAccessorFactory(IServiceProvider provider) - { - return new FakeHttpContextAccessor(provider.GetRequiredService()); - } + private static IHttpContextAccessor FakeHttpContextAccessorFactory(IServiceProvider provider) + { + return new FakeHttpContextAccessor(provider.GetRequiredService()); } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Tweaker.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Tweaker.cs index 83e3a7a..116c425 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Tweaker.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Tweaker.cs @@ -1,12 +1,11 @@ using System; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +internal static class Tweaker { - internal static class Tweaker + internal static T Adjust(T value, Func converter) { - internal static T Adjust(T value, Func converter) - { - return converter == null ? value : converter.Invoke(value); - } + return converter == null ? value : converter.Invoke(value); } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/WebHostFixtureExtensions.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/WebHostFixtureExtensions.cs index 246aa40..c589bfa 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/WebHostFixtureExtensions.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/WebHostFixtureExtensions.cs @@ -1,23 +1,22 @@ -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +/// +/// Extension methods for the interface. +/// +public static class WebHostFixtureExtensions { /// - /// Extension methods for the interface. + /// Determines whether the specified has a valid state. /// - public static class WebHostFixtureExtensions + /// The to check. + /// true if the specified has a valid state; otherwise, false. + /// + /// A valid state is defined as having non-null values for the following properties: + /// , and . + /// + public static bool HasValidState(this IWebHostFixture hostFixture) { - /// - /// Determines whether the specified has a valid state. - /// - /// The to check. - /// true if the specified has a valid state; otherwise, false. - /// - /// A valid state is defined as having non-null values for the following properties: - /// , and . - /// - public static bool HasValidState(this IWebHostFixture hostFixture) - { - var hasValidState = ((IGenericHostFixture)hostFixture).HasValidState(); - return hasValidState && hostFixture.ConfigureApplicationCallback != null; - } + var hasValidState = ((IGenericHostFixture)hostFixture).HasValidState(); + return hasValidState && hostFixture.ConfigureApplicationCallback != null; } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/WebHostTest.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/WebHostTest.cs index b7b6b99..7a89a13 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/WebHostTest.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/WebHostTest.cs @@ -3,60 +3,59 @@ using Microsoft.Extensions.Hosting; using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +/// +/// Represents a base class from which all implementations of unit testing, that uses Microsoft Dependency Injection and depends on ASP.NET Core, should derive. +/// +/// The type of the object that implements the interface. +/// +/// +public abstract class WebHostTest : HostTest, IWebHostTest where T : class, IWebHostFixture { /// - /// Represents a base class from which all implementations of unit testing, that uses Microsoft Dependency Injection and depends on ASP.NET Core, should derive. + /// Initializes a new instance of the class. /// - /// The type of the object that implements the interface. - /// - /// - public abstract class WebHostTest : HostTest, IWebHostTest where T : class, IWebHostFixture + /// An implementation of the interface. + /// An implementation of the interface. + /// The of caller that ends up invoking this instance. + protected WebHostTest(T hostFixture, ITestOutputHelper output = null, Type callerType = null) : this(false, hostFixture, output, callerType) { - /// - /// Initializes a new instance of the class. - /// - /// An implementation of the interface. - /// An implementation of the interface. - /// The of caller that ends up invoking this instance. - protected WebHostTest(T hostFixture, ITestOutputHelper output = null, Type callerType = null) : this(false, hostFixture, output, callerType) - { - } + } - /// - /// Initializes a new instance of the class. - /// - /// A value indicating whether to skip the host fixture initialization. - /// An implementation of the interface. - /// An implementation of the interface. - /// The of caller that ends up invoking this instance. - protected WebHostTest(bool skipHostFixtureInitialization, T hostFixture, ITestOutputHelper output = null, Type callerType = null) : base(skipHostFixtureInitialization, hostFixture, output, callerType) + /// + /// Initializes a new instance of the class. + /// + /// A value indicating whether to skip the host fixture initialization. + /// An implementation of the interface. + /// An implementation of the interface. + /// The of caller that ends up invoking this instance. + protected WebHostTest(bool skipHostFixtureInitialization, T hostFixture, ITestOutputHelper output = null, Type callerType = null) : base(skipHostFixtureInitialization, hostFixture, output, callerType) + { + ArgumentNullException.ThrowIfNull(hostFixture); + if (skipHostFixtureInitialization) { return; } + if (!hostFixture.HasValidState()) { - ArgumentNullException.ThrowIfNull(hostFixture); - if (skipHostFixtureInitialization) { return; } - if (!hostFixture.HasValidState()) - { - hostFixture.ConfigureHostCallback = ConfigureHost; - hostFixture.ConfigureCallback = Configure; - hostFixture.ConfigureServicesCallback = ConfigureServices; - hostFixture.ConfigureApplicationCallback = ConfigureApplication; - hostFixture.ConfigureHost(this); - } - Host = hostFixture.Host; - Application = hostFixture.Application; - Configure(hostFixture.Configuration, hostFixture.Environment); + hostFixture.ConfigureHostCallback = ConfigureHost; + hostFixture.ConfigureCallback = Configure; + hostFixture.ConfigureServicesCallback = ConfigureServices; + hostFixture.ConfigureApplicationCallback = ConfigureApplication; + hostFixture.ConfigureHost(this); } + Host = hostFixture.Host; + Application = hostFixture.Application; + Configure(hostFixture.Configuration, hostFixture.Environment); + } - /// - /// Gets the initialized by the . - /// - /// The initialized by the . - public IApplicationBuilder Application { get; protected set; } + /// + /// Gets the initialized by the . + /// + /// The initialized by the . + public IApplicationBuilder Application { get; protected set; } - /// - /// Configures the HTTP request pipeline. - /// - /// The type that provides the mechanisms to configure the HTTP request pipeline. - public abstract void ConfigureApplication(IApplicationBuilder app); - } + /// + /// Configures the HTTP request pipeline. + /// + /// The type that provides the mechanisms to configure the HTTP request pipeline. + public abstract void ConfigureApplication(IApplicationBuilder app); } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/WebHostTestFactory.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/WebHostTestFactory.cs index 68131f8..4904d93 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/WebHostTestFactory.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/WebHostTestFactory.cs @@ -7,68 +7,67 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +/// +/// Provides a set of static methods for ASP.NET Core (including, but not limited to MVC, Razor and related) unit testing. +/// +/// . +public static class WebHostTestFactory { /// - /// Provides a set of static methods for ASP.NET Core (including, but not limited to MVC, Razor and related) unit testing. + /// Creates and returns an implementation. /// - /// . - public static class WebHostTestFactory + /// The which may be configured. + /// The which may be configured. + /// The which may be configured. + /// An optional implementation to use instead of the default instance. + /// An instance of an implementation. + public static IWebHostTest Create(Action serviceSetup = null, Action pipelineSetup = null, Action hostSetup = null, IWebHostFixture hostFixture = null) { - /// - /// Creates and returns an implementation. - /// - /// The which may be configured. - /// The which may be configured. - /// The which may be configured. - /// An optional implementation to use instead of the default instance. - /// An instance of an implementation. - public static IWebHostTest Create(Action serviceSetup = null, Action pipelineSetup = null, Action hostSetup = null, IWebHostFixture hostFixture = null) - { - return new WebHostTest(serviceSetup, pipelineSetup, hostSetup, hostFixture ?? new ManagedWebHostFixture()); - } + return new WebHostTest(serviceSetup, pipelineSetup, hostSetup, hostFixture ?? new ManagedWebHostFixture()); + } - /// - /// Creates and returns an implementation. - /// - /// The which may be configured. - /// The which may be configured. - /// The which may be configured. - /// An optional implementation to use instead of the default instance. - /// An instance of an implementation. - public static IWebHostTest CreateWithHostBuilderContext(Action serviceSetup = null, Action pipelineSetup = null, Action hostSetup = null, IWebHostFixture hostFixture = null) - { - return new WebHostTest(serviceSetup, pipelineSetup, hostSetup, hostFixture ?? new ManagedWebHostFixture()); - } + /// + /// Creates and returns an implementation. + /// + /// The which may be configured. + /// The which may be configured. + /// The which may be configured. + /// An optional implementation to use instead of the default instance. + /// An instance of an implementation. + public static IWebHostTest CreateWithHostBuilderContext(Action serviceSetup = null, Action pipelineSetup = null, Action hostSetup = null, IWebHostFixture hostFixture = null) + { + return new WebHostTest(serviceSetup, pipelineSetup, hostSetup, hostFixture ?? new ManagedWebHostFixture()); + } - /// - /// Runs a middleware and returns an for making HTTP requests to the test server. - /// - /// The which may be configured. - /// The which may be configured. - /// The which may be configured. - /// The function delegate that creates a from the . Default is a GET request to the root URL ("/"). - /// An optional implementation to use instead of the default instance. - /// A that represents the asynchronous operation. The task result contains the for the test server. - public static async Task RunAsync(Action serviceSetup = null, Action pipelineSetup = null, Action hostSetup = null, Func> responseFactory = null, IWebHostFixture hostFixture = null) - { - using var client = Create(serviceSetup, pipelineSetup, hostSetup, hostFixture).Host.GetTestClient(); - return await client.ToHttpResponseMessageAsync(responseFactory).ConfigureAwait(false); - } + /// + /// Runs a middleware and returns an for making HTTP requests to the test server. + /// + /// The which may be configured. + /// The which may be configured. + /// The which may be configured. + /// The function delegate that creates a from the . Default is a GET request to the root URL ("/"). + /// An optional implementation to use instead of the default instance. + /// A that represents the asynchronous operation. The task result contains the for the test server. + public static async Task RunAsync(Action serviceSetup = null, Action pipelineSetup = null, Action hostSetup = null, Func> responseFactory = null, IWebHostFixture hostFixture = null) + { + using var client = Create(serviceSetup, pipelineSetup, hostSetup, hostFixture).Host.GetTestClient(); + return await client.ToHttpResponseMessageAsync(responseFactory).ConfigureAwait(false); + } - /// - /// Runs a filter/middleware test. - /// - /// The which may be configured. - /// The which may be configured. - /// The which may be configured. - /// The function delegate that creates a from the . Default is a GET request to the root URL ("/"). - /// An optional implementation to use instead of the default instance. - /// A that represents the asynchronous operation. The task result contains the for the test server. - public static async Task RunWithHostBuilderContextAsync(Action serviceSetup = null, Action pipelineSetup = null, Action hostSetup = null, Func> responseFactory = null, IWebHostFixture hostFixture = null) - { - using var client = CreateWithHostBuilderContext(serviceSetup, pipelineSetup, hostSetup, hostFixture).Host.GetTestClient(); - return await client.ToHttpResponseMessageAsync(responseFactory).ConfigureAwait(false); - } + /// + /// Runs a filter/middleware test. + /// + /// The which may be configured. + /// The which may be configured. + /// The which may be configured. + /// The function delegate that creates a from the . Default is a GET request to the root URL ("/"). + /// An optional implementation to use instead of the default instance. + /// A that represents the asynchronous operation. The task result contains the for the test server. + public static async Task RunWithHostBuilderContextAsync(Action serviceSetup = null, Action pipelineSetup = null, Action hostSetup = null, Func> responseFactory = null, IWebHostFixture hostFixture = null) + { + using var client = CreateWithHostBuilderContext(serviceSetup, pipelineSetup, hostSetup, hostFixture).Host.GetTestClient(); + return await client.ToHttpResponseMessageAsync(responseFactory).ConfigureAwait(false); } } diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/WebMinimalHostFixtureExtensions.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/WebMinimalHostFixtureExtensions.cs index ce03641..de3562f 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/WebMinimalHostFixtureExtensions.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/WebMinimalHostFixtureExtensions.cs @@ -1,24 +1,23 @@ -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +/// +/// Extension methods for the interface. +/// +public static class WebMinimalHostFixtureExtensions { /// - /// Extension methods for the interface. + /// Determines whether the specified has a valid state. /// - public static class WebMinimalHostFixtureExtensions + /// The to check. + /// true if the specified has a valid state; otherwise, false. + /// + /// A valid state is defined as having non-null values for the following properties: + /// , , + /// , and . + /// + public static bool HasValidState(this IWebMinimalHostFixture hostFixture) { - /// - /// Determines whether the specified has a valid state. - /// - /// The to check. - /// true if the specified has a valid state; otherwise, false. - /// - /// A valid state is defined as having non-null values for the following properties: - /// , , - /// , and . - /// - public static bool HasValidState(this IWebMinimalHostFixture hostFixture) - { - var hasValidState = ((IMinimalHostFixture)hostFixture).HasValidState(); - return hasValidState && hostFixture.ConfigureApplicationCallback != null && hostFixture.Application != null; - } + var hasValidState = ((IMinimalHostFixture)hostFixture).HasValidState(); + return hasValidState && hostFixture.ConfigureApplicationCallback != null && hostFixture.Application != null; } } From 535ac9974d6d16387d486c6302daac96d25b8397 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Thu, 21 May 2026 23:29:45 +0200 Subject: [PATCH 11/16] =?UTF-8?q?=F0=9F=8E=A8=20refactor=20tooling=20and?= =?UTF-8?q?=20benchmark=20projects=20to=20file-scoped=20namespaces?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Converted benchmark-runner Program.cs and both benchmark classes (DelimitedStringBenchmark, TestBenchmark) from block-scoped to file-scoped namespace declarations. Pure structural change — no behavior modifications. --- tooling/benchmark-runner/Program.cs | 31 +++-- .../DelimitedStringBenchmark.cs | 83 ++++++------- .../TestBenchmark.cs | 117 +++++++++--------- 3 files changed, 114 insertions(+), 117 deletions(-) diff --git a/tooling/benchmark-runner/Program.cs b/tooling/benchmark-runner/Program.cs index 0b884c9..9f8e908 100644 --- a/tooling/benchmark-runner/Program.cs +++ b/tooling/benchmark-runner/Program.cs @@ -1,28 +1,27 @@ -using Codebelt.Extensions.BenchmarkDotNet; +using Codebelt.Extensions.BenchmarkDotNet; using Codebelt.Extensions.BenchmarkDotNet.Console; using BenchmarkDotNet.Configs; using BenchmarkDotNet.Environments; using BenchmarkDotNet.Jobs; -namespace benchmark_runner +namespace benchmark_runner; + +public static class Program { - public class Program + public static void Main(string[] args) { - public static void Main(string[] args) + BenchmarkProgram.Run(args, o => { - BenchmarkProgram.Run(args, o => + o.AllowDebugBuild = BenchmarkProgram.IsDebugBuild; + o.SkipBenchmarksWithReports = true; + o.ConfigureBenchmarkDotNet(c => { - o.AllowDebugBuild = BenchmarkProgram.IsDebugBuild; - o.SkipBenchmarksWithReports = true; - o.ConfigureBenchmarkDotNet(c => - { - var slimJob = BenchmarkWorkspaceOptions.Slim; - return c - .AddJob(slimJob.WithRuntime(ClrRuntime.Net48)) - .AddJob(slimJob.WithRuntime(CoreRuntime.Core90)) - .AddJob(slimJob.WithRuntime(CoreRuntime.Core10_0)); - }); + var slimJob = BenchmarkWorkspaceOptions.Slim; + return c + .AddJob(slimJob.WithRuntime(ClrRuntime.Net48)) + .AddJob(slimJob.WithRuntime(CoreRuntime.Core90)) + .AddJob(slimJob.WithRuntime(CoreRuntime.Core10_0)); }); - } + }); } } diff --git a/tuning/Codebelt.Extensions.Xunit.Benchmarks/DelimitedStringBenchmark.cs b/tuning/Codebelt.Extensions.Xunit.Benchmarks/DelimitedStringBenchmark.cs index 945733b..49dbd51 100644 --- a/tuning/Codebelt.Extensions.Xunit.Benchmarks/DelimitedStringBenchmark.cs +++ b/tuning/Codebelt.Extensions.Xunit.Benchmarks/DelimitedStringBenchmark.cs @@ -3,62 +3,61 @@ using BenchmarkDotNet.Configs; using Xunit; -namespace Codebelt.Extensions.Xunit +namespace Codebelt.Extensions.Xunit; + +[MemoryDiagnoser] +[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)] +public class DelimitedStringBenchmark { - [MemoryDiagnoser] - [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)] - public class DelimitedStringBenchmark + [Params(8, 256, 4096)] + public int Count { get; set; } + + private string[] _strings; + private int[] _ints; + private ITestOutputHelper _helper; + + [GlobalSetup] + public void Setup() { - [Params(8, 256, 4096)] - public int Count { get; set; } + _strings = Enumerable.Range(0, Count).Select(i => $"item-{i}").ToArray(); + _ints = Enumerable.Range(0, Count).ToArray(); + _helper = new DummyTestOutputHelper(); + } - private string[] _strings; - private int[] _ints; - private ITestOutputHelper _helper; + [Benchmark(Baseline = true, Description = "Create from string sequence via WriteLines")] + public void Create_String_WriteLines() + { + TestOutputHelperExtensions.WriteLines(_helper, _strings); + } - [GlobalSetup] - public void Setup() + [Benchmark(Description = "Create from int sequence via WriteLines")] + public void Create_Int_WriteLines() + { + TestOutputHelperExtensions.WriteLines(_helper, _ints); + } + + private sealed class DummyTestOutputHelper : ITestOutputHelper + { + public void WriteLine(string message) { - _strings = Enumerable.Range(0, Count).Select(i => $"item-{i}").ToArray(); - _ints = Enumerable.Range(0, Count).ToArray(); - _helper = new DummyTestOutputHelper(); + // no-op; avoid I/O during benchmark } - [Benchmark(Baseline = true, Description = "Create from string sequence via WriteLines")] - public void Create_String_WriteLines() + public void WriteLine(string format, params object[] args) { - TestOutputHelperExtensions.WriteLines(_helper, _strings); + // no-op; avoid I/O during benchmark } - [Benchmark(Description = "Create from int sequence via WriteLines")] - public void Create_Int_WriteLines() + public void Write(string message) { - TestOutputHelperExtensions.WriteLines(_helper, _ints); + // no-op; avoid I/O during benchmark } - private sealed class DummyTestOutputHelper : ITestOutputHelper + public void Write(string format, params object[] args) { - public void WriteLine(string message) - { - // no-op; avoid I/O during benchmark - } - - public void WriteLine(string format, params object[] args) - { - // no-op; avoid I/O during benchmark - } - - public void Write(string message) - { - // no-op; avoid I/O during benchmark - } - - public void Write(string format, params object[] args) - { - // no-op; avoid I/O during benchmark - } - - public string Output => string.Empty; + // no-op; avoid I/O during benchmark } + + public string Output => string.Empty; } } diff --git a/tuning/Codebelt.Extensions.Xunit.Benchmarks/TestBenchmark.cs b/tuning/Codebelt.Extensions.Xunit.Benchmarks/TestBenchmark.cs index 5edd2a3..aeec4a1 100644 --- a/tuning/Codebelt.Extensions.Xunit.Benchmarks/TestBenchmark.cs +++ b/tuning/Codebelt.Extensions.Xunit.Benchmarks/TestBenchmark.cs @@ -2,74 +2,73 @@ using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Configs; -namespace Codebelt.Extensions.Xunit -{ - /// - /// Benchmarks for the method. - /// - [MemoryDiagnoser] - [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)] - public class TestBenchmark - { - [Params(8, 256, 4096)] - public int Length { get; set; } - - private string _shortPattern; - private string _shortActual; - private string _wildcardPattern; - private string _wildcardActual; - private string _multilinePattern; - private string _multilineActual; - private string _complexWildcardPattern; - private string _complexWildcardActual; +namespace Codebelt.Extensions.Xunit; - [GlobalSetup] - public void Setup() - { - // Simple exact match - baseline - _shortPattern = "test-string"; - _shortActual = "test-string"; +/// +/// Benchmarks for the method. +/// +[MemoryDiagnoser] +[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)] +public class TestBenchmark +{ + [Params(8, 256, 4096)] + public int Length { get; set; } - // Simple wildcard match - _wildcardPattern = "test-*"; - _wildcardActual = "test-string"; + private string _shortPattern; + private string _shortActual; + private string _wildcardPattern; + private string _wildcardActual; + private string _multilinePattern; + private string _multilineActual; + private string _complexWildcardPattern; + private string _complexWildcardActual; - // Multiline pattern matching - var lines = new string[Length / 10]; - for (int i = 0; i < lines.Length; i++) - { - lines[i] = $"Line {i}: Some content here"; - } - _multilinePattern = string.Join(Environment.NewLine, lines); - _multilineActual = string.Join(Environment.NewLine, lines); + [GlobalSetup] + public void Setup() + { + // Simple exact match - baseline + _shortPattern = "test-string"; + _shortActual = "test-string"; - // Complex wildcard with multiple wildcards - _complexWildcardPattern = "prefix-*-middle-?-suffix"; - _complexWildcardActual = "prefix-some-long-text-middle-X-suffix"; - } + // Simple wildcard match + _wildcardPattern = "test-*"; + _wildcardActual = "test-string"; - [Benchmark(Baseline = true, Description = "Match - exact string")] - public bool Match_Exact() + // Multiline pattern matching + var lines = new string[Length / 10]; + for (int i = 0; i < lines.Length; i++) { - return Test.Match(_shortPattern, _shortActual); + lines[i] = $"Line {i}: Some content here"; } + _multilinePattern = string.Join(Environment.NewLine, lines); + _multilineActual = string.Join(Environment.NewLine, lines); - [Benchmark(Description = "Match - simple wildcard")] - public bool Match_SimpleWildcard() - { - return Test.Match(_wildcardPattern, _wildcardActual); - } + // Complex wildcard with multiple wildcards + _complexWildcardPattern = "prefix-*-middle-?-suffix"; + _complexWildcardActual = "prefix-some-long-text-middle-X-suffix"; + } - [Benchmark(Description = "Match - multiline")] - public bool Match_Multiline() - { - return Test.Match(_multilinePattern, _multilineActual); - } + [Benchmark(Baseline = true, Description = "Match - exact string")] + public bool Match_Exact() + { + return Test.Match(_shortPattern, _shortActual); + } - [Benchmark(Description = "Match - complex wildcard")] - public bool Match_ComplexWildcard() - { - return Test.Match(_complexWildcardPattern, _complexWildcardActual); - } + [Benchmark(Description = "Match - simple wildcard")] + public bool Match_SimpleWildcard() + { + return Test.Match(_wildcardPattern, _wildcardActual); + } + + [Benchmark(Description = "Match - multiline")] + public bool Match_Multiline() + { + return Test.Match(_multilinePattern, _multilineActual); + } + + [Benchmark(Description = "Match - complex wildcard")] + public bool Match_ComplexWildcard() + { + return Test.Match(_complexWildcardPattern, _complexWildcardActual); } } From ad36b857278a0863a5307e4559045d1508ac072b Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Thu, 21 May 2026 23:29:51 +0200 Subject: [PATCH 12/16] =?UTF-8?q?=F0=9F=93=9D=20mandate=20file-scoped=20na?= =?UTF-8?q?mespaces=20in=20developer=20instructions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated copilot-instructions.md and AGENTS.md to reflect that the entire codebase has been refactored to file-scoped namespaces. All code examples updated to file-scoped syntax; AGENTS.md wording changed from 'Prefer' to 'Always use' and notes that block-scoped namespaces must never be used. --- .github/copilot-instructions.md | 45 +++++++++++++++------------------ AGENTS.md | 5 ++-- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index c646bce..2e6351e 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -17,16 +17,15 @@ This ensures consistent setup, teardown, and output handling across all tests. using Codebelt.Extensions.Xunit; using Xunit; -namespace Your.Namespace +namespace Your.Namespace; + +public class YourTestClass : Test { - public class YourTestClass : Test + public YourTestClass(ITestOutputHelper output) : base(output) { - public YourTestClass(ITestOutputHelper output) : base(output) - { - } - - // Your tests here } + + // Your tests here } ``` @@ -47,21 +46,20 @@ namespace Your.Namespace ## 5. File and Namespace Organization +- **Always use file-scoped namespaces** (`namespace YourProject.Foo.Bar;`) — the entire codebase has been refactored to file-scoped namespaces. Never use block-scoped namespaces. - Place test files in the appropriate test project and folder structure. - Use namespaces that mirror the source code structure. The namespace of a test file MUST match the namespace of the System Under Test (SUT). Do NOT append ".Tests", ".Benchmarks" or similar suffixes to the namespace. Only the assembly/project name should indicate that the file is a test/benchmark (for example: YourProject.Foo.Tests assembly, but namespace YourProject.Foo). - Example: If the SUT class is declared as: ```csharp - namespace YourProject.Foo.Bar - { - public class Zoo { /* ... */ } - } + namespace YourProject.Foo.Bar; + + public class Zoo { /* ... */ } ``` then the corresponding unit test class must use the exact same namespace: ```csharp - namespace YourProject.Foo.Bar - { - public class ZooTest : Test { /* ... */ } - } + namespace YourProject.Foo.Bar; + + public class ZooTest : Test { /* ... */ } ``` - Do NOT use: ```csharp @@ -91,16 +89,16 @@ using System.Globalization; using Codebelt.Extensions.Xunit; using Xunit; -namespace YourProject +namespace YourProject; + +/// +/// Tests for the class. +/// +public class DateSpanTest : Test { - /// - /// Tests for the class. - /// - public class DateSpanTest : Test + public DateSpanTest(ITestOutputHelper output) : base(output) { - public DateSpanTest(ITestOutputHelper output) : base(output) - { - } + } [Fact] public void Parse_ShouldGetOneMonthOfDifference_UsingIso8601String() @@ -132,7 +130,6 @@ namespace YourProject TestOutput.WriteLine(span.ToString()); } - } } ``` diff --git a/AGENTS.md b/AGENTS.md index 5083095..0faab13 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -91,9 +91,8 @@ dotnet test --collect:"XPlat Code Coverage" - Keep existing style in files; many modern analyzers are explicitly disabled. ### Namespace Style -- **Prefer file-scoped namespaces** (`namespace Codebelt.Extensions.Xunit;`) for new files. -- The current majority of the codebase uses **block-scoped namespaces** — do not convert existing files unless explicitly asked. -- When editing an existing file, follow whichever style that file already uses. +- **Always use file-scoped namespaces** (`namespace Codebelt.Extensions.Xunit;`) — the entire codebase has been refactored to file-scoped namespaces. +- **Never use block-scoped namespaces** for new or edited files. - **Never use top-level statements.** Always use explicit class declarations with a proper namespace. ### Disabled Analyzers (key rules — do NOT introduce these patterns) From fb520373427c1263c870bd092e224784953ea806 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Thu, 21 May 2026 23:29:58 +0200 Subject: [PATCH 13/16] =?UTF-8?q?=F0=9F=92=AC=20add=20v11.0.10=20changelog?= =?UTF-8?q?=20entry?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documented codebase modernization patch release: file-scoped namespace refactoring across all three assemblies, new ASP.NET Core hosting fixture test coverage (BlockingManagedWebHostFixture, SelfManagedWebHostFixture, SelfManagedWebMinimalHostFixture, FakeHttpResponseFeature), NGINX base image upgrade, and GitHub repo reference corrections. --- CHANGELOG.md | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5549d44..494ae73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,24 @@ For more details, please refer to `PackageReleaseNotes.txt` on a per assembly ba ## [11.0.10] - 2026-05-21 -This is a service update that focuses on package dependencies. +This is a patch release focused on codebase modernization, enhanced testing coverage, and developer workflow improvements. + +### Changed + +- Refactored entire codebase across all three assemblies to use file-scoped namespaces for consistency with modern C# style conventions, +- Updated developer instructions in `.github/copilot-instructions.md` and `AGENTS.md` to mandate file-scoped namespaces throughout the project, +- Upgraded NGINX base image in documentation build Dockerfile to version 1.31.0-alpine for improved security and stability, +- Normalized whitespace and line endings across dependency configuration and package metadata files for consistency. + +### Added + +- Comprehensive unit tests for ASP.NET Core hosting fixtures including BlockingManagedWebHostFixture, SelfManagedWebHostFixture, SelfManagedWebMinimalHostFixture, HostBuilderApplicationExtensions, and FakeHttpResponseFeature to ensure robust hosting infrastructure, +- Unit test coverage for HTTP response feature mocking and request/response handling. + +### Fixed + +- Updated package README examples to reflect current API usage patterns with ManagedHostFixture and correct service provider access, +- Corrected GitHub repository references in package documentation to point to the codebeltnet organization namespace. ## [11.0.9] - 2026-04-16 @@ -364,3 +381,15 @@ This major release is first and foremost focused on ironing out any wrinkles tha - Added null conditional operator to the ServiceProvider property on the HostFixture class in the Codebelt.Extensions.Xunit.Hosting namespace + +[Unreleased]: https://github.com/codebeltnet/xunit/compare/v11.0.10...HEAD +[11.0.10]: https://github.com/codebeltnet/xunit/compare/v11.0.9...v11.0.10 +[11.0.9]: https://github.com/codebeltnet/xunit/compare/v11.0.8...v11.0.9 +[11.0.8]: https://github.com/codebeltnet/xunit/compare/v11.0.7...v11.0.8 +[11.0.7]: https://github.com/codebeltnet/xunit/compare/v11.0.6...v11.0.7 +[11.0.6]: https://github.com/codebeltnet/xunit/compare/v11.0.5...v11.0.6 +[11.0.5]: https://github.com/codebeltnet/xunit/compare/v11.0.4...v11.0.5 +[11.0.4]: https://github.com/codebeltnet/xunit/compare/v11.0.3...v11.0.4 +[11.0.3]: https://github.com/codebeltnet/xunit/compare/v11.0.2...v11.0.3 +[11.0.2]: https://github.com/codebeltnet/xunit/compare/v11.0.1...v11.0.2 +[11.0.1]: https://github.com/codebeltnet/xunit/compare/v11.0.0...v11.0.1 From 02f6d45bfd0809cd25b08e6fd5a3057d8099d9cf Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Thu, 21 May 2026 23:52:45 +0200 Subject: [PATCH 14/16] =?UTF-8?q?=F0=9F=8E=A8=20enforce=20file-scoped=20na?= =?UTF-8?q?mespaces=20in=20test=20projects?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert all test files from block-scoped to file-scoped namespaces for consistency with modern .NET coding standards and to match production code conventions. This improves readability and aligns with the project's stated namespace guidelines in AGENTS.md and copilot-instructions.md. --- .../Assets/BoolMiddleware.cs | 55 +- .../Assets/BoolOptions.cs | 21 +- .../Assets/FakeController.cs | 25 +- .../Assets/InvalidHostTest.cs | 11 +- .../Assets/ScopedCorrelation.cs | 9 +- .../Assets/SingletonCorrelation.cs | 9 +- .../Assets/TransientCorrelation.cs | 11 +- .../Assets/ValidHostTest.cs | 27 +- .../BlockingManagedWebHostFixtureTest.cs | 21 +- .../HostBuilderApplicationExtensionsTest.cs | 35 +- .../Features/FakeHttpResponseFeatureTest.cs | 63 +- .../ManagedWebHostFixtureTest.cs | 127 ++-- .../MinimalMvcWebHostTestTest.cs | 89 ++- .../MinimalWebHostTestFactoryTest.cs | 203 +++--- .../MinimalWebHostTestTest.cs | 243 ++++---- .../MvcWebHostTestTest.cs | 89 ++- .../SelfManagedWebHostFixtureTest.cs | 21 +- .../SelfManagedWebMinimalHostFixtureTest.cs | 27 +- .../ServiceCollectionExtensionsTest.cs | 61 +- .../WebHostTestFactoryTest.cs | 265 ++++---- .../WebHostTestTest.cs | 241 ++++--- .../Assets/InvalidHostTest.cs | 11 +- .../Assets/MinimalValidHostTest.cs | 11 +- .../Assets/ScopedCorrelation.cs | 9 +- .../Assets/SingletonCorrelation.cs | 9 +- .../Assets/TransientCorrelation.cs | 11 +- .../Assets/ValidHostTest.cs | 19 +- .../HostTestFactoryTest.cs | 73 ++- .../HostTestTest.cs | 179 +++--- .../ManagedHostFixtureTest.cs | 119 ++-- .../MinimalHostFixtureTest.cs | 113 ++-- .../MinimalHostTestFactoryTest.cs | 69 +- .../MinimalHostTestTest.cs | 151 +++-- .../ServiceCollectionExtensions.cs | 281 +++++---- .../Assets/AsyncDisposable.cs | 47 +- .../Assets/ManagedDisposable.cs | 33 +- .../Assets/UnmanagedDisposable.cs | 177 +++--- .../Assets/WemoryStream.cs | 23 +- .../DisposableTest.cs | 133 ++-- .../InMemoryTestStoreTest.cs | 587 +++++++++--------- .../StringExtensionsTest.cs | 47 +- .../TestOutputHelperExtensionsTest.cs | 361 ++++++----- .../TestTest.cs | 531 ++++++++-------- 43 files changed, 2302 insertions(+), 2345 deletions(-) diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/BoolMiddleware.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/BoolMiddleware.cs index 69320d1..f70ead9 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/BoolMiddleware.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/BoolMiddleware.cs @@ -4,37 +4,36 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets; + +public class BoolMiddleware : ConfigurableMiddleware { - public class BoolMiddleware : ConfigurableMiddleware + /// + /// Initializes a new instance of the class. + /// + /// The delegate of the request pipeline to invoke. + /// The which need to be configured. + public BoolMiddleware(RequestDelegate next, IOptions setup) : base(next, setup) { - /// - /// Initializes a new instance of the class. - /// - /// The delegate of the request pipeline to invoke. - /// The which need to be configured. - public BoolMiddleware(RequestDelegate next, IOptions setup) : base(next, setup) - { - } + } - /// - /// Initializes a new instance of the class. - /// - /// The delegate of the request pipeline to invoke. - /// The which need to be configured. - public BoolMiddleware(RequestDelegate next, Action setup) : base(next, setup) - { - } + /// + /// Initializes a new instance of the class. + /// + /// The delegate of the request pipeline to invoke. + /// The which need to be configured. + public BoolMiddleware(RequestDelegate next, Action setup) : base(next, setup) + { + } - /// - /// Executes the . - /// - /// The context of the current request. - /// A task that represents the execution of this middleware. - public override async Task InvokeAsync(HttpContext context) - { - await context.Response.WriteAsync($"A:{Options.A}, B:{Options.B}, C:{Options.C}, D:{Options.D}, E:{Options.E}, F:{Options.F}"); - await Next(context); - } + /// + /// Executes the . + /// + /// The context of the current request. + /// A task that represents the execution of this middleware. + public override async Task InvokeAsync(HttpContext context) + { + await context.Response.WriteAsync($"A:{Options.A}, B:{Options.B}, C:{Options.C}, D:{Options.D}, E:{Options.E}, F:{Options.F}"); + await Next(context); } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/BoolOptions.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/BoolOptions.cs index da478cb..10bb47c 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/BoolOptions.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/BoolOptions.cs @@ -1,19 +1,18 @@ -using Cuemon.Configuration; +using Cuemon.Configuration; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets; + +public class BoolOptions : IParameterObject { - public class BoolOptions : IParameterObject - { - public bool A { get; set; } + public bool A { get; set; } - public bool B { get; set; } + public bool B { get; set; } - public bool C { get; set; } + public bool C { get; set; } - public bool D { get; set; } + public bool D { get; set; } - public bool E { get; set; } + public bool E { get; set; } - public bool F { get; set; } - } + public bool F { get; set; } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/FakeController.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/FakeController.cs index e27552b..01980c9 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/FakeController.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/FakeController.cs @@ -1,19 +1,18 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets; + +[ApiController] +[Route("[controller]")] +public class FakeController : ControllerBase { - [ApiController] - [Route("[controller]")] - public class FakeController : ControllerBase + public FakeController() { - public FakeController() - { - } + } - [HttpGet] - public IActionResult Get() - { - return Ok("Unit Test"); - } + [HttpGet] + public IActionResult Get() + { + return Ok("Unit Test"); } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/InvalidHostTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/InvalidHostTest.cs index 6b98e35..7d1defb 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/InvalidHostTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/InvalidHostTest.cs @@ -1,11 +1,10 @@ -using Xunit; +using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets; + +public class InvalidHostTest : Test, IClassFixture where T : class, IGenericHostFixture { - public class InvalidHostTest : Test, IClassFixture where T : class, IGenericHostFixture + public InvalidHostTest(T hostFixture) { - public InvalidHostTest(T hostFixture) - { - } } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/ScopedCorrelation.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/ScopedCorrelation.cs index fca7bea..8448c64 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/ScopedCorrelation.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/ScopedCorrelation.cs @@ -1,8 +1,7 @@ -using Cuemon.Messaging; +using Cuemon.Messaging; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets; + +public sealed record ScopedCorrelation : CorrelationToken { - public sealed record ScopedCorrelation : CorrelationToken - { - } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/SingletonCorrelation.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/SingletonCorrelation.cs index 91c264f..71243ab 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/SingletonCorrelation.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/SingletonCorrelation.cs @@ -1,8 +1,7 @@ -using Cuemon.Messaging; +using Cuemon.Messaging; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets; + +public sealed record SingletonCorrelation : CorrelationToken { - public sealed record SingletonCorrelation : CorrelationToken - { - } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/TransientCorrelation.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/TransientCorrelation.cs index 1656baa..3c4b0fb 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/TransientCorrelation.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/TransientCorrelation.cs @@ -1,8 +1,7 @@ -using Cuemon.Messaging; +using Cuemon.Messaging; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets; + +public sealed record TransientCorrelation : CorrelationToken { - public sealed record TransientCorrelation : CorrelationToken - { - } -} \ No newline at end of file +} diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/ValidHostTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/ValidHostTest.cs index 548c5eb..68018cf 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/ValidHostTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Assets/ValidHostTest.cs @@ -1,22 +1,21 @@ -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets; + +public class ValidHostTest : WebHostTest { - public class ValidHostTest : WebHostTest + public ValidHostTest(ManagedWebHostFixture hostFixture) : base(hostFixture) { - public ValidHostTest(ManagedWebHostFixture hostFixture) : base(hostFixture) - { - } + } - public override void ConfigureServices(IServiceCollection services) - { - - } + public override void ConfigureServices(IServiceCollection services) + { + + } - public override void ConfigureApplication(IApplicationBuilder app) - { - - } + public override void ConfigureApplication(IApplicationBuilder app) + { + } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/BlockingManagedWebHostFixtureTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/BlockingManagedWebHostFixtureTest.cs index 48d0dc7..0b95263 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/BlockingManagedWebHostFixtureTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/BlockingManagedWebHostFixtureTest.cs @@ -1,19 +1,18 @@ using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +public class BlockingManagedWebHostFixtureTest : Test { - public class BlockingManagedWebHostFixtureTest : Test + public BlockingManagedWebHostFixtureTest(ITestOutputHelper output) : base(output) { - public BlockingManagedWebHostFixtureTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public void Create_ShouldSucceed_WhenBlockingManagedWebHostFixtureIsUsed() - { - using var startup = WebHostTestFactory.Create(hostFixture: new BlockingManagedWebHostFixture()); + [Fact] + public void Create_ShouldSucceed_WhenBlockingManagedWebHostFixtureIsUsed() + { + using var startup = WebHostTestFactory.Create(hostFixture: new BlockingManagedWebHostFixture()); - Assert.NotNull(startup.Host); - } + Assert.NotNull(startup.Host); } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/HostBuilderApplicationExtensionsTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/HostBuilderApplicationExtensionsTest.cs index 1f90b4a..125a5ba 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/HostBuilderApplicationExtensionsTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/HostBuilderApplicationExtensionsTest.cs @@ -3,30 +3,29 @@ using Microsoft.Extensions.Hosting; using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +public class HostBuilderApplicationExtensionsTest : Test { - public class HostBuilderApplicationExtensionsTest : Test + public HostBuilderApplicationExtensionsTest(ITestOutputHelper output) : base(output) { - public HostBuilderApplicationExtensionsTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public void ToHostBuilder_ShouldReturnHostBuilder_WhenWebApplicationBuilderIsProvided() - { - IHostApplicationBuilder builder = WebApplication.CreateBuilder(); + [Fact] + public void ToHostBuilder_ShouldReturnHostBuilder_WhenWebApplicationBuilderIsProvided() + { + IHostApplicationBuilder builder = WebApplication.CreateBuilder(); - var hostBuilder = builder.ToHostBuilder(); + var hostBuilder = builder.ToHostBuilder(); - Assert.NotNull(hostBuilder); - } + Assert.NotNull(hostBuilder); + } - [Fact] - public void ToHostBuilder_ShouldThrowArgumentException_WhenNotWebApplicationBuilder() - { - IHostApplicationBuilder builder = Host.CreateApplicationBuilder(); + [Fact] + public void ToHostBuilder_ShouldThrowArgumentException_WhenNotWebApplicationBuilder() + { + IHostApplicationBuilder builder = Host.CreateApplicationBuilder(); - Assert.Throws(() => builder.ToHostBuilder()); - } + Assert.Throws(() => builder.ToHostBuilder()); } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Http/Features/FakeHttpResponseFeatureTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Http/Features/FakeHttpResponseFeatureTest.cs index 4da6593..3aed258 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Http/Features/FakeHttpResponseFeatureTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Http/Features/FakeHttpResponseFeatureTest.cs @@ -2,48 +2,47 @@ using Codebelt.Extensions.Xunit.Hosting.AspNetCore.Http.Features; using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Http.Features +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore.Http.Features; + +public class FakeHttpResponseFeatureTest : Test { - public class FakeHttpResponseFeatureTest : Test + public FakeHttpResponseFeatureTest(ITestOutputHelper output) : base(output) { - public FakeHttpResponseFeatureTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public void OnStarting_ShouldInvokeCallback_OnFirstCall() - { - var feature = new FakeHttpResponseFeature(); - var invoked = false; + [Fact] + public void OnStarting_ShouldInvokeCallback_OnFirstCall() + { + var feature = new FakeHttpResponseFeature(); + var invoked = false; - feature.OnStarting(_ => { invoked = true; return Task.CompletedTask; }, null); + feature.OnStarting(_ => { invoked = true; return Task.CompletedTask; }, null); - Assert.True(invoked); - Assert.True(feature.HasStarted); - } + Assert.True(invoked); + Assert.True(feature.HasStarted); + } - [Fact] - public void OnStarting_ShouldNotInvokeCallback_OnSubsequentCalls() - { - var feature = new FakeHttpResponseFeature(); - var count = 0; + [Fact] + public void OnStarting_ShouldNotInvokeCallback_OnSubsequentCalls() + { + var feature = new FakeHttpResponseFeature(); + var count = 0; - feature.OnStarting(_ => { count++; return Task.CompletedTask; }, null); - feature.OnStarting(_ => { count++; return Task.CompletedTask; }, null); + feature.OnStarting(_ => { count++; return Task.CompletedTask; }, null); + feature.OnStarting(_ => { count++; return Task.CompletedTask; }, null); - Assert.Equal(1, count); - Assert.True(feature.HasStarted); - } + Assert.Equal(1, count); + Assert.True(feature.HasStarted); + } - [Fact] - public void OnStarting_ShouldNotThrow_WhenCallbackIsNull() - { - var feature = new FakeHttpResponseFeature(); + [Fact] + public void OnStarting_ShouldNotThrow_WhenCallbackIsNull() + { + var feature = new FakeHttpResponseFeature(); - var ex = Record.Exception(() => feature.OnStarting(null, null)); + var ex = Record.Exception(() => feature.OnStarting(null, null)); - Assert.Null(ex); - Assert.True(feature.HasStarted); - } + Assert.Null(ex); + Assert.True(feature.HasStarted); } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/ManagedWebHostFixtureTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/ManagedWebHostFixtureTest.cs index 1a097f0..75129a6 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/ManagedWebHostFixtureTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/ManagedWebHostFixtureTest.cs @@ -1,64 +1,63 @@ -using System; -using Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets; -using Microsoft.AspNetCore.Builder; -using Xunit; - -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore -{ - public class ManagedWebHostFixtureTest : Test - { - public ManagedWebHostFixtureTest(ITestOutputHelper output) : base(output) - { - } - - [Fact] - public void ConfigureHost_NullHostTest_ThrowsArgumentNullException() - { - // Arrange - var fixture = new ManagedWebHostFixture(); - - // Act & Assert - Assert.Throws(() => fixture.ConfigureHost(null)); - } - - [Fact] - public void ConfigureHost_InvalidHostTestType_ThrowsArgumentOutOfRangeException() - { - // Arrange - var fixture = new ManagedWebHostFixture(); - var invalidHostTest = new InvalidHostTest(fixture); - - // Act & Assert - Assert.Throws(() => fixture.ConfigureHost(invalidHostTest)); - } - - [Fact] - public void ConfigureApplicationCallback_SetAndGet_ReturnsCorrectValue() - { - // Arrange - var fixture = new ManagedWebHostFixture(); - Action callback = app => { }; - - // Act - fixture.ConfigureApplicationCallback = callback; - - // Assert - Assert.Equal(callback, fixture.ConfigureApplicationCallback); - } - - [Fact] - public void ConfigureHost_ValidHostTest_ConfiguresHostCorrectly() - { - // Arrange - var fixture = new ManagedWebHostFixture(); - var hostTest = new ValidHostTest(fixture); - - // Act - fixture.ConfigureHost(hostTest); - - // Assert - Assert.NotNull(fixture.Host); - Assert.NotNull(fixture.Application); - } - } -} +using System; +using Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets; +using Microsoft.AspNetCore.Builder; +using Xunit; + +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +public class ManagedWebHostFixtureTest : Test +{ + public ManagedWebHostFixtureTest(ITestOutputHelper output) : base(output) + { + } + + [Fact] + public void ConfigureHost_NullHostTest_ThrowsArgumentNullException() + { + // Arrange + var fixture = new ManagedWebHostFixture(); + + // Act & Assert + Assert.Throws(() => fixture.ConfigureHost(null)); + } + + [Fact] + public void ConfigureHost_InvalidHostTestType_ThrowsArgumentOutOfRangeException() + { + // Arrange + var fixture = new ManagedWebHostFixture(); + var invalidHostTest = new InvalidHostTest(fixture); + + // Act & Assert + Assert.Throws(() => fixture.ConfigureHost(invalidHostTest)); + } + + [Fact] + public void ConfigureApplicationCallback_SetAndGet_ReturnsCorrectValue() + { + // Arrange + var fixture = new ManagedWebHostFixture(); + Action callback = app => { }; + + // Act + fixture.ConfigureApplicationCallback = callback; + + // Assert + Assert.Equal(callback, fixture.ConfigureApplicationCallback); + } + + [Fact] + public void ConfigureHost_ValidHostTest_ConfiguresHostCorrectly() + { + // Arrange + var fixture = new ManagedWebHostFixture(); + var hostTest = new ValidHostTest(fixture); + + // Act + fixture.ConfigureHost(hostTest); + + // Assert + Assert.NotNull(fixture.Host); + Assert.NotNull(fixture.Application); + } +} diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/MinimalMvcWebHostTestTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/MinimalMvcWebHostTestTest.cs index a74192b..8e62b8a 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/MinimalMvcWebHostTestTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/MinimalMvcWebHostTestTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Net.Http; using System.Threading.Tasks; using Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets; @@ -8,51 +8,50 @@ using Microsoft.Extensions.Hosting; using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +public class MinimalMvcWebHostTestTest : MinimalWebHostTest { - public class MinimalMvcWebHostTestTest : MinimalWebHostTest + private readonly ManagedWebMinimalHostFixture _hostFixture; + private readonly HttpClient _client; + + public MinimalMvcWebHostTestTest(ManagedWebMinimalHostFixture hostFixture, ITestOutputHelper output = null, Type callerType = null) : base(hostFixture, output, callerType) + { + hostFixture.Host.Services.GetRequiredService().TestOutput = output; + _hostFixture = hostFixture; + _client = hostFixture.Host.GetTestClient(); + } + + [Fact] + public async Task GetTestAsync() + { + var response = await _client.GetAsync("/Fake"); + response.EnsureSuccessStatusCode(); + var body = await response.Content.ReadAsStringAsync(); + Assert.Equal("Unit Test", body); + } + + [Fact] + public async Task GetTestAsync2() + { + var response = await _client.GetAsync("/Fake"); + response.EnsureSuccessStatusCode(); + var body = await response.Content.ReadAsStringAsync(); + Assert.Equal("Unit Test", body); + } + + protected override void ConfigureHost(IHostApplicationBuilder hb) + { + hb.Services.AddControllers() + .AddApplicationPart(typeof(FakeController).Assembly); + + hb.Services.AddXunitTestLoggingOutputHelperAccessor(); + hb.Services.AddXunitTestLogging(TestOutput); + } + + public override void ConfigureApplication(IApplicationBuilder app) { - private readonly ManagedWebMinimalHostFixture _hostFixture; - private readonly HttpClient _client; - - public MinimalMvcWebHostTestTest(ManagedWebMinimalHostFixture hostFixture, ITestOutputHelper output = null, Type callerType = null) : base(hostFixture, output, callerType) - { - hostFixture.Host.Services.GetRequiredService().TestOutput = output; - _hostFixture = hostFixture; - _client = hostFixture.Host.GetTestClient(); - } - - [Fact] - public async Task GetTestAsync() - { - var response = await _client.GetAsync("/Fake"); - response.EnsureSuccessStatusCode(); - var body = await response.Content.ReadAsStringAsync(); - Assert.Equal("Unit Test", body); - } - - [Fact] - public async Task GetTestAsync2() - { - var response = await _client.GetAsync("/Fake"); - response.EnsureSuccessStatusCode(); - var body = await response.Content.ReadAsStringAsync(); - Assert.Equal("Unit Test", body); - } - - protected override void ConfigureHost(IHostApplicationBuilder hb) - { - hb.Services.AddControllers() - .AddApplicationPart(typeof(FakeController).Assembly); - - hb.Services.AddXunitTestLoggingOutputHelperAccessor(); - hb.Services.AddXunitTestLogging(TestOutput); - } - - public override void ConfigureApplication(IApplicationBuilder app) - { - app.UseRouting(); - app.UseEndpoints(routes => { routes.MapControllers(); }); - } + app.UseRouting(); + app.UseEndpoints(routes => { routes.MapControllers(); }); } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/MinimalWebHostTestFactoryTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/MinimalWebHostTestFactoryTest.cs index 44ed8a3..bca3e60 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/MinimalWebHostTestFactoryTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/MinimalWebHostTestFactoryTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using System.Linq; using System.Security; @@ -12,125 +12,124 @@ using Microsoft.Extensions.DependencyInjection; using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +public class MinimalWebHostTestFactoryTest : Test { - public class MinimalWebHostTestFactoryTest : Test + public MinimalWebHostTestFactoryTest(ITestOutputHelper output) : base(output) { - public MinimalWebHostTestFactoryTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public void Create_ShouldThrowSecurityException_DueToBlockingAspNetCoreHostFixture() - { - Assert.Throws(() => MinimalWebHostTestFactory.Create( - services => - { - services.AddXunitTestLogging(TestOutput); - services.AddAuthorization(o => - { - o.AddPolicy("Test", _ => throw new SecurityException()); - }); - }, - app => + [Fact] + public void Create_ShouldThrowSecurityException_DueToBlockingAspNetCoreHostFixture() + { + Assert.Throws(() => MinimalWebHostTestFactory.Create( + services => + { + services.AddXunitTestLogging(TestOutput); + services.AddAuthorization(o => { - var policy = app.ApplicationServices.GetRequiredService(); - })); - } + o.AddPolicy("Test", _ => throw new SecurityException()); + }); + }, + app => + { + var policy = app.ApplicationServices.GetRequiredService(); + })); + } - [Fact] - public void Create_CallerTypeShouldHaveDeclaringTypeOfMiddlewareTestFactoryTest() - { - Type sut1 = GetType(); - string sut2 = null; - var middleware = MinimalWebHostTestFactory.Create(Assert.NotNull, Assert.NotNull, host => + [Fact] + public void Create_CallerTypeShouldHaveDeclaringTypeOfMiddlewareTestFactoryTest() + { + Type sut1 = GetType(); + string sut2 = null; + var middleware = MinimalWebHostTestFactory.Create(Assert.NotNull, Assert.NotNull, host => + { + var hb = host.ToHostBuilder(); + hb.ConfigureAppConfiguration((context, _) => { - var hb = host.ToHostBuilder(); - hb.ConfigureAppConfiguration((context, _) => - { - sut2 = context.HostingEnvironment.ApplicationName; - }); + sut2 = context.HostingEnvironment.ApplicationName; }); + }); - Assert.True(sut1 == middleware.CallerType.DeclaringType); - Assert.Equal(GetType().Assembly.GetName().Name, sut2); - } + Assert.True(sut1 == middleware.CallerType.DeclaringType); + Assert.Equal(GetType().Assembly.GetName().Name, sut2); + } - [Fact] - public Task RunAsync_ShouldHaveApplicationNameEqualToThisAssembly() - { - return MinimalWebHostTestFactory.RunAsync(Assert.NotNull, Assert.NotNull, host => + [Fact] + public Task RunAsync_ShouldHaveApplicationNameEqualToThisAssembly() + { + return MinimalWebHostTestFactory.RunAsync(Assert.NotNull, Assert.NotNull, host => + { + var hb = host.ToHostBuilder(); + hb.ConfigureAppConfiguration((context, _) => { - var hb = host.ToHostBuilder(); - hb.ConfigureAppConfiguration((context, _) => - { - TestOutput.WriteLine(context.HostingEnvironment.ApplicationName); - Assert.Equal(GetType().Assembly.GetName().Name, context.HostingEnvironment.ApplicationName); - }); + TestOutput.WriteLine(context.HostingEnvironment.ApplicationName); + Assert.Equal(GetType().Assembly.GetName().Name, context.HostingEnvironment.ApplicationName); }); - } + }); + } - [Fact] - public Task RunWithHostBuilderContextAsync_ShouldHaveApplicationNameEqualToThisAssembly_WithHostBuilderContext() - { - return MinimalWebHostTestFactory.RunWithHostBuilderContextAsync((context, app) => - { - Assert.NotNull(context); - Assert.NotNull(context.HostingEnvironment); - Assert.NotNull(context.Configuration); - Assert.NotNull(context.Properties); - Assert.NotNull(app); - }, - (context, services) => - { - Assert.NotNull(context); - Assert.NotNull(context.HostingEnvironment); - Assert.NotNull(context.Configuration); - Assert.NotNull(context.Properties); - Assert.NotNull(services); - }, - host => + [Fact] + public Task RunWithHostBuilderContextAsync_ShouldHaveApplicationNameEqualToThisAssembly_WithHostBuilderContext() + { + return MinimalWebHostTestFactory.RunWithHostBuilderContextAsync((context, app) => + { + Assert.NotNull(context); + Assert.NotNull(context.HostingEnvironment); + Assert.NotNull(context.Configuration); + Assert.NotNull(context.Properties); + Assert.NotNull(app); + }, + (context, services) => + { + Assert.NotNull(context); + Assert.NotNull(context.HostingEnvironment); + Assert.NotNull(context.Configuration); + Assert.NotNull(context.Properties); + Assert.NotNull(services); + }, + host => + { + var hb = host.ToHostBuilder(); + hb.ConfigureAppConfiguration((context, configuration) => { - var hb = host.ToHostBuilder(); - hb.ConfigureAppConfiguration((context, configuration) => - { - TestOutput.WriteLine(context.HostingEnvironment.ApplicationName); - Assert.Equal(GetType().Assembly.GetName().Name, context.HostingEnvironment.ApplicationName); - }); + TestOutput.WriteLine(context.HostingEnvironment.ApplicationName); + Assert.Equal(GetType().Assembly.GetName().Name, context.HostingEnvironment.ApplicationName); }); - } + }); + } - [Fact] - public async Task RunAsync_ShouldWorkWithXunitTestLogging() - { - using var response = await MinimalWebHostTestFactory.RunAsync( - services => - { - services.AddXunitTestLogging(TestOutput); - services.AddServerTiming(o => o.SuppressHeaderPredicate = _ => false); - }, - app => + [Fact] + public async Task RunAsync_ShouldWorkWithXunitTestLogging() + { + using var response = await MinimalWebHostTestFactory.RunAsync( + services => + { + services.AddXunitTestLogging(TestOutput); + services.AddServerTiming(o => o.SuppressHeaderPredicate = _ => false); + }, + app => + { + app.UseServerTiming(); + app.Use(async (context, next) => { - app.UseServerTiming(); - app.Use(async (context, next) => - { - var sw = Stopwatch.StartNew(); - context.Response.OnStarting(() => - { - sw.Stop(); - context.RequestServices.GetRequiredService().AddServerTiming("use-middleware", sw.Elapsed); - return Task.CompletedTask; - }); - await next(context).ConfigureAwait(false); - }); - app.Run(context => + var sw = Stopwatch.StartNew(); + context.Response.OnStarting(() => { - Thread.Sleep(400); - return context.Response.WriteAsync("Hello World!"); + sw.Stop(); + context.RequestServices.GetRequiredService().AddServerTiming("use-middleware", sw.Elapsed); + return Task.CompletedTask; }); - }).ConfigureAwait(false); + await next(context).ConfigureAwait(false); + }); + app.Run(context => + { + Thread.Sleep(400); + return context.Response.WriteAsync("Hello World!"); + }); + }).ConfigureAwait(false); - Assert.StartsWith("use-middleware;dur=", response.Headers.Single(kvp => kvp.Key == ServerTiming.HeaderName).Value.FirstOrDefault()); - } + Assert.StartsWith("use-middleware;dur=", response.Headers.Single(kvp => kvp.Key == ServerTiming.HeaderName).Value.FirstOrDefault()); } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/MinimalWebHostTestTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/MinimalWebHostTestTest.cs index cb2b0b9..7a15b44 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/MinimalWebHostTestTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/MinimalWebHostTestTest.cs @@ -12,154 +12,153 @@ using Microsoft.Extensions.Options; using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +public class MinimalWebHostTestTest : MinimalWebHostTest { - public class MinimalWebHostTestTest : MinimalWebHostTest - { - private readonly IServiceProvider _provider; - private readonly IApplicationBuilder _pipeline; + private readonly IServiceProvider _provider; + private readonly IApplicationBuilder _pipeline; - public MinimalWebHostTestTest(ManagedWebMinimalHostFixture hostFixture, ITestOutputHelper output) : base(hostFixture, output) - { - _pipeline = hostFixture.Application; - _provider = hostFixture.Host.Services; - _provider.GetRequiredService().TestOutput = output; - } + public MinimalWebHostTestTest(ManagedWebMinimalHostFixture hostFixture, ITestOutputHelper output) : base(hostFixture, output) + { + _pipeline = hostFixture.Application; + _provider = hostFixture.Host.Services; + _provider.GetRequiredService().TestOutput = output; + } - [Fact] - public async Task ShouldHaveResultOfBoolMiddlewareInBody() - { - var context = _provider.GetRequiredService().HttpContext; - var options = _provider.GetRequiredService>(); - var pipeline = _pipeline.Build(); + [Fact] + public async Task ShouldHaveResultOfBoolMiddlewareInBody() + { + var context = _provider.GetRequiredService().HttpContext; + var options = _provider.GetRequiredService>(); + var pipeline = _pipeline.Build(); - Assert.Equal("Hello awesome developers!", context!.Response.Body.ToEncodedString(o => o.LeaveOpen = true)); + Assert.Equal("Hello awesome developers!", context!.Response.Body.ToEncodedString(o => o.LeaveOpen = true)); - var logger = _pipeline.ApplicationServices.GetRequiredService>(); - logger.LogInformation("Hello from {0}", nameof(ShouldHaveResultOfBoolMiddlewareInBody)); + var logger = _pipeline.ApplicationServices.GetRequiredService>(); + logger.LogInformation("Hello from {0}", nameof(ShouldHaveResultOfBoolMiddlewareInBody)); - await pipeline(context); + await pipeline(context); - Assert.Equal("A:True, B:False, C:True, D:False, E:True, F:False", context.Response.Body.ToEncodedString()); + Assert.Equal("A:True, B:False, C:True, D:False, E:True, F:False", context.Response.Body.ToEncodedString()); - Assert.True(options.Value.A); - Assert.False(options.Value.B); - Assert.True(options.Value.C); - Assert.False(options.Value.D); - Assert.True(options.Value.E); - Assert.False(options.Value.F); - } + Assert.True(options.Value.A); + Assert.False(options.Value.B); + Assert.True(options.Value.C); + Assert.False(options.Value.D); + Assert.True(options.Value.E); + Assert.False(options.Value.F); + } #if NET9_0_OR_GREATER - [Fact] - public void ShouldThrowInvalidOperationException_BecauseOneOfTheServicesIsScoped() - { - var ex = Assert.Throws(() => _provider.GetServices()); + [Fact] + public void ShouldThrowInvalidOperationException_BecauseOneOfTheServicesIsScoped() + { + var ex = Assert.Throws(() => _provider.GetServices()); - TestOutput.WriteLine(ex.Message); + TestOutput.WriteLine(ex.Message); - Assert.Contains("from root provider because it requires scoped service", ex.Message); - } + Assert.Contains("from root provider because it requires scoped service", ex.Message); + } #endif - [Fact] - public void ShouldHaveAccessToCorrelationTokens_UsingScopedProvider() - { - using var scope = _provider.CreateScope(); + [Fact] + public void ShouldHaveAccessToCorrelationTokens_UsingScopedProvider() + { + using var scope = _provider.CreateScope(); - var firstRequest = scope.ServiceProvider.GetServices().ToList(); - var secondRequest = scope.ServiceProvider.GetServices().ToList(); + var firstRequest = scope.ServiceProvider.GetServices().ToList(); + var secondRequest = scope.ServiceProvider.GetServices().ToList(); - TestOutput.WriteLine("----"); - TestOutput.WriteLines(firstRequest); - TestOutput.WriteLine("----"); - TestOutput.WriteLines(secondRequest); + TestOutput.WriteLine("----"); + TestOutput.WriteLines(firstRequest); + TestOutput.WriteLine("----"); + TestOutput.WriteLines(secondRequest); - Assert.Equal(3, firstRequest.Count); - Assert.Equal(3, secondRequest.Count); + Assert.Equal(3, firstRequest.Count); + Assert.Equal(3, secondRequest.Count); - Assert.Same(firstRequest[0], secondRequest[0]); - Assert.NotSame(firstRequest[1], secondRequest[1]); - Assert.Same(firstRequest[2], secondRequest[2]); + Assert.Same(firstRequest[0], secondRequest[0]); + Assert.NotSame(firstRequest[1], secondRequest[1]); + Assert.Same(firstRequest[2], secondRequest[2]); - Assert.Equal(firstRequest[0].CorrelationId, secondRequest[0].CorrelationId); - Assert.NotEqual(firstRequest[1].CorrelationId, secondRequest[1].CorrelationId); - Assert.Equal(firstRequest[2].CorrelationId, secondRequest[2].CorrelationId); - } + Assert.Equal(firstRequest[0].CorrelationId, secondRequest[0].CorrelationId); + Assert.NotEqual(firstRequest[1].CorrelationId, secondRequest[1].CorrelationId); + Assert.Equal(firstRequest[2].CorrelationId, secondRequest[2].CorrelationId); + } - [Fact] - public void ShouldHaveAccessToCorrelationTokens_UsingRequestServices() // reference: https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http/src/Features/RequestServicesFeature.cs - { - var context = _provider.GetRequiredService().HttpContext!; + [Fact] + public void ShouldHaveAccessToCorrelationTokens_UsingRequestServices() // reference: https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http/src/Features/RequestServicesFeature.cs + { + var context = _provider.GetRequiredService().HttpContext!; - var firstRequest = context.RequestServices.GetServices().ToList(); - var secondRequest = context.RequestServices.GetServices().ToList(); + var firstRequest = context.RequestServices.GetServices().ToList(); + var secondRequest = context.RequestServices.GetServices().ToList(); - TestOutput.WriteLine("----"); - TestOutput.WriteLines(firstRequest); - TestOutput.WriteLine("----"); - TestOutput.WriteLines(secondRequest); + TestOutput.WriteLine("----"); + TestOutput.WriteLines(firstRequest); + TestOutput.WriteLine("----"); + TestOutput.WriteLines(secondRequest); - Assert.Equal(3, firstRequest.Count); - Assert.Equal(3, secondRequest.Count); + Assert.Equal(3, firstRequest.Count); + Assert.Equal(3, secondRequest.Count); - Assert.Same(firstRequest[0], secondRequest[0]); - Assert.NotSame(firstRequest[1], secondRequest[1]); - Assert.Same(firstRequest[2], secondRequest[2]); + Assert.Same(firstRequest[0], secondRequest[0]); + Assert.NotSame(firstRequest[1], secondRequest[1]); + Assert.Same(firstRequest[2], secondRequest[2]); - Assert.Equal(firstRequest[0].CorrelationId, secondRequest[0].CorrelationId); - Assert.NotEqual(firstRequest[1].CorrelationId, secondRequest[1].CorrelationId); - Assert.Equal(firstRequest[2].CorrelationId, secondRequest[2].CorrelationId); - } + Assert.Equal(firstRequest[0].CorrelationId, secondRequest[0].CorrelationId); + Assert.NotEqual(firstRequest[1].CorrelationId, secondRequest[1].CorrelationId); + Assert.Equal(firstRequest[2].CorrelationId, secondRequest[2].CorrelationId); + } - [Fact] - public void ShouldLogToXunitTestLogging() - { - var context = _provider.GetRequiredService().HttpContext; - var logger = _pipeline.ApplicationServices.GetRequiredService>(); - logger.LogInformation("Hello stranger {0}", nameof(ShouldLogToXunitTestLogging)); - var store = _pipeline.ApplicationServices.GetRequiredService>().GetTestStore(); - var entry = store.Query(entry => entry.Message.Contains("Hello stranger", StringComparison.OrdinalIgnoreCase)).SingleOrDefault(); - - Assert.NotNull(entry); - Assert.Equal("Information: Hello stranger ShouldLogToXunitTestLogging", entry.Message); - } - - [Fact] - public void Test_VerifyAbstractions() - { - using var hostTest = WebHostTestFactory.Create(); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - } - - protected override void ConfigureHost(IHostApplicationBuilder hb) - { - hb.Services.AddFakeHttpContextAccessor(); - hb.Services.Configure(o => - { - o.A = true; - o.C = true; - o.E = true; - }); - hb.Services.AddXunitTestLoggingOutputHelperAccessor(); - hb.Services.AddXunitTestLogging(TestOutput); - - hb.Services.AddSingleton(); - hb.Services.AddTransient(); - hb.Services.AddScoped(); - } - - public override void ConfigureApplication(IApplicationBuilder app) + [Fact] + public void ShouldLogToXunitTestLogging() + { + var context = _provider.GetRequiredService().HttpContext; + var logger = _pipeline.ApplicationServices.GetRequiredService>(); + logger.LogInformation("Hello stranger {0}", nameof(ShouldLogToXunitTestLogging)); + var store = _pipeline.ApplicationServices.GetRequiredService>().GetTestStore(); + var entry = store.Query(entry => entry.Message.Contains("Hello stranger", StringComparison.OrdinalIgnoreCase)).SingleOrDefault(); + + Assert.NotNull(entry); + Assert.Equal("Information: Hello stranger ShouldLogToXunitTestLogging", entry.Message); + } + + [Fact] + public void Test_VerifyAbstractions() + { + using var hostTest = WebHostTestFactory.Create(); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + } + + protected override void ConfigureHost(IHostApplicationBuilder hb) + { + hb.Services.AddFakeHttpContextAccessor(); + hb.Services.Configure(o => { - app.ApplicationServices.GetRequiredService>().LogInformation(nameof(ConfigureApplication)); - app.UseMiddleware(); - } + o.A = true; + o.C = true; + o.E = true; + }); + hb.Services.AddXunitTestLoggingOutputHelperAccessor(); + hb.Services.AddXunitTestLogging(TestOutput); + + hb.Services.AddSingleton(); + hb.Services.AddTransient(); + hb.Services.AddScoped(); + } + + public override void ConfigureApplication(IApplicationBuilder app) + { + app.ApplicationServices.GetRequiredService>().LogInformation(nameof(ConfigureApplication)); + app.UseMiddleware(); } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/MvcWebHostTestTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/MvcWebHostTestTest.cs index 363ccb0..301512b 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/MvcWebHostTestTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/MvcWebHostTestTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Net.Http; using System.Threading.Tasks; using Codebelt.Extensions.Xunit.Hosting.AspNetCore.Assets; @@ -7,51 +7,50 @@ using Microsoft.Extensions.DependencyInjection; using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +public class MvcWebHostTestTest : WebHostTest { - public class MvcWebHostTestTest : WebHostTest + private readonly ManagedWebHostFixture _hostFixture; + private readonly HttpClient _client; + + public MvcWebHostTestTest(ManagedWebHostFixture hostFixture, ITestOutputHelper output = null, Type callerType = null) : base(hostFixture, output, callerType) + { + hostFixture.Host.Services.GetRequiredService().TestOutput = output; + _hostFixture = hostFixture; + _client = hostFixture.Host.GetTestClient(); + } + + [Fact] + public async Task GetTestAsync() + { + var response = await _client.GetAsync("/Fake"); + response.EnsureSuccessStatusCode(); + var body = await response.Content.ReadAsStringAsync(); + Assert.Equal("Unit Test", body); + } + + [Fact] + public async Task GetTestAsync2() + { + var response = await _client.GetAsync("/Fake"); + response.EnsureSuccessStatusCode(); + var body = await response.Content.ReadAsStringAsync(); + Assert.Equal("Unit Test", body); + } + + public override void ConfigureServices(IServiceCollection services) + { + services.AddControllers() + .AddApplicationPart(typeof(FakeController).Assembly); + + services.AddXunitTestLoggingOutputHelperAccessor(); + services.AddXunitTestLogging(TestOutput); + } + + public override void ConfigureApplication(IApplicationBuilder app) { - private readonly ManagedWebHostFixture _hostFixture; - private readonly HttpClient _client; - - public MvcWebHostTestTest(ManagedWebHostFixture hostFixture, ITestOutputHelper output = null, Type callerType = null) : base(hostFixture, output, callerType) - { - hostFixture.Host.Services.GetRequiredService().TestOutput = output; - _hostFixture = hostFixture; - _client = hostFixture.Host.GetTestClient(); - } - - [Fact] - public async Task GetTestAsync() - { - var response = await _client.GetAsync("/Fake"); - response.EnsureSuccessStatusCode(); - var body = await response.Content.ReadAsStringAsync(); - Assert.Equal("Unit Test", body); - } - - [Fact] - public async Task GetTestAsync2() - { - var response = await _client.GetAsync("/Fake"); - response.EnsureSuccessStatusCode(); - var body = await response.Content.ReadAsStringAsync(); - Assert.Equal("Unit Test", body); - } - - public override void ConfigureServices(IServiceCollection services) - { - services.AddControllers() - .AddApplicationPart(typeof(FakeController).Assembly); - - services.AddXunitTestLoggingOutputHelperAccessor(); - services.AddXunitTestLogging(TestOutput); - } - - public override void ConfigureApplication(IApplicationBuilder app) - { - app.UseRouting(); - app.UseEndpoints(routes => { routes.MapControllers(); }); - } + app.UseRouting(); + app.UseEndpoints(routes => { routes.MapControllers(); }); } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/SelfManagedWebHostFixtureTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/SelfManagedWebHostFixtureTest.cs index f9abec3..da2e3b7 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/SelfManagedWebHostFixtureTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/SelfManagedWebHostFixtureTest.cs @@ -1,19 +1,18 @@ using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +public class SelfManagedWebHostFixtureTest : Test { - public class SelfManagedWebHostFixtureTest : Test + public SelfManagedWebHostFixtureTest(ITestOutputHelper output) : base(output) { - public SelfManagedWebHostFixtureTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public void Create_ShouldSucceed_WhenSelfManagedWebHostFixtureIsUsed() - { - using var startup = WebHostTestFactory.Create(hostFixture: new SelfManagedWebHostFixture()); + [Fact] + public void Create_ShouldSucceed_WhenSelfManagedWebHostFixtureIsUsed() + { + using var startup = WebHostTestFactory.Create(hostFixture: new SelfManagedWebHostFixture()); - Assert.NotNull(startup.Host); - } + Assert.NotNull(startup.Host); } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/SelfManagedWebMinimalHostFixtureTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/SelfManagedWebMinimalHostFixtureTest.cs index 79e03b9..9ad6eae 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/SelfManagedWebMinimalHostFixtureTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/SelfManagedWebMinimalHostFixtureTest.cs @@ -1,23 +1,22 @@ using Microsoft.AspNetCore.Builder; using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +public class SelfManagedWebMinimalHostFixtureTest : MinimalWebHostTest { - public class SelfManagedWebMinimalHostFixtureTest : MinimalWebHostTest + public SelfManagedWebMinimalHostFixtureTest(SelfManagedWebMinimalHostFixture hostFixture, ITestOutputHelper output) : base(hostFixture, output) { - public SelfManagedWebMinimalHostFixtureTest(SelfManagedWebMinimalHostFixture hostFixture, ITestOutputHelper output) : base(hostFixture, output) - { - } + } - [Fact] - public void Host_ShouldNotBeNull_WhenNoOpRunnerIsUsed() - { - Assert.NotNull(Host); - Assert.NotNull(Application); - } + [Fact] + public void Host_ShouldNotBeNull_WhenNoOpRunnerIsUsed() + { + Assert.NotNull(Host); + Assert.NotNull(Application); + } - public override void ConfigureApplication(IApplicationBuilder app) - { - } + public override void ConfigureApplication(IApplicationBuilder app) + { } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/ServiceCollectionExtensionsTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/ServiceCollectionExtensionsTest.cs index 3871c2a..2cc6d43 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/ServiceCollectionExtensionsTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/ServiceCollectionExtensionsTest.cs @@ -1,45 +1,44 @@ -using System.ComponentModel; +using System.ComponentModel; using Codebelt.Extensions.Xunit.Hosting.AspNetCore.Http; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +public class ServiceCollectionExtensionsTest : Test { - public class ServiceCollectionExtensionsTest : Test + public ServiceCollectionExtensionsTest(ITestOutputHelper output) : base(output) { - public ServiceCollectionExtensionsTest(ITestOutputHelper output) : base(output) - { - } + } - [Theory] - [InlineData(ServiceLifetime.Transient)] - [InlineData(ServiceLifetime.Scoped)] - [InlineData(ServiceLifetime.Singleton)] - public void AddFakeHttpContextAccessor_ShouldAddService(ServiceLifetime lifetime) - { - // Arrange - var services = new ServiceCollection(); + [Theory] + [InlineData(ServiceLifetime.Transient)] + [InlineData(ServiceLifetime.Scoped)] + [InlineData(ServiceLifetime.Singleton)] + public void AddFakeHttpContextAccessor_ShouldAddService(ServiceLifetime lifetime) + { + // Arrange + var services = new ServiceCollection(); - // Act - services.AddFakeHttpContextAccessor(lifetime); - var serviceProvider = services.BuildServiceProvider(); - var httpContextAccessor = serviceProvider.GetService(); + // Act + services.AddFakeHttpContextAccessor(lifetime); + var serviceProvider = services.BuildServiceProvider(); + var httpContextAccessor = serviceProvider.GetService(); - // Assert - Assert.NotNull(httpContextAccessor); - Assert.IsType(httpContextAccessor); - } + // Assert + Assert.NotNull(httpContextAccessor); + Assert.IsType(httpContextAccessor); + } - [Fact] - public void AddFakeHttpContextAccessor_ShouldThrowInvalidEnumArgumentException_ForInvalidLifetime() - { - // Arrange - var services = new ServiceCollection(); - var invalidLifetime = (ServiceLifetime)999; + [Fact] + public void AddFakeHttpContextAccessor_ShouldThrowInvalidEnumArgumentException_ForInvalidLifetime() + { + // Arrange + var services = new ServiceCollection(); + var invalidLifetime = (ServiceLifetime)999; - // Act & Assert - Assert.Throws(() => services.AddFakeHttpContextAccessor(invalidLifetime)); - } + // Act & Assert + Assert.Throws(() => services.AddFakeHttpContextAccessor(invalidLifetime)); } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/WebHostTestFactoryTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/WebHostTestFactoryTest.cs index a774341..019f0c3 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/WebHostTestFactoryTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/WebHostTestFactoryTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using System.Linq; using System.Security; @@ -14,161 +14,160 @@ using Microsoft.Extensions.Logging; using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +public class WebHostTestFactoryTest : Test { - public class WebHostTestFactoryTest : Test + public WebHostTestFactoryTest(ITestOutputHelper output) : base(output) { - public WebHostTestFactoryTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public void Create_ShouldThrowSecurityException_DueToBlockingAspNetCoreHostFixture() - { - Assert.Throws(() => WebHostTestFactory.Create( - services => - { - services.AddXunitTestLogging(TestOutput); - services.AddAuthorization(o => - { - o.AddPolicy("Test", _ => throw new SecurityException()); - }); - }, - app => + [Fact] + public void Create_ShouldThrowSecurityException_DueToBlockingAspNetCoreHostFixture() + { + Assert.Throws(() => WebHostTestFactory.Create( + services => + { + services.AddXunitTestLogging(TestOutput); + services.AddAuthorization(o => { - var policy = app.ApplicationServices.GetRequiredService(); - }, - host => + o.AddPolicy("Test", _ => throw new SecurityException()); + }); + }, + app => + { + var policy = app.ApplicationServices.GetRequiredService(); + }, + host => + { + host.UseDefaultServiceProvider(o => { - host.UseDefaultServiceProvider(o => - { - o.ValidateOnBuild = false; - o.ValidateScopes = false; - }); - }, - new BlockingManagedWebHostFixture())); - } + o.ValidateOnBuild = false; + o.ValidateScopes = false; + }); + }, + new BlockingManagedWebHostFixture())); + } - [Fact] - public void Create_ShouldCaptureSecurityException_DueToNonBlockingAspNetCoreHostFixture() - { - using (var startup = WebHostTestFactory.Create( - services => - { - services.AddXunitTestLogging(TestOutput); + [Fact] + public void Create_ShouldCaptureSecurityException_DueToNonBlockingAspNetCoreHostFixture() + { + using (var startup = WebHostTestFactory.Create( + services => + { + services.AddXunitTestLogging(TestOutput); - services.AddAuthorization(o => { o.AddPolicy("Test", _ => throw new SecurityException()); }); - }, - app => + services.AddAuthorization(o => { o.AddPolicy("Test", _ => throw new SecurityException()); }); + }, + app => + { + var policy = app.ApplicationServices.GetRequiredService(); + }, + host => + { + host.UseDefaultServiceProvider(o => { - var policy = app.ApplicationServices.GetRequiredService(); - }, - host => - { - host.UseDefaultServiceProvider(o => - { - o.ValidateOnBuild = false; - o.ValidateScopes = false; - }); - })) - { - var loggerStore = startup.Host.Services.GetRequiredService>().GetTestStore(null); - var message = loggerStore.Query(entry => entry.Severity == LogLevel.Critical && entry.Message.Contains("SecurityException", StringComparison.OrdinalIgnoreCase)).SingleOrDefault()?.Message; - Assert.NotNull(message); - Assert.Contains("System.Security.SecurityException: Security error.", message); - } + o.ValidateOnBuild = false; + o.ValidateScopes = false; + }); + })) + { + var loggerStore = startup.Host.Services.GetRequiredService>().GetTestStore(null); + var message = loggerStore.Query(entry => entry.Severity == LogLevel.Critical && entry.Message.Contains("SecurityException", StringComparison.OrdinalIgnoreCase)).SingleOrDefault()?.Message; + Assert.NotNull(message); + Assert.Contains("System.Security.SecurityException: Security error.", message); } + } - [Fact] - public void Create_CallerTypeShouldHaveDeclaringTypeOfMiddlewareTestFactoryTest() - { - Type sut1 = GetType(); - string sut2 = null; - var middleware = WebHostTestFactory.Create(Assert.NotNull, Assert.NotNull, host => + [Fact] + public void Create_CallerTypeShouldHaveDeclaringTypeOfMiddlewareTestFactoryTest() + { + Type sut1 = GetType(); + string sut2 = null; + var middleware = WebHostTestFactory.Create(Assert.NotNull, Assert.NotNull, host => + { + host.ConfigureAppConfiguration((context, _) => { - host.ConfigureAppConfiguration((context, _) => - { - sut2 = context.HostingEnvironment.ApplicationName; - }); + sut2 = context.HostingEnvironment.ApplicationName; }); + }); - Assert.True(sut1 == middleware.CallerType.DeclaringType); - Assert.Equal(GetType().Assembly.GetName().Name, sut2); - } + Assert.True(sut1 == middleware.CallerType.DeclaringType); + Assert.Equal(GetType().Assembly.GetName().Name, sut2); + } - [Fact] - public Task RunAsync_ShouldHaveApplicationNameEqualToThisAssembly() - { - return WebHostTestFactory.RunAsync(Assert.NotNull, Assert.NotNull, host => + [Fact] + public Task RunAsync_ShouldHaveApplicationNameEqualToThisAssembly() + { + return WebHostTestFactory.RunAsync(Assert.NotNull, Assert.NotNull, host => + { + host.ConfigureAppConfiguration((context, _) => { - host.ConfigureAppConfiguration((context, _) => - { - TestOutput.WriteLine(context.HostingEnvironment.ApplicationName); - Assert.Equal(GetType().Assembly.GetName().Name, context.HostingEnvironment.ApplicationName); - }); + TestOutput.WriteLine(context.HostingEnvironment.ApplicationName); + Assert.Equal(GetType().Assembly.GetName().Name, context.HostingEnvironment.ApplicationName); }); - } + }); + } - [Fact] - public Task RunWithHostBuilderContextAsync_ShouldHaveApplicationNameEqualToThisAssembly_WithHostBuilderContext() - { - return WebHostTestFactory.RunWithHostBuilderContextAsync((context, app) => - { - Assert.NotNull(context); - Assert.NotNull(context.HostingEnvironment); - Assert.NotNull(context.Configuration); - Assert.NotNull(context.Properties); - Assert.NotNull(app); - }, - (context, services) => - { - Assert.NotNull(context); - Assert.NotNull(context.HostingEnvironment); - Assert.NotNull(context.Configuration); - Assert.NotNull(context.Properties); - Assert.NotNull(services); - }, - host => + [Fact] + public Task RunWithHostBuilderContextAsync_ShouldHaveApplicationNameEqualToThisAssembly_WithHostBuilderContext() + { + return WebHostTestFactory.RunWithHostBuilderContextAsync((context, app) => + { + Assert.NotNull(context); + Assert.NotNull(context.HostingEnvironment); + Assert.NotNull(context.Configuration); + Assert.NotNull(context.Properties); + Assert.NotNull(app); + }, + (context, services) => + { + Assert.NotNull(context); + Assert.NotNull(context.HostingEnvironment); + Assert.NotNull(context.Configuration); + Assert.NotNull(context.Properties); + Assert.NotNull(services); + }, + host => + { + host.ConfigureAppConfiguration((context, configuration) => { - host.ConfigureAppConfiguration((context, configuration) => - { - TestOutput.WriteLine(context.HostingEnvironment.ApplicationName); - Assert.Equal(GetType().Assembly.GetName().Name, context.HostingEnvironment.ApplicationName); - }); + TestOutput.WriteLine(context.HostingEnvironment.ApplicationName); + Assert.Equal(GetType().Assembly.GetName().Name, context.HostingEnvironment.ApplicationName); }); - } + }); + } - [Fact] - public async Task RunAsync_ShouldWorkWithXunitTestLogging() - { - using var response = await WebHostTestFactory.RunAsync( - services => - { - services.AddXunitTestLogging(TestOutput); - services.AddServerTiming(o => o.SuppressHeaderPredicate = _ => false); - }, - app => + [Fact] + public async Task RunAsync_ShouldWorkWithXunitTestLogging() + { + using var response = await WebHostTestFactory.RunAsync( + services => + { + services.AddXunitTestLogging(TestOutput); + services.AddServerTiming(o => o.SuppressHeaderPredicate = _ => false); + }, + app => + { + app.UseServerTiming(); + app.Use(async (context, next) => { - app.UseServerTiming(); - app.Use(async (context, next) => + var sw = Stopwatch.StartNew(); + context.Response.OnStarting(() => { - var sw = Stopwatch.StartNew(); - context.Response.OnStarting(() => - { - sw.Stop(); - context.RequestServices.GetRequiredService().AddServerTiming("use-middleware", sw.Elapsed); - return Task.CompletedTask; - }); - await next(context).ConfigureAwait(false); + sw.Stop(); + context.RequestServices.GetRequiredService().AddServerTiming("use-middleware", sw.Elapsed); + return Task.CompletedTask; }); - app.Run(context => - { - Thread.Sleep(400); - return context.Response.WriteAsync("Hello World!"); - }); - }).ConfigureAwait(false); + await next(context).ConfigureAwait(false); + }); + app.Run(context => + { + Thread.Sleep(400); + return context.Response.WriteAsync("Hello World!"); + }); + }).ConfigureAwait(false); - Assert.StartsWith("use-middleware;dur=", response.Headers.Single(kvp => kvp.Key == ServerTiming.HeaderName).Value.FirstOrDefault()); - } + Assert.StartsWith("use-middleware;dur=", response.Headers.Single(kvp => kvp.Key == ServerTiming.HeaderName).Value.FirstOrDefault()); } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/WebHostTestTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/WebHostTestTest.cs index 431aacd..c78fd1a 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/WebHostTestTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/WebHostTestTest.cs @@ -11,154 +11,153 @@ using Microsoft.Extensions.Options; using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore; + +public class WebHostTestTest : WebHostTest { - public class WebHostTestTest : WebHostTest - { - private readonly IServiceProvider _provider; - private readonly IApplicationBuilder _pipeline; + private readonly IServiceProvider _provider; + private readonly IApplicationBuilder _pipeline; - public WebHostTestTest(ManagedWebHostFixture hostFixture, ITestOutputHelper output) : base(hostFixture, output) - { - _pipeline = hostFixture.Application; - _provider = hostFixture.Host.Services; - _provider.GetRequiredService().TestOutput = output; - } + public WebHostTestTest(ManagedWebHostFixture hostFixture, ITestOutputHelper output) : base(hostFixture, output) + { + _pipeline = hostFixture.Application; + _provider = hostFixture.Host.Services; + _provider.GetRequiredService().TestOutput = output; + } - [Fact] - public async Task ShouldHaveResultOfBoolMiddlewareInBody() - { - var context = _provider.GetRequiredService().HttpContext; - var options = _provider.GetRequiredService>(); - var pipeline = _pipeline.Build(); + [Fact] + public async Task ShouldHaveResultOfBoolMiddlewareInBody() + { + var context = _provider.GetRequiredService().HttpContext; + var options = _provider.GetRequiredService>(); + var pipeline = _pipeline.Build(); - Assert.Equal("Hello awesome developers!", context!.Response.Body.ToEncodedString(o => o.LeaveOpen = true)); + Assert.Equal("Hello awesome developers!", context!.Response.Body.ToEncodedString(o => o.LeaveOpen = true)); - var logger = _pipeline.ApplicationServices.GetRequiredService>(); - logger.LogInformation("Hello from {0}", nameof(ShouldHaveResultOfBoolMiddlewareInBody)); + var logger = _pipeline.ApplicationServices.GetRequiredService>(); + logger.LogInformation("Hello from {0}", nameof(ShouldHaveResultOfBoolMiddlewareInBody)); - await pipeline(context); + await pipeline(context); - Assert.Equal("A:True, B:False, C:True, D:False, E:True, F:False", context.Response.Body.ToEncodedString()); + Assert.Equal("A:True, B:False, C:True, D:False, E:True, F:False", context.Response.Body.ToEncodedString()); - Assert.True(options.Value.A); - Assert.False(options.Value.B); - Assert.True(options.Value.C); - Assert.False(options.Value.D); - Assert.True(options.Value.E); - Assert.False(options.Value.F); - } + Assert.True(options.Value.A); + Assert.False(options.Value.B); + Assert.True(options.Value.C); + Assert.False(options.Value.D); + Assert.True(options.Value.E); + Assert.False(options.Value.F); + } #if NET9_0_OR_GREATER - [Fact] - public void ShouldThrowInvalidOperationException_BecauseOneOfTheServicesIsScoped() - { - var ex = Assert.Throws(() => _provider.GetServices()); + [Fact] + public void ShouldThrowInvalidOperationException_BecauseOneOfTheServicesIsScoped() + { + var ex = Assert.Throws(() => _provider.GetServices()); - TestOutput.WriteLine(ex.Message); + TestOutput.WriteLine(ex.Message); - Assert.Contains("from root provider because it requires scoped service", ex.Message); - } + Assert.Contains("from root provider because it requires scoped service", ex.Message); + } #endif - [Fact] - public void ShouldHaveAccessToCorrelationTokens_UsingScopedProvider() - { - using var scope = _provider.CreateScope(); + [Fact] + public void ShouldHaveAccessToCorrelationTokens_UsingScopedProvider() + { + using var scope = _provider.CreateScope(); - var firstRequest = scope.ServiceProvider.GetServices().ToList(); - var secondRequest = scope.ServiceProvider.GetServices().ToList(); + var firstRequest = scope.ServiceProvider.GetServices().ToList(); + var secondRequest = scope.ServiceProvider.GetServices().ToList(); - TestOutput.WriteLine("----"); - TestOutput.WriteLines(firstRequest); - TestOutput.WriteLine("----"); - TestOutput.WriteLines(secondRequest); + TestOutput.WriteLine("----"); + TestOutput.WriteLines(firstRequest); + TestOutput.WriteLine("----"); + TestOutput.WriteLines(secondRequest); - Assert.Equal(3, firstRequest.Count); - Assert.Equal(3, secondRequest.Count); + Assert.Equal(3, firstRequest.Count); + Assert.Equal(3, secondRequest.Count); - Assert.Same(firstRequest[0], secondRequest[0]); - Assert.NotSame(firstRequest[1], secondRequest[1]); - Assert.Same(firstRequest[2], secondRequest[2]); + Assert.Same(firstRequest[0], secondRequest[0]); + Assert.NotSame(firstRequest[1], secondRequest[1]); + Assert.Same(firstRequest[2], secondRequest[2]); - Assert.Equal(firstRequest[0].CorrelationId, secondRequest[0].CorrelationId); - Assert.NotEqual(firstRequest[1].CorrelationId, secondRequest[1].CorrelationId); - Assert.Equal(firstRequest[2].CorrelationId, secondRequest[2].CorrelationId); - } + Assert.Equal(firstRequest[0].CorrelationId, secondRequest[0].CorrelationId); + Assert.NotEqual(firstRequest[1].CorrelationId, secondRequest[1].CorrelationId); + Assert.Equal(firstRequest[2].CorrelationId, secondRequest[2].CorrelationId); + } - [Fact] - public void ShouldHaveAccessToCorrelationTokens_UsingRequestServices() // reference: https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http/src/Features/RequestServicesFeature.cs - { - var context = _provider.GetRequiredService().HttpContext!; + [Fact] + public void ShouldHaveAccessToCorrelationTokens_UsingRequestServices() // reference: https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http/src/Features/RequestServicesFeature.cs + { + var context = _provider.GetRequiredService().HttpContext!; - var firstRequest = context.RequestServices.GetServices().ToList(); - var secondRequest = context.RequestServices.GetServices().ToList(); + var firstRequest = context.RequestServices.GetServices().ToList(); + var secondRequest = context.RequestServices.GetServices().ToList(); - TestOutput.WriteLine("----"); - TestOutput.WriteLines(firstRequest); - TestOutput.WriteLine("----"); - TestOutput.WriteLines(secondRequest); + TestOutput.WriteLine("----"); + TestOutput.WriteLines(firstRequest); + TestOutput.WriteLine("----"); + TestOutput.WriteLines(secondRequest); - Assert.Equal(3, firstRequest.Count); - Assert.Equal(3, secondRequest.Count); + Assert.Equal(3, firstRequest.Count); + Assert.Equal(3, secondRequest.Count); - Assert.Same(firstRequest[0], secondRequest[0]); - Assert.NotSame(firstRequest[1], secondRequest[1]); - Assert.Same(firstRequest[2], secondRequest[2]); + Assert.Same(firstRequest[0], secondRequest[0]); + Assert.NotSame(firstRequest[1], secondRequest[1]); + Assert.Same(firstRequest[2], secondRequest[2]); - Assert.Equal(firstRequest[0].CorrelationId, secondRequest[0].CorrelationId); - Assert.NotEqual(firstRequest[1].CorrelationId, secondRequest[1].CorrelationId); - Assert.Equal(firstRequest[2].CorrelationId, secondRequest[2].CorrelationId); - } + Assert.Equal(firstRequest[0].CorrelationId, secondRequest[0].CorrelationId); + Assert.NotEqual(firstRequest[1].CorrelationId, secondRequest[1].CorrelationId); + Assert.Equal(firstRequest[2].CorrelationId, secondRequest[2].CorrelationId); + } - [Fact] - public void ShouldLogToXunitTestLogging() - { - var context = _provider.GetRequiredService().HttpContext; - var logger = _pipeline.ApplicationServices.GetRequiredService>(); - logger.LogInformation("Hello stranger {0}", nameof(ShouldLogToXunitTestLogging)); - var store = _pipeline.ApplicationServices.GetRequiredService>().GetTestStore(); - var entry = store.Query(entry => entry.Message.Contains("Hello stranger", StringComparison.OrdinalIgnoreCase)).SingleOrDefault(); - - Assert.NotNull(entry); - Assert.Equal("Information: Hello stranger ShouldLogToXunitTestLogging", entry.Message); - } - - [Fact] - public void Test_VerifyAbstractions() - { - using var hostTest = WebHostTestFactory.Create(); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - } - - public override void ConfigureApplication(IApplicationBuilder app) - { - app.ApplicationServices.GetRequiredService>().LogInformation(nameof(ConfigureApplication)); - app.UseMiddleware(); - } + [Fact] + public void ShouldLogToXunitTestLogging() + { + var context = _provider.GetRequiredService().HttpContext; + var logger = _pipeline.ApplicationServices.GetRequiredService>(); + logger.LogInformation("Hello stranger {0}", nameof(ShouldLogToXunitTestLogging)); + var store = _pipeline.ApplicationServices.GetRequiredService>().GetTestStore(); + var entry = store.Query(entry => entry.Message.Contains("Hello stranger", StringComparison.OrdinalIgnoreCase)).SingleOrDefault(); + + Assert.NotNull(entry); + Assert.Equal("Information: Hello stranger ShouldLogToXunitTestLogging", entry.Message); + } - public override void ConfigureServices(IServiceCollection services) + [Fact] + public void Test_VerifyAbstractions() + { + using var hostTest = WebHostTestFactory.Create(); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + } + + public override void ConfigureApplication(IApplicationBuilder app) + { + app.ApplicationServices.GetRequiredService>().LogInformation(nameof(ConfigureApplication)); + app.UseMiddleware(); + } + + public override void ConfigureServices(IServiceCollection services) + { + services.AddFakeHttpContextAccessor(); + services.Configure(o => { - services.AddFakeHttpContextAccessor(); - services.Configure(o => - { - o.A = true; - o.C = true; - o.E = true; - }); - services.AddXunitTestLoggingOutputHelperAccessor(); - services.AddXunitTestLogging(TestOutput); - - services.AddSingleton(); - services.AddTransient(); - services.AddScoped(); - } + o.A = true; + o.C = true; + o.E = true; + }); + services.AddXunitTestLoggingOutputHelperAccessor(); + services.AddXunitTestLogging(TestOutput); + + services.AddSingleton(); + services.AddTransient(); + services.AddScoped(); } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/InvalidHostTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/InvalidHostTest.cs index 847c6ed..c531268 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/InvalidHostTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/InvalidHostTest.cs @@ -1,11 +1,10 @@ -using Xunit; +using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting.Assets +namespace Codebelt.Extensions.Xunit.Hosting.Assets; + +public class InvalidHostTest : Test, IClassFixture where T : class, IGenericHostFixture { - public class InvalidHostTest : Test, IClassFixture where T : class, IGenericHostFixture + public InvalidHostTest(T hostFixture) { - public InvalidHostTest(T hostFixture) - { - } } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/MinimalValidHostTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/MinimalValidHostTest.cs index 74e693a..07e646e 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/MinimalValidHostTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/MinimalValidHostTest.cs @@ -1,12 +1,11 @@ -using System; +using System; using Microsoft.Extensions.DependencyInjection; -namespace Codebelt.Extensions.Xunit.Hosting.Assets +namespace Codebelt.Extensions.Xunit.Hosting.Assets; + +public class MinimalValidHostTest : MinimalHostTest { - public class MinimalValidHostTest : MinimalHostTest + public MinimalValidHostTest(ManagedMinimalHostFixture hostFixture) : base(hostFixture) { - public MinimalValidHostTest(ManagedMinimalHostFixture hostFixture) : base(hostFixture) - { - } } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/ScopedCorrelation.cs b/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/ScopedCorrelation.cs index 2e8cc65..252a720 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/ScopedCorrelation.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/ScopedCorrelation.cs @@ -1,8 +1,7 @@ -using Cuemon.Messaging; +using Cuemon.Messaging; -namespace Codebelt.Extensions.Xunit.Hosting.Assets +namespace Codebelt.Extensions.Xunit.Hosting.Assets; + +public sealed record ScopedCorrelation : CorrelationToken { - public sealed record ScopedCorrelation : CorrelationToken - { - } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/SingletonCorrelation.cs b/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/SingletonCorrelation.cs index 0848afe..3b4cc09 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/SingletonCorrelation.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/SingletonCorrelation.cs @@ -1,8 +1,7 @@ -using Cuemon.Messaging; +using Cuemon.Messaging; -namespace Codebelt.Extensions.Xunit.Hosting.Assets +namespace Codebelt.Extensions.Xunit.Hosting.Assets; + +public sealed record SingletonCorrelation : CorrelationToken { - public sealed record SingletonCorrelation : CorrelationToken - { - } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/TransientCorrelation.cs b/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/TransientCorrelation.cs index e53336c..5fb3ca4 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/TransientCorrelation.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/TransientCorrelation.cs @@ -1,8 +1,7 @@ -using Cuemon.Messaging; +using Cuemon.Messaging; -namespace Codebelt.Extensions.Xunit.Hosting.Assets +namespace Codebelt.Extensions.Xunit.Hosting.Assets; + +public sealed record TransientCorrelation : CorrelationToken { - public sealed record TransientCorrelation : CorrelationToken - { - } -} \ No newline at end of file +} diff --git a/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/ValidHostTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/ValidHostTest.cs index f683f78..003092b 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/ValidHostTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.Tests/Assets/ValidHostTest.cs @@ -1,18 +1,17 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using System; using static System.Net.Mime.MediaTypeNames; -namespace Codebelt.Extensions.Xunit.Hosting.Assets +namespace Codebelt.Extensions.Xunit.Hosting.Assets; + +public class ValidHostTest : HostTest { - public class ValidHostTest : HostTest + public ValidHostTest(ManagedHostFixture hostFixture) : base(hostFixture) { - public ValidHostTest(ManagedHostFixture hostFixture) : base(hostFixture) - { - } + } - public override void ConfigureServices(IServiceCollection services) - { - - } + public override void ConfigureServices(IServiceCollection services) + { + } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.Tests/HostTestFactoryTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.Tests/HostTestFactoryTest.cs index 1a68f38..4b25ba6 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.Tests/HostTestFactoryTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.Tests/HostTestFactoryTest.cs @@ -1,51 +1,50 @@ -using System; +using System; using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +public class HostTestFactoryTest : Test { - public class HostTestFactoryTest : Test + public HostTestFactoryTest(ITestOutputHelper output) : base(output) { - public HostTestFactoryTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public void Create_CallerTypeShouldHaveDeclaringTypeOfMiddlewareTestFactoryTest() - { - Type sut1 = GetType(); - string sut2 = null; - var middleware = HostTestFactory.Create(Assert.NotNull, host => + [Fact] + public void Create_CallerTypeShouldHaveDeclaringTypeOfMiddlewareTestFactoryTest() + { + Type sut1 = GetType(); + string sut2 = null; + var middleware = HostTestFactory.Create(Assert.NotNull, host => + { + host.ConfigureAppConfiguration((context, _) => { - host.ConfigureAppConfiguration((context, _) => - { - sut2 = context.HostingEnvironment.ApplicationName; - }); + sut2 = context.HostingEnvironment.ApplicationName; }); + }); - Assert.True(sut1 == middleware.CallerType.DeclaringType); - Assert.Equal(GetType().Assembly.GetName().Name, sut2); - } + Assert.True(sut1 == middleware.CallerType.DeclaringType); + Assert.Equal(GetType().Assembly.GetName().Name, sut2); + } - [Fact] - public void CreateWithHostBuilderContext_ShouldHaveApplicationNameEqualToThisAssembly_WithHostBuilderContext() - { - HostTestFactory.CreateWithHostBuilderContext((context, services) => - { - Assert.NotNull(context); - Assert.NotNull(context.HostingEnvironment); - Assert.NotNull(context.Configuration); - Assert.NotNull(context.Properties); - Assert.NotNull(services); - }, - host => + [Fact] + public void CreateWithHostBuilderContext_ShouldHaveApplicationNameEqualToThisAssembly_WithHostBuilderContext() + { + HostTestFactory.CreateWithHostBuilderContext((context, services) => + { + Assert.NotNull(context); + Assert.NotNull(context.HostingEnvironment); + Assert.NotNull(context.Configuration); + Assert.NotNull(context.Properties); + Assert.NotNull(services); + }, + host => + { + host.ConfigureAppConfiguration((context, configuration) => { - host.ConfigureAppConfiguration((context, configuration) => - { - TestOutput.WriteLine(context.HostingEnvironment.ApplicationName); - Assert.Equal(GetType().Assembly.GetName().Name, context.HostingEnvironment.ApplicationName); - }); + TestOutput.WriteLine(context.HostingEnvironment.ApplicationName); + Assert.Equal(GetType().Assembly.GetName().Name, context.HostingEnvironment.ApplicationName); }); - } + }); } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.Tests/HostTestTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.Tests/HostTestTest.cs index 8610bd8..267a022 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.Tests/HostTestTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.Tests/HostTestTest.cs @@ -9,109 +9,108 @@ using Xunit; using Xunit.v3.Priority; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +[TestCaseOrderer(typeof(PriorityOrderer))] +public class HostTestTest : HostTest { - [TestCaseOrderer(typeof(PriorityOrderer))] - public class HostTestTest : HostTest - { - private bool _isHostRunning = false; - private readonly IServiceScope _scope; - private readonly IHost _constructorHost; - private readonly IServiceProvider _constructorServices; - private readonly Func> _correlationsFactory; - private static readonly ConcurrentBag ScopedCorrelations = new(); + private bool _isHostRunning = false; + private readonly IServiceScope _scope; + private readonly IHost _constructorHost; + private readonly IServiceProvider _constructorServices; + private readonly Func> _correlationsFactory; + private static readonly ConcurrentBag ScopedCorrelations = new(); - public HostTestTest(ManagedHostFixture hostFixture, ITestOutputHelper output) : base(hostFixture, output) - { - _constructorHost = hostFixture.Host; - _constructorServices = hostFixture.Host?.Services; + public HostTestTest(ManagedHostFixture hostFixture, ITestOutputHelper output) : base(hostFixture, output) + { + _constructorHost = hostFixture.Host; + _constructorServices = hostFixture.Host?.Services; - Assert.NotNull(_constructorHost); - Assert.NotNull(_constructorServices); - Assert.NotNull(Host); - Assert.NotNull(Configuration); - Assert.NotNull(Environment); + Assert.NotNull(_constructorHost); + Assert.NotNull(_constructorServices); + Assert.NotNull(Host); + Assert.NotNull(Configuration); + Assert.NotNull(Environment); - _scope = hostFixture.Host.Services.CreateScope(); - _correlationsFactory = () => _scope.ServiceProvider.GetServices().ToList(); - var lifetime = hostFixture.Host.Services.GetRequiredService(); - lifetime.ApplicationStarted.Register(() => _isHostRunning = true); - } + _scope = hostFixture.Host.Services.CreateScope(); + _correlationsFactory = () => _scope.ServiceProvider.GetServices().ToList(); + var lifetime = hostFixture.Host.Services.GetRequiredService(); + lifetime.ApplicationStarted.Register(() => _isHostRunning = true); + } - [Fact, Priority(1)] - public void Test_SingletonShouldBeSame() // simulate a request - { - ScopedCorrelations.Add(_correlationsFactory().Single(c => c is ScopedCorrelation)); - var c1 = _correlationsFactory().Single(c => c is SingletonCorrelation); - var c2 = _correlationsFactory().Single(c => c is SingletonCorrelation); - Assert.Equal(c1.CorrelationId, c2.CorrelationId); - } + [Fact, Priority(1)] + public void Test_SingletonShouldBeSame() // simulate a request + { + ScopedCorrelations.Add(_correlationsFactory().Single(c => c is ScopedCorrelation)); + var c1 = _correlationsFactory().Single(c => c is SingletonCorrelation); + var c2 = _correlationsFactory().Single(c => c is SingletonCorrelation); + Assert.Equal(c1.CorrelationId, c2.CorrelationId); + } - [Fact, Priority(2)] - public void Test_TransientShouldBeDifferent() // simulate a request - { - ScopedCorrelations.Add(_correlationsFactory().Single(c => c is ScopedCorrelation)); - var c1 = _correlationsFactory().Single(c => c is TransientCorrelation); - var c2 = _correlationsFactory().Single(c => c is TransientCorrelation); - Assert.NotEqual(c1.CorrelationId, c2.CorrelationId); - } + [Fact, Priority(2)] + public void Test_TransientShouldBeDifferent() // simulate a request + { + ScopedCorrelations.Add(_correlationsFactory().Single(c => c is ScopedCorrelation)); + var c1 = _correlationsFactory().Single(c => c is TransientCorrelation); + var c2 = _correlationsFactory().Single(c => c is TransientCorrelation); + Assert.NotEqual(c1.CorrelationId, c2.CorrelationId); + } - [Fact, Priority(3)] - public void Test_ScopedShouldBeSame() // simulate a request - { - ScopedCorrelations.Add(_correlationsFactory().Single(c => c is ScopedCorrelation)); - var c1 = _correlationsFactory().Single(c => c is ScopedCorrelation); - var c2 = _correlationsFactory().Single(c => c is ScopedCorrelation); - Assert.Equal(c1.CorrelationId, c2.CorrelationId); - } + [Fact, Priority(3)] + public void Test_ScopedShouldBeSame() // simulate a request + { + ScopedCorrelations.Add(_correlationsFactory().Single(c => c is ScopedCorrelation)); + var c1 = _correlationsFactory().Single(c => c is ScopedCorrelation); + var c2 = _correlationsFactory().Single(c => c is ScopedCorrelation); + Assert.Equal(c1.CorrelationId, c2.CorrelationId); + } - [Fact] - public void Test_ShouldHaveRunningHost() - { - Assert.True(_isHostRunning); - } + [Fact] + public void Test_ShouldHaveRunningHost() + { + Assert.True(_isHostRunning); + } - [Fact] - public void Test_ShouldHaveConfigurationEntry() - { - Assert.Equal("xUnit", Configuration.GetSection("unitTestTool").Value); - } + [Fact] + public void Test_ShouldHaveConfigurationEntry() + { + Assert.Equal("xUnit", Configuration.GetSection("unitTestTool").Value); + } - [Fact] - public void Test_ShouldHaveEnvironmentOfDevelopment() - { - Assert.Equal("Development", Environment.EnvironmentName); - } + [Fact] + public void Test_ShouldHaveEnvironmentOfDevelopment() + { + Assert.Equal("Development", Environment.EnvironmentName); + } - [Fact] - public void Test_ShouldHaveHostAndServicesAvailableInConstructor() - { - Assert.Same(Host, _constructorHost); - Assert.Same(Host.Services, _constructorServices); - } + [Fact] + public void Test_ShouldHaveHostAndServicesAvailableInConstructor() + { + Assert.Same(Host, _constructorHost); + Assert.Same(Host.Services, _constructorServices); + } - [Fact] - public void Test_VerifyAbstractions() - { - using var hostTest = HostTestFactory.Create(); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - } + [Fact] + public void Test_VerifyAbstractions() + { + using var hostTest = HostTestFactory.Create(); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + } - protected override void OnDisposeManagedResources() - { - _scope?.Dispose(); - } + protected override void OnDisposeManagedResources() + { + _scope?.Dispose(); + } - public override void ConfigureServices(IServiceCollection services) - { - services.AddSingleton(); - services.AddTransient(); - services.AddScoped(); - } + public override void ConfigureServices(IServiceCollection services) + { + services.AddSingleton(); + services.AddTransient(); + services.AddScoped(); } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.Tests/ManagedHostFixtureTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.Tests/ManagedHostFixtureTest.cs index ce0cb58..5f69e91 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.Tests/ManagedHostFixtureTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.Tests/ManagedHostFixtureTest.cs @@ -1,60 +1,59 @@ -using System; -using System.Threading.Tasks; -using Codebelt.Extensions.Xunit.Hosting.Assets; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Xunit; - -namespace Codebelt.Extensions.Xunit.Hosting -{ - public class ManagedHostFixtureTest : Test - { - private readonly ManagedHostFixture _hostFixture; - - public ManagedHostFixtureTest(ITestOutputHelper output) : base(output) - { - _hostFixture = new ManagedHostFixture(); - } - - [Fact] - public void ConfigureHost_ShouldThrowArgumentNullException_WhenHostTestIsNull() - { - Assert.Throws(() => _hostFixture.ConfigureHost(null)); - } - - [Fact] - public void ConfigureHost_ShouldThrowArgumentOutOfRangeException_WhenHostTestIsNotAssignableFromHostTest() - { - var invalidHostTest = new InvalidHostTest(new ManagedHostFixture()); - Assert.Throws(() => _hostFixture.ConfigureHost(invalidHostTest)); - } - - [Fact] - public void ConfigureHost_ShouldConfigureHostSuccessfully() - { - var validHostTest = new ValidHostTest(_hostFixture); - - _hostFixture.ConfigureHost(validHostTest); - - Assert.NotNull(_hostFixture.Host); - Assert.NotNull(_hostFixture.Host.Services); - Assert.NotNull(_hostFixture.Configuration); - Assert.NotNull(_hostFixture.Environment); - } - - [Fact] - public void Dispose_ShouldDisposeResources() - { - _hostFixture.Dispose(); - Assert.True(_hostFixture.Disposed); - } - - [Fact] - public async Task DisposeAsync_ShouldDisposeResourcesAsync() - { - await _hostFixture.DisposeAsync(); - Assert.True(_hostFixture.Disposed); - } - } -} +using System; +using System.Threading.Tasks; +using Codebelt.Extensions.Xunit.Hosting.Assets; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Xunit; + +namespace Codebelt.Extensions.Xunit.Hosting; + +public class ManagedHostFixtureTest : Test +{ + private readonly ManagedHostFixture _hostFixture; + + public ManagedHostFixtureTest(ITestOutputHelper output) : base(output) + { + _hostFixture = new ManagedHostFixture(); + } + + [Fact] + public void ConfigureHost_ShouldThrowArgumentNullException_WhenHostTestIsNull() + { + Assert.Throws(() => _hostFixture.ConfigureHost(null)); + } + + [Fact] + public void ConfigureHost_ShouldThrowArgumentOutOfRangeException_WhenHostTestIsNotAssignableFromHostTest() + { + var invalidHostTest = new InvalidHostTest(new ManagedHostFixture()); + Assert.Throws(() => _hostFixture.ConfigureHost(invalidHostTest)); + } + + [Fact] + public void ConfigureHost_ShouldConfigureHostSuccessfully() + { + var validHostTest = new ValidHostTest(_hostFixture); + + _hostFixture.ConfigureHost(validHostTest); + + Assert.NotNull(_hostFixture.Host); + Assert.NotNull(_hostFixture.Host.Services); + Assert.NotNull(_hostFixture.Configuration); + Assert.NotNull(_hostFixture.Environment); + } + + [Fact] + public void Dispose_ShouldDisposeResources() + { + _hostFixture.Dispose(); + Assert.True(_hostFixture.Disposed); + } + + [Fact] + public async Task DisposeAsync_ShouldDisposeResourcesAsync() + { + await _hostFixture.DisposeAsync(); + Assert.True(_hostFixture.Disposed); + } +} diff --git a/test/Codebelt.Extensions.Xunit.Hosting.Tests/MinimalHostFixtureTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.Tests/MinimalHostFixtureTest.cs index b9e446b..b2ecd13 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.Tests/MinimalHostFixtureTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.Tests/MinimalHostFixtureTest.cs @@ -1,57 +1,56 @@ -using System; -using System.Threading.Tasks; -using Codebelt.Extensions.Xunit.Hosting.Assets; -using Xunit; - -namespace Codebelt.Extensions.Xunit.Hosting -{ - public class MinimalHostFixtureTest : Test - { - private readonly ManagedMinimalHostFixture _hostFixture; - - public MinimalHostFixtureTest(ITestOutputHelper output) : base(output) - { - _hostFixture = new ManagedMinimalHostFixture(); - } - - [Fact] - public void ConfigureHost_ShouldThrowArgumentNullException_WhenHostTestIsNull() - { - Assert.Throws(() => _hostFixture.ConfigureHost(null)); - } - - [Fact] - public void ConfigureHost_ShouldThrowArgumentOutOfRangeException_WhenHostTestIsNotAssignableFromHostTest() - { - var invalidHostTest = new InvalidHostTest(new ManagedHostFixture()); - Assert.Throws(() => _hostFixture.ConfigureHost(invalidHostTest)); - } - - [Fact] - public void ConfigureHost_ShouldConfigureHostSuccessfully() - { - var validHostTest = new MinimalValidHostTest(_hostFixture); - - _hostFixture.ConfigureHost(validHostTest); - - Assert.NotNull(_hostFixture.Host); - Assert.NotNull(_hostFixture.Host.Services); - Assert.NotNull(_hostFixture.Configuration); - Assert.NotNull(_hostFixture.Environment); - } - - [Fact] - public void Dispose_ShouldDisposeResources() - { - _hostFixture.Dispose(); - Assert.True(_hostFixture.Disposed); - } - - [Fact] - public async Task DisposeAsync_ShouldDisposeResourcesAsync() - { - await _hostFixture.DisposeAsync(); - Assert.True(_hostFixture.Disposed); - } - } -} +using System; +using System.Threading.Tasks; +using Codebelt.Extensions.Xunit.Hosting.Assets; +using Xunit; + +namespace Codebelt.Extensions.Xunit.Hosting; + +public class MinimalHostFixtureTest : Test +{ + private readonly ManagedMinimalHostFixture _hostFixture; + + public MinimalHostFixtureTest(ITestOutputHelper output) : base(output) + { + _hostFixture = new ManagedMinimalHostFixture(); + } + + [Fact] + public void ConfigureHost_ShouldThrowArgumentNullException_WhenHostTestIsNull() + { + Assert.Throws(() => _hostFixture.ConfigureHost(null)); + } + + [Fact] + public void ConfigureHost_ShouldThrowArgumentOutOfRangeException_WhenHostTestIsNotAssignableFromHostTest() + { + var invalidHostTest = new InvalidHostTest(new ManagedHostFixture()); + Assert.Throws(() => _hostFixture.ConfigureHost(invalidHostTest)); + } + + [Fact] + public void ConfigureHost_ShouldConfigureHostSuccessfully() + { + var validHostTest = new MinimalValidHostTest(_hostFixture); + + _hostFixture.ConfigureHost(validHostTest); + + Assert.NotNull(_hostFixture.Host); + Assert.NotNull(_hostFixture.Host.Services); + Assert.NotNull(_hostFixture.Configuration); + Assert.NotNull(_hostFixture.Environment); + } + + [Fact] + public void Dispose_ShouldDisposeResources() + { + _hostFixture.Dispose(); + Assert.True(_hostFixture.Disposed); + } + + [Fact] + public async Task DisposeAsync_ShouldDisposeResourcesAsync() + { + await _hostFixture.DisposeAsync(); + Assert.True(_hostFixture.Disposed); + } +} diff --git a/test/Codebelt.Extensions.Xunit.Hosting.Tests/MinimalHostTestFactoryTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.Tests/MinimalHostTestFactoryTest.cs index 030006b..9ce11ec 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.Tests/MinimalHostTestFactoryTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.Tests/MinimalHostTestFactoryTest.cs @@ -1,45 +1,44 @@ -using System; +using System; using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +public class MinimalHostTestFactoryTest : Test { - public class MinimalHostTestFactoryTest : Test + public MinimalHostTestFactoryTest(ITestOutputHelper output) : base(output) { - public MinimalHostTestFactoryTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public void Create_CallerTypeShouldHaveDeclaringTypeOfMiddlewareTestFactoryTest() - { - Type sut1 = GetType(); - string sut2 = null; - var middleware = MinimalHostTestFactory.Create(Assert.NotNull, host => - { - sut2 = host.Environment.ApplicationName; - }); + [Fact] + public void Create_CallerTypeShouldHaveDeclaringTypeOfMiddlewareTestFactoryTest() + { + Type sut1 = GetType(); + string sut2 = null; + var middleware = MinimalHostTestFactory.Create(Assert.NotNull, host => + { + sut2 = host.Environment.ApplicationName; + }); - Assert.True(sut1 == middleware.CallerType.DeclaringType); - Assert.Equal(GetType().Assembly.GetName().Name, sut2); - } + Assert.True(sut1 == middleware.CallerType.DeclaringType); + Assert.Equal(GetType().Assembly.GetName().Name, sut2); + } - [Fact] - public void CreateWithHostBuilderContext_ShouldHaveApplicationNameEqualToThisAssembly_WithHostBuilderContext() - { - MinimalHostTestFactory.CreateWithHostBuilderContext((context, services) => - { - Assert.NotNull(context); - Assert.NotNull(context.HostingEnvironment); - Assert.NotNull(context.Configuration); - Assert.NotNull(context.Properties); - Assert.NotNull(services); - }, - host => - { - TestOutput.WriteLine(host.Environment.ApplicationName); - Assert.Equal(GetType().Assembly.GetName().Name, host.Environment.ApplicationName); - }); - } + [Fact] + public void CreateWithHostBuilderContext_ShouldHaveApplicationNameEqualToThisAssembly_WithHostBuilderContext() + { + MinimalHostTestFactory.CreateWithHostBuilderContext((context, services) => + { + Assert.NotNull(context); + Assert.NotNull(context.HostingEnvironment); + Assert.NotNull(context.Configuration); + Assert.NotNull(context.Properties); + Assert.NotNull(services); + }, + host => + { + TestOutput.WriteLine(host.Environment.ApplicationName); + Assert.Equal(GetType().Assembly.GetName().Name, host.Environment.ApplicationName); + }); } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.Tests/MinimalHostTestTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.Tests/MinimalHostTestTest.cs index d3e1acb..5778a2f 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.Tests/MinimalHostTestTest.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.Tests/MinimalHostTestTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -9,91 +9,90 @@ using Xunit; using Xunit.v3.Priority; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +[TestCaseOrderer(typeof(PriorityOrderer))] +public class MinimalHostTestTest : MinimalHostTest { - [TestCaseOrderer(typeof(PriorityOrderer))] - public class MinimalHostTestTest : MinimalHostTest - { - private bool _isHostRunning = false; - private readonly IServiceScope _scope; - private readonly Func> _correlationsFactory; - private static readonly ConcurrentBag ScopedCorrelations = new(); + private bool _isHostRunning = false; + private readonly IServiceScope _scope; + private readonly Func> _correlationsFactory; + private static readonly ConcurrentBag ScopedCorrelations = new(); - public MinimalHostTestTest(ManagedMinimalHostFixture hostFixture, ITestOutputHelper output) : base(hostFixture, output) - { - _scope = hostFixture.Host.Services.CreateScope(); - _correlationsFactory = () => _scope.ServiceProvider.GetServices().ToList(); - var lifetime = hostFixture.Host.Services.GetRequiredService(); - lifetime.ApplicationStarted.Register(() => _isHostRunning = true); - } + public MinimalHostTestTest(ManagedMinimalHostFixture hostFixture, ITestOutputHelper output) : base(hostFixture, output) + { + _scope = hostFixture.Host.Services.CreateScope(); + _correlationsFactory = () => _scope.ServiceProvider.GetServices().ToList(); + var lifetime = hostFixture.Host.Services.GetRequiredService(); + lifetime.ApplicationStarted.Register(() => _isHostRunning = true); + } - [Fact, Priority(1)] - public void Test_SingletonShouldBeSame() // simulate a request - { - ScopedCorrelations.Add(_correlationsFactory().Single(c => c is ScopedCorrelation)); - var c1 = _correlationsFactory().Single(c => c is SingletonCorrelation); - var c2 = _correlationsFactory().Single(c => c is SingletonCorrelation); - Assert.Equal(c1.CorrelationId, c2.CorrelationId); - } + [Fact, Priority(1)] + public void Test_SingletonShouldBeSame() // simulate a request + { + ScopedCorrelations.Add(_correlationsFactory().Single(c => c is ScopedCorrelation)); + var c1 = _correlationsFactory().Single(c => c is SingletonCorrelation); + var c2 = _correlationsFactory().Single(c => c is SingletonCorrelation); + Assert.Equal(c1.CorrelationId, c2.CorrelationId); + } - [Fact, Priority(2)] - public void Test_TransientShouldBeDifferent() // simulate a request - { - ScopedCorrelations.Add(_correlationsFactory().Single(c => c is ScopedCorrelation)); - var c1 = _correlationsFactory().Single(c => c is TransientCorrelation); - var c2 = _correlationsFactory().Single(c => c is TransientCorrelation); - Assert.NotEqual(c1.CorrelationId, c2.CorrelationId); - } + [Fact, Priority(2)] + public void Test_TransientShouldBeDifferent() // simulate a request + { + ScopedCorrelations.Add(_correlationsFactory().Single(c => c is ScopedCorrelation)); + var c1 = _correlationsFactory().Single(c => c is TransientCorrelation); + var c2 = _correlationsFactory().Single(c => c is TransientCorrelation); + Assert.NotEqual(c1.CorrelationId, c2.CorrelationId); + } - [Fact, Priority(3)] - public void Test_ScopedShouldBeSame() // simulate a request - { - ScopedCorrelations.Add(_correlationsFactory().Single(c => c is ScopedCorrelation)); - var c1 = _correlationsFactory().Single(c => c is ScopedCorrelation); - var c2 = _correlationsFactory().Single(c => c is ScopedCorrelation); - Assert.Equal(c1.CorrelationId, c2.CorrelationId); - } + [Fact, Priority(3)] + public void Test_ScopedShouldBeSame() // simulate a request + { + ScopedCorrelations.Add(_correlationsFactory().Single(c => c is ScopedCorrelation)); + var c1 = _correlationsFactory().Single(c => c is ScopedCorrelation); + var c2 = _correlationsFactory().Single(c => c is ScopedCorrelation); + Assert.Equal(c1.CorrelationId, c2.CorrelationId); + } - [Fact] - public void Test_ShouldHaveRunningHost() - { - Assert.True(_isHostRunning); - } + [Fact] + public void Test_ShouldHaveRunningHost() + { + Assert.True(_isHostRunning); + } - [Fact] - public void Test_ShouldHaveConfigurationEntry() - { - Assert.Equal("xUnit", Configuration.GetSection("unitTestTool").Value); - } + [Fact] + public void Test_ShouldHaveConfigurationEntry() + { + Assert.Equal("xUnit", Configuration.GetSection("unitTestTool").Value); + } - [Fact] - public void Test_ShouldHaveEnvironmentOfDevelopment() - { - Assert.Equal("Development", Environment.EnvironmentName); - } + [Fact] + public void Test_ShouldHaveEnvironmentOfDevelopment() + { + Assert.Equal("Development", Environment.EnvironmentName); + } - [Fact] - public void Test_VerifyAbstractions() - { - using var hostTest = HostTestFactory.Create(); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - Assert.IsAssignableFrom(hostTest); - } + [Fact] + public void Test_VerifyAbstractions() + { + using var hostTest = HostTestFactory.Create(); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + Assert.IsAssignableFrom(hostTest); + } - protected override void OnDisposeManagedResources() - { - _scope?.Dispose(); - } + protected override void OnDisposeManagedResources() + { + _scope?.Dispose(); + } - protected override void ConfigureHost(IHostApplicationBuilder hb) - { - hb.Services.AddSingleton(); - hb.Services.AddTransient(); - hb.Services.AddScoped(); - } + protected override void ConfigureHost(IHostApplicationBuilder hb) + { + hb.Services.AddSingleton(); + hb.Services.AddTransient(); + hb.Services.AddScoped(); } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.Tests/ServiceCollectionExtensions.cs b/test/Codebelt.Extensions.Xunit.Hosting.Tests/ServiceCollectionExtensions.cs index c05e6f9..7815cf7 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.Tests/ServiceCollectionExtensions.cs +++ b/test/Codebelt.Extensions.Xunit.Hosting.Tests/ServiceCollectionExtensions.cs @@ -1,161 +1,160 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Xunit; -namespace Codebelt.Extensions.Xunit.Hosting +namespace Codebelt.Extensions.Xunit.Hosting; + +public class ServiceCollectionExtensions : Test { - public class ServiceCollectionExtensions : Test + public ServiceCollectionExtensions(ITestOutputHelper output) : base(output) { - public ServiceCollectionExtensions(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public void AddXunitTestLogging_ShouldAddXunitTestLogging() - { - var services = new ServiceCollection(); - services.AddXunitTestLogging(); + [Fact] + public void AddXunitTestLogging_ShouldAddXunitTestLogging() + { + var services = new ServiceCollection(); + services.AddXunitTestLogging(); - var provider = services.BuildServiceProvider(); - - var logger1 = provider.GetRequiredService>(); - var loggerStore1 = logger1.GetTestStore(); - var loggerStore1Duplicate = logger1.GetTestStore(typeof(ServiceCollectionExtensions).FullName!.ToLowerInvariant()); - - var logger2 = provider.GetRequiredService>(); - var loggerStore2 = logger2.GetTestStore(null); // all loggers - - logger1.LogCritical("SUT"); - logger1.LogTrace("SUT"); - logger1.LogDebug("SUT"); - logger1.LogError("SUT"); - logger1.LogInformation("SUT"); - logger1.LogWarning("SUT"); - - logger2.LogInformation("Unique message for logger2."); - - Assert.Throws(() => logger2.GetTestStore("InvalidValue")); - - Assert.Equal(loggerStore1, loggerStore1Duplicate); - - Assert.NotNull(logger1); - Assert.NotNull(loggerStore1); - - Assert.NotNull(logger2); - Assert.NotNull(loggerStore2); - - Assert.Equal(6, loggerStore1.Query().Count()); - Assert.Equal(7, loggerStore2.Query().Count()); - - Assert.Collection(loggerStore1.Query(), - entry => Assert.Equal("Critical: SUT", entry.ToString()), - entry => Assert.Equal("Trace: SUT", entry.ToString()), - entry => Assert.Equal("Debug: SUT", entry.ToString()), - entry => Assert.Equal("Error: SUT", entry.ToString()), - entry => Assert.Equal("Information: SUT", entry.ToString()), - entry => Assert.Equal("Warning: SUT", entry.ToString())); - - Assert.Collection(loggerStore2.Query(), - entry => Assert.Equal("Critical: SUT", entry.ToString()), - entry => Assert.Equal("Trace: SUT", entry.ToString()), - entry => Assert.Equal("Debug: SUT", entry.ToString()), - entry => Assert.Equal("Error: SUT", entry.ToString()), - entry => Assert.Equal("Information: SUT", entry.ToString()), - entry => Assert.Equal("Warning: SUT", entry.ToString()), - entry => Assert.Equal("Information: Unique message for logger2.", entry.ToString())); - } - - [Fact] - public void AddXunitTestLogging_ShouldAddXunitTestLoggingWithTestOutput() - { - var services = new ServiceCollection(); - services.AddXunitTestLogging(TestOutput); - - var provider = services.BuildServiceProvider(); - - var logger1 = provider.GetRequiredService>(); - var loggerStore1 = logger1.GetTestStore(); - var loggerStore1Duplicate = logger1.GetTestStore(typeof(ServiceCollectionExtensions).FullName!.ToLowerInvariant()); - - var logger2 = provider.GetRequiredService>(); - var loggerStore2 = logger2.GetTestStore(null); // all loggers - - logger1.LogCritical("SUT"); - logger1.LogTrace("SUT"); - logger1.LogDebug("SUT"); - logger1.LogError("SUT"); - logger1.LogInformation("SUT"); - logger1.LogWarning("SUT"); - - logger2.LogInformation("Unique message for logger2."); - - Assert.Throws(() => logger2.GetTestStore("InvalidValue")); - - Assert.Equal(loggerStore1, loggerStore1Duplicate); - - Assert.NotNull(logger1); - Assert.NotNull(loggerStore1); - - Assert.NotNull(logger2); - Assert.NotNull(loggerStore2); - - Assert.Equal(6, loggerStore1.Query().Count()); - Assert.Equal(7, loggerStore2.Query().Count()); - - Assert.Collection(loggerStore1.Query(), - entry => Assert.Equal("Critical: SUT", entry.ToString()), - entry => Assert.Equal("Trace: SUT", entry.ToString()), - entry => Assert.Equal("Debug: SUT", entry.ToString()), - entry => Assert.Equal("Error: SUT", entry.ToString()), - entry => Assert.Equal("Information: SUT", entry.ToString()), - entry => Assert.Equal("Warning: SUT", entry.ToString())); - - Assert.Collection(loggerStore2.Query(), - entry => Assert.Equal("Critical: SUT", entry.ToString()), - entry => Assert.Equal("Trace: SUT", entry.ToString()), - entry => Assert.Equal("Debug: SUT", entry.ToString()), - entry => Assert.Equal("Error: SUT", entry.ToString()), - entry => Assert.Equal("Information: SUT", entry.ToString()), - entry => Assert.Equal("Warning: SUT", entry.ToString()), - entry => Assert.Equal("Information: Unique message for logger2.", entry.ToString())); - } - - [Fact] - public void AddXunitTestLogging_ShouldAddXunitTestLogging_UsingHostTest() - { - using var test = HostTestFactory.Create(services => - { - services.AddXunitTestLogging(); - }); + var provider = services.BuildServiceProvider(); + + var logger1 = provider.GetRequiredService>(); + var loggerStore1 = logger1.GetTestStore(); + var loggerStore1Duplicate = logger1.GetTestStore(typeof(ServiceCollectionExtensions).FullName!.ToLowerInvariant()); + + var logger2 = provider.GetRequiredService>(); + var loggerStore2 = logger2.GetTestStore(null); // all loggers + + logger1.LogCritical("SUT"); + logger1.LogTrace("SUT"); + logger1.LogDebug("SUT"); + logger1.LogError("SUT"); + logger1.LogInformation("SUT"); + logger1.LogWarning("SUT"); + + logger2.LogInformation("Unique message for logger2."); + + Assert.Throws(() => logger2.GetTestStore("InvalidValue")); + + Assert.Equal(loggerStore1, loggerStore1Duplicate); + + Assert.NotNull(logger1); + Assert.NotNull(loggerStore1); + + Assert.NotNull(logger2); + Assert.NotNull(loggerStore2); + + Assert.Equal(6, loggerStore1.Query().Count()); + Assert.Equal(7, loggerStore2.Query().Count()); + + Assert.Collection(loggerStore1.Query(), + entry => Assert.Equal("Critical: SUT", entry.ToString()), + entry => Assert.Equal("Trace: SUT", entry.ToString()), + entry => Assert.Equal("Debug: SUT", entry.ToString()), + entry => Assert.Equal("Error: SUT", entry.ToString()), + entry => Assert.Equal("Information: SUT", entry.ToString()), + entry => Assert.Equal("Warning: SUT", entry.ToString())); + + Assert.Collection(loggerStore2.Query(), + entry => Assert.Equal("Critical: SUT", entry.ToString()), + entry => Assert.Equal("Trace: SUT", entry.ToString()), + entry => Assert.Equal("Debug: SUT", entry.ToString()), + entry => Assert.Equal("Error: SUT", entry.ToString()), + entry => Assert.Equal("Information: SUT", entry.ToString()), + entry => Assert.Equal("Warning: SUT", entry.ToString()), + entry => Assert.Equal("Information: Unique message for logger2.", entry.ToString())); + } + + [Fact] + public void AddXunitTestLogging_ShouldAddXunitTestLoggingWithTestOutput() + { + var services = new ServiceCollection(); + services.AddXunitTestLogging(TestOutput); + + var provider = services.BuildServiceProvider(); + + var logger1 = provider.GetRequiredService>(); + var loggerStore1 = logger1.GetTestStore(); + var loggerStore1Duplicate = logger1.GetTestStore(typeof(ServiceCollectionExtensions).FullName!.ToLowerInvariant()); + + var logger2 = provider.GetRequiredService>(); + var loggerStore2 = logger2.GetTestStore(null); // all loggers + + logger1.LogCritical("SUT"); + logger1.LogTrace("SUT"); + logger1.LogDebug("SUT"); + logger1.LogError("SUT"); + logger1.LogInformation("SUT"); + logger1.LogWarning("SUT"); - var logger = test.Host.Services.GetRequiredService>(); - logger.LogInformation("Test"); + logger2.LogInformation("Unique message for logger2."); - var store = logger.GetTestStore(); + Assert.Throws(() => logger2.GetTestStore("InvalidValue")); - Assert.Equal("Information: Test", store.Query().First().Message); - } + Assert.Equal(loggerStore1, loggerStore1Duplicate); + + Assert.NotNull(logger1); + Assert.NotNull(loggerStore1); + + Assert.NotNull(logger2); + Assert.NotNull(loggerStore2); + + Assert.Equal(6, loggerStore1.Query().Count()); + Assert.Equal(7, loggerStore2.Query().Count()); - [Fact] - public void AddXunitTestLogging_ShouldAddXunitTestLogging_UsingHostTest_WithOutputToRunner() + Assert.Collection(loggerStore1.Query(), + entry => Assert.Equal("Critical: SUT", entry.ToString()), + entry => Assert.Equal("Trace: SUT", entry.ToString()), + entry => Assert.Equal("Debug: SUT", entry.ToString()), + entry => Assert.Equal("Error: SUT", entry.ToString()), + entry => Assert.Equal("Information: SUT", entry.ToString()), + entry => Assert.Equal("Warning: SUT", entry.ToString())); + + Assert.Collection(loggerStore2.Query(), + entry => Assert.Equal("Critical: SUT", entry.ToString()), + entry => Assert.Equal("Trace: SUT", entry.ToString()), + entry => Assert.Equal("Debug: SUT", entry.ToString()), + entry => Assert.Equal("Error: SUT", entry.ToString()), + entry => Assert.Equal("Information: SUT", entry.ToString()), + entry => Assert.Equal("Warning: SUT", entry.ToString()), + entry => Assert.Equal("Information: Unique message for logger2.", entry.ToString())); + } + + [Fact] + public void AddXunitTestLogging_ShouldAddXunitTestLogging_UsingHostTest() + { + using var test = HostTestFactory.Create(services => + { + services.AddXunitTestLogging(); + }); + + var logger = test.Host.Services.GetRequiredService>(); + logger.LogInformation("Test"); + + var store = logger.GetTestStore(); + + Assert.Equal("Information: Test", store.Query().First().Message); + } + + [Fact] + public void AddXunitTestLogging_ShouldAddXunitTestLogging_UsingHostTest_WithOutputToRunner() + { + using var test = HostTestFactory.Create(services => { - using var test = HostTestFactory.Create(services => - { - services.AddXunitTestLoggingOutputHelperAccessor(); - services.AddXunitTestLogging(); - }); + services.AddXunitTestLoggingOutputHelperAccessor(); + services.AddXunitTestLogging(); + }); - test.Host.Services.GetRequiredService().TestOutput = TestOutput; - - var logger = test.Host.Services.GetRequiredService>(); - logger.LogInformation("Test"); + test.Host.Services.GetRequiredService().TestOutput = TestOutput; + + var logger = test.Host.Services.GetRequiredService>(); + logger.LogInformation("Test"); - var store = logger.GetTestStore(); + var store = logger.GetTestStore(); - Assert.Equal("Information: Test", store.Query().First().Message); - } + Assert.Equal("Information: Test", store.Query().First().Message); } } diff --git a/test/Codebelt.Extensions.Xunit.Tests/Assets/AsyncDisposable.cs b/test/Codebelt.Extensions.Xunit.Tests/Assets/AsyncDisposable.cs index 6adddb0..90b4961 100644 --- a/test/Codebelt.Extensions.Xunit.Tests/Assets/AsyncDisposable.cs +++ b/test/Codebelt.Extensions.Xunit.Tests/Assets/AsyncDisposable.cs @@ -1,38 +1,37 @@ -using System; +using System; using System.IO; using System.Threading.Tasks; -namespace Codebelt.Extensions.Xunit.Assets +namespace Codebelt.Extensions.Xunit.Assets; + +public class AsyncDisposable : Test { - public class AsyncDisposable : Test - { - IDisposable _disposableResource = new MemoryStream(); + IDisposable _disposableResource = new MemoryStream(); #if NET8_0_OR_GREATER - IAsyncDisposable _asyncDisposableResource = new MemoryStream(); + IAsyncDisposable _asyncDisposableResource = new MemoryStream(); #else - IAsyncDisposable _asyncDisposableResource = new WemoryStream(); + IAsyncDisposable _asyncDisposableResource = new WemoryStream(); #endif - protected override void OnDisposeManagedResources() - { - _disposableResource?.Dispose(); - _disposableResource = null; - DisposableResourceCalled = true; - } + protected override void OnDisposeManagedResources() + { + _disposableResource?.Dispose(); + _disposableResource = null; + DisposableResourceCalled = true; + } - public bool DisposableResourceCalled { get; private set; } + public bool DisposableResourceCalled { get; private set; } - protected override async ValueTask OnDisposeManagedResourcesAsync() + protected override async ValueTask OnDisposeManagedResourcesAsync() + { + if (_asyncDisposableResource is not null) { - if (_asyncDisposableResource is not null) - { - await _asyncDisposableResource.DisposeAsync().ConfigureAwait(false); - AsyncDisposableResourceCalled = true; - } - _asyncDisposableResource = null; - OnDisposeManagedResources(); + await _asyncDisposableResource.DisposeAsync().ConfigureAwait(false); + AsyncDisposableResourceCalled = true; } - - public bool AsyncDisposableResourceCalled { get; private set; } + _asyncDisposableResource = null; + OnDisposeManagedResources(); } + + public bool AsyncDisposableResourceCalled { get; private set; } } diff --git a/test/Codebelt.Extensions.Xunit.Tests/Assets/ManagedDisposable.cs b/test/Codebelt.Extensions.Xunit.Tests/Assets/ManagedDisposable.cs index 9720eeb..37dfd45 100644 --- a/test/Codebelt.Extensions.Xunit.Tests/Assets/ManagedDisposable.cs +++ b/test/Codebelt.Extensions.Xunit.Tests/Assets/ManagedDisposable.cs @@ -1,26 +1,25 @@ -using System.IO; +using System.IO; -namespace Codebelt.Extensions.Xunit.Assets +namespace Codebelt.Extensions.Xunit.Assets; + +public class ManagedDisposable : Test { - public class ManagedDisposable : Test + public ManagedDisposable() { - public ManagedDisposable() - { - Stream = new MemoryStream(); - } + Stream = new MemoryStream(); + } - public MemoryStream Stream { get; private set; } + public MemoryStream Stream { get; private set; } - protected override void OnDisposeManagedResources() + protected override void OnDisposeManagedResources() + { + try + { + Stream?.Dispose(); + } + finally { - try - { - Stream?.Dispose(); - } - finally - { - Stream = null; - } + Stream = null; } } } diff --git a/test/Codebelt.Extensions.Xunit.Tests/Assets/UnmanagedDisposable.cs b/test/Codebelt.Extensions.Xunit.Tests/Assets/UnmanagedDisposable.cs index 6a9201b..ff14b66 100644 --- a/test/Codebelt.Extensions.Xunit.Tests/Assets/UnmanagedDisposable.cs +++ b/test/Codebelt.Extensions.Xunit.Tests/Assets/UnmanagedDisposable.cs @@ -1,127 +1,126 @@ -using System; +using System; using System.Runtime.InteropServices; #if NET48_OR_GREATER using NativeLibraryLoader; #endif -namespace Codebelt.Extensions.Xunit.Assets +namespace Codebelt.Extensions.Xunit.Assets; + +public class UnmanagedDisposable : Test { - public class UnmanagedDisposable : Test - { - internal IntPtr _handle = IntPtr.Zero; - internal IntPtr _libHandle = IntPtr.Zero; + internal IntPtr _handle = IntPtr.Zero; + internal IntPtr _libHandle = IntPtr.Zero; - public delegate bool CloseHandle(IntPtr hObject); + public delegate bool CloseHandle(IntPtr hObject); - public delegate IntPtr CreateFileDelegate(string lpFileName, - uint dwDesiredAccess, - uint dwShareMode, - IntPtr lpSecurityAttributes, - uint dwCreationDisposition, - uint dwFlagsAndAttributes, - IntPtr hTemplateFile); + public delegate IntPtr CreateFileDelegate(string lpFileName, + uint dwDesiredAccess, + uint dwShareMode, + IntPtr lpSecurityAttributes, + uint dwCreationDisposition, + uint dwFlagsAndAttributes, + IntPtr hTemplateFile); - public delegate IntPtr PtSname(int fd); + public delegate IntPtr PtSname(int fd); #if NET48_OR_GREATER - internal NativeLibrary _nativeLibrary; + internal NativeLibrary _nativeLibrary; #endif - public UnmanagedDisposable() - { + public UnmanagedDisposable() + { #if NET8_0_OR_GREATER - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - if (NativeLibrary.TryLoad("kernel32.dll", GetType().Assembly, DllImportSearchPath.System32, out _libHandle)) - { - if (NativeLibrary.TryGetExport(_libHandle, "CreateFileW", out var functionHandle)) - { - var createFileFunc = Marshal.GetDelegateForFunctionPointer(functionHandle); - _handle = createFileFunc(@"C:\TestFile.txt", - 0x80000000, //access read-only - 1, //share-read - IntPtr.Zero, - 3, //open existing - 0, - IntPtr.Zero); - } - } - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + if (NativeLibrary.TryLoad("kernel32.dll", GetType().Assembly, DllImportSearchPath.System32, out _libHandle)) { - if (NativeLibrary.TryLoad("libc.so.6", GetType().Assembly, DllImportSearchPath.SafeDirectories, out _libHandle)) + if (NativeLibrary.TryGetExport(_libHandle, "CreateFileW", out var functionHandle)) { - _handle = _libHandle; // i don't know of any native methods on unix + var createFileFunc = Marshal.GetDelegateForFunctionPointer(functionHandle); + _handle = createFileFunc(@"C:\TestFile.txt", + 0x80000000, //access read-only + 1, //share-read + IntPtr.Zero, + 3, //open existing + 0, + IntPtr.Zero); } } -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - _nativeLibrary = new NativeLibrary("kernel32.dll"); - _libHandle = _nativeLibrary.Handle; - var functionHandle = _nativeLibrary.LoadFunction("CreateFileW"); - var createFileFunc = Marshal.GetDelegateForFunctionPointer(functionHandle); - _handle = createFileFunc(@"C:\TestFile.txt", - 0x80000000, //access read-only - 1, //share-read - IntPtr.Zero, - 3, //open existing - 0, - IntPtr.Zero); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + if (NativeLibrary.TryLoad("libc.so.6", GetType().Assembly, DllImportSearchPath.SafeDirectories, out _libHandle)) { - _nativeLibrary = new NativeLibrary("libc.so.6"); - _libHandle = _nativeLibrary.Handle; _handle = _libHandle; // i don't know of any native methods on unix } -#endif } - - ~UnmanagedDisposable() +#else + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - Dispose(false); + _nativeLibrary = new NativeLibrary("kernel32.dll"); + _libHandle = _nativeLibrary.Handle; + var functionHandle = _nativeLibrary.LoadFunction("CreateFileW"); + var createFileFunc = Marshal.GetDelegateForFunctionPointer(functionHandle); + _handle = createFileFunc(@"C:\TestFile.txt", + 0x80000000, //access read-only + 1, //share-read + IntPtr.Zero, + 3, //open existing + 0, + IntPtr.Zero); } - - protected override void OnDisposeManagedResources() + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { - + _nativeLibrary = new NativeLibrary("libc.so.6"); + _libHandle = _nativeLibrary.Handle; + _handle = _libHandle; // i don't know of any native methods on unix } +#endif + } - protected override void OnDisposeUnmanagedResources() - { + ~UnmanagedDisposable() + { + Dispose(false); + } + + protected override void OnDisposeManagedResources() + { + + } + + protected override void OnDisposeUnmanagedResources() + { #if NET8_0_OR_GREATER - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - if (_handle != IntPtr.Zero) - { - if (NativeLibrary.TryGetExport(_libHandle, "CloseHandle", out var closeHandle)) - { - var closeHandleAction = Marshal.GetDelegateForFunctionPointer(closeHandle); - closeHandleAction(_handle); - } - } - NativeLibrary.Free(_libHandle); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - NativeLibrary.Free(_libHandle); - } -#else - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + if (_handle != IntPtr.Zero) { - if (_handle != IntPtr.Zero) + if (NativeLibrary.TryGetExport(_libHandle, "CloseHandle", out var closeHandle)) { - var closeHandle = _nativeLibrary.LoadFunction("CloseHandle"); var closeHandleAction = Marshal.GetDelegateForFunctionPointer(closeHandle); closeHandleAction(_handle); } - _nativeLibrary.Dispose(); } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + NativeLibrary.Free(_libHandle); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + NativeLibrary.Free(_libHandle); + } +#else + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + if (_handle != IntPtr.Zero) { - _nativeLibrary.Dispose(); + var closeHandle = _nativeLibrary.LoadFunction("CloseHandle"); + var closeHandleAction = Marshal.GetDelegateForFunctionPointer(closeHandle); + closeHandleAction(_handle); } -#endif + _nativeLibrary.Dispose(); } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + _nativeLibrary.Dispose(); + } +#endif } } diff --git a/test/Codebelt.Extensions.Xunit.Tests/Assets/WemoryStream.cs b/test/Codebelt.Extensions.Xunit.Tests/Assets/WemoryStream.cs index eb02c50..c98a203 100644 --- a/test/Codebelt.Extensions.Xunit.Tests/Assets/WemoryStream.cs +++ b/test/Codebelt.Extensions.Xunit.Tests/Assets/WemoryStream.cs @@ -1,20 +1,19 @@ -using System; +using System; using System.IO; using System.Threading.Tasks; -namespace Codebelt.Extensions.Xunit.Assets +namespace Codebelt.Extensions.Xunit.Assets; + +public class WemoryStream : MemoryStream, IAsyncDisposable { - public class WemoryStream : MemoryStream, IAsyncDisposable + protected virtual async ValueTask DisposeAsyncCore() { - protected virtual async ValueTask DisposeAsyncCore() - { - Dispose(false); - } + Dispose(false); + } - public async ValueTask DisposeAsync() - { - await DisposeAsyncCore(); - GC.SuppressFinalize(this); - } + public async ValueTask DisposeAsync() + { + await DisposeAsyncCore(); + GC.SuppressFinalize(this); } } diff --git a/test/Codebelt.Extensions.Xunit.Tests/DisposableTest.cs b/test/Codebelt.Extensions.Xunit.Tests/DisposableTest.cs index f531e06..2481f1b 100644 --- a/test/Codebelt.Extensions.Xunit.Tests/DisposableTest.cs +++ b/test/Codebelt.Extensions.Xunit.Tests/DisposableTest.cs @@ -1,94 +1,93 @@ -using System; +using System; using System.Threading.Tasks; using Codebelt.Extensions.Xunit.Assets; using Xunit; -namespace Codebelt.Extensions.Xunit +namespace Codebelt.Extensions.Xunit; + +public class DisposableTest : Test { - public class DisposableTest : Test + public DisposableTest(ITestOutputHelper output) : base(output) { - public DisposableTest(ITestOutputHelper output) : base(output) - { - } + } #if NET8_0_OR_GREATER - [Fact] - public async Task AsyncDisposable_VerifyThatAssetIsBeingDisposed() + [Fact] + public async Task AsyncDisposable_VerifyThatAssetIsBeingDisposed() + { + AsyncDisposable ad = new AsyncDisposable(); + await using (ad.ConfigureAwait(false)) { - AsyncDisposable ad = new AsyncDisposable(); - await using (ad.ConfigureAwait(false)) - { - Assert.NotNull(ad); - Assert.False(ad.DisposableResourceCalled); - Assert.False(ad.AsyncDisposableResourceCalled); - } - Assert.NotNull(ad); - Assert.True(ad.DisposableResourceCalled); - Assert.True(ad.AsyncDisposableResourceCalled); + Assert.False(ad.DisposableResourceCalled); + Assert.False(ad.AsyncDisposableResourceCalled); } + + Assert.NotNull(ad); + Assert.True(ad.DisposableResourceCalled); + Assert.True(ad.AsyncDisposableResourceCalled); + } #else - [Fact] - public async Task AsyncDisposable_VerifyThatAssetIsBeingDisposed() - { - AsyncDisposable ad = new AsyncDisposable(); + [Fact] + public async Task AsyncDisposable_VerifyThatAssetIsBeingDisposed() + { + AsyncDisposable ad = new AsyncDisposable(); - Assert.NotNull(ad); - Assert.False(ad.DisposableResourceCalled); - Assert.False(ad.AsyncDisposableResourceCalled); + Assert.NotNull(ad); + Assert.False(ad.DisposableResourceCalled); + Assert.False(ad.AsyncDisposableResourceCalled); - await ad.DisposeAsync().ConfigureAwait(false); + await ad.DisposeAsync().ConfigureAwait(false); - Assert.NotNull(ad); - Assert.True(ad.DisposableResourceCalled); - Assert.True(ad.AsyncDisposableResourceCalled); - } + Assert.NotNull(ad); + Assert.True(ad.DisposableResourceCalled); + Assert.True(ad.AsyncDisposableResourceCalled); + } #endif - [Fact] - public void ManagedDisposable_VerifyThatAssetIsBeingDisposed() + [Fact] + public void ManagedDisposable_VerifyThatAssetIsBeingDisposed() + { + ManagedDisposable mdRef = null; + using (var md = new ManagedDisposable()) { - ManagedDisposable mdRef = null; - using (var md = new ManagedDisposable()) - { - mdRef = md; - Assert.NotNull(md.Stream); - Assert.Equal(0, md.Stream.Length); - Assert.False(mdRef.Disposed); - } - Assert.NotNull(mdRef); - Assert.Null(mdRef.Stream); - Assert.True(mdRef.Disposed); + mdRef = md; + Assert.NotNull(md.Stream); + Assert.Equal(0, md.Stream.Length); + Assert.False(mdRef.Disposed); } + Assert.NotNull(mdRef); + Assert.Null(mdRef.Stream); + Assert.True(mdRef.Disposed); + } - private WeakReference unmanaged = null; + private WeakReference unmanaged = null; - [Fact] - public void UnmanagedDisposable_VerifyThatAssetIsBeingDisposedOnFinalize() + [Fact] + public void UnmanagedDisposable_VerifyThatAssetIsBeingDisposedOnFinalize() + { + Action body = () => { - Action body = () => - { - var o = new UnmanagedDisposable(); - Assert.NotEqual(IntPtr.Zero, o._libHandle); - Assert.NotEqual(IntPtr.Zero, o._handle); - unmanaged = new WeakReference(o, true); - }; + var o = new UnmanagedDisposable(); + Assert.NotEqual(IntPtr.Zero, o._libHandle); + Assert.NotEqual(IntPtr.Zero, o._handle); + unmanaged = new WeakReference(o, true); + }; - try - { - body(); - } - finally - { - GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); - GC.WaitForPendingFinalizers(); - Task.Delay(500).Wait(); // Add a small delay - } + try + { + body(); + } + finally + { + GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); + GC.WaitForPendingFinalizers(); + Task.Delay(500).Wait(); // Add a small delay + } - if (unmanaged.TryGetTarget(out var ud2)) - { - Assert.True(ud2.Disposed); - } + if (unmanaged.TryGetTarget(out var ud2)) + { + Assert.True(ud2.Disposed); } } } diff --git a/test/Codebelt.Extensions.Xunit.Tests/InMemoryTestStoreTest.cs b/test/Codebelt.Extensions.Xunit.Tests/InMemoryTestStoreTest.cs index 12d64bc..d45115c 100644 --- a/test/Codebelt.Extensions.Xunit.Tests/InMemoryTestStoreTest.cs +++ b/test/Codebelt.Extensions.Xunit.Tests/InMemoryTestStoreTest.cs @@ -1,305 +1,304 @@ using System.Linq; using Xunit; -namespace Codebelt.Extensions.Xunit +namespace Codebelt.Extensions.Xunit; + +/// +/// Tests for the class. +/// +public class InMemoryTestStoreTest : Test { - /// - /// Tests for the class. - /// - public class InMemoryTestStoreTest : Test + public InMemoryTestStoreTest(ITestOutputHelper output) : base(output) + { + } + + [Fact] + public void Constructor_ShouldInitializeEmptyStore() + { + var sut = new InMemoryTestStore(); + + Assert.Equal(0, sut.Count); + } + + [Fact] + public void Add_ShouldAddItemToStore() + { + var sut = new InMemoryTestStore(); + + sut.Add("test"); + + Assert.Equal(1, sut.Count); + } + + [Fact] + public void Add_ShouldAddMultipleItems() + { + var sut = new InMemoryTestStore(); + + sut.Add("first"); + sut.Add("second"); + sut.Add("third"); + + Assert.Equal(3, sut.Count); + } + + [Fact] + public void Add_ShouldAllowDuplicateItems() + { + var sut = new InMemoryTestStore(); + + sut.Add("duplicate"); + sut.Add("duplicate"); + + Assert.Equal(2, sut.Count); + } + + [Fact] + public void Add_ShouldAllowNullValues() + { + var sut = new InMemoryTestStore(); + + sut.Add(null); + + Assert.Equal(1, sut.Count); + } + + [Fact] + public void Count_ShouldReturnZero_WhenStoreIsEmpty() + { + var sut = new InMemoryTestStore(); + + Assert.Equal(0, sut.Count); + } + + [Fact] + public void Count_ShouldReturnCorrectNumber_AfterAddingItems() + { + var sut = new InMemoryTestStore(); + + sut.Add(1); + sut.Add(2); + sut.Add(3); + + Assert.Equal(3, sut.Count); + } + + [Fact] + public void Query_ShouldReturnAllItems_WhenPredicateIsNull() + { + var sut = new InMemoryTestStore(); + sut.Add("alpha"); + sut.Add("beta"); + sut.Add("gamma"); + + var result = sut.Query(null); + + Assert.Equal(3, result.Count()); + Assert.Contains("alpha", result); + Assert.Contains("beta", result); + Assert.Contains("gamma", result); + } + + [Fact] + public void Query_ShouldReturnAllItems_WhenNoPredicateProvided() + { + var sut = new InMemoryTestStore(); + sut.Add("one"); + sut.Add("two"); + + var result = sut.Query(); + + Assert.Equal(2, result.Count()); + } + + [Fact] + public void Query_ShouldReturnFilteredItems_WhenPredicateProvided() + { + var sut = new InMemoryTestStore(); + sut.Add(1); + sut.Add(2); + sut.Add(3); + sut.Add(4); + sut.Add(5); + + var result = sut.Query(x => x > 3); + + Assert.Equal(2, result.Count()); + Assert.Contains(4, result); + Assert.Contains(5, result); + } + + [Fact] + public void Query_ShouldReturnEmptySequence_WhenNoItemsMatchPredicate() + { + var sut = new InMemoryTestStore(); + sut.Add("cat"); + sut.Add("dog"); + + var result = sut.Query(x => x.StartsWith("z")); + + Assert.Empty(result); + } + + [Fact] + public void Query_ShouldReturnEmptySequence_WhenStoreIsEmpty() + { + var sut = new InMemoryTestStore(); + + var result = sut.Query(x => x.Length > 5); + + Assert.Empty(result); + } + + [Fact] + public void Query_ShouldSupportComplexPredicates() + { + var sut = new InMemoryTestStore(); + sut.Add("apple"); + sut.Add("apricot"); + sut.Add("banana"); + sut.Add("avocado"); + + var result = sut.Query(x => x.StartsWith("a") && x.Length > 5); + + Assert.Equal(2, result.Count()); + Assert.Contains("apricot", result); + Assert.Contains("avocado", result); + } + + [Fact] + public void QueryFor_ShouldReturnOnlyMatchingType() + { + var sut = new InMemoryTestStore(); + sut.Add(new Dog { Name = "Buddy" }); + sut.Add(new Cat { Name = "Whiskers" }); + sut.Add(new Dog { Name = "Max" }); + + var dogs = sut.QueryFor(); + + Assert.Equal(2, dogs.Count()); + Assert.All(dogs, dog => Assert.IsType(dog)); + } + + [Fact] + public void QueryFor_ShouldReturnEmptySequence_WhenNoMatchingType() + { + var sut = new InMemoryTestStore(); + sut.Add(new Dog { Name = "Buddy" }); + sut.Add(new Dog { Name = "Max" }); + + var cats = sut.QueryFor(); + + Assert.Empty(cats); + } + + [Fact] + public void QueryFor_ShouldReturnEmptySequence_WhenStoreIsEmpty() + { + var sut = new InMemoryTestStore(); + + var dogs = sut.QueryFor(); + + Assert.Empty(dogs); + } + + [Fact] + public void QueryFor_ShouldNotReturnDerivedTypes() + { + var sut = new InMemoryTestStore(); + sut.Add(new Dog { Name = "Buddy" }); + sut.Add(new ServiceDog { Name = "Guide", Task = "Assistance" }); + + var dogs = sut.QueryFor(); + + Assert.Single(dogs); + Assert.Equal("Buddy", dogs.First().Name); + } + + [Fact] + public void QueryFor_ShouldWorkWithMultipleTypes() + { + var sut = new InMemoryTestStore(); + sut.Add(new Dog { Name = "Buddy" }); + sut.Add(new Cat { Name = "Whiskers" }); + sut.Add(new Dog { Name = "Max" }); + sut.Add(new Cat { Name = "Fluffy" }); + + var dogs = sut.QueryFor(); + var cats = sut.QueryFor(); + + Assert.Equal(2, dogs.Count()); + Assert.Equal(2, cats.Count()); + } + + [Fact] + public void InMemoryTestStore_ShouldWorkWithReferenceTypes() { - public InMemoryTestStoreTest(ITestOutputHelper output) : base(output) - { - } + var sut = new InMemoryTestStore(); + var entity1 = new TestEntity { Id = 1, Name = "First" }; + var entity2 = new TestEntity { Id = 2, Name = "Second" }; + + sut.Add(entity1); + sut.Add(entity2); - [Fact] - public void Constructor_ShouldInitializeEmptyStore() - { - var sut = new InMemoryTestStore(); - - Assert.Equal(0, sut.Count); - } - - [Fact] - public void Add_ShouldAddItemToStore() - { - var sut = new InMemoryTestStore(); - - sut.Add("test"); - - Assert.Equal(1, sut.Count); - } - - [Fact] - public void Add_ShouldAddMultipleItems() - { - var sut = new InMemoryTestStore(); - - sut.Add("first"); - sut.Add("second"); - sut.Add("third"); - - Assert.Equal(3, sut.Count); - } - - [Fact] - public void Add_ShouldAllowDuplicateItems() - { - var sut = new InMemoryTestStore(); + var result = sut.Query(e => e.Id == 1); + + Assert.Single(result); + Assert.Equal("First", result.First().Name); + } + + [Fact] + public void InMemoryTestStore_ShouldWorkWithValueTypes() + { + var sut = new InMemoryTestStore(); - sut.Add("duplicate"); - sut.Add("duplicate"); + sut.Add(10); + sut.Add(20); + sut.Add(30); - Assert.Equal(2, sut.Count); - } - - [Fact] - public void Add_ShouldAllowNullValues() - { - var sut = new InMemoryTestStore(); - - sut.Add(null); - - Assert.Equal(1, sut.Count); - } - - [Fact] - public void Count_ShouldReturnZero_WhenStoreIsEmpty() - { - var sut = new InMemoryTestStore(); - - Assert.Equal(0, sut.Count); - } - - [Fact] - public void Count_ShouldReturnCorrectNumber_AfterAddingItems() - { - var sut = new InMemoryTestStore(); - - sut.Add(1); - sut.Add(2); - sut.Add(3); - - Assert.Equal(3, sut.Count); - } - - [Fact] - public void Query_ShouldReturnAllItems_WhenPredicateIsNull() - { - var sut = new InMemoryTestStore(); - sut.Add("alpha"); - sut.Add("beta"); - sut.Add("gamma"); - - var result = sut.Query(null); - - Assert.Equal(3, result.Count()); - Assert.Contains("alpha", result); - Assert.Contains("beta", result); - Assert.Contains("gamma", result); - } - - [Fact] - public void Query_ShouldReturnAllItems_WhenNoPredicateProvided() - { - var sut = new InMemoryTestStore(); - sut.Add("one"); - sut.Add("two"); - - var result = sut.Query(); - - Assert.Equal(2, result.Count()); - } - - [Fact] - public void Query_ShouldReturnFilteredItems_WhenPredicateProvided() - { - var sut = new InMemoryTestStore(); - sut.Add(1); - sut.Add(2); - sut.Add(3); - sut.Add(4); - sut.Add(5); - - var result = sut.Query(x => x > 3); - - Assert.Equal(2, result.Count()); - Assert.Contains(4, result); - Assert.Contains(5, result); - } - - [Fact] - public void Query_ShouldReturnEmptySequence_WhenNoItemsMatchPredicate() - { - var sut = new InMemoryTestStore(); - sut.Add("cat"); - sut.Add("dog"); - - var result = sut.Query(x => x.StartsWith("z")); - - Assert.Empty(result); - } - - [Fact] - public void Query_ShouldReturnEmptySequence_WhenStoreIsEmpty() - { - var sut = new InMemoryTestStore(); - - var result = sut.Query(x => x.Length > 5); - - Assert.Empty(result); - } - - [Fact] - public void Query_ShouldSupportComplexPredicates() - { - var sut = new InMemoryTestStore(); - sut.Add("apple"); - sut.Add("apricot"); - sut.Add("banana"); - sut.Add("avocado"); - - var result = sut.Query(x => x.StartsWith("a") && x.Length > 5); - - Assert.Equal(2, result.Count()); - Assert.Contains("apricot", result); - Assert.Contains("avocado", result); - } - - [Fact] - public void QueryFor_ShouldReturnOnlyMatchingType() - { - var sut = new InMemoryTestStore(); - sut.Add(new Dog { Name = "Buddy" }); - sut.Add(new Cat { Name = "Whiskers" }); - sut.Add(new Dog { Name = "Max" }); - - var dogs = sut.QueryFor(); - - Assert.Equal(2, dogs.Count()); - Assert.All(dogs, dog => Assert.IsType(dog)); - } - - [Fact] - public void QueryFor_ShouldReturnEmptySequence_WhenNoMatchingType() - { - var sut = new InMemoryTestStore(); - sut.Add(new Dog { Name = "Buddy" }); - sut.Add(new Dog { Name = "Max" }); - - var cats = sut.QueryFor(); - - Assert.Empty(cats); - } - - [Fact] - public void QueryFor_ShouldReturnEmptySequence_WhenStoreIsEmpty() - { - var sut = new InMemoryTestStore(); - - var dogs = sut.QueryFor(); - - Assert.Empty(dogs); - } - - [Fact] - public void QueryFor_ShouldNotReturnDerivedTypes() - { - var sut = new InMemoryTestStore(); - sut.Add(new Dog { Name = "Buddy" }); - sut.Add(new ServiceDog { Name = "Guide", Task = "Assistance" }); - - var dogs = sut.QueryFor(); - - Assert.Single(dogs); - Assert.Equal("Buddy", dogs.First().Name); - } - - [Fact] - public void QueryFor_ShouldWorkWithMultipleTypes() - { - var sut = new InMemoryTestStore(); - sut.Add(new Dog { Name = "Buddy" }); - sut.Add(new Cat { Name = "Whiskers" }); - sut.Add(new Dog { Name = "Max" }); - sut.Add(new Cat { Name = "Fluffy" }); - - var dogs = sut.QueryFor(); - var cats = sut.QueryFor(); - - Assert.Equal(2, dogs.Count()); - Assert.Equal(2, cats.Count()); - } - - [Fact] - public void InMemoryTestStore_ShouldWorkWithReferenceTypes() - { - var sut = new InMemoryTestStore(); - var entity1 = new TestEntity { Id = 1, Name = "First" }; - var entity2 = new TestEntity { Id = 2, Name = "Second" }; - - sut.Add(entity1); - sut.Add(entity2); - - var result = sut.Query(e => e.Id == 1); - - Assert.Single(result); - Assert.Equal("First", result.First().Name); - } - - [Fact] - public void InMemoryTestStore_ShouldWorkWithValueTypes() - { - var sut = new InMemoryTestStore(); - - sut.Add(10); - sut.Add(20); - sut.Add(30); - - var result = sut.Query(x => x >= 20); - - Assert.Equal(2, result.Count()); - } - - [Fact] - public void InMemoryTestStore_ShouldMaintainInsertionOrder() - { - var sut = new InMemoryTestStore(); - - sut.Add("first"); - sut.Add("second"); - sut.Add("third"); - - var result = sut.Query().ToList(); - - Assert.Equal("first", result[0]); - Assert.Equal("second", result[1]); - Assert.Equal("third", result[2]); - } - - // Test helper classes - private abstract class Animal - { - public string Name { get; set; } - } - - private class Dog : Animal - { - } + var result = sut.Query(x => x >= 20); - private class ServiceDog : Dog - { - public string Task { get; set; } - } - - private class Cat : Animal - { - } - - private class TestEntity - { - public int Id { get; set; } - public string Name { get; set; } - } + Assert.Equal(2, result.Count()); + } + + [Fact] + public void InMemoryTestStore_ShouldMaintainInsertionOrder() + { + var sut = new InMemoryTestStore(); + + sut.Add("first"); + sut.Add("second"); + sut.Add("third"); + + var result = sut.Query().ToList(); + + Assert.Equal("first", result[0]); + Assert.Equal("second", result[1]); + Assert.Equal("third", result[2]); + } + + // Test helper classes + private abstract class Animal + { + public string Name { get; set; } + } + + private class Dog : Animal + { + } + + private class ServiceDog : Dog + { + public string Task { get; set; } + } + + private class Cat : Animal + { + } + + private class TestEntity + { + public int Id { get; set; } + public string Name { get; set; } } } diff --git a/test/Codebelt.Extensions.Xunit.Tests/StringExtensionsTest.cs b/test/Codebelt.Extensions.Xunit.Tests/StringExtensionsTest.cs index 89de10f..96d9f31 100644 --- a/test/Codebelt.Extensions.Xunit.Tests/StringExtensionsTest.cs +++ b/test/Codebelt.Extensions.Xunit.Tests/StringExtensionsTest.cs @@ -1,35 +1,34 @@ -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; using Xunit; -namespace Codebelt.Extensions.Xunit +namespace Codebelt.Extensions.Xunit; + +public class StringExtensionsTest : Test { - public class StringExtensionsTest : Test + public StringExtensionsTest(ITestOutputHelper output) : base(output) { - public StringExtensionsTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public void ReplaceLineEndings_ShouldReplaceNewLineOccurrences() - { - var lineEndings = "Windows has \r\n (CRLF) and Linux has \n (LF)"; + [Fact] + public void ReplaceLineEndings_ShouldReplaceNewLineOccurrences() + { + var lineEndings = "Windows has \r\n (CRLF) and Linux has \n (LF)"; - TestOutput.WriteLine($$""" - Before: {{lineEndings}} - After: {{lineEndings.ReplaceLineEndings()}} - """); + TestOutput.WriteLine($$""" + Before: {{lineEndings}} + After: {{lineEndings.ReplaceLineEndings()}} + """); - TestOutput.WriteLine(RuntimeInformation.OSDescription); - TestOutput.WriteLine(RuntimeInformation.FrameworkDescription); + TestOutput.WriteLine(RuntimeInformation.OSDescription); + TestOutput.WriteLine(RuntimeInformation.FrameworkDescription); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - Assert.Equal("Windows has \n (CRLF) and Linux has \n (LF)", lineEndings.ReplaceLineEndings()); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - Assert.Equal("Windows has \r\n (CRLF) and Linux has \r\n (LF)", lineEndings.ReplaceLineEndings()); - } + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + Assert.Equal("Windows has \n (CRLF) and Linux has \n (LF)", lineEndings.ReplaceLineEndings()); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + Assert.Equal("Windows has \r\n (CRLF) and Linux has \r\n (LF)", lineEndings.ReplaceLineEndings()); } } } diff --git a/test/Codebelt.Extensions.Xunit.Tests/TestOutputHelperExtensionsTest.cs b/test/Codebelt.Extensions.Xunit.Tests/TestOutputHelperExtensionsTest.cs index 8ba2f90..e7105ca 100644 --- a/test/Codebelt.Extensions.Xunit.Tests/TestOutputHelperExtensionsTest.cs +++ b/test/Codebelt.Extensions.Xunit.Tests/TestOutputHelperExtensionsTest.cs @@ -3,249 +3,248 @@ using System.Text; using Xunit; -namespace Codebelt.Extensions.Xunit +namespace Codebelt.Extensions.Xunit; + +public class TestOutputHelperExtensionsTest : Test { - public class TestOutputHelperExtensionsTest : Test + public TestOutputHelperExtensionsTest(ITestOutputHelper output) : base(output) { - public TestOutputHelperExtensionsTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public void WriteLines_WithParamsObjects_ShouldWriteMultipleLines() - { - var helper = new FakeTestOutputHelper(); - var values = new object[] { "Line1", "Line2", "Line3" }; + [Fact] + public void WriteLines_WithParamsObjects_ShouldWriteMultipleLines() + { + var helper = new FakeTestOutputHelper(); + var values = new object[] { "Line1", "Line2", "Line3" }; - helper.WriteLines(values); + helper.WriteLines(values); - var expected = $"Line1{Environment.NewLine}Line2{Environment.NewLine}Line3"; - Assert.Equal(expected, helper.Output); - } + var expected = $"Line1{Environment.NewLine}Line2{Environment.NewLine}Line3"; + Assert.Equal(expected, helper.Output); + } - [Fact] - public void WriteLines_WithParamsObjects_NullHelper_ShouldThrowArgumentNullException() - { - ITestOutputHelper helper = null; + [Fact] + public void WriteLines_WithParamsObjects_NullHelper_ShouldThrowArgumentNullException() + { + ITestOutputHelper helper = null; - var exception = Assert.Throws(() => helper.WriteLines(new object[] { "test" })); + var exception = Assert.Throws(() => helper.WriteLines(new object[] { "test" })); - Assert.Equal("helper", exception.ParamName); - } + Assert.Equal("helper", exception.ParamName); + } - [Fact] - public void WriteLines_WithTypedArray_ShouldWriteMultipleLines() - { - var helper = new FakeTestOutputHelper(); - var values = new[] { 1, 2, 3 }; + [Fact] + public void WriteLines_WithTypedArray_ShouldWriteMultipleLines() + { + var helper = new FakeTestOutputHelper(); + var values = new[] { 1, 2, 3 }; - helper.WriteLines(values); + helper.WriteLines(values); - var expected = $"1{Environment.NewLine}2{Environment.NewLine}3"; - Assert.Equal(expected, helper.Output); - } + var expected = $"1{Environment.NewLine}2{Environment.NewLine}3"; + Assert.Equal(expected, helper.Output); + } - [Fact] - public void WriteLines_WithTypedArray_NullHelper_ShouldThrowArgumentNullException() - { - ITestOutputHelper helper = null; - var values = new[] { 1, 2, 3 }; + [Fact] + public void WriteLines_WithTypedArray_NullHelper_ShouldThrowArgumentNullException() + { + ITestOutputHelper helper = null; + var values = new[] { 1, 2, 3 }; - var exception = Assert.Throws(() => helper.WriteLines(values)); + var exception = Assert.Throws(() => helper.WriteLines(values)); - Assert.Equal("helper", exception.ParamName); - } + Assert.Equal("helper", exception.ParamName); + } - [Fact] - public void WriteLines_WithEnumerable_ShouldWriteMultipleLines() - { - var helper = new FakeTestOutputHelper(); - var values = new List { "First", "Second", "Third" }; + [Fact] + public void WriteLines_WithEnumerable_ShouldWriteMultipleLines() + { + var helper = new FakeTestOutputHelper(); + var values = new List { "First", "Second", "Third" }; - helper.WriteLines(values); + helper.WriteLines(values); - var expected = $"First{Environment.NewLine}Second{Environment.NewLine}Third"; - Assert.Equal(expected, helper.Output); - } + var expected = $"First{Environment.NewLine}Second{Environment.NewLine}Third"; + Assert.Equal(expected, helper.Output); + } - [Fact] - public void WriteLines_WithEnumerable_NullHelper_ShouldThrowArgumentNullException() - { - ITestOutputHelper helper = null; - var values = new List { "test" }; + [Fact] + public void WriteLines_WithEnumerable_NullHelper_ShouldThrowArgumentNullException() + { + ITestOutputHelper helper = null; + var values = new List { "test" }; - var exception = Assert.Throws(() => helper.WriteLines(values)); + var exception = Assert.Throws(() => helper.WriteLines(values)); - Assert.Equal("helper", exception.ParamName); - } + Assert.Equal("helper", exception.ParamName); + } - [Fact] - public void WriteLines_WithEmptyArray_ShouldWriteEmptyString() - { - var helper = new FakeTestOutputHelper(); - var values = Array.Empty(); + [Fact] + public void WriteLines_WithEmptyArray_ShouldWriteEmptyString() + { + var helper = new FakeTestOutputHelper(); + var values = Array.Empty(); - helper.WriteLines(values); + helper.WriteLines(values); - Assert.Equal(string.Empty, helper.Output); - } + Assert.Equal(string.Empty, helper.Output); + } - [Fact] - public void WriteLines_WithSingleObjectInArray_ShouldWriteSingleLine() - { - var helper = new FakeTestOutputHelper(); - var values = new object[] { "SingleLine" }; + [Fact] + public void WriteLines_WithSingleObjectInArray_ShouldWriteSingleLine() + { + var helper = new FakeTestOutputHelper(); + var values = new object[] { "SingleLine" }; - helper.WriteLines(values); + helper.WriteLines(values); - Assert.Equal("SingleLine", helper.Output); - } + Assert.Equal("SingleLine", helper.Output); + } - [Fact] - public void WriteLines_WithMixedTypes_ShouldConvertToString() - { - var helper = new FakeTestOutputHelper(); - var values = new object[] { 42, true, 3.14, "text" }; + [Fact] + public void WriteLines_WithMixedTypes_ShouldConvertToString() + { + var helper = new FakeTestOutputHelper(); + var values = new object[] { 42, true, 3.14, "text" }; - helper.WriteLines(values); + helper.WriteLines(values); - var expected = $"42{Environment.NewLine}True{Environment.NewLine}{3.14.ToString()}{Environment.NewLine}text"; - Assert.Equal(expected, helper.Output); - } + var expected = $"42{Environment.NewLine}True{Environment.NewLine}{3.14.ToString()}{Environment.NewLine}text"; + Assert.Equal(expected, helper.Output); + } - [Fact] - public void WriteLines_WithComplexObjects_ShouldUseToString() + [Fact] + public void WriteLines_WithComplexObjects_ShouldUseToString() + { + var helper = new FakeTestOutputHelper(); + var values = new object[] { - var helper = new FakeTestOutputHelper(); - var values = new object[] - { - new TestObject { Name = "Object1" }, - new TestObject { Name = "Object2" } - }; + new TestObject { Name = "Object1" }, + new TestObject { Name = "Object2" } + }; - helper.WriteLines(values); + helper.WriteLines(values); - var expected = $"TestObject: Object1{Environment.NewLine}TestObject: Object2"; - Assert.Equal(expected, helper.Output); - } - - [Theory] - [InlineData(1)] - [InlineData(5)] - [InlineData(10)] - public void WriteLines_WithVariousArraySizes_ShouldHandleCorrectly(int count) - { - var helper = new FakeTestOutputHelper(); - var values = new string[count]; - var expectedBuilder = new StringBuilder(); - - for (var i = 0; i < count; i++) - { - values[i] = $"Item{i}"; - if (i > 0) { expectedBuilder.Append(Environment.NewLine); } - expectedBuilder.Append($"Item{i}"); - } + var expected = $"TestObject: Object1{Environment.NewLine}TestObject: Object2"; + Assert.Equal(expected, helper.Output); + } - helper.WriteLines(values); + [Theory] + [InlineData(1)] + [InlineData(5)] + [InlineData(10)] + public void WriteLines_WithVariousArraySizes_ShouldHandleCorrectly(int count) + { + var helper = new FakeTestOutputHelper(); + var values = new string[count]; + var expectedBuilder = new StringBuilder(); - Assert.Equal(expectedBuilder.ToString(), helper.Output); + for (var i = 0; i < count; i++) + { + values[i] = $"Item{i}"; + if (i > 0) { expectedBuilder.Append(Environment.NewLine); } + expectedBuilder.Append($"Item{i}"); } + helper.WriteLines(values); - [Fact] - public void WriteLines_WithEnumerableOfIntegers_ShouldFormatCorrectly() - { - var helper = new FakeTestOutputHelper(); - var values = new List { 100, 200, 300 }; + Assert.Equal(expectedBuilder.ToString(), helper.Output); + } - helper.WriteLines(values); - var expected = $"100{Environment.NewLine}200{Environment.NewLine}300"; - Assert.Equal(expected, helper.Output); - } + [Fact] + public void WriteLines_WithEnumerableOfIntegers_ShouldFormatCorrectly() + { + var helper = new FakeTestOutputHelper(); + var values = new List { 100, 200, 300 }; - [Fact] - public void WriteLines_WithEnumerableOfBooleans_ShouldFormatCorrectly() - { - var helper = new FakeTestOutputHelper(); - var values = new List { true, false, true }; + helper.WriteLines(values); - helper.WriteLines(values); + var expected = $"100{Environment.NewLine}200{Environment.NewLine}300"; + Assert.Equal(expected, helper.Output); + } - var expected = $"True{Environment.NewLine}False{Environment.NewLine}True"; - Assert.Equal(expected, helper.Output); - } + [Fact] + public void WriteLines_WithEnumerableOfBooleans_ShouldFormatCorrectly() + { + var helper = new FakeTestOutputHelper(); + var values = new List { true, false, true }; - [Fact] - public void WriteLines_WithEnumerableOfDecimals_ShouldFormatCorrectly() - { - var helper = new FakeTestOutputHelper(); - var values = new List { 1.5m, 2.75m, 3.99m }; + helper.WriteLines(values); - helper.WriteLines(values); + var expected = $"True{Environment.NewLine}False{Environment.NewLine}True"; + Assert.Equal(expected, helper.Output); + } - var expected = $"{1.5m.ToString()}{Environment.NewLine}{2.75m.ToString()}{Environment.NewLine}{3.99m.ToString()}"; - Assert.Equal(expected, helper.Output); - } + [Fact] + public void WriteLines_WithEnumerableOfDecimals_ShouldFormatCorrectly() + { + var helper = new FakeTestOutputHelper(); + var values = new List { 1.5m, 2.75m, 3.99m }; - [Fact] - public void WriteLines_WithEnumerableOfDoubles_ShouldFormatCorrectly() - { - var helper = new FakeTestOutputHelper(); - var values = new List { 1.1, 2.2, 3.3 }; + helper.WriteLines(values); - helper.WriteLines(values); + var expected = $"{1.5m.ToString()}{Environment.NewLine}{2.75m.ToString()}{Environment.NewLine}{3.99m.ToString()}"; + Assert.Equal(expected, helper.Output); + } - var expected = $"{1.1.ToString()}{Environment.NewLine}{2.2.ToString()}{Environment.NewLine}{3.3.ToString()}"; - Assert.Equal(expected, helper.Output); - } + [Fact] + public void WriteLines_WithEnumerableOfDoubles_ShouldFormatCorrectly() + { + var helper = new FakeTestOutputHelper(); + var values = new List { 1.1, 2.2, 3.3 }; - [Fact] - public void WriteLines_WithEmptyEnumerable_ShouldWriteEmptyString() - { - var helper = new FakeTestOutputHelper(); - var values = new List(); + helper.WriteLines(values); - helper.WriteLines(values); + var expected = $"{1.1.ToString()}{Environment.NewLine}{2.2.ToString()}{Environment.NewLine}{3.3.ToString()}"; + Assert.Equal(expected, helper.Output); + } - Assert.Equal(string.Empty, helper.Output); - } + [Fact] + public void WriteLines_WithEmptyEnumerable_ShouldWriteEmptyString() + { + var helper = new FakeTestOutputHelper(); + var values = new List(); - private class FakeTestOutputHelper : ITestOutputHelper - { - private readonly StringBuilder _output = new(); + helper.WriteLines(values); - public string Output => _output.ToString(); + Assert.Equal(string.Empty, helper.Output); + } + + private class FakeTestOutputHelper : ITestOutputHelper + { + private readonly StringBuilder _output = new(); - public void Write(string message) - { - _output.Append(message); - } + public string Output => _output.ToString(); - public void Write(string format, params object[] args) - { - _output.Append(string.Format(format, args)); - } + public void Write(string message) + { + _output.Append(message); + } - public void WriteLine(string message) - { - _output.Append(message); - } + public void Write(string format, params object[] args) + { + _output.Append(string.Format(format, args)); + } - public void WriteLine(string format, params object[] args) - { - _output.Append(string.Format(format, args)); - } + public void WriteLine(string message) + { + _output.Append(message); } - private class TestObject + public void WriteLine(string format, params object[] args) { - public string Name { get; set; } + _output.Append(string.Format(format, args)); + } + } - public override string ToString() - { - return $"TestObject: {Name}"; - } + private class TestObject + { + public string Name { get; set; } + + public override string ToString() + { + return $"TestObject: {Name}"; } } } diff --git a/test/Codebelt.Extensions.Xunit.Tests/TestTest.cs b/test/Codebelt.Extensions.Xunit.Tests/TestTest.cs index 1112f09..c835b09 100644 --- a/test/Codebelt.Extensions.Xunit.Tests/TestTest.cs +++ b/test/Codebelt.Extensions.Xunit.Tests/TestTest.cs @@ -1,323 +1,322 @@ -using System; +using System; using System.Threading.Tasks; using Xunit; using Xunit.v3; -namespace Codebelt.Extensions.Xunit +namespace Codebelt.Extensions.Xunit; + +public class TestTest : Test { - public class TestTest : Test + private const string ExpectedStringValue = "AllIsGood"; + private bool _onDisposeManagedResourcesCalled; + private bool _initializeAsyncCalled; + + public TestTest(ITestOutputHelper output) : base(output) + { + } + + public override ValueTask InitializeAsync() + { + _initializeAsyncCalled = true; + return default; + } + + protected override ValueTask OnDisposeManagedResourcesAsync() + { + TestOutput.WriteLine($"{nameof(IAsyncLifetime.DisposeAsync)} was called."); + return default; + } + + [Fact] + public void Test_InitializeAsyncCalled_ShouldBeTrue() + { + Assert.True(_initializeAsyncCalled); + } + + [Fact] + public void Test_ShouldHaveTestOutput() + { + Assert.True(HasTestOutput); + Assert.IsAssignableFrom(TestOutput); + Assert.IsType(TestOutput); + } + + [Fact] + public void Test_ShouldInvokeDispose() + { + Assert.Equal(ExpectedStringValue, DisposeSensitiveMethod()); + Assert.False(_onDisposeManagedResourcesCalled); + Dispose(); + Assert.True(_onDisposeManagedResourcesCalled); + Assert.True(Disposed); + Assert.Throws(DisposeSensitiveMethod); + } + + [Fact] + public void Test_ShouldHaveCallerTypeOfTestTest() + { + Assert.True(GetType() == typeof(TestTest), "GetType() == typeof(TestTest)"); + } + + [Fact] + public void Match_ShouldReturnTrue_WhenExactMatch() + { + var expected = "Hello World"; + var actual = "Hello World"; + + var result = Test.Match(expected, actual); + + Assert.True(result); + } + + [Fact] + public void Match_ShouldReturnFalse_WhenNoMatch() + { + var expected = "Hello World"; + var actual = "Goodbye World"; + + var result = Test.Match(expected, actual); + + Assert.False(result); + } + + [Fact] + public void Match_ShouldReturnTrue_WhenUsingGroupOfCharactersWildcard() + { + var expected = "Hello * World"; + var actual = "Hello Beautiful World"; + + var result = Test.Match(expected, actual); + + Assert.True(result); + } + + [Fact] + public void Match_ShouldReturnTrue_WhenUsingSingleCharacterWildcard() + { + var expected = "Hello ?orld"; + var actual = "Hello World"; + + var result = Test.Match(expected, actual); + + Assert.True(result); + } + + [Fact] + public void Match_ShouldReturnTrue_WhenUsingMultipleWildcards() + { + var expected = "* test ? result *"; + var actual = "This is a test 1 result with more text"; + + var result = Test.Match(expected, actual); + + Assert.True(result); + } + + [Fact] + public void Match_ShouldReturnTrue_WhenUsingGroupOfCharactersWildcardAtStart() { - private const string ExpectedStringValue = "AllIsGood"; - private bool _onDisposeManagedResourcesCalled; - private bool _initializeAsyncCalled; - - public TestTest(ITestOutputHelper output) : base(output) - { - } - - public override ValueTask InitializeAsync() - { - _initializeAsyncCalled = true; - return default; - } - - protected override ValueTask OnDisposeManagedResourcesAsync() - { - TestOutput.WriteLine($"{nameof(IAsyncLifetime.DisposeAsync)} was called."); - return default; - } - - [Fact] - public void Test_InitializeAsyncCalled_ShouldBeTrue() - { - Assert.True(_initializeAsyncCalled); - } - - [Fact] - public void Test_ShouldHaveTestOutput() - { - Assert.True(HasTestOutput); - Assert.IsAssignableFrom(TestOutput); - Assert.IsType(TestOutput); - } - - [Fact] - public void Test_ShouldInvokeDispose() - { - Assert.Equal(ExpectedStringValue, DisposeSensitiveMethod()); - Assert.False(_onDisposeManagedResourcesCalled); - Dispose(); - Assert.True(_onDisposeManagedResourcesCalled); - Assert.True(Disposed); - Assert.Throws(DisposeSensitiveMethod); - } - - [Fact] - public void Test_ShouldHaveCallerTypeOfTestTest() - { - Assert.True(GetType() == typeof(TestTest), "GetType() == typeof(TestTest)"); - } - - [Fact] - public void Match_ShouldReturnTrue_WhenExactMatch() - { - var expected = "Hello World"; - var actual = "Hello World"; - - var result = Test.Match(expected, actual); - - Assert.True(result); - } - - [Fact] - public void Match_ShouldReturnFalse_WhenNoMatch() - { - var expected = "Hello World"; - var actual = "Goodbye World"; - - var result = Test.Match(expected, actual); - - Assert.False(result); - } - - [Fact] - public void Match_ShouldReturnTrue_WhenUsingGroupOfCharactersWildcard() - { - var expected = "Hello * World"; - var actual = "Hello Beautiful World"; - - var result = Test.Match(expected, actual); - - Assert.True(result); - } - - [Fact] - public void Match_ShouldReturnTrue_WhenUsingSingleCharacterWildcard() - { - var expected = "Hello ?orld"; - var actual = "Hello World"; - - var result = Test.Match(expected, actual); - - Assert.True(result); - } - - [Fact] - public void Match_ShouldReturnTrue_WhenUsingMultipleWildcards() - { - var expected = "* test ? result *"; - var actual = "This is a test 1 result with more text"; - - var result = Test.Match(expected, actual); - - Assert.True(result); - } - - [Fact] - public void Match_ShouldReturnTrue_WhenUsingGroupOfCharactersWildcardAtStart() - { - var expected = "*World"; - var actual = "Hello World"; - - var result = Test.Match(expected, actual); - - Assert.True(result); - } - - [Fact] - public void Match_ShouldReturnTrue_WhenUsingGroupOfCharactersWildcardAtEnd() - { - var expected = "Hello*"; - var actual = "Hello World"; + var expected = "*World"; + var actual = "Hello World"; + + var result = Test.Match(expected, actual); - var result = Test.Match(expected, actual); + Assert.True(result); + } + + [Fact] + public void Match_ShouldReturnTrue_WhenUsingGroupOfCharactersWildcardAtEnd() + { + var expected = "Hello*"; + var actual = "Hello World"; + + var result = Test.Match(expected, actual); + + Assert.True(result); + } - Assert.True(result); - } - - [Fact] - public void Match_ShouldReturnFalse_WhenWildcardPatternDoesNotMatch() - { - var expected = "Hello ? World"; - var actual = "Hello Beautiful World"; + [Fact] + public void Match_ShouldReturnFalse_WhenWildcardPatternDoesNotMatch() + { + var expected = "Hello ? World"; + var actual = "Hello Beautiful World"; - var result = Test.Match(expected, actual); + var result = Test.Match(expected, actual); - Assert.False(result); - } + Assert.False(result); + } - [Fact] - public void Match_ShouldThrowArgumentOutOfRangeException_WhenThrowOnNoMatchIsTrue() - { - var expected = "Hello World"; - var actual = "Goodbye World"; + [Fact] + public void Match_ShouldThrowArgumentOutOfRangeException_WhenThrowOnNoMatchIsTrue() + { + var expected = "Hello World"; + var actual = "Goodbye World"; - var exception = Assert.Throws(() => - Test.Match(expected, actual, options => options.ThrowOnNoMatch = true)); + var exception = Assert.Throws(() => + Test.Match(expected, actual, options => options.ThrowOnNoMatch = true)); - TestOutput.WriteLine(exception.Message); - TestOutput.WriteLine($"ParamName: {exception.ParamName}"); - TestOutput.WriteLine($"ActualValue: {exception.ActualValue}"); - TestOutput.WriteLine($"Expected: {expected}"); + TestOutput.WriteLine(exception.Message); + TestOutput.WriteLine($"ParamName: {exception.ParamName}"); + TestOutput.WriteLine($"ActualValue: {exception.ActualValue}"); + TestOutput.WriteLine($"Expected: {expected}"); - Assert.Equal("expected", exception.ParamName); - Assert.Contains("The expected value does not match the actual value", exception.Message); - } + Assert.Equal("expected", exception.ParamName); + Assert.Contains("The expected value does not match the actual value", exception.Message); + } - [Fact] - public void Match_ShouldReturnTrue_WithCustomGroupOfCharacters() - { - var expected = "Hello ## World"; - var actual = "Hello Beautiful World"; + [Fact] + public void Match_ShouldReturnTrue_WithCustomGroupOfCharacters() + { + var expected = "Hello ## World"; + var actual = "Hello Beautiful World"; - var result = Test.Match(expected, actual, options => options.GroupOfCharacters = "\\#\\#"); + var result = Test.Match(expected, actual, options => options.GroupOfCharacters = "\\#\\#"); - Assert.True(result); - } + Assert.True(result); + } - [Fact] - public void Match_ShouldReturnTrue_WithCustomSingleCharacter() - { - var expected = "Hello #orld"; - var actual = "Hello World"; + [Fact] + public void Match_ShouldReturnTrue_WithCustomSingleCharacter() + { + var expected = "Hello #orld"; + var actual = "Hello World"; - var result = Test.Match(expected, actual, options => options.SingleCharacter = "\\#"); + var result = Test.Match(expected, actual, options => options.SingleCharacter = "\\#"); - Assert.True(result); - } + Assert.True(result); + } - [Fact] - public void Match_ShouldReturnTrue_WhenMatchingMultilineStrings() - { - var expected = $"Line 1{Environment.NewLine}Line 2{Environment.NewLine}Line 3"; - var actual = $"Line 1{Environment.NewLine}Line 2{Environment.NewLine}Line 3"; + [Fact] + public void Match_ShouldReturnTrue_WhenMatchingMultilineStrings() + { + var expected = $"Line 1{Environment.NewLine}Line 2{Environment.NewLine}Line 3"; + var actual = $"Line 1{Environment.NewLine}Line 2{Environment.NewLine}Line 3"; - var result = Test.Match(expected, actual); + var result = Test.Match(expected, actual); - Assert.True(result); - } + Assert.True(result); + } - [Fact] - public void Match_ShouldReturnTrue_WhenMatchingMultilineStringsWithWildcards() - { - var expected = $"Line 1{Environment.NewLine}Line ?{Environment.NewLine}Line *"; - var actual = $"Line 1{Environment.NewLine}Line 2{Environment.NewLine}Line 3"; + [Fact] + public void Match_ShouldReturnTrue_WhenMatchingMultilineStringsWithWildcards() + { + var expected = $"Line 1{Environment.NewLine}Line ?{Environment.NewLine}Line *"; + var actual = $"Line 1{Environment.NewLine}Line 2{Environment.NewLine}Line 3"; - var result = Test.Match(expected, actual); + var result = Test.Match(expected, actual); - Assert.True(result); - } + Assert.True(result); + } - [Fact] - public void Match_ShouldReturnFalse_WhenMultilineStringsDoNotMatch() - { - var expected = $"Line 1{Environment.NewLine}Line 2{Environment.NewLine}Line 3"; - var actual = $"Line 1{Environment.NewLine}Line 4{Environment.NewLine}Line 3"; + [Fact] + public void Match_ShouldReturnFalse_WhenMultilineStringsDoNotMatch() + { + var expected = $"Line 1{Environment.NewLine}Line 2{Environment.NewLine}Line 3"; + var actual = $"Line 1{Environment.NewLine}Line 4{Environment.NewLine}Line 3"; - var result = Test.Match(expected, actual); + var result = Test.Match(expected, actual); - Assert.False(result); - } + Assert.False(result); + } - [Fact] - public void Match_ShouldReturnTrue_WhenMatchingEmptyStrings() - { - var expected = string.Empty; - var actual = string.Empty; + [Fact] + public void Match_ShouldReturnTrue_WhenMatchingEmptyStrings() + { + var expected = string.Empty; + var actual = string.Empty; - var result = Test.Match(expected, actual); + var result = Test.Match(expected, actual); - Assert.True(result); - } + Assert.True(result); + } - [Fact] - public void Match_ShouldReturnTrue_WhenMatchingSpecialRegexCharacters() - { - var expected = "Hello.World"; - var actual = "Hello.World"; + [Fact] + public void Match_ShouldReturnTrue_WhenMatchingSpecialRegexCharacters() + { + var expected = "Hello.World"; + var actual = "Hello.World"; - var result = Test.Match(expected, actual); + var result = Test.Match(expected, actual); - Assert.True(result); - } + Assert.True(result); + } - [Fact] - public void Match_ShouldReturnTrue_WhenMatchingWithParentheses() - { - var expected = "Test (value)"; - var actual = "Test (value)"; + [Fact] + public void Match_ShouldReturnTrue_WhenMatchingWithParentheses() + { + var expected = "Test (value)"; + var actual = "Test (value)"; - var result = Test.Match(expected, actual); + var result = Test.Match(expected, actual); - Assert.True(result); - } + Assert.True(result); + } - [Fact] - public void Match_ShouldReturnTrue_WhenMatchingWithSquareBrackets() - { - var expected = "Test [value]"; - var actual = "Test [value]"; + [Fact] + public void Match_ShouldReturnTrue_WhenMatchingWithSquareBrackets() + { + var expected = "Test [value]"; + var actual = "Test [value]"; - var result = Test.Match(expected, actual); + var result = Test.Match(expected, actual); - Assert.True(result); - } + Assert.True(result); + } - [Fact] - public void Match_ShouldReturnTrue_WhenMatchingWithPlusSign() - { - var expected = "Test+Value"; - var actual = "Test+Value"; + [Fact] + public void Match_ShouldReturnTrue_WhenMatchingWithPlusSign() + { + var expected = "Test+Value"; + var actual = "Test+Value"; - var result = Test.Match(expected, actual); + var result = Test.Match(expected, actual); - Assert.True(result); - } + Assert.True(result); + } - [Fact] - public void Match_ShouldReturnFalse_WhenSingleCharacterWildcardMatchesMultipleCharacters() - { - var expected = "Test?Value"; - var actual = "TestMultipleValue"; + [Fact] + public void Match_ShouldReturnFalse_WhenSingleCharacterWildcardMatchesMultipleCharacters() + { + var expected = "Test?Value"; + var actual = "TestMultipleValue"; - var result = Test.Match(expected, actual); + var result = Test.Match(expected, actual); - Assert.False(result); - } + Assert.False(result); + } - [Fact] - public void Match_ShouldReturnTrue_WhenGroupOfCharactersWildcardMatchesZeroCharacters() - { - var expected = "Test*Value"; - var actual = "TestValue"; + [Fact] + public void Match_ShouldReturnTrue_WhenGroupOfCharactersWildcardMatchesZeroCharacters() + { + var expected = "Test*Value"; + var actual = "TestValue"; - var result = Test.Match(expected, actual); + var result = Test.Match(expected, actual); - Assert.True(result); - } + Assert.True(result); + } - [Fact] - public void Match_ShouldThrowArgumentOutOfRangeException_WithNonMatchingLines() - { - var expected = $"Line 1{Environment.NewLine}Expected Line{Environment.NewLine}Line 3"; - var actual = $"Line 1{Environment.NewLine}Actual Line{Environment.NewLine}Line 3"; + [Fact] + public void Match_ShouldThrowArgumentOutOfRangeException_WithNonMatchingLines() + { + var expected = $"Line 1{Environment.NewLine}Expected Line{Environment.NewLine}Line 3"; + var actual = $"Line 1{Environment.NewLine}Actual Line{Environment.NewLine}Line 3"; - var exception = Assert.Throws(() => - Test.Match(expected, actual, options => options.ThrowOnNoMatch = true)); + var exception = Assert.Throws(() => + Test.Match(expected, actual, options => options.ThrowOnNoMatch = true)); - Assert.Contains("Expected Line", exception.ActualValue.ToString()); - } + Assert.Contains("Expected Line", exception.ActualValue.ToString()); + } - public string DisposeSensitiveMethod() - { - if (Disposed) { throw new ObjectDisposedException(GetType().FullName); } - return ExpectedStringValue; - } + public string DisposeSensitiveMethod() + { + if (Disposed) { throw new ObjectDisposedException(GetType().FullName); } + return ExpectedStringValue; + } - protected override void OnDisposeManagedResources() - { - _onDisposeManagedResourcesCalled = true; - base.OnDisposeManagedResources(); - } + protected override void OnDisposeManagedResources() + { + _onDisposeManagedResourcesCalled = true; + base.OnDisposeManagedResources(); } } From f098e1d9fe1244b7b4aa30f33e62bbc214467e84 Mon Sep 17 00:00:00 2001 From: gimlichael Date: Thu, 21 May 2026 23:57:00 +0200 Subject: [PATCH 15/16] =?UTF-8?q?=E2=9C=A8=20add=20overload=20for=20GetTes?= =?UTF-8?q?tStore=20to=20support=20generic=20ILogger?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LoggerExtensions.cs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Codebelt.Extensions.Xunit.Hosting/LoggerExtensions.cs b/src/Codebelt.Extensions.Xunit.Hosting/LoggerExtensions.cs index da04953..ac007f6 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/LoggerExtensions.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/LoggerExtensions.cs @@ -37,6 +37,22 @@ public static ITestStore GetTestStore(this ILogger logger, if (store != null) { return store; } } throw new ArgumentException($"Logger does not contain a test store; did you remember to call {nameof(ServiceCollectionExtensions.AddXunitTestLogging)} before calling this method?", nameof(logger)); + } + + /// + /// Returns the associated that is provided when settings up services from or related. + /// + /// The from which to retrieve the . + /// Returns an implementation of with all logged entries expressed as . + /// + /// cannot be null. + /// + /// + /// does not contain a test store. + /// + public static ITestStore GetTestStore(this ILogger logger) + { + return GetTestStore(logger, typeof(T).FullName); } private static object GetInternalLogger(ILogger logger) @@ -68,20 +84,4 @@ private static ITestStore TryGetTestStore(object loggerInf ? xunitTestLogger.Provider : xunitTestLogger.Provider[categoryName]; } - - /// - /// Returns the associated that is provided when settings up services from or related. - /// - /// The from which to retrieve the . - /// Returns an implementation of with all logged entries expressed as . - /// - /// cannot be null. - /// - /// - /// does not contain a test store. - /// - public static ITestStore GetTestStore(this ILogger logger) - { - return GetTestStore(logger, typeof(T).FullName); - } } From ed19a25df128f728508170444dd49f2803aa522a Mon Sep 17 00:00:00 2001 From: gimlichael Date: Fri, 22 May 2026 00:06:32 +0200 Subject: [PATCH 16/16] =?UTF-8?q?=F0=9F=94=A7=20fix=20constructor=20parame?= =?UTF-8?q?ter=20type=20in=20HostTestTest=20class?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .nuget/Codebelt.Extensions.Xunit.Hosting/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nuget/Codebelt.Extensions.Xunit.Hosting/README.md b/.nuget/Codebelt.Extensions.Xunit.Hosting/README.md index 6b87a9b..27c0ece 100644 --- a/.nuget/Codebelt.Extensions.Xunit.Hosting/README.md +++ b/.nuget/Codebelt.Extensions.Xunit.Hosting/README.md @@ -31,7 +31,7 @@ public class HostTestTest : HostTest { private readonly IServiceProvider _provider; - public HostTestTest(HostFixture hostFixture, ITestOutputHelper output) : base(hostFixture, output) + public HostTestTest(ManagedHostFixture hostFixture, ITestOutputHelper output) : base(hostFixture, output) { _provider = hostFixture.Host?.Services; _provider.GetRequiredService().TestOutput = output;