using GFramework.Core.Abstractions.Logging; using GFramework.Core.Logging; namespace GFramework.Core.Tests.Logging; /// /// 验证可配置 Logger 工厂在配置归一化、级别合并与释放路径上的行为契约。 /// [TestFixture] public sealed class ConfigurableLoggerFactoryTests { /// /// 验证当反序列化结果把集合字段写成 时,工厂会将其归一化为空集合而不是抛出空引用异常。 /// [Test] public void CreateFactory_ShouldNormalizeNullCollectionsFromConfiguration() { var config = LoggingConfigurationLoader.LoadFromJsonString( """ { "minLevel": "Warning", "appenders": null, "loggerLevels": null } """); var factory = LoggingConfigurationLoader.CreateFactory(config); var logger = factory.GetLogger("TestLogger"); Assert.Multiple(() => { Assert.That(config.Appenders, Is.Not.Null); Assert.That(config.LoggerLevels, Is.Not.Null); Assert.That(logger.IsInfoEnabled(), Is.False); Assert.That(logger.IsWarnEnabled(), Is.True); }); } /// /// 验证当配置输入把 appenders 集合中的某个元素反序列化为 时,工厂会抛出可诊断异常。 /// [Test] public void CreateFactory_ShouldThrowInvalidOperationException_WhenAppenderEntryIsNull() { var config = LoggingConfigurationLoader.LoadFromJsonString( """ { "appenders": [ null ] } """); var exception = Assert.Throws(() => LoggingConfigurationLoader.CreateFactory(config)); Assert.That(exception!.Message, Is.EqualTo("Appender configuration cannot be null.")); } /// /// 验证在未命中命名空间覆盖时,调用方传入的默认最小级别会作为最终 logger 级别的下限参与计算。 /// [Test] public void GetLogger_ShouldHonorStricterCallerMinLevelWhenNoOverrideMatches() { var config = LoggingConfigurationLoader.LoadFromJsonString( """ { "minLevel": "Info", "appenders": [ { "type": "Console", "formatter": "Default", "useColors": false } ] } """); var factory = LoggingConfigurationLoader.CreateFactory(config); var logger = factory.GetLogger("TestLogger", LogLevel.Warning); Assert.Multiple(() => { Assert.That(logger.IsInfoEnabled(), Is.False); Assert.That(logger.IsWarnEnabled(), Is.True); }); } /// /// 验证命名空间覆盖级别会优先于调用方传入的默认最小级别,确保覆盖配置保持最高优先级。 /// [Test] public void GetLogger_ShouldPreferNamespaceOverrideOverCallerMinLevel() { var config = LoggingConfigurationLoader.LoadFromJsonString( """ { "minLevel": "Info", "appenders": [ { "type": "Console", "formatter": "Default", "useColors": false } ], "loggerLevels": { "MyApp.Services": "Debug" } } """); var factory = LoggingConfigurationLoader.CreateFactory(config); var logger = factory.GetLogger("MyApp.Services.OrderService", LogLevel.Fatal); Assert.Multiple(() => { Assert.That(logger.IsDebugEnabled(), Is.True); Assert.That(logger.IsTraceEnabled(), Is.False); }); } /// /// 验证调用方传入空 logger 名称时,会得到显式的参数异常而不是后续字符串操作的空引用异常。 /// [Test] public void GetLogger_WithNullName_ShouldThrowArgumentNullException() { var factory = LoggingConfigurationLoader.CreateFactory(new LoggingConfiguration()); Assert.Throws(() => factory.GetLogger(null!)); } /// /// 验证工厂释放时会兼容释放未实现 的异步 appender,并让既有 logger 观察到已释放状态。 /// [Test] public void Dispose_ShouldDisposeAsyncLogAppenderCreatedFromConfiguration() { var config = LoggingConfigurationLoader.LoadFromJsonString( """ { "appenders": [ { "type": "Async", "bufferSize": 8, "innerAppender": { "type": "Console", "formatter": "Default", "useColors": false } } ] } """); var factory = LoggingConfigurationLoader.CreateFactory(config); var logger = factory.GetLogger("AsyncLogger"); logger.Info("dispose-path"); ((IDisposable)factory).Dispose(); Assert.Throws(() => logger.Info("after-dispose")); } }