From eb1d482e2498973d8b5efdc60661bcb043a94571 Mon Sep 17 00:00:00 2001 From: Nicolas Kogler Date: Wed, 13 May 2026 23:47:31 +0200 Subject: [PATCH] fix: avoid startup crash when saved appdata path is unavailable --- .../Features/Settings/PathManagerTests.cs | 27 +++++++++++++++++++ WheelWizard/Services/PathManager.cs | 23 +++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 WheelWizard.Test/Features/Settings/PathManagerTests.cs diff --git a/WheelWizard.Test/Features/Settings/PathManagerTests.cs b/WheelWizard.Test/Features/Settings/PathManagerTests.cs new file mode 100644 index 00000000..fbef7d2a --- /dev/null +++ b/WheelWizard.Test/Features/Settings/PathManagerTests.cs @@ -0,0 +1,27 @@ +using WheelWizard.Services; + +namespace WheelWizard.Test.Features.Settings; + +[Collection("SettingsFeature")] +public class PathManagerTests +{ + [Fact] + public void TrySetWheelWizardAppdataPath_ReturnsFalse_WhenTargetPathIsUnavailable() + { + if (!OperatingSystem.IsWindows()) + return; + + var unavailablePath = GetUnavailableWindowsPath(); + var result = PathManager.TrySetWheelWizardAppdataPath(unavailablePath, out var errorMessage, out _); + + Assert.False(result); + Assert.False(string.IsNullOrWhiteSpace(errorMessage)); + } + + private static string GetUnavailableWindowsPath() + { + var used = DriveInfo.GetDrives().Select(d => char.ToUpperInvariant(d.Name[0])).ToHashSet(); + var drive = "ZYXWVUTSRQPONMLKJIHGFEDCBA".FirstOrDefault(letter => !used.Contains(letter), 'Z'); + return $@"{drive}:\WheelWizardTests\{Guid.NewGuid():N}"; + } +} diff --git a/WheelWizard/Services/PathManager.cs b/WheelWizard/Services/PathManager.cs index 998bce82..d7e5fdca 100644 --- a/WheelWizard/Services/PathManager.cs +++ b/WheelWizard/Services/PathManager.cs @@ -95,7 +95,15 @@ public static bool IsUsingCustomWheelWizardAppdataPath return null; var normalized = FileHelper.NormalizePath(storedPath); - return FileHelper.PathsEqual(normalized, DefaultWheelWizardAppdataPath) ? null : normalized; + if (FileHelper.PathsEqual(normalized, DefaultWheelWizardAppdataPath)) + return null; + + // If a previously selected custom location is no longer available (for example, + // when an external drive letter changes), fall back to the default path. + if (!TryEnsureWheelWizardAppdataPathAccessible(normalized)) + return null; + + return normalized; } catch { @@ -103,6 +111,19 @@ public static bool IsUsingCustomWheelWizardAppdataPath } } + private static bool TryEnsureWheelWizardAppdataPathAccessible(string normalizedPath) + { + try + { + FileHelper.EnsureDirectory(normalizedPath); + return true; + } + catch + { + return false; + } + } + private static string? LoadPersistedWheelWizardAppdataOverride() { #if WINDOWS