diff --git a/src/NetEvolve.Extensions.Hosting.WinForms/IHostBuilderExtensions.cs b/src/NetEvolve.Extensions.Hosting.WinForms/IHostBuilderExtensions.cs index 68ec520..15e7ae6 100644 --- a/src/NetEvolve.Extensions.Hosting.WinForms/IHostBuilderExtensions.cs +++ b/src/NetEvolve.Extensions.Hosting.WinForms/IHostBuilderExtensions.cs @@ -6,11 +6,7 @@ using Microsoft.Extensions.Hosting; using NetEvolve.Extensions.Hosting.WinForms.Internals; -#if NET8_0_OR_GREATER -/// -/// Extension methods for or to configure Windows Forms Lifetime. -/// -#elif NET7_0 +#if NET7_0_OR_GREATER /// /// Extension methods for or to configure Windows Forms Lifetime. /// @@ -68,13 +64,14 @@ public static IHostBuilder UseWindowsForms( return builder.ConfigureServices(services => { services = contextFactory is null - ? services.AddSingleton() - : services.AddSingleton(sp => contextFactory.Invoke(sp)); + ? services.AddSingleton() + : services.AddSingleton(sp => + contextFactory.Invoke(sp) + ); _ = services - .AddSingleton() - // Default WindowsForms services - .AddWindowsFormsLifetime(configure); + // Default WindowsForms services + .AddWindowsFormsLifetime(configure); }); } @@ -115,7 +112,7 @@ public static IHostBuilder UseWindowsForms( ); } -#if NET7_0 +#if NET7_0_OR_GREATER /// /// Enables Windows Forms support, builds and starts the host with the specified , /// then waits for the host to close the before shutting down. @@ -160,13 +157,14 @@ public static HostApplicationBuilder UseWindowsForms( ArgumentNullException.ThrowIfNull(builder); var services = contextFactory is null - ? builder.Services.AddSingleton() - : builder.Services.AddSingleton(sp => contextFactory.Invoke(sp)); + ? builder.Services.AddSingleton() + : builder.Services.AddSingleton(sp => + contextFactory.Invoke(sp) + ); _ = services - .AddSingleton(sp => sp.GetRequiredService()) - // Default WindowsForms services - .AddWindowsFormsLifetime(configure); + // Default WindowsForms services + .AddWindowsFormsLifetime(configure); return builder; } @@ -206,96 +204,4 @@ public static HostApplicationBuilder UseWindowsForms - /// Enables Windows Forms support, builds and starts the host with the specified , - /// then waits for the host to close the before shutting down. - /// - /// Form with which the application is to be started. - /// The to configure. - /// The action to be executed for the configuration of the . - /// with enabled Windows Forms support. - public static IHostApplicationBuilder UseWindowsForms( - this IHostApplicationBuilder builder, - Action? configure = null - ) - where TStartForm : Form - { - ArgumentNullException.ThrowIfNull(builder); - - _ = builder - .Services.AddSingleton() - .AddSingleton(sp => new ApplicationContext(sp.GetRequiredService())) - // Default WindowsForms services - .AddWindowsFormsLifetime(configure); - - return builder; - } - - /// - /// Enables Windows Forms support, builds and starts the host with the specified , - /// then waits for the host to close the before shutting down. - /// - /// - /// The to configure. - /// The factory. - /// The action to be executed for the configuration of the . - /// with enabled Windows Forms support. - public static IHostApplicationBuilder UseWindowsForms( - this IHostApplicationBuilder builder, - Func? contextFactory = null, - Action? configure = null - ) - where TApplicationContext : ApplicationContext - { - ArgumentNullException.ThrowIfNull(builder); - - var services = contextFactory is null - ? builder.Services.AddSingleton() - : builder.Services.AddSingleton(sp => contextFactory(sp)); - - _ = services - .AddSingleton(sp => sp.GetRequiredService()) - // Default WindowsForms services - .AddWindowsFormsLifetime(configure); - - return builder; - } - - /// - /// Enables Windows Forms support, builds and starts the host with the specified , - /// which is created by the function, then waits for the host to close the before shutting down. - /// - /// - /// Form with which the application is to be started. - /// The to configure. - /// The factory. - /// The action to be executed for the configuration of the . - /// with enabled Windows Forms support. - public static IHostApplicationBuilder UseWindowsForms( - this IHostApplicationBuilder builder, - Func contextFactory, - Action? configure = null - ) - where TApplicationContext : ApplicationContext - where TStartForm : Form - { - ArgumentNullException.ThrowIfNull(builder); - ArgumentNullException.ThrowIfNull(contextFactory); - - _ = builder - .Services.AddSingleton() - .AddSingleton(sp => - { - var startForm = sp.GetRequiredService(); - return contextFactory(sp, startForm); - }) - .AddSingleton(sp => sp.GetRequiredService()) - // Default WindowsForms services - .AddWindowsFormsLifetime(configure); - - return builder; - } -#endif } diff --git a/tests/NetEvolve.Extensions.Hosting.WinForms.Tests.Integration/IHostBuilderExtensionsTests.cs b/tests/NetEvolve.Extensions.Hosting.WinForms.Tests.Integration/IHostBuilderExtensionsTests.cs new file mode 100644 index 0000000..54022d8 --- /dev/null +++ b/tests/NetEvolve.Extensions.Hosting.WinForms.Tests.Integration/IHostBuilderExtensionsTests.cs @@ -0,0 +1,290 @@ +namespace NetEvolve.Extensions.Hosting.WinForms.Tests.Integration; + +using System; +using System.Threading.Tasks; +using System.Windows.Forms; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Xunit; + +public class IHostBuilderExtensionsTests +{ + [Fact] + public async Task UseWindowsForms_IHostBuilder_StartForm_ConfigureNull_Expected() + { + using var host = Host.CreateDefaultBuilder().UseWindowsForms().Build(); + + await host.StartAsync(); + + var provider = host.Services.GetService()!; + var mainForm = await provider.GetMainFormularAsync(); + + do + { + // This test runs too fast for the handle to be created. + // Therefore, we have to slow down a little. + await Task.Delay(15); + } while (!mainForm.IsHandleCreated); + + Assert.NotNull(mainForm); + _ = Assert.IsType(mainForm); + + await host.StopAsync(); + } + + [Fact] + public async Task UseWindowsForms_IHostBuilder_StartForm_ConfigureFine_Expected() + { + using var host = Host.CreateDefaultBuilder() + .UseWindowsForms(options => + { + options.EnableConsoleShutdown = true; + options.EnableVisualStyles = false; + }) + .Build(); + + await host.StartAsync(); + + var provider = host.Services.GetService()!; + var mainForm = await provider.GetMainFormularAsync(); + + do + { + // This test runs too fast for the handle to be created. + // Therefore, we have to slow down a little. + await Task.Delay(15); + } while (!mainForm.IsHandleCreated); + + Assert.NotNull(mainForm); + _ = Assert.IsType(mainForm); + + await host.StopAsync(); + } + + [Fact] + public async Task UseWindowsForms_IHostBuilder_ApplicationContext_Expected() + { + using var host = Host.CreateDefaultBuilder() + .UseWindowsForms() + .Build(); + + await host.StartAsync(); + + var provider = host.Services.GetService()!; + var mainForm = await provider.GetMainFormularAsync(); + + do + { + // This test runs too fast for the handle to be created. + // Therefore, we have to slow down a little. + await Task.Delay(15); + } while (!mainForm.IsHandleCreated); + + Assert.NotNull(mainForm); + _ = Assert.IsType(mainForm); + + await host.StopAsync(); + } + + [Fact] + public async Task UseWindowsForms_IHostBuilder_ApplicationContextFactory_Expected() + { + using var host = Host.CreateDefaultBuilder() + .UseWindowsForms(sp => new TestApplicationContext(new TestForm())) + .Build(); + + await host.StartAsync(); + + var provider = host.Services.GetService()!; + var mainForm = await provider.GetMainFormularAsync(); + + do + { + // This test runs too fast for the handle to be created. + // Therefore, we have to slow down a little. + await Task.Delay(15); + } while (!mainForm.IsHandleCreated); + + Assert.NotNull(mainForm); + _ = Assert.IsType(mainForm); + + await host.StopAsync(); + } + + [Fact] + public async Task UseWindowsForms_IHostBuilder_AdvancedFactory_Expected() + { + using var host = Host.CreateDefaultBuilder() + .UseWindowsForms( + (sp, form) => new TestApplicationContext(form) + ) + .Build(); + + await host.StartAsync(); + + var provider = host.Services.GetService()!; + var mainForm = await provider.GetMainFormularAsync(); + + do + { + // This test runs too fast for the handle to be created. + // Therefore, we have to slow down a little. + await Task.Delay(15); + } while (!mainForm.IsHandleCreated); + + Assert.NotNull(mainForm); + _ = Assert.IsType(mainForm); + + await host.StopAsync(); + } + +#if NET7_0_OR_GREATER + [Fact] + public async Task UseWindowsForms_HostApplicationBuilder_StartForm_ConfigureNull_Expected() + { + var builder = Host.CreateApplicationBuilder(); + _ = builder.UseWindowsForms(); + using var host = builder.Build(); + + await host.StartAsync(); + + var provider = host.Services.GetService()!; + var mainForm = await provider.GetMainFormularAsync(); + + do + { + // This test runs too fast for the handle to be created. + // Therefore, we have to slow down a little. + await Task.Delay(15); + } while (!mainForm.IsHandleCreated); + + Assert.NotNull(mainForm); + _ = Assert.IsType(mainForm); + + await host.StopAsync(); + } + + [Fact] + public async Task UseWindowsForms_HostApplicationBuilder_StartForm_ConfigureFine_Expected() + { + var builder = Host.CreateApplicationBuilder(); + _ = builder.UseWindowsForms(options => + { + options.EnableConsoleShutdown = true; + options.EnableVisualStyles = false; + }); + using var host = builder.Build(); + + await host.StartAsync(); + + var provider = host.Services.GetService()!; + var mainForm = await provider.GetMainFormularAsync(); + + do + { + // This test runs too fast for the handle to be created. + // Therefore, we have to slow down a little. + await Task.Delay(15); + } while (!mainForm.IsHandleCreated); + + Assert.NotNull(mainForm); + _ = Assert.IsType(mainForm); + + await host.StopAsync(); + } + + [Fact] + public async Task UseWindowsForms_HostApplicationBuilder_ApplicationContext_Expected() + { + var builder = Host.CreateApplicationBuilder(); + _ = builder.UseWindowsForms(); + using var host = builder.Build(); + + await host.StartAsync(); + + var provider = host.Services.GetService()!; + var mainForm = await provider.GetMainFormularAsync(); + + do + { + // This test runs too fast for the handle to be created. + // Therefore, we have to slow down a little. + await Task.Delay(15); + } while (!mainForm.IsHandleCreated); + + Assert.NotNull(mainForm); + _ = Assert.IsType(mainForm); + + await host.StopAsync(); + } + + [Fact] + public async Task UseWindowsForms_HostApplicationBuilder_ApplicationContextFactory_Expected() + { + var builder = Host.CreateApplicationBuilder(); + _ = builder.UseWindowsForms(sp => new TestApplicationContext(new TestForm())); + using var host = builder.Build(); + + await host.StartAsync(); + + var provider = host.Services.GetService()!; + var mainForm = await provider.GetMainFormularAsync(); + + do + { + // This test runs too fast for the handle to be created. + // Therefore, we have to slow down a little. + await Task.Delay(15); + } while (!mainForm.IsHandleCreated); + + Assert.NotNull(mainForm); + _ = Assert.IsType(mainForm); + + await host.StopAsync(); + } + + [Fact] + public async Task UseWindowsForms_HostApplicationBuilder_AdvancedFactory_Expected() + { + var builder = Host.CreateApplicationBuilder(); + _ = builder.UseWindowsForms( + (sp, form) => new TestApplicationContext(form) + ); + using var host = builder.Build(); + + await host.StartAsync(); + + var provider = host.Services.GetService()!; + var mainForm = await provider.GetMainFormularAsync(); + + do + { + // This test runs too fast for the handle to be created. + // Therefore, we have to slow down a little. + await Task.Delay(15); + } while (!mainForm.IsHandleCreated); + + Assert.NotNull(mainForm); + _ = Assert.IsType(mainForm); + + await host.StopAsync(); + } +#endif + +#pragma warning disable CA1812 +#pragma warning disable S2094 // Classes should not be empty + private sealed class TestApplicationContext : ApplicationContext + { + public TestApplicationContext() +#pragma warning disable CA2000 // Dispose objects before losing scope + : this(new TestForm()) { } +#pragma warning restore CA2000 // Dispose objects before losing scope + + public TestApplicationContext(Form form) + : base(form) { } + } + + private sealed class TestForm : Form { } +#pragma warning restore S2094 // Classes should not be empty +#pragma warning restore CA1812 +}