Skip to content

Commit 941f487

Browse files
authored
feat: Implemented MockDirectory.CreateTempSubDirectory (#964)
Implemented MockDirectory.CreateTempSubdirectory(). This implementation generates a random 6 character string with an optional user specified prefix and creates the directory in the temporary directory returned by `Path.GetTempPath()`. The 6 random characters seems to be the algorithm used on my platform (Mac) by the System.IO implementation. Notes on this PR 1. There's a potential temporary directory namespace of $62^6$ or about 56.8 billion. As we get closer to this limit, the likelihood of generating a duplicate increases as well as the likelihood of slowdowns of the random generation. At the extreme case, if all possible temporary directories are created, creating a random directory name will effectively become an infinite loop. I assume we don't need to handle conditions close to the limit. 2. `MockDirectory` now contains a `Random` instance to generate random temp directory names. `Random.Shared` can't be used as it was introduced in .NET 6 it it appears we are supporting earlier .NET versions. 3. `MockDirectory` is marked as `[Serializable]`, however the `Random` instance cannot be serialized. I have marked the `Random` instance as `[NonSerialized]` and created a new `Random` instance on deserializing. The state of the random number generator will be different when deserialized. I don't think this is an issue as there was no way to specify the seed of the `Random` instance when creating the `MockDirectory` instance, so there's no way to generate the same sequence of random directories again (besides a very slim chance). 4. I have had to add `<EnableUnsafeBinaryFormatterSerialization>` on the test project and `#pragma warning disable SYSLIB0011` on the deserialize method to allow testing that deserialization of a `MockDirectory` also instantiates a new random number generator. Deserialization is heavily deprecated and this is only on test classes, so I am assuming this is OK.
1 parent 85fc762 commit 941f487

File tree

2 files changed

+42
-1
lines changed

2 files changed

+42
-1
lines changed

src/TestableIO.System.IO.Abstractions.TestingHelpers/MockDirectory.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,17 @@ public override IFileSystemInfo CreateSymbolicLink(string path, string pathToTar
110110
/// <inheritdoc />
111111
public override IDirectoryInfo CreateTempSubdirectory(string prefix = null)
112112
{
113-
throw CommonExceptions.NotImplemented();
113+
prefix ??= "";
114+
string potentialTempDirectory;
115+
116+
// Perform directory name generation in a loop, just in case the randomly generated name already exists.
117+
do
118+
{
119+
var randomDir = $"{prefix}{Path.GetRandomFileName()}";
120+
potentialTempDirectory = Path.Combine(Path.GetTempPath(), randomDir);
121+
} while (Exists(potentialTempDirectory));
122+
123+
return CreateDirectoryInternal(potentialTempDirectory);
114124
}
115125
#endif
116126

tests/TestableIO.System.IO.Abstractions.TestingHelpers.Tests/MockDirectoryTests.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,37 @@ public void MockDirectory_CreateDirectory_ShouldSucceedIfTryingToCreateUNCPathSh
813813
Assert.IsTrue(fileSystem.Directory.Exists(@"\\server\share\"));
814814
}
815815

816+
#if FEATURE_CREATE_TEMP_SUBDIRECTORY
817+
[Test]
818+
public void MockDirectory_CreateTempSubdirectory_ShouldCreateSubdirectoryInTempDirectory()
819+
{
820+
// Arrange
821+
var fileSystem = new MockFileSystem();
822+
823+
// Act
824+
var result = fileSystem.Directory.CreateTempSubdirectory();
825+
826+
// Assert
827+
Assert.IsTrue(fileSystem.Directory.Exists(result.FullName));
828+
Assert.IsTrue(result.FullName.Contains(Path.GetTempPath()));
829+
}
830+
831+
[Test]
832+
public void MockDirectory_CreateTempSubdirectoryWithPrefix_ShouldCreateDirectoryWithGivenPrefixInTempDirectory()
833+
{
834+
// Arrange
835+
var fileSystem = new MockFileSystem();
836+
837+
// Act
838+
var result = fileSystem.Directory.CreateTempSubdirectory("foo-");
839+
840+
// Assert
841+
Assert.IsTrue(fileSystem.Directory.Exists(result.FullName));
842+
Assert.IsTrue(Path.GetFileName(result.FullName).StartsWith("foo-"));
843+
Assert.IsTrue(result.FullName.Contains(Path.GetTempPath()));
844+
}
845+
#endif
846+
816847
[Test]
817848
public void MockDirectory_Delete_ShouldDeleteDirectory()
818849
{

0 commit comments

Comments
 (0)