using FluentAssertions; using IBKRTrader.Core.Settings; namespace IBKRTrader.Tests.Settings; [Trait("cat", "unit")] public class SettingsSchemaTests { [Fact] public void Build_ExtractsSectionsAndFieldsFromAppSettings() { var settings = new AppSettings(); var sections = SettingsSchema.Build(settings); sections.Should().NotBeEmpty(); sections.SelectMany(s => s.Fields).Should().NotBeEmpty(); // Webserver-Abschnitt prüfen var ws = sections.FirstOrDefault(s => s.Fields.Any(f => f.Path == "Webserver.Port")); ws.Should().NotBeNull(); } [Fact] public void ToDto_MasksPasswordsAndTokens() { var settings = new AppSettings(); settings.Webserver.AuthToken = "super-secret-1234"; settings.Database.Password = "db-pass-secret"; var dtos = SettingsSchema.ToDto(settings); var allFields = dtos.SelectMany(s => s.Fields).ToList(); // AuthToken prüfen var tokenField = allFields.FirstOrDefault(f => f.Path == "Webserver.AuthToken"); tokenField.Should().NotBeNull(); tokenField!.IsPassword.Should().BeTrue(); tokenField.HasValue.Should().BeTrue(); tokenField.Value.Should().BeNull("Passwörter und Tokens dürfen niemals im Klartext im DTO stehen!"); // DB Password prüfen var passField = allFields.FirstOrDefault(f => f.Path == "Database.Password"); passField.Should().NotBeNull(); passField!.IsPassword.Should().BeTrue(); passField.Value.Should().BeNull(); } [Fact] public void TrySetValue_UpdatesValueByPath() { var settings = new AppSettings(); settings.Webserver.Port = 5001; var success = SettingsSchema.TrySetValue(settings, "Webserver.Port", 6002); success.Should().BeTrue(); settings.Webserver.Port.Should().Be(6002); } [Fact] public void TrySetValue_PreservesPasswordWhenEmptyPassed() { var settings = new AppSettings(); settings.Webserver.AuthToken = "keep-this-token"; var success = SettingsSchema.TrySetValue(settings, "Webserver.AuthToken", ""); success.Should().BeTrue(); settings.Webserver.AuthToken.Should().Be("keep-this-token"); } [Fact] public void TrySetValue_ReturnsFalseForUnknownPath() { var settings = new AppSettings(); var success = SettingsSchema.TrySetValue(settings, "NonExistent.Field", "val"); success.Should().BeFalse(); } [Fact] public void TrySetValue_ParsesStringRepresentationOfTypes() { var settings = new AppSettings(); // int als string SettingsSchema.TrySetValue(settings, "Webserver.Port", "7001").Should().BeTrue(); settings.Webserver.Port.Should().Be(7001); // bool als string SettingsSchema.TrySetValue(settings, "Webserver.Enabled", "true").Should().BeTrue(); settings.Webserver.Enabled.Should().BeTrue(); // bool als false SettingsSchema.TrySetValue(settings, "Webserver.Enabled", "false").Should().BeTrue(); settings.Webserver.Enabled.Should().BeFalse(); } }