Skip to content

Commit 4e00a36

Browse files
fix: validate dotnet path exists before returning from TryFindDotNetExePath
TryFindDotNetExePath() was always returning a constructed path even when the file didn't exist (e.g., /usr/local/share/dotnet/dotnet on Alpine). This prevented FullPathOrDefault() from falling back to just "dotnet". Added File.Exists check and extracted FindDotNetInRoot as an internal method for testability. Added tests covering exists/not-exists scenarios. Fixes #600 Co-authored-by: Nate McMaster <natemcmaster@users.noreply.github.com>
1 parent 0709a62 commit 4e00a36

2 files changed

Lines changed: 64 additions & 1 deletion

File tree

src/CommandLineUtils/Utilities/DotNetExe.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,13 @@ public static string FullPathOrDefault()
6565
dotnetRoot = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "C:\\Program Files\\dotnet" : "/usr/local/share/dotnet";
6666
}
6767

68-
return Path.Combine(dotnetRoot, fileName);
68+
return FindDotNetInRoot(dotnetRoot, fileName);
69+
}
70+
71+
internal static string? FindDotNetInRoot(string dotnetRoot, string fileName)
72+
{
73+
var dotnetPath = Path.Combine(dotnetRoot, fileName);
74+
return File.Exists(dotnetPath) ? dotnetPath : null;
6975
}
7076
}
7177
}

test/CommandLineUtils.Tests/DotNetExeTests.cs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#if NET6_0_OR_GREATER
77
using System.IO;
8+
using System.Runtime.InteropServices;
89
using Xunit;
910

1011
namespace McMaster.Extensions.CommandLineUtils.Tests
@@ -20,6 +21,62 @@ public void FindsTheDotNetPath()
2021
Assert.True(Path.IsPathRooted(dotnetPath), "The path should be rooted");
2122
Assert.Equal("dotnet", Path.GetFileNameWithoutExtension(dotnetPath), ignoreCase: true);
2223
}
24+
25+
[Fact]
26+
public void FullPathOrDefaultReturnsPathOrDotnet()
27+
{
28+
var result = DotNetExe.FullPathOrDefault();
29+
Assert.NotNull(result);
30+
Assert.NotEmpty(result);
31+
// Should either be a rooted path that exists, or just "dotnet"
32+
if (Path.IsPathRooted(result))
33+
{
34+
Assert.True(File.Exists(result), "The file did not exist");
35+
}
36+
else
37+
{
38+
Assert.Equal("dotnet", result);
39+
}
40+
}
41+
42+
[Fact]
43+
public void FindDotNetInRoot_ReturnsNull_WhenDirectoryDoesNotExist()
44+
{
45+
var fileName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "dotnet.exe" : "dotnet";
46+
var result = DotNetExe.FindDotNetInRoot("/nonexistent/path/that/does/not/exist", fileName);
47+
Assert.Null(result);
48+
}
49+
50+
[Fact]
51+
public void FindDotNetInRoot_ReturnsNull_WhenFileDoesNotExist()
52+
{
53+
// Use a directory that exists but won't contain dotnet
54+
var tempDir = Path.GetTempPath();
55+
var result = DotNetExe.FindDotNetInRoot(tempDir, "dotnet-nonexistent-file");
56+
Assert.Null(result);
57+
}
58+
59+
[Fact]
60+
public void FindDotNetInRoot_ReturnsPath_WhenFileExists()
61+
{
62+
// Create a temp file to simulate dotnet existing
63+
var tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
64+
Directory.CreateDirectory(tempDir);
65+
try
66+
{
67+
var fakeDotnet = "dotnet-test";
68+
var fakePath = Path.Combine(tempDir, fakeDotnet);
69+
File.WriteAllText(fakePath, "");
70+
71+
var result = DotNetExe.FindDotNetInRoot(tempDir, fakeDotnet);
72+
Assert.NotNull(result);
73+
Assert.Equal(fakePath, result);
74+
}
75+
finally
76+
{
77+
Directory.Delete(tempDir, recursive: true);
78+
}
79+
}
2380
}
2481
}
2582
#elif NET472_OR_GREATER

0 commit comments

Comments
 (0)