diff --git a/src/Microsoft.ComponentDetection.Detectors/dotnet/DotNetComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/dotnet/DotNetComponentDetector.cs index 48bafd9e8..0a0199ad2 100644 --- a/src/Microsoft.ComponentDetection.Detectors/dotnet/DotNetComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/dotnet/DotNetComponentDetector.cs @@ -58,8 +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 : Path.TrimEndingDirectorySeparator(this.pathUtilityService.NormalizePath(path)); + 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, 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.