using System.IO; using System.Text; using System.Text.Json; using SharepointToolbox.Core.Models; using SharepointToolbox.Infrastructure.Persistence; using SharepointToolbox.Services; namespace SharepointToolbox.Tests.Services; [Trait("Category", "Unit")] public class SettingsServiceTests : IDisposable { private readonly string _tempFile; public SettingsServiceTests() { _tempFile = Path.GetTempFileName(); File.Delete(_tempFile); } public void Dispose() { if (File.Exists(_tempFile)) File.Delete(_tempFile); if (File.Exists(_tempFile + ".tmp")) File.Delete(_tempFile + ".tmp"); } private SettingsRepository CreateRepository() => new(_tempFile); private SettingsService CreateService() => new(CreateRepository()); [Fact] public async Task LoadAsync_MissingFile_ReturnsDefaultSettings() { var repo = CreateRepository(); var settings = await repo.LoadAsync(); Assert.Equal(string.Empty, settings.DataFolder); Assert.Equal("en", settings.Lang); } [Fact] public async Task SaveAndLoad_RoundTrips_DataFolderAndLang() { var repo = CreateRepository(); var original = new AppSettings { DataFolder = @"C:\Exports", Lang = "fr" }; await repo.SaveAsync(original); var loaded = await repo.LoadAsync(); Assert.Equal(@"C:\Exports", loaded.DataFolder); Assert.Equal("fr", loaded.Lang); } [Fact] public async Task SaveAsync_SerializedJson_UsesDataFolderAndLangKeys() { var repo = CreateRepository(); await repo.SaveAsync(new AppSettings { DataFolder = @"C:\Exports", Lang = "fr" }); var json = await File.ReadAllTextAsync(_tempFile); using var doc = JsonDocument.Parse(json); Assert.True(doc.RootElement.TryGetProperty("dataFolder", out _), "JSON must contain 'dataFolder' key (camelCase for schema compatibility)"); Assert.True(doc.RootElement.TryGetProperty("lang", out _), "JSON must contain 'lang' key (camelCase for schema compatibility)"); } [Fact] public async Task SaveAsync_UsesTmpFileThenMove() { var repo = CreateRepository(); // The .tmp file should not exist after a successful save await repo.SaveAsync(new AppSettings { DataFolder = @"C:\Test", Lang = "en" }); Assert.False(File.Exists(_tempFile + ".tmp"), "Temp file should have been moved/deleted after successful save"); Assert.True(File.Exists(_tempFile), "Settings file must exist after save"); } [Fact] public async Task SetLanguageAsync_PersistsLang() { var service = CreateService(); await service.SetLanguageAsync("fr"); var settings = await service.GetSettingsAsync(); Assert.Equal("fr", settings.Lang); } [Fact] public async Task SetDataFolderAsync_PersistsPath() { var service = CreateService(); await service.SetDataFolderAsync(@"C:\Exports"); var settings = await service.GetSettingsAsync(); Assert.Equal(@"C:\Exports", settings.DataFolder); } [Fact] public async Task SetDataFolderAsync_EmptyString_IsAllowed() { var service = CreateService(); await service.SetDataFolderAsync(@"C:\Exports"); await service.SetDataFolderAsync(string.Empty); var settings = await service.GetSettingsAsync(); Assert.Equal(string.Empty, settings.DataFolder); } [Fact] public async Task SetLanguageAsync_InvalidCode_ThrowsArgumentException() { var service = CreateService(); await Assert.ThrowsAsync(() => service.SetLanguageAsync("de")); } }