From f2e2260e30457825296972904d7f7f27e07094f3 Mon Sep 17 00:00:00 2001 From: Julian Verdurmen <5808377+304NotModified@users.noreply.github.com> Date: Thu, 29 Oct 2026 16:38:40 +0100 Subject: [PATCH 1/2] Extra tests --- .../HostLayoutRendererTests.cs | 59 +++++++++++++++++++ .../SetupExtensionsBuilderExtensionsTests.cs | 31 ++++++++++ 2 files changed, 90 insertions(+) create mode 100644 test/NLog.Extensions.Hosting.Tests/HostLayoutRendererTests.cs create mode 100644 test/NLog.Extensions.Hosting.Tests/SetupExtensionsBuilderExtensionsTests.cs diff --git a/test/NLog.Extensions.Hosting.Tests/HostLayoutRendererTests.cs b/test/NLog.Extensions.Hosting.Tests/HostLayoutRendererTests.cs new file mode 100644 index 00000000..b2a7be4e --- /dev/null +++ b/test/NLog.Extensions.Hosting.Tests/HostLayoutRendererTests.cs @@ -0,0 +1,59 @@ +using System.Collections.Generic; +using System.IO; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using NLog.Extensions.Logging; +using Xunit; + +namespace NLog.Extensions.Hosting.Tests +{ + public class HostLayoutRendererTests + { + [Fact] + public void UseNLog_RendersHostEnvironmentValues() + { + // Arrange + var contentRootPath = Path.GetTempPath(); + var hostConfiguration = new Dictionary + { + [HostDefaults.ApplicationKey] = "TestApplication", + [HostDefaults.EnvironmentKey] = "TestEnvironment", + [HostDefaults.ContentRootKey] = contentRootPath + }; + var target = new Targets.MemoryTarget + { + Layout = "${host-appname}|${host-rootdir}|${host-environment}" + }; + var host = new HostBuilder() + .ConfigureHostConfiguration(configuration => configuration.AddInMemoryCollection(hostConfiguration)) + .UseNLog(null, serviceProvider => + { + var logFactory = new LogFactory(); + logFactory.Setup().SetupExtensions(extensions => + { + extensions.RegisterServiceProvider(serviceProvider); + extensions.RegisterHostSettings(serviceProvider.GetRequiredService()); + }); + logFactory.Setup().LoadConfiguration(configuration => configuration.ForLogger().WriteTo(target)); + return logFactory; + }) + .Build(); + + try + { + // Act + var loggerProvider = host.Services.GetService() as NLogLoggerProvider; + loggerProvider.LogFactory.GetLogger("test").Info("test"); + + // Assert + Assert.Equal($"TestApplication|{contentRootPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)}|TestEnvironment", Assert.Single(target.Logs)); + } + finally + { + host.Dispose(); + } + } + } +} diff --git a/test/NLog.Extensions.Hosting.Tests/SetupExtensionsBuilderExtensionsTests.cs b/test/NLog.Extensions.Hosting.Tests/SetupExtensionsBuilderExtensionsTests.cs new file mode 100644 index 00000000..4a90dfda --- /dev/null +++ b/test/NLog.Extensions.Hosting.Tests/SetupExtensionsBuilderExtensionsTests.cs @@ -0,0 +1,31 @@ +using System.Linq; +using NLog.Layouts; +using NLog.Extensions.Hosting; +using NLog.Extensions.Logging; +using Xunit; + +namespace NLog.Extensions.Hosting.Tests +{ + public class SetupExtensionsBuilderExtensionsTests + { + [Fact] + public void WriteToJsonTargets_ConfiguresJsonLayoutsAndScopes() + { + // Arrange + var logFactory = new LogFactory(); + + // Act + logFactory.Setup().LoadConfiguration(configuration => + { + configuration.ForLogger().WriteToJsonFile(new SimpleLayout("test.json"), includeScopes: true); + configuration.ForLogger().WriteToJsonConsole(); + }); + + // Assert + var fileTarget = Assert.IsType(logFactory.Configuration.AllTargets.Single(target => target is Targets.FileTarget)); + var consoleTarget = Assert.IsType(logFactory.Configuration.AllTargets.Single(target => target is Targets.ConsoleTarget)); + Assert.True(Assert.IsType(fileTarget.Layout).IncludeScopes); + Assert.False(Assert.IsType(consoleTarget.Layout).IncludeScopes); + } + } +} \ No newline at end of file From 6cfab48e507eb743bdca3407534cfdd0c83150c5 Mon Sep 17 00:00:00 2001 From: Julian Verdurmen <5808377+304NotModified@users.noreply.github.com> Date: Thu, 29 Oct 2026 16:49:15 +0100 Subject: [PATCH 2/2] more tests --- .../HostAppNameLayoutRendererTests.cs | 51 ++++++++++ .../HostEnvironmentLayoutRendererTests.cs | 96 +++++++++++++++++++ .../HostLayoutRendererTestHelper.cs | 92 ++++++++++++++++++ .../HostLayoutRendererTests.cs | 59 ------------ .../HostRootDirLayoutRendererTests.cs | 87 +++++++++++++++++ 5 files changed, 326 insertions(+), 59 deletions(-) create mode 100644 test/NLog.Extensions.Hosting.Tests/HostAppNameLayoutRendererTests.cs create mode 100644 test/NLog.Extensions.Hosting.Tests/HostEnvironmentLayoutRendererTests.cs create mode 100644 test/NLog.Extensions.Hosting.Tests/HostLayoutRendererTestHelper.cs delete mode 100644 test/NLog.Extensions.Hosting.Tests/HostLayoutRendererTests.cs create mode 100644 test/NLog.Extensions.Hosting.Tests/HostRootDirLayoutRendererTests.cs diff --git a/test/NLog.Extensions.Hosting.Tests/HostAppNameLayoutRendererTests.cs b/test/NLog.Extensions.Hosting.Tests/HostAppNameLayoutRendererTests.cs new file mode 100644 index 00000000..4b553f5b --- /dev/null +++ b/test/NLog.Extensions.Hosting.Tests/HostAppNameLayoutRendererTests.cs @@ -0,0 +1,51 @@ +using System.Diagnostics; +using Xunit; + +namespace NLog.Extensions.Hosting.Tests +{ + public class HostAppNameLayoutRendererTests + { + [Fact] + public void RendersHostApplicationName() + { + // Arrange + var hostEnvironment = new TestHostEnvironment { ApplicationName = "TestApplication" }; + + // Act + var result = HostLayoutRendererTestHelper.Render("host-appname", "${host-appname}", hostEnvironment); + + // Assert + Assert.Equal("TestApplication", result); + } + + [Theory] + [InlineData("")] + [InlineData(" ")] + public void FallsBackToProcessNameWhenApplicationNameIsBlank(string applicationName) + { + // Arrange + var hostEnvironment = new TestHostEnvironment { ApplicationName = applicationName }; + var processName = Process.GetCurrentProcess().ProcessName; + + // Act + var result = HostLayoutRendererTestHelper.Render("host-appname", "${host-appname}", hostEnvironment); + + // Assert + Assert.Equal(processName, result); + } + + [Fact] + public void FallsBackToProcessNameWhenHostEnvironmentThrows() + { + // Arrange + var hostEnvironment = new TestHostEnvironment { ThrowOnApplicationName = true }; + var processName = Process.GetCurrentProcess().ProcessName; + + // Act + var result = HostLayoutRendererTestHelper.Render("host-appname", "${host-appname}", hostEnvironment); + + // Assert + Assert.Equal(processName, result); + } + } +} \ No newline at end of file diff --git a/test/NLog.Extensions.Hosting.Tests/HostEnvironmentLayoutRendererTests.cs b/test/NLog.Extensions.Hosting.Tests/HostEnvironmentLayoutRendererTests.cs new file mode 100644 index 00000000..5fb0bc7e --- /dev/null +++ b/test/NLog.Extensions.Hosting.Tests/HostEnvironmentLayoutRendererTests.cs @@ -0,0 +1,96 @@ +using Xunit; + +namespace NLog.Extensions.Hosting.Tests +{ + [Collection("Host renderer environment")] + public class HostEnvironmentLayoutRendererTests + { + [Fact] + public void RendersHostEnvironmentName() + { + // Arrange + var hostEnvironment = new TestHostEnvironment { EnvironmentName = "TestEnvironment" }; + + // Act + var result = HostLayoutRendererTestHelper.Render("host-environment", "${host-environment}", hostEnvironment); + + // Assert + Assert.Equal("TestEnvironment", result); + } + + [Fact] + public void UsesAspNetCoreEnvironmentBeforeDotnetEnvironmentAndTrimsIt() + { + // Arrange + using var variables = new EnvironmentVariableScope("ASPNETCORE_ENVIRONMENT", "DOTNET_ENVIRONMENT"); + variables.Set("ASPNETCORE_ENVIRONMENT", " Staging "); + variables.Set("DOTNET_ENVIRONMENT", "Development"); + var hostEnvironment = new TestHostEnvironment(); + + // Act + var result = HostLayoutRendererTestHelper.Render("host-environment", "${host-environment}", hostEnvironment); + + // Assert + Assert.Equal("Staging", result); + } + + [Fact] + public void UsesDotnetEnvironmentWhenAspNetCoreEnvironmentIsBlank() + { + // Arrange + using var variables = new EnvironmentVariableScope("ASPNETCORE_ENVIRONMENT", "DOTNET_ENVIRONMENT"); + variables.Set("ASPNETCORE_ENVIRONMENT", " "); + variables.Set("DOTNET_ENVIRONMENT", " Development "); + var hostEnvironment = new TestHostEnvironment(); + + // Act + var result = HostLayoutRendererTestHelper.Render("host-environment", "${host-environment}", hostEnvironment); + + // Assert + Assert.Equal("Development", result); + } + + [Fact] + public void UsesEnvironmentFallbackWhenHostEnvironmentThrows() + { + // Arrange + using var variables = new EnvironmentVariableScope("ASPNETCORE_ENVIRONMENT", "DOTNET_ENVIRONMENT"); + variables.Set("DOTNET_ENVIRONMENT", "TestEnvironment"); + var hostEnvironment = new TestHostEnvironment { ThrowOnEnvironmentName = true }; + + // Act + var result = HostLayoutRendererTestHelper.Render("host-environment", "${host-environment}", hostEnvironment); + + // Assert + Assert.Equal("TestEnvironment", result); + } + + [Fact] + public void DefaultsToProductionWhenEnvironmentValuesAreMissing() + { + // Arrange + using var variables = new EnvironmentVariableScope("ASPNETCORE_ENVIRONMENT", "DOTNET_ENVIRONMENT"); + var hostEnvironment = new TestHostEnvironment(); + + // Act + var result = HostLayoutRendererTestHelper.Render("host-environment", "${host-environment}", hostEnvironment); + + // Assert + Assert.Equal("Production", result); + } + + [Fact] + public void PreservesWhitespaceHostEnvironmentName() + { + // Arrange + using var variables = new EnvironmentVariableScope("ASPNETCORE_ENVIRONMENT", "DOTNET_ENVIRONMENT"); + var hostEnvironment = new TestHostEnvironment { EnvironmentName = " " }; + + // Act + var result = HostLayoutRendererTestHelper.Render("host-environment", "${host-environment}", hostEnvironment); + + // Assert + Assert.Equal(" ", result); + } + } +} \ No newline at end of file diff --git a/test/NLog.Extensions.Hosting.Tests/HostLayoutRendererTestHelper.cs b/test/NLog.Extensions.Hosting.Tests/HostLayoutRendererTestHelper.cs new file mode 100644 index 00000000..b741dffe --- /dev/null +++ b/test/NLog.Extensions.Hosting.Tests/HostLayoutRendererTestHelper.cs @@ -0,0 +1,92 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Hosting; +using NLog.LayoutRenderers; +using Xunit; + +namespace NLog.Extensions.Hosting.Tests +{ + [CollectionDefinition("Host renderer environment", DisableParallelization = true)] + public class HostRendererEnvironmentCollection + { + } + + internal static class HostLayoutRendererTestHelper + { + public static string Render(string rendererName, string layout, IHostEnvironment? hostEnvironment = null) + where TLayoutRenderer : LayoutRenderer, new() + { + using var logFactory = new LogFactory(); + var target = new Targets.MemoryTarget { Layout = layout }; + + logFactory.Setup().SetupExtensions(extensions => + { + extensions.RegisterLayoutRenderer(rendererName); + if (hostEnvironment is not null) + extensions.RegisterSingletonService(hostEnvironment); + }); + logFactory.Setup().LoadConfiguration(configuration => configuration.ForLogger().WriteTo(target)); + + return target.Layout.Render(LogEventInfo.CreateNullEvent()); + } + } + + internal sealed class TestHostEnvironment : IHostEnvironment + { + private string _applicationName = string.Empty; + private string _contentRootPath = string.Empty; + private string _environmentName = string.Empty; + + public bool ThrowOnApplicationName { get; set; } + public bool ThrowOnContentRootPath { get; set; } + public bool ThrowOnEnvironmentName { get; set; } + + public string ApplicationName + { + get => ThrowOnApplicationName ? throw new InvalidOperationException() : _applicationName; + set => _applicationName = value; + } + + public string ContentRootPath + { + get => ThrowOnContentRootPath ? throw new InvalidOperationException() : _contentRootPath; + set => _contentRootPath = value; + } + + public string EnvironmentName + { + get => ThrowOnEnvironmentName ? throw new InvalidOperationException() : _environmentName; + set => _environmentName = value; + } + + public IFileProvider ContentRootFileProvider { get; set; } = new NullFileProvider(); + } + + internal sealed class EnvironmentVariableScope : IDisposable + { + private readonly Dictionary _originalValues = new Dictionary(); + + public EnvironmentVariableScope(params string[] variableNames) + { + foreach (var variableName in variableNames) + { + _originalValues[variableName] = Environment.GetEnvironmentVariable(variableName); + Environment.SetEnvironmentVariable(variableName, null); + } + } + + public void Set(string variableName, string? value) + { + Environment.SetEnvironmentVariable(variableName, value); + } + + public void Dispose() + { + foreach (var variable in _originalValues) + Environment.SetEnvironmentVariable(variable.Key, variable.Value); + } + } +} \ No newline at end of file diff --git a/test/NLog.Extensions.Hosting.Tests/HostLayoutRendererTests.cs b/test/NLog.Extensions.Hosting.Tests/HostLayoutRendererTests.cs deleted file mode 100644 index b2a7be4e..00000000 --- a/test/NLog.Extensions.Hosting.Tests/HostLayoutRendererTests.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using NLog.Extensions.Logging; -using Xunit; - -namespace NLog.Extensions.Hosting.Tests -{ - public class HostLayoutRendererTests - { - [Fact] - public void UseNLog_RendersHostEnvironmentValues() - { - // Arrange - var contentRootPath = Path.GetTempPath(); - var hostConfiguration = new Dictionary - { - [HostDefaults.ApplicationKey] = "TestApplication", - [HostDefaults.EnvironmentKey] = "TestEnvironment", - [HostDefaults.ContentRootKey] = contentRootPath - }; - var target = new Targets.MemoryTarget - { - Layout = "${host-appname}|${host-rootdir}|${host-environment}" - }; - var host = new HostBuilder() - .ConfigureHostConfiguration(configuration => configuration.AddInMemoryCollection(hostConfiguration)) - .UseNLog(null, serviceProvider => - { - var logFactory = new LogFactory(); - logFactory.Setup().SetupExtensions(extensions => - { - extensions.RegisterServiceProvider(serviceProvider); - extensions.RegisterHostSettings(serviceProvider.GetRequiredService()); - }); - logFactory.Setup().LoadConfiguration(configuration => configuration.ForLogger().WriteTo(target)); - return logFactory; - }) - .Build(); - - try - { - // Act - var loggerProvider = host.Services.GetService() as NLogLoggerProvider; - loggerProvider.LogFactory.GetLogger("test").Info("test"); - - // Assert - Assert.Equal($"TestApplication|{contentRootPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)}|TestEnvironment", Assert.Single(target.Logs)); - } - finally - { - host.Dispose(); - } - } - } -} diff --git a/test/NLog.Extensions.Hosting.Tests/HostRootDirLayoutRendererTests.cs b/test/NLog.Extensions.Hosting.Tests/HostRootDirLayoutRendererTests.cs new file mode 100644 index 00000000..999bd1a3 --- /dev/null +++ b/test/NLog.Extensions.Hosting.Tests/HostRootDirLayoutRendererTests.cs @@ -0,0 +1,87 @@ +using System.IO; +using Xunit; + +namespace NLog.Extensions.Hosting.Tests +{ + [Collection("Host renderer environment")] + public class HostRootDirLayoutRendererTests + { + [Fact] + public void RendersHostContentRootWithoutTrailingSeparators() + { + // Arrange + var contentRootPath = Path.Combine(Path.GetTempPath(), "HostRoot") + Path.DirectorySeparatorChar + Path.AltDirectorySeparatorChar; + var hostEnvironment = new TestHostEnvironment { ContentRootPath = contentRootPath }; + + // Act + var result = HostLayoutRendererTestHelper.Render("host-rootdir", "${host-rootdir}", hostEnvironment); + + // Assert + Assert.Equal(contentRootPath.TrimEnd(Path.DirectorySeparatorChar).TrimEnd(Path.AltDirectorySeparatorChar), result); + } + + [Fact] + public void UsesAspNetCoreContentRootBeforeDotnetContentRoot() + { + // Arrange + using var variables = new EnvironmentVariableScope("ASPNETCORE_CONTENTROOT", "DOTNET_CONTENTROOT"); + var aspNetCoreRoot = Path.Combine(Path.GetTempPath(), "AspNetCoreRoot") + Path.DirectorySeparatorChar; + variables.Set("ASPNETCORE_CONTENTROOT", $" {aspNetCoreRoot} "); + variables.Set("DOTNET_CONTENTROOT", Path.Combine(Path.GetTempPath(), "DotnetRoot")); + var hostEnvironment = new TestHostEnvironment(); + + // Act + var result = HostLayoutRendererTestHelper.Render("host-rootdir", "${host-rootdir}", hostEnvironment); + + // Assert + Assert.Equal(aspNetCoreRoot.TrimEnd(Path.DirectorySeparatorChar).TrimEnd(Path.AltDirectorySeparatorChar), result); + } + + [Fact] + public void UsesDotnetContentRootWhenAspNetCoreContentRootIsBlank() + { + // Arrange + using var variables = new EnvironmentVariableScope("ASPNETCORE_CONTENTROOT", "DOTNET_CONTENTROOT"); + var dotnetRoot = Path.Combine(Path.GetTempPath(), "DotnetRoot") + Path.AltDirectorySeparatorChar; + variables.Set("ASPNETCORE_CONTENTROOT", " "); + variables.Set("DOTNET_CONTENTROOT", dotnetRoot); + var hostEnvironment = new TestHostEnvironment(); + + // Act + var result = HostLayoutRendererTestHelper.Render("host-rootdir", "${host-rootdir}", hostEnvironment); + + // Assert + Assert.Equal(dotnetRoot.TrimEnd(Path.DirectorySeparatorChar).TrimEnd(Path.AltDirectorySeparatorChar), result); + } + + [Fact] + public void UsesEnvironmentFallbackWhenHostContentRootThrows() + { + // Arrange + using var variables = new EnvironmentVariableScope("ASPNETCORE_CONTENTROOT", "DOTNET_CONTENTROOT"); + var environmentRoot = Path.Combine(Path.GetTempPath(), "EnvironmentRoot"); + variables.Set("DOTNET_CONTENTROOT", environmentRoot); + var hostEnvironment = new TestHostEnvironment { ThrowOnContentRootPath = true }; + + // Act + var result = HostLayoutRendererTestHelper.Render("host-rootdir", "${host-rootdir}", hostEnvironment); + + // Assert + Assert.Equal(environmentRoot, result); + } + + [Fact] + public void FallsBackToCurrentApplicationDirectoryWhenContentRootsAreMissing() + { + // Arrange + using var variables = new EnvironmentVariableScope("ASPNETCORE_CONTENTROOT", "DOTNET_CONTENTROOT"); + + // Act + var result = HostLayoutRendererTestHelper.Render("host-rootdir", "${host-rootdir}"); + + // Assert + Assert.True(Path.IsPathRooted(result)); + Assert.NotEmpty(result); + } + } +} \ No newline at end of file