From 1d67fb164490d29cbc6e8d93b5a907b06494415b Mon Sep 17 00:00:00 2001 From: Thomas Eggerling Date: Tue, 5 Dec 2023 22:12:18 +0100 Subject: [PATCH] fix: prefix bug in MockDirectory.EnumerateDirectories (#815) (#1046) Fixes #815 `System.IO.Directory.EnumerateDirectories(path)` guarantees that returned paths are always prefixed with the value provided in the `path` parameter. However, `MockDirectory.EnumerateDirectories` always returned absolute paths, leading to an inconsistent behavior (e.g. when using relative paths). We now check returned paths from `MockDirectory.EnumerateDirectories` and provide the proper prefix path. --- .../MockDirectory.cs | 24 +++++++------- .../MockDirectoryTests.cs | 32 +++++++++++++++---- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockDirectory.cs b/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockDirectory.cs index 525c78fa0..d7f0a6d34 100644 --- a/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockDirectory.cs +++ b/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockDirectory.cs @@ -627,16 +627,12 @@ public override void SetLastWriteTimeUtc(string path, DateTime lastWriteTimeUtc) /// public override IEnumerable EnumerateDirectories(string path) { - mockFileDataAccessor.PathVerifier.IsLegalAbsoluteOrRelative(path, "path"); - return EnumerateDirectories(path, "*"); } /// public override IEnumerable EnumerateDirectories(string path, string searchPattern) { - mockFileDataAccessor.PathVerifier.IsLegalAbsoluteOrRelative(path, "path"); - return EnumerateDirectories(path, searchPattern, SearchOption.TopDirectoryOnly); } @@ -644,22 +640,28 @@ public override IEnumerable EnumerateDirectories(string path, string sea public override IEnumerable EnumerateDirectories(string path, string searchPattern, SearchOption searchOption) { mockFileDataAccessor.PathVerifier.IsLegalAbsoluteOrRelative(path, "path"); + var originalPath = path; path = path.TrimSlashes(); path = mockFileDataAccessor.Path.GetFullPath(path); return GetFilesInternal(mockFileDataAccessor.AllDirectories, path, searchPattern, searchOption) - .Where(p => !mockFileDataAccessor.StringOperations.Equals(p, path)); + .Where(p => !mockFileDataAccessor.StringOperations.Equals(p, path)) + .Select(p => FixPrefix(p, originalPath)); } - + + private string FixPrefix(string path, string originalPath) + { + var normalizedOriginalPath = mockFileDataAccessor.Path.GetFullPath(originalPath); + var pathWithoutOriginalPath = path.Substring(normalizedOriginalPath.Length) + .TrimStart(mockFileDataAccessor.Path.DirectorySeparatorChar); + return mockFileDataAccessor.Path.Combine(originalPath, pathWithoutOriginalPath); + } + #if FEATURE_ENUMERATION_OPTIONS /// public override IEnumerable EnumerateDirectories(string path, string searchPattern, EnumerationOptions enumerationOptions) { var searchOption = enumerationOptions.RecurseSubdirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; - mockFileDataAccessor.PathVerifier.IsLegalAbsoluteOrRelative(path, "path"); - path = path.TrimSlashes(); - path = mockFileDataAccessor.Path.GetFullPath(path); - return GetFilesInternal(mockFileDataAccessor.AllDirectories, path, searchPattern, searchOption) - .Where(p => !mockFileDataAccessor.StringOperations.Equals(p, path)); + return EnumerateDirectories(path, searchPattern, searchOption); } #endif diff --git a/tests/TestableIO.System.IO.Abstractions.TestingHelpers.Tests/MockDirectoryTests.cs b/tests/TestableIO.System.IO.Abstractions.TestingHelpers.Tests/MockDirectoryTests.cs index adfe56a9f..289b8dc90 100644 --- a/tests/TestableIO.System.IO.Abstractions.TestingHelpers.Tests/MockDirectoryTests.cs +++ b/tests/TestableIO.System.IO.Abstractions.TestingHelpers.Tests/MockDirectoryTests.cs @@ -1271,7 +1271,7 @@ public void MockDirectory_GetDirectories_WithTopDirectories_ShouldOnlyReturnTopD fileSystem.AddFile(XFS.Path(@"C:\Folder\.foo\bar"), new MockFileData(string.Empty)); // Act - var actualResult = fileSystem.Directory.GetDirectories(XFS.Path(@"c:\Folder\"), "*.foo"); + var actualResult = fileSystem.Directory.GetDirectories(XFS.Path(@"C:\Folder\"), "*.foo"); // Assert Assert.That(actualResult, Is.EquivalentTo(new[] { XFS.Path(@"C:\Folder\.foo"), XFS.Path(@"C:\Folder\foo.foo") })); @@ -1321,7 +1321,7 @@ public void MockDirectory_GetDirectories_RelativeDirectory_WithChildren_ShouldRe // Assert CollectionAssert.AreEqual( - new[] { XFS.Path(currentDirectory + @"\" + relativeDirPath + @"\child") }, + new[] { XFS.Path(relativeDirPath + @"\child") }, actualResult ); } @@ -1353,7 +1353,7 @@ public void MockDirectory_GetDirectories_WithAllDirectories_ShouldReturnsAllMatc fileSystem.AddFile(XFS.Path(@"C:\Folder\.foo\bar"), new MockFileData(string.Empty)); // Act - var actualResult = fileSystem.Directory.GetDirectories(XFS.Path(@"c:\Folder\"), "*.foo", SearchOption.AllDirectories); + var actualResult = fileSystem.Directory.GetDirectories(XFS.Path(@"C:\Folder\"), "*.foo", SearchOption.AllDirectories); // Assert Assert.That(actualResult, Is.EquivalentTo(new[] { XFS.Path(@"C:\Folder\.foo"), XFS.Path(@"C:\Folder\foo.foo"), XFS.Path(@"C:\Folder\.foo\.foo") })); @@ -1415,7 +1415,7 @@ public void MockDirectory_EnumerateDirectories_WithTopDirectories_ShouldOnlyRetu fileSystem.AddFile(XFS.Path(@"C:\Folder\.foo\bar"), new MockFileData(string.Empty)); // Act - var actualResult = fileSystem.Directory.EnumerateDirectories(XFS.Path(@"c:\Folder\"), "*.foo"); + var actualResult = fileSystem.Directory.EnumerateDirectories(XFS.Path(@"C:\Folder\"), "*.foo"); // Assert Assert.That(actualResult, Is.EquivalentTo(new[] { XFS.Path(@"C:\Folder\.foo"), XFS.Path(@"C:\Folder\foo.foo") })); @@ -1439,7 +1439,7 @@ public void MockDirectory_EnumerateDirectories_WithEnumerationOptionsTopDirector }; // Act - var actualResult = fileSystem.Directory.EnumerateDirectories(XFS.Path(@"c:\Folder\"), "*.foo", enumerationOptions); + var actualResult = fileSystem.Directory.EnumerateDirectories(XFS.Path(@"C:\Folder\"), "*.foo", enumerationOptions); // Assert Assert.That(actualResult, Is.EquivalentTo(new[] { XFS.Path(@"C:\Folder\.foo"), XFS.Path(@"C:\Folder\foo.foo") })); @@ -1457,7 +1457,7 @@ public void MockDirectory_EnumerateDirectories_WithAllDirectories_ShouldReturnsA fileSystem.AddFile(XFS.Path(@"C:\Folder\.foo\bar"), new MockFileData(string.Empty)); // Act - var actualResult = fileSystem.Directory.EnumerateDirectories(XFS.Path(@"c:\Folder\"), "*.foo", SearchOption.AllDirectories); + var actualResult = fileSystem.Directory.EnumerateDirectories(XFS.Path(@"C:\Folder\"), "*.foo", SearchOption.AllDirectories); // Assert Assert.That(actualResult, Is.EquivalentTo(new[] { XFS.Path(@"C:\Folder\.foo"), XFS.Path(@"C:\Folder\foo.foo"), XFS.Path(@"C:\Folder\.foo\.foo") })); @@ -1486,6 +1486,26 @@ public void MockDirectory_EnumerateDirectories_ShouldThrowWhenPathIsNotMocked() // Assert Assert.Throws(action); } + + [TestCaseSource(nameof(GetPrefixTestPaths))] + public void MockDirectory_EnumerateDirectories_ShouldReturnPathsPrefixedWithQueryPath( + string queryPath, string expectedPath) + { + var fileSystem = new MockFileSystem(); + fileSystem.Directory.CreateDirectory("Folder/SubFolder"); + + var actualResult = fileSystem.Directory.EnumerateDirectories(queryPath); + + CollectionAssert.AreEqual(new[] { expectedPath }, actualResult); + } + + private static IEnumerable GetPrefixTestPaths() + { + var sep = Path.DirectorySeparatorChar; + yield return new object[] { "Folder", $"Folder{sep}SubFolder" }; + yield return new object[] { $"Folder{sep}", $"Folder{sep}SubFolder" }; + yield return new object[] { $"Folder{sep}..{sep}.{sep}Folder", $"Folder{sep}..{sep}.{sep}Folder{sep}SubFolder" }; + } public static IEnumerable GetPathsForMoving() {