Skip to content
Merged
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,9 @@ FodyWeavers.xsd
# Local History for Visual Studio Code
.history/

# Avalonia build task artifacts
**/.avalonia-build-tasks/

# Windows Installer files from build outputs
*.cab
*.msi
Expand Down
126 changes: 126 additions & 0 deletions WheelWizard.Test/Features/LinuxDolphinInstallerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
using WheelWizard.DolphinInstaller;
using WheelWizard.Shared;

namespace WheelWizard.Test.Features;

public class LinuxDolphinInstallerTests
{
private readonly ILinuxCommandEnvironment _commandEnvironment;
private readonly ILinuxProcessService _processService;
private readonly LinuxDolphinInstaller _installer;

public LinuxDolphinInstallerTests()
{
_commandEnvironment = Substitute.For<ILinuxCommandEnvironment>();
_processService = Substitute.For<ILinuxProcessService>();
_installer = new LinuxDolphinInstaller(_commandEnvironment, _processService);
}

[Fact]
public void IsDolphinInstalledInFlatpak_ReturnsTrue_WhenFlatpakInfoExitCodeIsZero()
{
_processService.Run("flatpak", "info org.DolphinEmu.dolphin-emu").Returns(Ok(0));

var result = _installer.IsDolphinInstalledInFlatpak();

Assert.True(result);
}
Comment thread
DirkDoes marked this conversation as resolved.

[Fact]
public void IsDolphinInstalledInFlatpak_ReturnsFalse_WhenFlatpakInfoExitCodeIsNonZero()
{
_processService.Run("flatpak", "info org.DolphinEmu.dolphin-emu").Returns(Ok(1));

var result = _installer.IsDolphinInstalledInFlatpak();

Assert.False(result);
}

[Fact]
public async Task InstallFlatpak_ReturnsFailure_WhenPackageManagerCannotBeDetected()
{
_commandEnvironment.IsCommandAvailable("flatpak").Returns(false);
_commandEnvironment.DetectPackageManagerInstallCommand().Returns(string.Empty);

var result = await _installer.InstallFlatpak();

Assert.True(result.IsFailure);
Assert.Contains("Unsupported Linux distribution", result.Error.Message);
}

[Fact]
public async Task InstallFlatpak_ReturnsFailure_WhenPkexecIsUnauthorized()
{
_commandEnvironment.IsCommandAvailable("flatpak").Returns(false);
_commandEnvironment.DetectPackageManagerInstallCommand().Returns("apt-get install -y");
_processService
.RunWithProgressAsync("pkexec", "apt-get install -y flatpak", Arg.Any<IProgress<int>?>())
.Returns(Task.FromResult<OperationResult<int>>(Ok(126)));

var result = await _installer.InstallFlatpak();

Assert.True(result.IsFailure);
Assert.Contains("administrator", result.Error.Message);
}

[Fact]
public async Task InstallFlatpak_ReturnsSuccess_WhenInstallCompletesAndCommandBecomesAvailable()
{
_commandEnvironment.IsCommandAvailable("flatpak").Returns(false, true);
_commandEnvironment.DetectPackageManagerInstallCommand().Returns("apt-get install -y");
_processService
.RunWithProgressAsync("pkexec", "apt-get install -y flatpak", Arg.Any<IProgress<int>?>())
.Returns(Task.FromResult<OperationResult<int>>(Ok(0)));

var result = await _installer.InstallFlatpak();

Assert.True(result.IsSuccess);
}

[Fact]
public async Task InstallFlatpakDolphin_ReturnsFailure_WhenDolphinInstallCommandFails()
{
_commandEnvironment.IsCommandAvailable("flatpak").Returns(true);
_processService
.RunWithProgressAsync("pkexec", "flatpak --system install -y org.DolphinEmu.dolphin-emu", Arg.Any<IProgress<int>?>())
.Returns(Task.FromResult<OperationResult<int>>(Ok(1)));

var result = await _installer.InstallFlatpakDolphin();

Assert.True(result.IsFailure);
Assert.Contains("exit code 1", result.Error.Message);
}

[Fact]
public async Task InstallFlatpakDolphin_ReturnsFailure_WhenWarmupLaunchFails()
{
_commandEnvironment.IsCommandAvailable("flatpak").Returns(true);
_processService
.RunWithProgressAsync("pkexec", "flatpak --system install -y org.DolphinEmu.dolphin-emu", Arg.Any<IProgress<int>?>())
.Returns(Task.FromResult<OperationResult<int>>(Ok(0)));
_processService
.LaunchAndStopAsync("flatpak", "run org.DolphinEmu.dolphin-emu", TimeSpan.FromSeconds(4))
.Returns(Task.FromResult<OperationResult>(Fail("Launch failed")));

var result = await _installer.InstallFlatpakDolphin();

Assert.True(result.IsFailure);
Assert.Equal("Launch failed", result.Error.Message);
}

[Fact]
public async Task InstallFlatpakDolphin_ReturnsSuccess_WhenInstallAndWarmupSucceed()
{
_commandEnvironment.IsCommandAvailable("flatpak").Returns(true);
_processService
.RunWithProgressAsync("pkexec", "flatpak --system install -y org.DolphinEmu.dolphin-emu", Arg.Any<IProgress<int>?>())
.Returns(Task.FromResult<OperationResult<int>>(Ok(0)));
_processService
.LaunchAndStopAsync("flatpak", "run org.DolphinEmu.dolphin-emu", TimeSpan.FromSeconds(4))
.Returns(Task.FromResult<OperationResult>(Ok()));

var result = await _installer.InstallFlatpakDolphin();

Assert.True(result.IsSuccess);
}
}
149 changes: 149 additions & 0 deletions WheelWizard.Test/Features/Settings/DolphinSettingsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
using Testably.Abstractions.Testing;
using WheelWizard.Services;
using WheelWizard.Settings;
using WheelWizard.Settings.Types;

namespace WheelWizard.Test.Features.Settings;

[Collection("SettingsFeature")]
public class DolphinSettingTests
{
[Fact]
public void Constructor_Throws_WhenFileNameIsNotIni()
{
var action = () => new DolphinSetting(typeof(string), ("Dolphin.cfg", "General", "NANDRootPath"), "value");

Assert.Throws<ArgumentException>(action);
}

[Fact]
public void SetFromString_ParsesEnumAndFormatsAsIntegerString()
{
var setting = new DolphinSetting(
typeof(DolphinShaderCompilationMode),
("GFX.ini", "Settings", "ShaderCompilationMode"),
DolphinShaderCompilationMode.Default
);

var result = setting.SetFromString("2", skipSave: true);

Assert.True(result);
Assert.Equal(DolphinShaderCompilationMode.HybridUberShaders, Assert.IsType<DolphinShaderCompilationMode>(setting.Get()));
Assert.Equal("2", setting.GetStringValue());
}

[Fact]
public void Set_ReturnsFalseAndKeepsOldValue_WhenValidationFails()
{
var setting = new DolphinSetting(typeof(int), ("GFX.ini", "Settings", "InternalResolution"), 1).SetValidation(value =>
(int)value! >= 0
);
setting.Set(2);

var result = setting.Set(-1);

Assert.False(result);
Assert.Equal(2, Assert.IsType<int>(setting.Get()));
}

[Fact]
public void SetFromString_Throws_WhenTypeIsUnsupported()
{
var setting = new DolphinSetting(typeof(decimal), ("GFX.ini", "Settings", "Price"), 1m);

Assert.Throws<InvalidOperationException>(() => setting.SetFromString("3.14"));
}
}

[Collection("SettingsFeature")]
public class DolphinSettingManagerTests : IDisposable
{
[Fact]
public void LoadSettings_ReadsExistingValue_FromIniFile()
{
var fileSystem = new MockFileSystem();
var userFolderPath = $"/wheelwizard-user-{Guid.NewGuid():N}";
SettingsTestUtils.InitializeSettingsRuntime(userFolderPath);
var configFolderPath = PathManager.ConfigFolderPath;
var iniPath = Path.Combine(configFolderPath, "Dolphin.ini");
fileSystem.Directory.CreateDirectory(configFolderPath);
fileSystem.File.WriteAllLines(iniPath, ["[General]", "NANDRootPath = /persisted"]);
var manager = new DolphinSettingManager(fileSystem);
var setting = new DolphinSetting(typeof(string), ("Dolphin.ini", "General", "NANDRootPath"), "/default");

manager.RegisterSetting(setting);
manager.LoadSettings();

Assert.Equal("/persisted", Assert.IsType<string>(setting.Get()));
}
Comment thread
DirkDoes marked this conversation as resolved.

[Fact]
public void LoadSettings_WritesDefaultValue_WhenIniEntryIsMissing()
{
var fileSystem = new MockFileSystem();
var userFolderPath = $"/wheelwizard-user-{Guid.NewGuid():N}";
SettingsTestUtils.InitializeSettingsRuntime(userFolderPath);
var configFolderPath = PathManager.ConfigFolderPath;
var iniPath = Path.Combine(configFolderPath, "Dolphin.ini");
fileSystem.Directory.CreateDirectory(configFolderPath);
fileSystem.File.WriteAllLines(iniPath, ["[General]", "OtherSetting = 1"]);
var manager = new DolphinSettingManager(fileSystem);
var setting = new DolphinSetting(typeof(string), ("Dolphin.ini", "General", "NANDRootPath"), "/default");

manager.RegisterSetting(setting);
manager.LoadSettings();

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

[Fact]
public void SaveSettings_UpdatesExistingSettingLine_InIniFile()
{
var fileSystem = new MockFileSystem();
var userFolderPath = $"/wheelwizard-user-{Guid.NewGuid():N}";
SettingsTestUtils.InitializeSettingsRuntime(userFolderPath);
var configFolderPath = PathManager.ConfigFolderPath;
var iniPath = Path.Combine(configFolderPath, "Dolphin.ini");
fileSystem.Directory.CreateDirectory(configFolderPath);
fileSystem.File.WriteAllLines(iniPath, ["[General]", "NANDRootPath = /old"]);
var manager = new DolphinSettingManager(fileSystem);
var setting = new DolphinSetting(typeof(string), ("Dolphin.ini", "General", "NANDRootPath"), "/default");

manager.RegisterSetting(setting);
manager.LoadSettings();
setting.Set("/new", skipSave: true);
manager.SaveSettings(setting);

var updatedFile = fileSystem.File.ReadAllText(iniPath);
Assert.Contains("NANDRootPath = /new", updatedFile);
Assert.DoesNotContain("NANDRootPath = /old", updatedFile);
}

[Fact]
public void ReloadSettings_ReReadsFile_AfterItChangesOnDisk()
{
var fileSystem = new MockFileSystem();
var userFolderPath = $"/wheelwizard-user-{Guid.NewGuid():N}";
SettingsTestUtils.InitializeSettingsRuntime(userFolderPath);
var configFolderPath = PathManager.ConfigFolderPath;
var iniPath = Path.Combine(configFolderPath, "Dolphin.ini");
fileSystem.Directory.CreateDirectory(configFolderPath);
fileSystem.File.WriteAllLines(iniPath, ["[General]", "NANDRootPath = /first"]);
var manager = new DolphinSettingManager(fileSystem);
var setting = new DolphinSetting(typeof(string), ("Dolphin.ini", "General", "NANDRootPath"), "/default");

manager.RegisterSetting(setting);
manager.LoadSettings();
fileSystem.File.WriteAllLines(iniPath, ["[General]", "NANDRootPath = /second"]);
manager.ReloadSettings();

Assert.Equal("/second", Assert.IsType<string>(setting.Get()));
}

public void Dispose()
{
SettingsTestUtils.ResetSettingsRuntime();
SettingsTestUtils.ResetSignalRuntime();
}
}
Loading
Loading