From 63ea83583585637ef002464633d5a55962c85ac6 Mon Sep 17 00:00:00 2001 From: Eric StJohn Date: Tue, 21 Oct 2025 14:21:25 -0700 Subject: [PATCH 1/2] Handle multiple trailing directory separators --- .../dotnet/DotNetComponentDetector.cs | 3 ++- .../DotNetComponentDetectorTests.cs | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.ComponentDetection.Detectors/dotnet/DotNetComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/dotnet/DotNetComponentDetector.cs index 48bafd9e8..199c6af60 100644 --- a/src/Microsoft.ComponentDetection.Detectors/dotnet/DotNetComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/dotnet/DotNetComponentDetector.cs @@ -59,7 +59,8 @@ public DotNetComponentDetector( public override IEnumerable Categories => ["DotNet"]; [return: NotNullIfNotNull(nameof(path))] - private string? NormalizeDirectory(string? path) => string.IsNullOrEmpty(path) ? path : Path.TrimEndingDirectorySeparator(this.pathUtilityService.NormalizePath(path)); + private string? NormalizeDirectory(string? path) => string.IsNullOrEmpty(path) ? path : + this.pathUtilityService.NormalizePath(path).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); /// /// Given a path under sourceDirectory, and the same path in another filesystem, diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/DotNetComponentDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/DotNetComponentDetectorTests.cs index 3aae504a7..08c021b6b 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/DotNetComponentDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/DotNetComponentDetectorTests.cs @@ -654,8 +654,19 @@ public async Task TestDotNetDetectorNoGlobalJsonSourceRoot() discoveredComponents.Where(component => component.Component.Id == "0.0.0 net8.0 unknown - DotNet").Should().ContainSingle(); } +#pragma warning disable SA1201 // Elements should appear in the correct order + private static IEnumerable AdditionalPathSegments { get; } = +#pragma warning restore SA1201 // Elements should appear in the correct order + [ + [string.Empty], + [$"{Path.DirectorySeparatorChar}{Path.DirectorySeparatorChar}"], + [$"{Path.AltDirectorySeparatorChar}{Path.DirectorySeparatorChar}"], + [$"{Path.AltDirectorySeparatorChar}{Path.AltDirectorySeparatorChar}"], + ]; + [TestMethod] - public async Task TestDotNetDetectorRebasePaths() + [DynamicData(nameof(AdditionalPathSegments))] + public async Task TestDotNetDetectorRebasePaths(string additionalPathSegment) { // DetectorTestUtility runs under Path.GetTempPath() var scanRoot = Path.TrimEndingDirectorySeparator(Path.GetTempPath()); @@ -676,7 +687,7 @@ public async Task TestDotNetDetectorRebasePaths() this.AddFile(libraryProjectPath, null); var libraryOutputPath = Path.Combine(Path.GetDirectoryName(libraryProjectPath), "obj"); - var libraryBuildOutputPath = Path.Combine(Path.GetDirectoryName(libraryBuildProjectPath), "obj"); + var libraryBuildOutputPath = Path.Combine(Path.GetDirectoryName(libraryBuildProjectPath), "obj") + additionalPathSegment; var libraryAssetsPath = Path.Combine(libraryOutputPath, "project.assets.json"); // use "build" paths to simulate an Assets file that has a different root. Here the build assets have RootDir, but the scanned filesystem has scanRoot. From 777711febdd4ba6f6798d1e1567682d33d410b03 Mon Sep 17 00:00:00 2001 From: Eric StJohn Date: Tue, 21 Oct 2025 15:39:47 -0700 Subject: [PATCH 2/2] Don't trim the root separator --- .../dotnet/DotNetComponentDetector.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.ComponentDetection.Detectors/dotnet/DotNetComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/dotnet/DotNetComponentDetector.cs index 199c6af60..0a0199ad2 100644 --- a/src/Microsoft.ComponentDetection.Detectors/dotnet/DotNetComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/dotnet/DotNetComponentDetector.cs @@ -58,9 +58,22 @@ public DotNetComponentDetector( public override IEnumerable Categories => ["DotNet"]; + private static string TrimAllEndingDirectorySeparators(string path) + { + string last; + + do + { + last = path; + path = Path.TrimEndingDirectorySeparator(last); + } + while (!ReferenceEquals(last, path)); + + return path; + } + [return: NotNullIfNotNull(nameof(path))] - private string? NormalizeDirectory(string? path) => string.IsNullOrEmpty(path) ? path : - this.pathUtilityService.NormalizePath(path).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + private string? NormalizeDirectory(string? path) => string.IsNullOrEmpty(path) ? path : TrimAllEndingDirectorySeparators(this.pathUtilityService.NormalizePath(path)); /// /// Given a path under sourceDirectory, and the same path in another filesystem,