diff --git a/src/TestableIO.System.IO.Abstractions.TestingHelpers/IMockFileDataAccessor.cs b/src/TestableIO.System.IO.Abstractions.TestingHelpers/IMockFileDataAccessor.cs
index ba479cdd8..abe98671c 100644
--- a/src/TestableIO.System.IO.Abstractions.TestingHelpers/IMockFileDataAccessor.cs
+++ b/src/TestableIO.System.IO.Abstractions.TestingHelpers/IMockFileDataAccessor.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
using System.Reflection;
namespace System.IO.Abstractions.TestingHelpers;
@@ -110,4 +111,9 @@ public interface IMockFileDataAccessor : IFileSystem
/// Gets a reference to the underlying file system.
///
IFileSystem FileSystem { get; }
+
+ ///
+ /// Gets a reference to the open file handles.
+ ///
+ ConcurrentDictionary> FileHandles { get; }
}
\ No newline at end of file
diff --git a/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFile.cs b/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFile.cs
index 0f9a97a48..e4d739704 100644
--- a/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFile.cs
+++ b/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFile.cs
@@ -677,7 +677,7 @@ private FileSystemStream OpenInternal(
}
mockFileDataAccessor.AdjustTimes(mockFileData, timeAdjustments);
- return new MockFileStream(mockFileDataAccessor, path, mode, access, options);
+ return new MockFileStream(mockFileDataAccessor, path, mode, access, FileShare.Read, options);
}
///
diff --git a/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFileStream.cs b/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFileStream.cs
index 1be2241af..0908dbaca 100644
--- a/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFileStream.cs
+++ b/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFileStream.cs
@@ -2,6 +2,7 @@
using System.Threading;
using System.Runtime.Versioning;
using System.Security.AccessControl;
+using System.Collections.Concurrent;
namespace System.IO.Abstractions.TestingHelpers;
@@ -31,7 +32,9 @@ public NullFileSystemStream() : base(Null, ".", true)
private readonly IMockFileDataAccessor mockFileDataAccessor;
private readonly string path;
+ private readonly Guid guid = Guid.NewGuid();
private readonly FileAccess access = FileAccess.ReadWrite;
+ private readonly FileShare share = FileShare.Read;
private readonly FileOptions options;
private readonly MockFileData fileData;
private bool disposed;
@@ -42,6 +45,7 @@ public MockFileStream(
string path,
FileMode mode,
FileAccess access = FileAccess.ReadWrite,
+ FileShare share = FileShare.Read,
FileOptions options = FileOptions.None)
: base(new MemoryStream(),
path == null ? null : Path.GetFullPath(path),
@@ -51,6 +55,7 @@ public MockFileStream(
ThrowIfInvalidModeAccess(mode, access);
this.mockFileDataAccessor = mockFileDataAccessor ?? throw new ArgumentNullException(nameof(mockFileDataAccessor));
+ path = mockFileDataAccessor.PathVerifier.FixPath(path);
this.path = path;
this.options = options;
@@ -97,7 +102,39 @@ public MockFileStream(
mockFileDataAccessor.AddFile(path, fileData);
}
+ var fileHandlesEntry = mockFileDataAccessor.FileHandles.GetOrAdd(
+ path,
+ _ => new ConcurrentDictionary());
+
+ var requiredShare = AccessToShare(access);
+ foreach (var (existingAccess, existingShare) in fileHandlesEntry.Values)
+ {
+ var existingRequiredShare = AccessToShare(existingAccess);
+ var existingBlocksNew = (existingShare & requiredShare) != requiredShare;
+ var newBlocksExisting = (share & existingRequiredShare) != existingRequiredShare;
+ if (existingBlocksNew || newBlocksExisting)
+ {
+ throw CommonExceptions.ProcessCannotAccessFileInUse(path);
+ }
+ }
+
+ fileHandlesEntry[guid] = (access, share);
this.access = access;
+ this.share = share;
+ }
+
+ private static FileShare AccessToShare(FileAccess access)
+ {
+ var share = FileShare.None;
+ if (access.HasFlag(FileAccess.Read))
+ {
+ share |= FileShare.Read;
+ }
+ if (access.HasFlag(FileAccess.Write))
+ {
+ share |= FileShare.Write;
+ }
+ return share;
}
private static void ThrowIfInvalidModeAccess(FileMode mode, FileAccess access)
@@ -144,6 +181,14 @@ protected override void Dispose(bool disposing)
{
return;
}
+ if (mockFileDataAccessor.FileHandles.TryGetValue(path, out var fileHandlesEntry))
+ {
+ fileHandlesEntry.TryRemove(guid, out _);
+ if (fileHandlesEntry.IsEmpty)
+ {
+ mockFileDataAccessor.FileHandles.TryRemove(path, out _);
+ }
+ }
InternalFlush();
base.Dispose(disposing);
OnClose();
diff --git a/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFileStreamFactory.cs b/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFileStreamFactory.cs
index 9cd34f7ae..1dc39759c 100644
--- a/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFileStreamFactory.cs
+++ b/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFileStreamFactory.cs
@@ -41,25 +41,25 @@ public FileSystemStream New(string path, FileMode mode, FileAccess access)
///
public FileSystemStream New(string path, FileMode mode, FileAccess access, FileShare share)
- => new MockFileStream(mockFileSystem, path, mode, access);
+ => new MockFileStream(mockFileSystem, path, mode, access, share);
///
public FileSystemStream New(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize)
- => new MockFileStream(mockFileSystem, path, mode, access);
+ => new MockFileStream(mockFileSystem, path, mode, access, share);
///
public FileSystemStream New(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool useAsync)
- => new MockFileStream(mockFileSystem, path, mode, access);
+ => new MockFileStream(mockFileSystem, path, mode, access, share);
///
public FileSystemStream New(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize,
FileOptions options)
- => new MockFileStream(mockFileSystem, path, mode, access, options);
+ => new MockFileStream(mockFileSystem, path, mode, access, share, options);
#if FEATURE_FILESTREAM_OPTIONS
///
public FileSystemStream New(string path, FileStreamOptions options)
- => new MockFileStream(mockFileSystem, path, options.Mode, options.Access, options.Options);
+ => new MockFileStream(mockFileSystem, path, options.Mode, options.Access, options.Share, options.Options);
#endif
///
diff --git a/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFileSystem.cs b/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFileSystem.cs
index 3f71206cb..969b09996 100644
--- a/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFileSystem.cs
+++ b/src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFileSystem.cs
@@ -1,3 +1,4 @@
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
@@ -21,6 +22,10 @@ public class MockFileSystem : FileSystemBase, IMockFileDataAccessor
private readonly PathVerifier pathVerifier;
#if FEATURE_SERIALIZABLE
[NonSerialized]
+#endif
+ private readonly ConcurrentDictionary> fileHandles = new();
+#if FEATURE_SERIALIZABLE
+ [NonSerialized]
#endif
private Func dateTimeProvider = defaultDateTimeProvider;
private static Func defaultDateTimeProvider = () => DateTime.UtcNow;
@@ -114,6 +119,9 @@ public MockFileSystem(IDictionary files, MockFileSystemOpt
public IFileSystem FileSystem => this;
///
public PathVerifier PathVerifier => pathVerifier;
+ ///
+ public ConcurrentDictionary> FileHandles
+ => fileHandles;
///
/// Replaces the time provider with a mocked instance. This allows to influence the used time in tests.
@@ -128,19 +136,6 @@ public MockFileSystem MockTime(Func dateTimeProvider)
return this;
}
- private string FixPath(string path, bool checkCaps = false)
- {
- if (path == null)
- {
- throw new ArgumentNullException(nameof(path), StringResources.Manager.GetString("VALUE_CANNOT_BE_NULL"));
- }
-
- var pathSeparatorFixed = path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
- var fullPath = Path.GetFullPath(pathSeparatorFixed);
-
- return checkCaps ? GetPathWithCorrectDirectoryCapitalization(fullPath) : fullPath;
- }
-
//If C:\foo exists, ensures that trying to save a file to "C:\FOO\file.txt" instead saves it to "C:\foo\file.txt".
private string GetPathWithCorrectDirectoryCapitalization(string fullPath)
{
@@ -194,7 +189,7 @@ public MockFileData AdjustTimes(MockFileData fileData, TimeAdjustments timeAdjus
///
public MockFileData GetFile(string path)
{
- path = FixPath(path).TrimSlashes();
+ path = pathVerifier.FixPath(path).TrimSlashes();
return GetFileWithoutFixingPath(path);
}
@@ -210,7 +205,9 @@ public MockDriveData GetDrive(string name)
private void SetEntry(string path, MockFileData mockFile)
{
- path = FixPath(path, true).TrimSlashes();
+ path = GetPathWithCorrectDirectoryCapitalization(
+ pathVerifier.FixPath(path)
+ ).TrimSlashes();
lock (files)
{
@@ -232,7 +229,9 @@ private void SetEntry(string path, MockFileData mockFile)
///
public void AddFile(string path, MockFileData mockFile, bool verifyAccess = true)
{
- var fixedPath = FixPath(path, true);
+ var fixedPath = GetPathWithCorrectDirectoryCapitalization(
+ pathVerifier.FixPath(path)
+ );
mockFile ??= new MockFileData(string.Empty);
var file = GetFile(fixedPath);
@@ -319,7 +318,9 @@ public MockFileData GetFile(IFileInfo path)
///
public void AddDirectory(string path)
{
- var fixedPath = FixPath(path, true);
+ var fixedPath = GetPathWithCorrectDirectoryCapitalization(
+ pathVerifier.FixPath(path)
+ );
var separator = Path.DirectorySeparatorChar.ToString();
if (FileExists(fixedPath) && FileIsReadOnly(fixedPath))
@@ -408,8 +409,8 @@ public void AddDrive(string name, MockDriveData mockDrive)
///
public void MoveDirectory(string sourcePath, string destPath)
{
- sourcePath = FixPath(sourcePath);
- destPath = FixPath(destPath);
+ sourcePath = pathVerifier.FixPath(sourcePath);
+ destPath = pathVerifier.FixPath(destPath);
var sourcePathSequence = sourcePath.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);
@@ -452,7 +453,7 @@ bool PathStartsWith(string path, string[] minMatch)
///
public void RemoveFile(string path, bool verifyAccess = true)
{
- path = FixPath(path);
+ path = pathVerifier.FixPath(path);
lock (files)
{
@@ -473,7 +474,7 @@ public bool FileExists(string path)
return false;
}
- path = FixPath(path).TrimSlashes();
+ path = pathVerifier.FixPath(path).TrimSlashes();
lock (files)
{
diff --git a/src/TestableIO.System.IO.Abstractions.TestingHelpers/PathVerifier.cs b/src/TestableIO.System.IO.Abstractions.TestingHelpers/PathVerifier.cs
index 2c426637c..93405eebb 100644
--- a/src/TestableIO.System.IO.Abstractions.TestingHelpers/PathVerifier.cs
+++ b/src/TestableIO.System.IO.Abstractions.TestingHelpers/PathVerifier.cs
@@ -183,4 +183,23 @@ public bool TryNormalizeDriveName(string name, out string result)
result = name;
return true;
}
+
+ ///
+ /// Resolves and normalizes a path.
+ ///
+ public string FixPath(string path)
+ {
+ if (path == null)
+ {
+ throw new ArgumentNullException(nameof(path), StringResources.Manager.GetString("VALUE_CANNOT_BE_NULL"));
+ }
+
+ var pathSeparatorFixed = path.Replace(
+ _mockFileDataAccessor.Path.AltDirectorySeparatorChar,
+ _mockFileDataAccessor.Path.DirectorySeparatorChar
+ );
+ var fullPath = _mockFileDataAccessor.Path.GetFullPath(pathSeparatorFixed);
+
+ return fullPath;
+ }
}
diff --git a/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_net472.txt b/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_net472.txt
index 788ddb703..0df64b93c 100644
--- a/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_net472.txt
+++ b/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_net472.txt
@@ -8,6 +8,7 @@ namespace System.IO.Abstractions.TestingHelpers
System.Collections.Generic.IEnumerable AllDrives { get; }
System.Collections.Generic.IEnumerable AllFiles { get; }
System.Collections.Generic.IEnumerable AllPaths { get; }
+ System.Collections.Concurrent.ConcurrentDictionary>> FileHandles { get; }
System.IO.Abstractions.IFileSystem FileSystem { get; }
System.IO.Abstractions.TestingHelpers.PathVerifier PathVerifier { get; }
System.IO.Abstractions.TestingHelpers.StringOperations StringOperations { get; }
@@ -297,7 +298,7 @@ namespace System.IO.Abstractions.TestingHelpers
[System.Serializable]
public class MockFileStream : System.IO.Abstractions.FileSystemStream, System.IO.Abstractions.IFileSystemAclSupport
{
- public MockFileStream(System.IO.Abstractions.TestingHelpers.IMockFileDataAccessor mockFileDataAccessor, string path, System.IO.FileMode mode, System.IO.FileAccess access = 3, System.IO.FileOptions options = 0) { }
+ public MockFileStream(System.IO.Abstractions.TestingHelpers.IMockFileDataAccessor mockFileDataAccessor, string path, System.IO.FileMode mode, System.IO.FileAccess access = 3, System.IO.FileShare share = 1, System.IO.FileOptions options = 0) { }
public override bool CanRead { get; }
public override bool CanWrite { get; }
public static System.IO.Abstractions.FileSystemStream Null { get; }
@@ -347,6 +348,7 @@ namespace System.IO.Abstractions.TestingHelpers
public override System.IO.Abstractions.IDirectoryInfoFactory DirectoryInfo { get; }
public override System.IO.Abstractions.IDriveInfoFactory DriveInfo { get; }
public override System.IO.Abstractions.IFile File { get; }
+ public System.Collections.Concurrent.ConcurrentDictionary>> FileHandles { get; }
public override System.IO.Abstractions.IFileInfoFactory FileInfo { get; }
public override System.IO.Abstractions.IFileStreamFactory FileStream { get; }
public System.IO.Abstractions.IFileSystem FileSystem { get; }
@@ -468,6 +470,7 @@ namespace System.IO.Abstractions.TestingHelpers
{
public PathVerifier(System.IO.Abstractions.TestingHelpers.IMockFileDataAccessor mockFileDataAccessor) { }
public void CheckInvalidPathChars(string path, bool checkAdditional = false) { }
+ public string FixPath(string path) { }
public bool HasIllegalCharacters(string path, bool checkAdditional) { }
public void IsLegalAbsoluteOrRelative(string path, string paramName) { }
public string NormalizeDriveName(string name) { }
diff --git a/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_net6.0.txt b/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_net6.0.txt
index afd2ce3c4..7498e9a31 100644
--- a/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_net6.0.txt
+++ b/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_net6.0.txt
@@ -8,6 +8,7 @@ namespace System.IO.Abstractions.TestingHelpers
System.Collections.Generic.IEnumerable AllDrives { get; }
System.Collections.Generic.IEnumerable AllFiles { get; }
System.Collections.Generic.IEnumerable AllPaths { get; }
+ System.Collections.Concurrent.ConcurrentDictionary>> FileHandles { get; }
System.IO.Abstractions.IFileSystem FileSystem { get; }
System.IO.Abstractions.TestingHelpers.PathVerifier PathVerifier { get; }
System.IO.Abstractions.TestingHelpers.StringOperations StringOperations { get; }
@@ -346,7 +347,7 @@ namespace System.IO.Abstractions.TestingHelpers
[System.Serializable]
public class MockFileStream : System.IO.Abstractions.FileSystemStream, System.IO.Abstractions.IFileSystemAclSupport
{
- public MockFileStream(System.IO.Abstractions.TestingHelpers.IMockFileDataAccessor mockFileDataAccessor, string path, System.IO.FileMode mode, System.IO.FileAccess access = 3, System.IO.FileOptions options = 0) { }
+ public MockFileStream(System.IO.Abstractions.TestingHelpers.IMockFileDataAccessor mockFileDataAccessor, string path, System.IO.FileMode mode, System.IO.FileAccess access = 3, System.IO.FileShare share = 1, System.IO.FileOptions options = 0) { }
public override bool CanRead { get; }
public override bool CanWrite { get; }
public static System.IO.Abstractions.FileSystemStream Null { get; }
@@ -402,6 +403,7 @@ namespace System.IO.Abstractions.TestingHelpers
public override System.IO.Abstractions.IDirectoryInfoFactory DirectoryInfo { get; }
public override System.IO.Abstractions.IDriveInfoFactory DriveInfo { get; }
public override System.IO.Abstractions.IFile File { get; }
+ public System.Collections.Concurrent.ConcurrentDictionary>> FileHandles { get; }
public override System.IO.Abstractions.IFileInfoFactory FileInfo { get; }
public override System.IO.Abstractions.IFileStreamFactory FileStream { get; }
public System.IO.Abstractions.IFileSystem FileSystem { get; }
@@ -524,6 +526,7 @@ namespace System.IO.Abstractions.TestingHelpers
{
public PathVerifier(System.IO.Abstractions.TestingHelpers.IMockFileDataAccessor mockFileDataAccessor) { }
public void CheckInvalidPathChars(string path, bool checkAdditional = false) { }
+ public string FixPath(string path) { }
public bool HasIllegalCharacters(string path, bool checkAdditional) { }
public void IsLegalAbsoluteOrRelative(string path, string paramName) { }
public string NormalizeDriveName(string name) { }
diff --git a/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_net8.0.txt b/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_net8.0.txt
index 1c581cab8..1fe7676be 100644
--- a/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_net8.0.txt
+++ b/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_net8.0.txt
@@ -8,6 +8,7 @@ namespace System.IO.Abstractions.TestingHelpers
System.Collections.Generic.IEnumerable AllDrives { get; }
System.Collections.Generic.IEnumerable AllFiles { get; }
System.Collections.Generic.IEnumerable AllPaths { get; }
+ System.Collections.Concurrent.ConcurrentDictionary>> FileHandles { get; }
System.IO.Abstractions.IFileSystem FileSystem { get; }
System.IO.Abstractions.TestingHelpers.PathVerifier PathVerifier { get; }
System.IO.Abstractions.TestingHelpers.StringOperations StringOperations { get; }
@@ -370,7 +371,7 @@ namespace System.IO.Abstractions.TestingHelpers
[System.Serializable]
public class MockFileStream : System.IO.Abstractions.FileSystemStream, System.IO.Abstractions.IFileSystemAclSupport
{
- public MockFileStream(System.IO.Abstractions.TestingHelpers.IMockFileDataAccessor mockFileDataAccessor, string path, System.IO.FileMode mode, System.IO.FileAccess access = 3, System.IO.FileOptions options = 0) { }
+ public MockFileStream(System.IO.Abstractions.TestingHelpers.IMockFileDataAccessor mockFileDataAccessor, string path, System.IO.FileMode mode, System.IO.FileAccess access = 3, System.IO.FileShare share = 1, System.IO.FileOptions options = 0) { }
public override bool CanRead { get; }
public override bool CanWrite { get; }
public static System.IO.Abstractions.FileSystemStream Null { get; }
@@ -426,6 +427,7 @@ namespace System.IO.Abstractions.TestingHelpers
public override System.IO.Abstractions.IDirectoryInfoFactory DirectoryInfo { get; }
public override System.IO.Abstractions.IDriveInfoFactory DriveInfo { get; }
public override System.IO.Abstractions.IFile File { get; }
+ public System.Collections.Concurrent.ConcurrentDictionary>> FileHandles { get; }
public override System.IO.Abstractions.IFileInfoFactory FileInfo { get; }
public override System.IO.Abstractions.IFileStreamFactory FileStream { get; }
public System.IO.Abstractions.IFileSystem FileSystem { get; }
@@ -549,6 +551,7 @@ namespace System.IO.Abstractions.TestingHelpers
{
public PathVerifier(System.IO.Abstractions.TestingHelpers.IMockFileDataAccessor mockFileDataAccessor) { }
public void CheckInvalidPathChars(string path, bool checkAdditional = false) { }
+ public string FixPath(string path) { }
public bool HasIllegalCharacters(string path, bool checkAdditional) { }
public void IsLegalAbsoluteOrRelative(string path, string paramName) { }
public string NormalizeDriveName(string name) { }
diff --git a/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_net9.0.txt b/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_net9.0.txt
index 6c78cf677..f119d8b86 100644
--- a/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_net9.0.txt
+++ b/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_net9.0.txt
@@ -8,6 +8,7 @@ namespace System.IO.Abstractions.TestingHelpers
System.Collections.Generic.IEnumerable AllDrives { get; }
System.Collections.Generic.IEnumerable AllFiles { get; }
System.Collections.Generic.IEnumerable AllPaths { get; }
+ System.Collections.Concurrent.ConcurrentDictionary>> FileHandles { get; }
System.IO.Abstractions.IFileSystem FileSystem { get; }
System.IO.Abstractions.TestingHelpers.PathVerifier PathVerifier { get; }
System.IO.Abstractions.TestingHelpers.StringOperations StringOperations { get; }
@@ -384,7 +385,7 @@ namespace System.IO.Abstractions.TestingHelpers
[System.Serializable]
public class MockFileStream : System.IO.Abstractions.FileSystemStream, System.IO.Abstractions.IFileSystemAclSupport
{
- public MockFileStream(System.IO.Abstractions.TestingHelpers.IMockFileDataAccessor mockFileDataAccessor, string path, System.IO.FileMode mode, System.IO.FileAccess access = 3, System.IO.FileOptions options = 0) { }
+ public MockFileStream(System.IO.Abstractions.TestingHelpers.IMockFileDataAccessor mockFileDataAccessor, string path, System.IO.FileMode mode, System.IO.FileAccess access = 3, System.IO.FileShare share = 1, System.IO.FileOptions options = 0) { }
public override bool CanRead { get; }
public override bool CanWrite { get; }
public static System.IO.Abstractions.FileSystemStream Null { get; }
@@ -440,6 +441,7 @@ namespace System.IO.Abstractions.TestingHelpers
public override System.IO.Abstractions.IDirectoryInfoFactory DirectoryInfo { get; }
public override System.IO.Abstractions.IDriveInfoFactory DriveInfo { get; }
public override System.IO.Abstractions.IFile File { get; }
+ public System.Collections.Concurrent.ConcurrentDictionary>> FileHandles { get; }
public override System.IO.Abstractions.IFileInfoFactory FileInfo { get; }
public override System.IO.Abstractions.IFileStreamFactory FileStream { get; }
public System.IO.Abstractions.IFileSystem FileSystem { get; }
@@ -563,6 +565,7 @@ namespace System.IO.Abstractions.TestingHelpers
{
public PathVerifier(System.IO.Abstractions.TestingHelpers.IMockFileDataAccessor mockFileDataAccessor) { }
public void CheckInvalidPathChars(string path, bool checkAdditional = false) { }
+ public string FixPath(string path) { }
public bool HasIllegalCharacters(string path, bool checkAdditional) { }
public void IsLegalAbsoluteOrRelative(string path, string paramName) { }
public string NormalizeDriveName(string name) { }
diff --git a/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_netstandard2.0.txt b/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_netstandard2.0.txt
index e0880b9f8..d8bcdae18 100644
--- a/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_netstandard2.0.txt
+++ b/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_netstandard2.0.txt
@@ -8,6 +8,7 @@ namespace System.IO.Abstractions.TestingHelpers
System.Collections.Generic.IEnumerable AllDrives { get; }
System.Collections.Generic.IEnumerable AllFiles { get; }
System.Collections.Generic.IEnumerable AllPaths { get; }
+ System.Collections.Concurrent.ConcurrentDictionary>> FileHandles { get; }
System.IO.Abstractions.IFileSystem FileSystem { get; }
System.IO.Abstractions.TestingHelpers.PathVerifier PathVerifier { get; }
System.IO.Abstractions.TestingHelpers.StringOperations StringOperations { get; }
@@ -297,7 +298,7 @@ namespace System.IO.Abstractions.TestingHelpers
[System.Serializable]
public class MockFileStream : System.IO.Abstractions.FileSystemStream, System.IO.Abstractions.IFileSystemAclSupport
{
- public MockFileStream(System.IO.Abstractions.TestingHelpers.IMockFileDataAccessor mockFileDataAccessor, string path, System.IO.FileMode mode, System.IO.FileAccess access = 3, System.IO.FileOptions options = 0) { }
+ public MockFileStream(System.IO.Abstractions.TestingHelpers.IMockFileDataAccessor mockFileDataAccessor, string path, System.IO.FileMode mode, System.IO.FileAccess access = 3, System.IO.FileShare share = 1, System.IO.FileOptions options = 0) { }
public override bool CanRead { get; }
public override bool CanWrite { get; }
public static System.IO.Abstractions.FileSystemStream Null { get; }
@@ -347,6 +348,7 @@ namespace System.IO.Abstractions.TestingHelpers
public override System.IO.Abstractions.IDirectoryInfoFactory DirectoryInfo { get; }
public override System.IO.Abstractions.IDriveInfoFactory DriveInfo { get; }
public override System.IO.Abstractions.IFile File { get; }
+ public System.Collections.Concurrent.ConcurrentDictionary>> FileHandles { get; }
public override System.IO.Abstractions.IFileInfoFactory FileInfo { get; }
public override System.IO.Abstractions.IFileStreamFactory FileStream { get; }
public System.IO.Abstractions.IFileSystem FileSystem { get; }
@@ -468,6 +470,7 @@ namespace System.IO.Abstractions.TestingHelpers
{
public PathVerifier(System.IO.Abstractions.TestingHelpers.IMockFileDataAccessor mockFileDataAccessor) { }
public void CheckInvalidPathChars(string path, bool checkAdditional = false) { }
+ public string FixPath(string path) { }
public bool HasIllegalCharacters(string path, bool checkAdditional) { }
public void IsLegalAbsoluteOrRelative(string path, string paramName) { }
public string NormalizeDriveName(string name) { }
diff --git a/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_netstandard2.1.txt b/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_netstandard2.1.txt
index 80f876c0c..edf06b564 100644
--- a/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_netstandard2.1.txt
+++ b/tests/TestableIO.System.IO.Abstractions.Api.Tests/Expected/TestableIO.System.IO.Abstractions.TestingHelpers_netstandard2.1.txt
@@ -8,6 +8,7 @@ namespace System.IO.Abstractions.TestingHelpers
System.Collections.Generic.IEnumerable AllDrives { get; }
System.Collections.Generic.IEnumerable AllFiles { get; }
System.Collections.Generic.IEnumerable AllPaths { get; }
+ System.Collections.Concurrent.ConcurrentDictionary>> FileHandles { get; }
System.IO.Abstractions.IFileSystem FileSystem { get; }
System.IO.Abstractions.TestingHelpers.PathVerifier PathVerifier { get; }
System.IO.Abstractions.TestingHelpers.StringOperations StringOperations { get; }
@@ -323,7 +324,7 @@ namespace System.IO.Abstractions.TestingHelpers
[System.Serializable]
public class MockFileStream : System.IO.Abstractions.FileSystemStream, System.IO.Abstractions.IFileSystemAclSupport
{
- public MockFileStream(System.IO.Abstractions.TestingHelpers.IMockFileDataAccessor mockFileDataAccessor, string path, System.IO.FileMode mode, System.IO.FileAccess access = 3, System.IO.FileOptions options = 0) { }
+ public MockFileStream(System.IO.Abstractions.TestingHelpers.IMockFileDataAccessor mockFileDataAccessor, string path, System.IO.FileMode mode, System.IO.FileAccess access = 3, System.IO.FileShare share = 1, System.IO.FileOptions options = 0) { }
public override bool CanRead { get; }
public override bool CanWrite { get; }
public static System.IO.Abstractions.FileSystemStream Null { get; }
@@ -375,6 +376,7 @@ namespace System.IO.Abstractions.TestingHelpers
public override System.IO.Abstractions.IDirectoryInfoFactory DirectoryInfo { get; }
public override System.IO.Abstractions.IDriveInfoFactory DriveInfo { get; }
public override System.IO.Abstractions.IFile File { get; }
+ public System.Collections.Concurrent.ConcurrentDictionary>> FileHandles { get; }
public override System.IO.Abstractions.IFileInfoFactory FileInfo { get; }
public override System.IO.Abstractions.IFileStreamFactory FileStream { get; }
public System.IO.Abstractions.IFileSystem FileSystem { get; }
@@ -497,6 +499,7 @@ namespace System.IO.Abstractions.TestingHelpers
{
public PathVerifier(System.IO.Abstractions.TestingHelpers.IMockFileDataAccessor mockFileDataAccessor) { }
public void CheckInvalidPathChars(string path, bool checkAdditional = false) { }
+ public string FixPath(string path) { }
public bool HasIllegalCharacters(string path, bool checkAdditional) { }
public void IsLegalAbsoluteOrRelative(string path, string paramName) { }
public string NormalizeDriveName(string name) { }
diff --git a/tests/TestableIO.System.IO.Abstractions.TestingHelpers.Tests/MockFileStreamTests.cs b/tests/TestableIO.System.IO.Abstractions.TestingHelpers.Tests/MockFileStreamTests.cs
index b82566d9a..a8f815a15 100644
--- a/tests/TestableIO.System.IO.Abstractions.TestingHelpers.Tests/MockFileStreamTests.cs
+++ b/tests/TestableIO.System.IO.Abstractions.TestingHelpers.Tests/MockFileStreamTests.cs
@@ -390,4 +390,43 @@ async Task Act() =>
await source.CopyToAsync(destination);
await That(Act).Throws();
}
+
+ [Test]
+ [TestCase(FileShare.None, FileAccess.Read)]
+ [TestCase(FileShare.None, FileAccess.ReadWrite)]
+ [TestCase(FileShare.None, FileAccess.Write)]
+ [TestCase(FileShare.Read, FileAccess.Write)]
+ [TestCase(FileShare.Read, FileAccess.ReadWrite)]
+ [TestCase(FileShare.Write, FileAccess.Read)]
+ public async Task MockFileStream_ConflictingShareOrAccess_ShouldThrowUntilHandleReleased(
+ FileShare share,
+ FileAccess access)
+ {
+ var fileSystem = new MockFileSystem();
+ fileSystem.File.WriteAllText("foo.txt", "");
+ using (new MockFileStream(fileSystem, "foo.txt", FileMode.Open, FileAccess.Read, share))
+ {
+ await That(() => new MockFileStream(fileSystem, "foo.txt", FileMode.Open, access)).Throws();
+ }
+ await That(() => new MockFileStream(fileSystem, "foo.txt", FileMode.Open, access)).DoesNotThrow();
+ }
+
+ [Test]
+ [TestCase(FileShare.Read, FileAccess.Read)]
+ [TestCase(FileShare.Read | FileShare.Write, FileAccess.Read)]
+ [TestCase(FileShare.Read | FileShare.Write, FileAccess.ReadWrite)]
+ [TestCase(FileShare.ReadWrite, FileAccess.Read)]
+ [TestCase(FileShare.ReadWrite, FileAccess.ReadWrite)]
+ [TestCase(FileShare.ReadWrite, FileAccess.Write)]
+ public async Task MockFileStream_CompatibleShareOrAccess_ShouldNotThrow(
+ FileShare share,
+ FileAccess access)
+ {
+ var fileSystem = new MockFileSystem();
+ fileSystem.File.WriteAllText("foo.txt", "");
+ using (new MockFileStream(fileSystem, "foo.txt", FileMode.Open, FileAccess.Read, share))
+ {
+ await That(() => new MockFileStream(fileSystem, "foo.txt", FileMode.Open, access)).DoesNotThrow();
+ }
+ }
}
\ No newline at end of file