using Decky.Core.Models; using Decky.Core.Services; namespace Decky.Core.Tests; public sealed class JsonSettingsServiceTests : IDisposable { private readonly string _testDirectory = Path.Combine( Path.GetTempPath(), $"Decky.Tests.{Guid.NewGuid():N}"); [Fact] public async Task LoadAsync_returns_defaults_when_file_does_not_exist() { using var service = CreateService(); var settings = await service.LoadAsync(); Assert.Equal(30, settings.RefreshIntervalSeconds); Assert.Empty(settings.OpenBoardTabs); } [Fact] public async Task SaveAsync_round_trips_connection_and_board_settings() { using var service = CreateService(); var expected = new AppSettings { ServerUrl = "https://cloud.example.test/", Username = "elijah", ApiPath = "index.php/apps/deck/api/v1.0/", OpenBoardTabs = [17], Boards = new Dictionary { [17] = new() { Orientation = BoardOrientation.Vertical }, }, }; await service.SaveAsync(expected); var actual = await service.LoadAsync(); Assert.Equal(expected.ServerUrl, actual.ServerUrl); Assert.Equal(expected.Username, actual.Username); Assert.Equal(expected.ApiPath, actual.ApiPath); Assert.Equal([17], actual.OpenBoardTabs); Assert.Equal(BoardOrientation.Vertical, actual.Boards[17].Orientation); Assert.DoesNotContain("password", await File.ReadAllTextAsync(GetSettingsPath()), StringComparison.OrdinalIgnoreCase); } [Fact] public async Task LoadAsync_preserves_corrupt_file_and_returns_defaults() { Directory.CreateDirectory(_testDirectory); await File.WriteAllTextAsync(GetSettingsPath(), "{ definitely not json }"); using var service = CreateService(); var settings = await service.LoadAsync(); Assert.Equal(string.Empty, settings.ServerUrl); Assert.False(File.Exists(GetSettingsPath())); Assert.Single(Directory.GetFiles(_testDirectory, "settings.corrupt-*.json")); } private JsonSettingsService CreateService() => new(GetSettingsPath()); private string GetSettingsPath() => Path.Combine(_testDirectory, "settings.json"); public void Dispose() { if (Directory.Exists(_testDirectory)) { Directory.Delete(_testDirectory, recursive: true); } } }