Skip to content

Commit 8ddcdc6

Browse files
committed
fix: address code-quality path and disposal findings
1 parent 447e64f commit 8ddcdc6

17 files changed

Lines changed: 96 additions & 35 deletions

File tree

ColDogLocker.Avalonia.Tests/ViewModels/MainWindowViewModelTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ internal static ObservableCollection<LockerItemViewModel> CreateLockers()
195195
{
196196
Guid = System.Guid.NewGuid().ToString(),
197197
Name = "Alpha",
198-
Location = Path.Combine(Path.DirectorySeparatorChar.ToString(), "vault", "alpha"),
198+
Location = $"{Path.DirectorySeparatorChar}{Path.Join("vault", "alpha")}",
199199
IsLocked = false,
200200
LastModified = new DateTime(2026, 1, 2, 0, 0, 0, DateTimeKind.Utc),
201201
Size = 200
@@ -204,7 +204,7 @@ internal static ObservableCollection<LockerItemViewModel> CreateLockers()
204204
{
205205
Guid = System.Guid.NewGuid().ToString(),
206206
Name = "Beta",
207-
Location = Path.Combine(Path.DirectorySeparatorChar.ToString(), "archive", "beta"),
207+
Location = $"{Path.DirectorySeparatorChar}{Path.Join("archive", "beta")}",
208208
IsLocked = true,
209209
LastModified = new DateTime(2026, 1, 1, 0, 0, 0, DateTimeKind.Utc),
210210
Size = 100

ColDogLocker.Avalonia.Tests/Views/DialogHeadlessTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ public void SettingsDialog_TracksChangesAndEnablesSave()
113113
private static string CreateSafeLockerPath()
114114
{
115115
var profile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
116-
return Path.Combine(profile, "Documents", "ColDogLockerHeadless", "HeadlessLocker");
116+
return Path.Join(profile, "Documents", "ColDogLockerHeadless", "HeadlessLocker");
117117
}
118118

119119
private static T RequiredControl<T>(Control root, string name) where T : Control

ColDogLocker.Avalonia/Views/Dialogs/ErrorDialog.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ private async void OpenLogsButton_Click(object? sender, RoutedEventArgs e)
8484
try
8585
{
8686
var logsPath = Path.GetDirectoryName(Logger.GetCurrentLogFilePath())
87-
?? Path.Combine(AppPaths.LocalConfig, "logs");
87+
?? Path.Join(AppPaths.LocalConfig, "logs");
8888
AppFilePermissions.EnsurePrivateDirectory(logsPath);
8989

9090
if (_platformService != null)

ColDogLocker.Avalonia/Views/Dialogs/SettingsDialog.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ private async void CheckForUpdates_Click(object? sender, RoutedEventArgs e)
192192
private async void OpenLogsFolder_Click(object? sender, RoutedEventArgs e)
193193
{
194194
var logsPath = Path.GetDirectoryName(Logger.GetCurrentLogFilePath())
195-
?? Path.Combine(AppPaths.LocalConfig, "logs");
195+
?? Path.Join(AppPaths.LocalConfig, "logs");
196196
await OpenFolderAsync(logsPath, "Failed to open logs folder");
197197
}
198198

ColDogLocker.Cli.Tests/CommandHelpTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public void ShowCommandHelp_ForUnknownCommand_PrintsCompleteCommandList()
5151

5252
private static string CaptureOutput(Action action)
5353
{
54-
var outputWriter = new StringWriter();
54+
using var outputWriter = new StringWriter();
5555
var originalOutput = Console.Out;
5656

5757
try

ColDogLocker.Cli.Tests/GuiLauncherTests.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public void Launch_WhenLinuxInstalledGuiExists_StartsOptExecutable()
5757
[Fact]
5858
public void Launch_WhenLinuxInstalledGuiIsMissing_ReturnsExecutableNotFoundError()
5959
{
60-
var errorWriter = new StringWriter();
60+
using var errorWriter = new StringWriter();
6161
var originalError = Console.Error;
6262

6363
try
@@ -102,7 +102,7 @@ public void GetCandidatePaths_WhenUnixSourceBuild_UsesUnixExecutableName()
102102
[Fact]
103103
public void Launch_WhenProcessCannotStart_ReturnsFailure()
104104
{
105-
var baseDirectory = Path.Combine(Path.GetTempPath(), $"cdlocker-gui-launcher-tests-{Guid.NewGuid():N}");
105+
var baseDirectory = Path.Join(Path.GetTempPath(), $"cdlocker-gui-launcher-tests-{Guid.NewGuid():N}");
106106
var expectedExecutable = Path.GetFullPath(Path.Combine(baseDirectory, "ColDogLocker"));
107107
var environment = CreateEnvironment(
108108
isMacOS: false,
@@ -147,7 +147,7 @@ public void Launch_WhenMacOsInstalledAppExists_StartsAppBundleExecutable()
147147
[Fact]
148148
public void Launch_WhenMacOsInstalledAppIsMissing_ReturnsExecutableNotFoundError()
149149
{
150-
var errorWriter = new StringWriter();
150+
using var errorWriter = new StringWriter();
151151
var originalError = Console.Error;
152152

153153
try
@@ -171,7 +171,7 @@ public void Launch_WhenMacOsInstalledAppIsMissing_ReturnsExecutableNotFoundError
171171
[Fact]
172172
public void GetCandidatePaths_WhenSourceTreeAndInstalledFallbackExist_PrefersSourceTreeBeforeInstalledFallback()
173173
{
174-
var sourceRoot = Path.Combine(Path.GetTempPath(), $"cdlocker-source-{Guid.NewGuid():N}");
174+
var sourceRoot = Path.Join(Path.GetTempPath(), $"cdlocker-source-{Guid.NewGuid():N}");
175175
var baseDirectory = Path.Combine(sourceRoot, "ColDogLocker.Cli", "bin", "Debug", "net10.0");
176176
var sourceCandidate = Path.Combine(sourceRoot, "ColDogLocker.Avalonia", "bin", "Debug", "net10.0", "ColDogLocker");
177177
var environment = CreateEnvironment(
@@ -202,7 +202,7 @@ private static GuiLauncherEnvironment CreateEnvironment(
202202
{
203203
return new GuiLauncherEnvironment
204204
{
205-
BaseDirectory = baseDirectory ?? Path.Combine(Path.GetTempPath(), $"cdlocker-gui-launcher-tests-{Guid.NewGuid():N}"),
205+
BaseDirectory = baseDirectory ?? Path.Join(Path.GetTempPath(), $"cdlocker-gui-launcher-tests-{Guid.NewGuid():N}"),
206206
IsMacOS = isMacOS,
207207
IsLinux = isLinux,
208208
IsWindows = isWindows,
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using ColDogStudios.ColDogLocker.Cli.Commands;
2+
3+
namespace ColDogStudios.ColDogLocker.Cli.Tests
4+
{
5+
public sealed class LockerCommandsTests
6+
{
7+
[Theory]
8+
[InlineData("bad/name", "Locker name must be a valid file name")]
9+
[InlineData("..", "Locker name must be a valid file name")]
10+
[InlineData("", "Locker name cannot be empty")]
11+
public void New_WithInvalidLockerName_ReturnsErrorBeforeCreatingLocker(string lockerName, string expectedError)
12+
{
13+
using var errorWriter = new StringWriter();
14+
var originalError = Console.Error;
15+
16+
try
17+
{
18+
Console.SetError(errorWriter);
19+
20+
var exitCode = LockerCommands.New(["new", lockerName, "--password", "ValidPassword123!"]);
21+
22+
Assert.Equal(1, exitCode);
23+
Assert.Contains(expectedError, errorWriter.ToString());
24+
}
25+
finally
26+
{
27+
Console.SetError(originalError);
28+
}
29+
}
30+
}
31+
}

ColDogLocker.Cli/Commands/LockerCommands.cs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ public static int New(string[] args)
4949
return 1;
5050
}
5151

52+
var lockerNameValidationError = ValidateLockerName(lockerName);
53+
if (lockerNameValidationError != null)
54+
{
55+
Console.Error.WriteLine($"Error: {lockerNameValidationError}");
56+
return 1;
57+
}
58+
5259
string? customPath = null;
5360
string? providedPassword = null;
5461

@@ -69,8 +76,8 @@ public static int New(string[] args)
6976

7077
// Determine locker location
7178
var lockerLocation = customPath is not null
72-
? Path.Combine(customPath, lockerName)
73-
: Path.Combine(AppPaths.CdlDir, lockerName);
79+
? Path.Join(customPath, lockerName)
80+
: Path.Join(AppPaths.CdlDir, lockerName);
7481

7582
// Validate path is not protected
7683
var pathValidationError = LockerPathFilter.ValidatePath(lockerLocation);
@@ -163,6 +170,25 @@ public static int New(string[] args)
163170
}
164171
}
165172

173+
private static string? ValidateLockerName(string lockerName)
174+
{
175+
if (string.IsNullOrWhiteSpace(lockerName))
176+
{
177+
return "Locker name cannot be empty.";
178+
}
179+
180+
var trimmedName = lockerName.Trim();
181+
if (trimmedName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0 ||
182+
trimmedName.Contains(Path.DirectorySeparatorChar) ||
183+
trimmedName.Contains(Path.AltDirectorySeparatorChar) ||
184+
trimmedName is "." or "..")
185+
{
186+
return "Locker name must be a valid file name, not a path.";
187+
}
188+
189+
return null;
190+
}
191+
166192
#endregion
167193

168194
#region Remove Locker

ColDogLocker.Core/Versioning/SemanticVersion.cs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -197,21 +197,12 @@ public static bool TryParse(string version, out SemanticVersion result)
197197
return false;
198198
}
199199

200-
// Validate pre-release format (no leading zeros in numeric identifiers per semver spec)
201-
if (preRelease != null)
200+
var preReleaseParts = preRelease?.Split('.');
201+
if (preReleaseParts?.Any(part => part.Length > 1 && part[0] == '0' && char.IsDigit(part[1])) == true)
202202
{
203-
var parts = preRelease.Split('.');
204-
foreach (var part in parts)
205-
{
206-
// Reject numeric identifiers with leading zeros (except "0" itself)
207-
if (part.Length > 1 && part[0] == '0' && char.IsDigit(part[1]))
208-
{
209-
return false;
210-
}
211-
}
203+
return false;
212204
}
213205

214-
var preReleaseParts = preRelease?.Split('.');
215206
result = new SemanticVersion(major, minor, patch, preRelease, preReleaseParts);
216207
return true;
217208
}

ColDogLocker.Services.Tests/Lockers/LockerArchiveServiceTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ public void Dispose()
283283

284284
public static TestWorkspace Create()
285285
{
286-
return new TestWorkspace(System.IO.Path.Combine(System.IO.Path.GetTempPath(), $"cdlocker-archive-tests-{Guid.NewGuid():N}"));
286+
return new TestWorkspace(System.IO.Path.Join(System.IO.Path.GetTempPath(), $"cdlocker-archive-tests-{Guid.NewGuid():N}"));
287287
}
288288

289289
public string CreateDirectory(string name)

0 commit comments

Comments
 (0)