From 555d65060ce51494611842554bcc0efbfd3bebd6 Mon Sep 17 00:00:00 2001 From: Michael Mortensen Date: Tue, 1 Oct 2024 22:32:06 +0200 Subject: [PATCH 1/5] :pencil2: fixed typo --- src/Codebelt.Extensions.Xunit/Test.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Codebelt.Extensions.Xunit/Test.cs b/src/Codebelt.Extensions.Xunit/Test.cs index 02172cb..d3ed751 100644 --- a/src/Codebelt.Extensions.Xunit/Test.cs +++ b/src/Codebelt.Extensions.Xunit/Test.cs @@ -66,7 +66,7 @@ protected Test(ITestOutputHelper output = null, Type callerType = null) /// /// Gets a value indicating whether has a reference to an implementation of . /// - /// true if this instance has has a reference to an implementation of ; otherwise, false. + /// true if this instance has a reference to an implementation of ; otherwise, false. protected bool HasTestOutput => TestOutput != null; /// From 5176fe098a27795a5d7b2248a153d00099c2894a Mon Sep 17 00:00:00 2001 From: Michael Mortensen Date: Tue, 1 Oct 2024 22:36:30 +0200 Subject: [PATCH 2/5] :alembic: experiment with PrivateAssets set to compile --- .../Codebelt.Extensions.Xunit.Hosting.AspNetCore.csproj | 3 +-- .../Codebelt.Extensions.Xunit.Hosting.csproj | 1 + src/Codebelt.Extensions.Xunit/Codebelt.Extensions.Xunit.csproj | 3 ++- .../Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests.csproj | 1 - .../Codebelt.Extensions.Xunit.Hosting.Tests.csproj | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Codebelt.Extensions.Xunit.Hosting.AspNetCore.csproj b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Codebelt.Extensions.Xunit.Hosting.AspNetCore.csproj index 0d0173e..0de0868 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Codebelt.Extensions.Xunit.Hosting.AspNetCore.csproj +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Codebelt.Extensions.Xunit.Hosting.AspNetCore.csproj @@ -24,8 +24,7 @@ - - + diff --git a/src/Codebelt.Extensions.Xunit.Hosting/Codebelt.Extensions.Xunit.Hosting.csproj b/src/Codebelt.Extensions.Xunit.Hosting/Codebelt.Extensions.Xunit.Hosting.csproj index d8b4cf5..2fb51d3 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/Codebelt.Extensions.Xunit.Hosting.csproj +++ b/src/Codebelt.Extensions.Xunit.Hosting/Codebelt.Extensions.Xunit.Hosting.csproj @@ -35,6 +35,7 @@ + diff --git a/src/Codebelt.Extensions.Xunit/Codebelt.Extensions.Xunit.csproj b/src/Codebelt.Extensions.Xunit/Codebelt.Extensions.Xunit.csproj index f09b8d9..24867e4 100644 --- a/src/Codebelt.Extensions.Xunit/Codebelt.Extensions.Xunit.csproj +++ b/src/Codebelt.Extensions.Xunit/Codebelt.Extensions.Xunit.csproj @@ -2,6 +2,7 @@ 0d0bdf91-e7c7-4cb4-a39d-e1a5374c5602 + true @@ -10,7 +11,7 @@ - + diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests.csproj b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests.csproj index f87662d..c67c1ea 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests.csproj +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests.csproj @@ -6,7 +6,6 @@ - diff --git a/test/Codebelt.Extensions.Xunit.Hosting.Tests/Codebelt.Extensions.Xunit.Hosting.Tests.csproj b/test/Codebelt.Extensions.Xunit.Hosting.Tests/Codebelt.Extensions.Xunit.Hosting.Tests.csproj index 7fa1000..cae2ea1 100644 --- a/test/Codebelt.Extensions.Xunit.Hosting.Tests/Codebelt.Extensions.Xunit.Hosting.Tests.csproj +++ b/test/Codebelt.Extensions.Xunit.Hosting.Tests/Codebelt.Extensions.Xunit.Hosting.Tests.csproj @@ -15,6 +15,7 @@ + From a4e4bd4eb77f736503cd411b072f3f151612d656 Mon Sep 17 00:00:00 2001 From: Michael Mortensen Date: Tue, 1 Oct 2024 22:53:41 +0200 Subject: [PATCH 3/5] :twisted_rightwards_arrows: reduce dependency to Cuemon --- .../Http/FakeHttpContextAccessor.cs | 22 +++++++-- .../ServiceCollectionExtensions.cs | 35 +++++++++----- .../ServiceCollectionExtensionsTest.cs | 46 +++++++++++++++++++ 3 files changed, 88 insertions(+), 15 deletions(-) create mode 100644 test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/ServiceCollectionExtensionsTest.cs diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Http/FakeHttpContextAccessor.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Http/FakeHttpContextAccessor.cs index 1346dc5..65437f6 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Http/FakeHttpContextAccessor.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/Http/FakeHttpContextAccessor.cs @@ -1,5 +1,8 @@ -using Codebelt.Extensions.Xunit.Hosting.AspNetCore.Http.Features; -using Cuemon.IO; +using System; +using System.IO; +using System.Text; +using Codebelt.Extensions.Xunit.Hosting.AspNetCore.Http.Features; +using Cuemon; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; @@ -20,10 +23,23 @@ public FakeHttpContextAccessor() var fc = new FeatureCollection(); fc.Set(new FakeHttpResponseFeature()); fc.Set(new FakeHttpRequestFeature()); - fc.Set(new StreamResponseBodyFeature(StreamFactory.Create(writer => writer.Write("Hello awesome developers!")))); + fc.Set(new StreamResponseBodyFeature(MakeGreeting("Hello awesome developers!"))); HttpContext = new DefaultHttpContext(fc); } + private Stream MakeGreeting(string greeting) + { + return Patterns.SafeInvoke(() => new MemoryStream(), ms => + { + var sw = new StreamWriter(ms, Encoding.UTF8); + sw.Write(greeting); + sw.Flush(); + ms.Flush(); + ms.Position = 0; + return ms; + }, ex => throw new InvalidOperationException("There is an error in the Stream being written.", ex)); + } + /// /// Gets or sets the HTTP context. /// diff --git a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/ServiceCollectionExtensions.cs b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/ServiceCollectionExtensions.cs index ced4ae9..859d0d3 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/ServiceCollectionExtensions.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting.AspNetCore/ServiceCollectionExtensions.cs @@ -1,7 +1,9 @@ -using Codebelt.Extensions.Xunit.Hosting.AspNetCore.Http; -using Cuemon.Extensions.DependencyInjection; +using System; +using System.ComponentModel; +using Codebelt.Extensions.Xunit.Hosting.AspNetCore.Http; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore { @@ -18,18 +20,27 @@ public static class ServiceCollectionExtensions /// A reference to after the operation has completed. public static IServiceCollection AddFakeHttpContextAccessor(this IServiceCollection services, ServiceLifetime lifetime) { - services.TryAdd(provider => + switch (lifetime) { - var contextAccessor = new FakeHttpContextAccessor - { - HttpContext = - { - RequestServices = provider - } - }; - return contextAccessor; - }, 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; } + + private static IHttpContextAccessor FakeHttpContextAccessorFactory(IServiceProvider provider) + { + var contextAccessor = new FakeHttpContextAccessor { HttpContext = { RequestServices = provider } }; + return contextAccessor; + } } } diff --git a/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/ServiceCollectionExtensionsTest.cs b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/ServiceCollectionExtensionsTest.cs new file mode 100644 index 0000000..dfb1996 --- /dev/null +++ b/test/Codebelt.Extensions.Xunit.Hosting.AspNetCore.Tests/ServiceCollectionExtensionsTest.cs @@ -0,0 +1,46 @@ +using System.ComponentModel; +using Codebelt.Extensions.Xunit.Hosting.AspNetCore.Http; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Xunit; +using Xunit.Abstractions; + +namespace Codebelt.Extensions.Xunit.Hosting.AspNetCore +{ + public class ServiceCollectionExtensionsTest : Test + { + 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(); + + // Act + services.AddFakeHttpContextAccessor(lifetime); + var serviceProvider = services.BuildServiceProvider(); + var httpContextAccessor = serviceProvider.GetService(); + + // Assert + Assert.NotNull(httpContextAccessor); + Assert.IsType(httpContextAccessor); + } + + [Fact] + public void AddFakeHttpContextAccessor_ShouldThrowInvalidEnumArgumentException_ForInvalidLifetime() + { + // Arrange + var services = new ServiceCollection(); + var invalidLifetime = (ServiceLifetime)999; + + // Act & Assert + Assert.Throws(() => services.AddFakeHttpContextAccessor(invalidLifetime)); + } + } +} From 31d40b38a016467db634275d2ee53eb0b1b37be8 Mon Sep 17 00:00:00 2001 From: Michael Mortensen Date: Tue, 1 Oct 2024 22:54:55 +0200 Subject: [PATCH 4/5] :twisted_rightwards_arrows: extracted and migrated Cuemon.Disposable abstraction to HostTest; this was done to reduce the risk of circular reference challenges as Cuemon relies on this library. Functionality wise, the change is backward compatible. --- .../GlobalSuppressions.cs | 8 ++++ .../HostFixture.cs | 44 +++++++++++++++++-- .../Assets/UnmanagedDisposable.cs | 1 - 3 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 src/Codebelt.Extensions.Xunit.Hosting/GlobalSuppressions.cs diff --git a/src/Codebelt.Extensions.Xunit.Hosting/GlobalSuppressions.cs b/src/Codebelt.Extensions.Xunit.Hosting/GlobalSuppressions.cs new file mode 100644 index 0000000..b73414a --- /dev/null +++ b/src/Codebelt.Extensions.Xunit.Hosting/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// 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("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")] diff --git a/src/Codebelt.Extensions.Xunit.Hosting/HostFixture.cs b/src/Codebelt.Extensions.Xunit.Hosting/HostFixture.cs index efba269..572fdac 100644 --- a/src/Codebelt.Extensions.Xunit.Hosting/HostFixture.cs +++ b/src/Codebelt.Extensions.Xunit.Hosting/HostFixture.cs @@ -11,9 +11,8 @@ namespace Codebelt.Extensions.Xunit.Hosting /// /// Provides a default implementation of the interface. /// - /// /// - public class HostFixture : Disposable, IHostFixture + public class HostFixture : IDisposable, IHostFixture { /// /// Initializes a new instance of the class. @@ -127,9 +126,15 @@ public virtual void ConfigureHost(Test hostTest) #endif /// - /// Called when this object is being disposed by either or having disposing set to true and is false. + /// Gets a value indicating whether this object is disposed. /// - protected override void OnDisposeManagedResources() + /// 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 (ServiceProvider is ServiceProvider sp) { @@ -137,5 +142,36 @@ protected override void OnDisposeManagedResources() } Host?.Dispose(); } + + /// + /// 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 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; } + if (disposing) + { + OnDisposeManagedResources(); + } + OnDisposeUnmanagedResources(); + Disposed = true; + } } } diff --git a/test/Codebelt.Extensions.Xunit.Tests/Assets/UnmanagedDisposable.cs b/test/Codebelt.Extensions.Xunit.Tests/Assets/UnmanagedDisposable.cs index fb07024..19da2fc 100644 --- a/test/Codebelt.Extensions.Xunit.Tests/Assets/UnmanagedDisposable.cs +++ b/test/Codebelt.Extensions.Xunit.Tests/Assets/UnmanagedDisposable.cs @@ -82,7 +82,6 @@ public UnmanagedDisposable() Dispose(false); } - protected override void OnDisposeManagedResources() { From 41d6a983c68b1404a23d2bb763236df24edf3427 Mon Sep 17 00:00:00 2001 From: Michael Mortensen Date: Tue, 1 Oct 2024 22:55:08 +0200 Subject: [PATCH 5/5] :construction_worker: updated CI/CD --- Directory.Build.targets | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.targets b/Directory.Build.targets index 85731bd..7f3a8bc 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -15,8 +15,8 @@ - 00000 - $(MinVerMajor).$(MinVerMinor).$(MinVerPatch).$(BUILD_BUILDNUMBER) + 0 + $(MinVerMajor).$(MinVerMinor).$(MinVerPatch).$(GITHUB_RUN_NUMBER)