diff --git a/src/Spectre.IO.Tests/Unit/PathComparerTests.cs b/src/Spectre.IO.Tests/Unit/PathComparerTests.cs index 263823f..f7be9b5 100644 --- a/src/Spectre.IO.Tests/Unit/PathComparerTests.cs +++ b/src/Spectre.IO.Tests/Unit/PathComparerTests.cs @@ -15,10 +15,10 @@ public sealed class TheEqualsMethod [Theory] [InlineData(true)] [InlineData(false)] - public void Same_Asset_Instances_Is_Considered_Equal(bool isCaseSensitive) + public void Same_Asset_Instances_Is_Considered_Equal(bool caseSensitive) { // Given, When - var comparer = new PathComparer(isCaseSensitive); + var comparer = new PathComparer(caseSensitive); var path = new FilePath("shaders/basic.vert"); // When @@ -31,10 +31,10 @@ public void Same_Asset_Instances_Is_Considered_Equal(bool isCaseSensitive) [Theory] [InlineData(true)] [InlineData(false)] - public void Two_Null_Paths_Are_Considered_Equal(bool isCaseSensitive) + public void Two_Null_Paths_Are_Considered_Equal(bool caseSensitive) { // Given - var comparer = new PathComparer(isCaseSensitive); + var comparer = new PathComparer(caseSensitive); // When var result = comparer.Equals(null, null); @@ -46,10 +46,10 @@ public void Two_Null_Paths_Are_Considered_Equal(bool isCaseSensitive) [Theory] [InlineData(true)] [InlineData(false)] - public void Paths_Are_Considered_Inequal_If_Any_Is_Null(bool isCaseSensitive) + public void Paths_Are_Considered_Inequal_If_Any_Is_Null(bool caseSensitive) { // Given - var comparer = new PathComparer(isCaseSensitive); + var comparer = new PathComparer(caseSensitive); // When var result = comparer.Equals(null, new FilePath("test.txt")); @@ -61,10 +61,10 @@ public void Paths_Are_Considered_Inequal_If_Any_Is_Null(bool isCaseSensitive) [Theory] [InlineData(true)] [InlineData(false)] - public void Same_Paths_Are_Considered_Equal(bool isCaseSensitive) + public void Same_Paths_Are_Considered_Equal(bool caseSensitive) { // Given, When - var comparer = new PathComparer(isCaseSensitive); + var comparer = new PathComparer(caseSensitive); var first = new FilePath("shaders/basic.vert"); var second = new FilePath("shaders/basic.vert"); @@ -76,10 +76,10 @@ public void Same_Paths_Are_Considered_Equal(bool isCaseSensitive) [Theory] [InlineData(true)] [InlineData(false)] - public void Different_Paths_Are_Not_Considered_Equal(bool isCaseSensitive) + public void Different_Paths_Are_Not_Considered_Equal(bool caseSensitive) { // Given, When - var comparer = new PathComparer(isCaseSensitive); + var comparer = new PathComparer(caseSensitive); var first = new FilePath("shaders/basic.vert"); var second = new FilePath("shaders/basic.frag"); @@ -92,10 +92,10 @@ public void Different_Paths_Are_Not_Considered_Equal(bool isCaseSensitive) [InlineData(true, false)] [InlineData(false, true)] public void Same_Paths_But_Different_Casing_Are_Considered_Equal_Depending_On_Case_Sensitivity( - bool isCaseSensitive, bool expected) + bool caseSensitive, bool expected) { // Given, When - var comparer = new PathComparer(isCaseSensitive); + var comparer = new PathComparer(caseSensitive); var first = new FilePath("shaders/basic.vert"); var second = new FilePath("SHADERS/BASIC.VERT"); @@ -120,7 +120,7 @@ public void Should_Sort_Paths() // When var result = paths - .Order(new PathComparer(isCaseSensitive: false)) + .Order(new PathComparer(caseSensitive: false)) .ToList(); // Then @@ -149,10 +149,10 @@ public void Should_Throw_If_Other_Path_Is_Null() [Theory] [InlineData(true)] [InlineData(false)] - public void Same_Paths_Get_Same_Hash_Code(bool isCaseSensitive) + public void Same_Paths_Get_Same_Hash_Code(bool caseSensitive) { // Given - var comparer = new PathComparer(isCaseSensitive); + var comparer = new PathComparer(caseSensitive); var first = new FilePath("shaders/basic.vert"); var second = new FilePath("shaders/basic.vert"); @@ -167,10 +167,10 @@ public void Same_Paths_Get_Same_Hash_Code(bool isCaseSensitive) [Theory] [InlineData(true)] [InlineData(false)] - public void Different_Paths_Get_Different_Hash_Codes(bool isCaseSensitive) + public void Different_Paths_Get_Different_Hash_Codes(bool caseSensitive) { // Given - var comparer = new PathComparer(isCaseSensitive); + var comparer = new PathComparer(caseSensitive); var first = new FilePath("shaders/basic.vert"); var second = new FilePath("shaders/basic.frag"); @@ -186,10 +186,10 @@ public void Different_Paths_Get_Different_Hash_Codes(bool isCaseSensitive) [InlineData(true, false)] [InlineData(false, true)] public void Same_Paths_But_Different_Casing_Get_Same_Hash_Code_Depending_On_Case_Sensitivity( - bool isCaseSensitive, bool expected) + bool caseSensitive, bool expected) { // Given, When - var comparer = new PathComparer(isCaseSensitive); + var comparer = new PathComparer(caseSensitive); var first = new FilePath("shaders/basic.vert"); var second = new FilePath("SHADERS/BASIC.VERT"); @@ -222,13 +222,13 @@ public sealed class TheIsCaseSensitiveProperty [Theory] [InlineData(true)] [InlineData(false)] - public void Should_Return_Whether_Or_Not_The_Comparer_Is_Case_Sensitive(bool isCaseSensitive) + public void Should_Return_Whether_Or_Not_The_Comparer_Is_Case_Sensitive(bool caseSensitive) { // Given, When - var comparer = new PathComparer(isCaseSensitive); + var comparer = new PathComparer(caseSensitive); // Then - comparer.IsCaseSensitive.ShouldBe(isCaseSensitive); + comparer.IsCaseSensitive.ShouldBe(caseSensitive); } } } \ No newline at end of file diff --git a/src/Spectre.IO/PathComparer.cs b/src/Spectre.IO/PathComparer.cs index f58aaaa..6396863 100644 --- a/src/Spectre.IO/PathComparer.cs +++ b/src/Spectre.IO/PathComparer.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using Spectre.IO.Internal; namespace Spectre.IO; @@ -11,7 +12,8 @@ public sealed class PathComparer : IPathComparer /// /// Gets the default path comparer. /// - public static PathComparer Default { get; } = new PathComparer(EnvironmentHelper.IsUnix()); + public static PathComparer Default { get; } + = new PathComparer(EnvironmentHelper.IsUnix()); /// /// Gets a value indicating whether comparison is case sensitive. @@ -24,10 +26,10 @@ public sealed class PathComparer : IPathComparer /// /// Initializes a new instance of the class. /// - /// if set to true, comparison is case sensitive. - public PathComparer(bool isCaseSensitive) + /// if set to true, comparison is case sensitive. + public PathComparer(bool caseSensitive) { - IsCaseSensitive = isCaseSensitive; + IsCaseSensitive = caseSensitive; } /// @@ -52,26 +54,39 @@ public int Compare(Path? x, Path? y) return 0; } - if (x != null && y == null) + // This might look strange, + // but for some reason, null reference tracking + // does not work correctly otherwise. + if (x == null || y == null) { - return -1; + if (x != null && y == null) + { + return -1; + } + + return 1; } - if (x == null && y != null) + if (x.Segments.Count != y.Segments.Count) { - return 1; + return x.Segments.Count + .CompareTo(y.Segments.Count); } - if (IsCaseSensitive) + var comparer = IsCaseSensitive + ? StringComparer.Ordinal + : StringComparer.OrdinalIgnoreCase; + + foreach (var (segmentX, segmentY) in x.Segments.Zip(y.Segments)) { - return StringComparer.Ordinal.Compare( - x!.FullPath, - y!.FullPath); + var sort = comparer.Compare(segmentX, segmentY); + if (sort != 0) + { + return sort; + } } - return StringComparer.OrdinalIgnoreCase.Compare( - x!.FullPath, - y!.FullPath); + return 0; } /// @@ -87,12 +102,24 @@ public bool Equals(Path? x, Path? y) return false; } - if (IsCaseSensitive) + if (x.Segments.Count != y.Segments.Count) + { + return false; + } + + var comparer = IsCaseSensitive + ? StringComparer.Ordinal + : StringComparer.OrdinalIgnoreCase; + + foreach (var (segmentX, segmentY) in x.Segments.Zip(y.Segments)) { - return x.FullPath.Equals(y.FullPath, StringComparison.Ordinal); + if (!comparer.Equals(segmentX, segmentY)) + { + return false; + } } - return x.FullPath.Equals(y.FullPath, StringComparison.OrdinalIgnoreCase); + return true; } ///