- AppSettings model: DataFolder + Lang with camelCase JSON serialization - SettingsRepository: SemaphoreSlim write lock + write-then-replace (tmp→validate→move) - SettingsService: GetSettings/SetLanguage/SetDataFolder; SetLanguage validates en/fr only - All 8 SettingsServiceTests pass; all 18 Unit tests pass
124 lines
3.7 KiB
C#
124 lines
3.7 KiB
C#
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<ArgumentException>(() => service.SetLanguageAsync("de"));
|
|
}
|
|
}
|