System.IO.Abstractions icon indicating copy to clipboard operation
System.IO.Abstractions copied to clipboard

MockFileSystem Directory.EnumerateFiles returns incorrect results, based on input pattern.

Open pianomanjh opened this issue 5 years ago • 12 comments

When calling Directory.EnumerateFiles on MockFileSystem, incorrect matching occurs, that differs from the real FileSystem.

Mock FileSystem

var results = Directory.EnumerateFiles(@"c:\jobfolder\result.rreq.001.afd", "*.rreq.*.*.*");
// results has no entries

Real FileSystem

var results = Directory.EnumerateFiles(@"c:\jobfolder\result.rreq.001.afd", "*.rreq.*.*.*");
// results has the entry `c:\jobfolder\result.rreq.001.afd`

pianomanjh avatar May 29 '20 20:05 pianomanjh

Thanks for reporting! Am I right assuming result.rreq.001.afd is a file (rather than a directory)?

fgreinacher avatar Jun 12 '20 09:06 fgreinacher

my apologies, the sample is not right. Here is something more representative.

mockFileSystem.AddFile(@"c:\test\result.rreq.001.afd", MockFileData.NullObject);
var results = mockFileSystem.Directory.EnumerateFiles(@"c:\test", "*.rreq.*.*.*");
// results has no entries, but should have `c:\test\result.rreq.001.afd`

pianomanjh avatar Jun 15 '20 22:06 pianomanjh

my apologies, the sample is not right. Here is something more representative.

mockFileSystem.AddFile(@"c:\test\result.rreq.001.afd", MockFileData.NullObject);
var results = mockFileSystem.Directory.EnumerateFiles(@"c:\test", "*.rreq.*.*.*");
// results has no entries, but should have `c:\test\result.rreq.001.afd`

This sample does also not look correct to me, the pattern has one asterisk too much:

result.rreq.001.afd
*     .rreq.*  .*  .*

The following test is passing:

// Arrange
var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
{
    { XFS.Path(@"c:\test\result.rreq.001.afd"), MockFileData.NullObject }
});

// Act
var result = fileSystem.Directory.EnumerateFiles(XFS.Path(@"c:\test"), "*.rreq.*.*");

// Assert
Assert.That(result, Is.EquivalentTo(new[]
{
    XFS.Path(@"c:\test\result.rreq.001.afd")
}));

fgreinacher avatar Jun 16 '20 23:06 fgreinacher

Now I get the problem. It seems like the real implementation ignores the .* elements at the end. This test case also succeeds 😩

// Arrange
var fileSystem = new FileSystem();
// var fileSystem = new MockFileSystem();
// fileSystem.Directory.CreateDirectory(XFS.Path(@"c:\tmp\"));

fileSystem.File.CreateText(XFS.Path(@"c:\tmp\result.rreq.001.afd")).Close();

// Act
var result = fileSystem.Directory.EnumerateFiles(XFS.Path(@"c:\tmp"), "*.rreq.*.*.*.*.*.*.*.*.*");

// Assert
Assert.That(result, Is.EquivalentTo(new[]
{
    XFS.Path(@"c:\tmp\result.rreq.001.afd")
}));

fgreinacher avatar Jun 16 '20 23:06 fgreinacher

@pianomanjh Please check whether the issue goes away once you use the "correct" pattern:

mockFileSystem.AddFile(@"c:\test\result.rreq.001.afd", MockFileData.NullObject);
mockFileSystem.Directory.EnumerateFiles(@"c:\test", "*.rreq.*.*"); // one `.*` pair less

fgreinacher avatar Jun 18 '20 19:06 fgreinacher

If I use a different pattern, the one you describe, the issue no longer reproduces, yes. However, using a different pattern doesn't fix the bug ;) (we need that pattern in production)

pianomanjh avatar Jun 18 '20 19:06 pianomanjh

Why do you need that exact pattern? It seems wrong to me 🤔 .NET behavior seems to be much more complex than we anticipated when implementing this logic 🐙

https://github.com/dotnet/runtime/blob/cd02b0612b3c758037eac9f85faa4ec91b1fbbda/src/libraries/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemName.cs has some of the logic - we might want to reuse (parts of) it.

fgreinacher avatar Jun 20 '20 10:06 fgreinacher

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] avatar Aug 20 '20 00:08 github-actions[bot]

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] avatar Oct 27 '20 00:10 github-actions[bot]

There are more differences in behaviour of Directory.EnumerateFiles between mock and real file system:

  • the string path parameter is case sensitive in the mock, while in real fs it isn't
  • real file system enumerates all files for the searchPattern value of string.Empty, while mock's enumeration yields no results

themcoo avatar Feb 08 '21 20:02 themcoo

There are more differences in behaviour of Directory.EnumerateFiles between mock and real file system:

  • the string path parameter is case sensitive in the mock, while in real fs it isn't
  • real file system enumerates all files for the searchPattern value of string.Empty, while mock's enumeration yields no results

Thanks for the additional input here @themcoo. Would you mind creating new issues for the problems so that we can tackle them separately?

fgreinacher avatar Feb 09 '21 18:02 fgreinacher

Another pattern that works in the real filesystem and not on the MockFileSystem is "someDirectory\\*.txt", this includes ".\\*.txt"

friketrike avatar Nov 24 '22 20:11 friketrike