Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions WheelWizard.Test/Features/Settings/DolphinSettingsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public void LoadSettings_ReadsExistingValue_FromIniFile()
}

[Fact]
public void LoadSettings_WritesDefaultValue_WhenIniEntryIsMissing()
public void LoadSettings_UsesDefaultWithoutWriting_WhenIniEntryIsMissing()
{
var fileSystem = new MockFileSystem();
var userFolderPath = $"/wheelwizard-user-{Guid.NewGuid():N}";
Expand All @@ -91,7 +91,8 @@ public void LoadSettings_WritesDefaultValue_WhenIniEntryIsMissing()
manager.LoadSettings(configFolderPath);

var updatedFile = fileSystem.File.ReadAllText(iniPath);
Assert.Contains("NANDRootPath = /default", updatedFile);
Assert.DoesNotContain("NANDRootPath", updatedFile);
Assert.Equal("/default", setting.Get());
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public void RecompSettings_DoNotCreateBackendOwnedFile_WhenMissing()
manager.RegisterSetting(setting);

manager.LoadSettings(configPath);
manager.SaveSettings(configPath, setting);
Assert.Throws<IOException>(() => manager.SaveSettings(configPath, setting));
manager.RemoveTomlSetting(configPath, "video", "show_fps");

Assert.False(fs.File.Exists(configPath));
Expand Down
111 changes: 111 additions & 0 deletions WheelWizard.Test/Features/Settings/SettingsRecoveryTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
using Microsoft.Extensions.Logging.Abstractions;
using Testably.Abstractions.Testing;
using WheelWizard.Settings;
using WheelWizard.Settings.Types;

namespace WheelWizard.Test.Features.Settings;

public class SettingsRecoveryTests
{
[Fact]
public void DolphinEditPreservesExternalValuesAndReloadDoesNotCarryPreviousProfile()
{
var fs = new MockFileSystem();
fs.Directory.CreateDirectory("/config");
fs.File.WriteAllText("/config/GFX.ini", "[Settings]\nShowFPS = False\nInternalResolution = 1\n");
var manager = new DolphinSettingManager(fs);
var fps = new DolphinSetting(typeof(bool), ("GFX.ini", "Settings", "ShowFPS"), false, s => manager.SaveSettings("/config", s));
var resolution = new DolphinSetting(typeof(int), ("GFX.ini", "Settings", "InternalResolution"), 1);
manager.RegisterSetting(fps);
manager.RegisterSetting(resolution);
manager.LoadSettings("/config");
fs.File.WriteAllText("/config/GFX.ini", "[Settings]\nShowFPS = False\nInternalResolution = 4\n");
Assert.True(fps.Set(true));
Assert.Contains("InternalResolution = 4", fs.File.ReadAllText("/config/GFX.ini"));
Assert.Contains("ShowFPS = False", fs.File.ReadAllText("/config/GFX.ini.bak"));
manager.ReloadSettings("/config");
Assert.Equal(4, resolution.Get());
fs.File.WriteAllText("/config/GFX.ini", "[Settings]\nInternalResolution = invalid\n");
manager.ReloadSettings("/config");
Assert.Equal(1, resolution.Get());
Assert.Equal(false, fps.Get());
Assert.Contains("invalid", fs.File.ReadAllText("/config/GFX.ini"));
}

[Fact]
public void RecompReloadMissingKeyUsesDefault()
{
var fs = new MockFileSystem();
fs.Directory.CreateDirectory("/config");
fs.File.WriteAllText("/config/Config.toml", "[video]\nshow_fps = false\n");
var manager = new RecompSettingManager(fs);
var setting = new RecompSetting(typeof(bool), ("video", "show_fps"), true, s => manager.SaveSettings("/config/Config.toml", s));
manager.RegisterSetting(setting);
manager.LoadSettings("/config/Config.toml");
fs.File.WriteAllText("/config/Config.toml", "[video]\n");
manager.ReloadSettings("/config/Config.toml");
Assert.Equal(true, setting.Get());
fs.File.Delete("/config/Config.toml");
Assert.False(setting.Set(false));
Assert.Equal(true, setting.Get());
}

[Fact]
public void FailedSaveRollsBackAndCanBeRetried()
{
var fail = true;
var setting = new WhWzSetting(
typeof(bool),
"Enabled",
false,
_ =>
{
if (fail)
throw new IOException("disk full");
}
);
var notifications = 0;
setting.Changed += _ => notifications++;
Assert.False(setting.Set(true));
Assert.Equal(false, setting.Get());
Assert.Equal(0, notifications);
fail = false;
Assert.True(setting.Set(true));
Assert.Null(setting.SaveError);
Assert.Equal(1, notifications);
}

[Fact]
public void JsonRetainsExistingKeysAndUnknownValuesAndPreservesCorruptFile()
{
var fs = new MockFileSystem();
fs.Directory.CreateDirectory("/config");
const string path = "/config/config.json";
const string original = "{\"EnableAnimations\":false,\"FutureSetting\":{\"value\":2}}";
fs.File.WriteAllText(path, original);
var manager = new WhWzSettingManager(NullLogger<WhWzSettingManager>.Instance, fs);
var setting = new WhWzSetting(typeof(bool), "EnableAnimations", true, s => manager.SaveSettings(path, s));
manager.RegisterSetting(setting);
manager.LoadSettings(path);
Assert.Equal(false, setting.Get());
Assert.True(setting.Set(true));
Assert.Contains("FutureSetting", fs.File.ReadAllText(path));
Assert.Equal(original, fs.File.ReadAllText(path + ".bak"));
fs.File.WriteAllText(path, "broken json");
var corrupt = new WhWzSettingManager(NullLogger<WhWzSettingManager>.Instance, fs);
corrupt.RegisterSetting(setting);
corrupt.LoadSettings(path);
Assert.Throws<IOException>(() => corrupt.SaveSettings(path, setting));
Assert.Equal("broken json", fs.File.ReadAllText(path));
}

[Fact]
public void VirtualSettingTracksDependenciesAfterSetterFailure()
{
var source = new WhWzSetting(typeof(int), "source", 1);
using var derived = new VirtualSetting(typeof(int), _ => throw new IOException("save failed"), source.Get).SetDependencies(source);
Assert.False(derived.Set(2));
source.Set(3);
Assert.Equal(3, derived.Get());
}
}
40 changes: 40 additions & 0 deletions WheelWizard.Test/Features/Settings/SettingsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,46 @@ public sealed class SettingsFeatureCollection;
[Collection("SettingsFeature")]
public class SettingsManagerTests
{
[Theory]
[InlineData("ShaderCompilationMode")]
#if WINDOWS
[InlineData("WaitForShadersBeforeStarting")]
#endif
[InlineData("MSAA")]
[InlineData("SSAA")]
public void RecommendedSettings_PropagatesChildSaveFailureAndCanRetry(string failedSetting)
{
using var manager = CreateManager(new MockFileSystem(), out _, out var dolphinManager, out _);
var children = dolphinManager
.ReceivedCalls()
.Where(call => call.GetMethodInfo().Name == nameof(IDolphinSettingManager.RegisterSetting))
.Select(call => (DolphinSetting)call.GetArguments()[0]!)
.ToDictionary(setting => setting.Name);
children["SSAA"].Set(true, skipSave: true);
var failure = new IOException("disk full");
var fail = true;
dolphinManager
.When(m => m.SaveSettings(Arg.Any<string>(), Arg.Is<DolphinSetting>(s => s.Name == failedSetting)))
.Do(_ =>
{
if (fail)
throw failure;
});
var notifications = 0;
manager.RECOMMENDED_SETTINGS.Changed += _ => notifications++;

Assert.False(manager.Set(manager.RECOMMENDED_SETTINGS, true));
Assert.Same(failure, manager.RECOMMENDED_SETTINGS.SaveError);
Assert.False(manager.Get<bool>(manager.RECOMMENDED_SETTINGS));
Assert.Equal(0, notifications);

fail = false;
Assert.True(manager.Set(manager.RECOMMENDED_SETTINGS, true));
Assert.True(manager.Get<bool>(manager.RECOMMENDED_SETTINGS));
Assert.Null(manager.RECOMMENDED_SETTINGS.SaveError);
Assert.Equal(1, notifications);
}

[Fact]
public void Get_Throws_WhenRequestedTypeDoesNotMatchSettingType()
{
Expand Down
5 changes: 3 additions & 2 deletions WheelWizard.Test/Features/Settings/WhWzSettingsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,11 @@ public void Reset_RestoresForceSave_WhenSavingThrows(bool forceSave)
.SetForceSave(forceSave);
setting.Set(12, skipSave: true);

Assert.Throws<IOException>(setting.Reset);
setting.Reset();
Assert.IsType<IOException>(setting.SaveError);

Assert.Equal(forceSave, setting.Set(6, skipSave: true));
Assert.Equal(forceSave ? 6 : 5, setting.Get());
Assert.Equal(forceSave ? 6 : 12, setting.Get());
}

[Fact]
Expand Down
Loading
Loading