diff --git a/Source/Testably.Abstractions.Testing/FileSystem/MockSafeFileHandleRegistry.cs b/Source/Testably.Abstractions.Testing/FileSystem/MockSafeFileHandleRegistry.cs index e57dbe81..57b12be6 100644 --- a/Source/Testably.Abstractions.Testing/FileSystem/MockSafeFileHandleRegistry.cs +++ b/Source/Testably.Abstractions.Testing/FileSystem/MockSafeFileHandleRegistry.cs @@ -87,9 +87,10 @@ internal SafeFileHandle Open(string path, { IntPtr value = new(Interlocked.Increment(ref _lastHandleValue)); SafeFileHandle handle = new(value, ownsHandle: false); + // The mode was applied above, so a stream on this handle must open the file as it is now. _entries[value] = new Entry( new WeakReference(handle), - new SafeFileHandleMock(location.FullPath, mode, share), + new SafeFileHandleMock(location.FullPath, FileMode.Open, share), accessLock, location, container, diff --git a/Tests/Testably.Abstractions.Tests/FileSystem/FileStreamFactory/OpenHandleStreamTests.cs b/Tests/Testably.Abstractions.Tests/FileSystem/FileStreamFactory/OpenHandleStreamTests.cs index 2d775446..84eaf82f 100644 --- a/Tests/Testably.Abstractions.Tests/FileSystem/FileStreamFactory/OpenHandleStreamTests.cs +++ b/Tests/Testably.Abstractions.Tests/FileSystem/FileStreamFactory/OpenHandleStreamTests.cs @@ -69,6 +69,62 @@ public async Task New_WithHandle_ShouldCreateWritableStream(string path) await That(FileSystem.File.ReadAllBytes(path)).IsEqualTo(new byte[] { 1, 2, 3, }); } + [Test] + [AutoArguments] + public async Task New_WithHandleOpenedWithCreateNew_ShouldNotThrow(string path) + { + using SafeFileHandle handle = FileSystem.File.OpenHandle(path, + FileMode.CreateNew, FileAccess.ReadWrite, FileShare.ReadWrite); + + void Act() + { + using FileSystemStream stream = FileSystem.FileStream.New(handle, FileAccess.Read); + } + + await That(Act).DoesNotThrow() + .Because("the stream wraps the open file instead of creating it again"); + } + + [Test] + [AutoArguments(FileMode.Create)] + [AutoArguments(FileMode.Truncate)] + public async Task New_WithHandleOpenedWithTruncatingMode_ShouldKeepWrittenContent( + FileMode mode, string path) + { + FileSystem.File.WriteAllText(path, "foobar"); + byte[] written = [1, 2, 3,]; + + using (SafeFileHandle handle = FileSystem.File.OpenHandle(path, + mode, FileAccess.ReadWrite, FileShare.ReadWrite)) + { + FileSystem.RandomAccess.Write(handle, written, 0); + using FileSystemStream stream = + FileSystem.FileStream.New(handle, FileAccess.ReadWrite); + + await That(stream.Length).IsEqualTo(written.Length) + .Because("the stream must not truncate the file again"); + } + + await That(FileSystem.File.ReadAllBytes(path)).IsEqualTo(written); + } + + [Test] + [AutoArguments] + public async Task New_WithHandleOpenedWithAppend_ShouldAllowReadWriteAccess(string path) + { + using SafeFileHandle handle = FileSystem.File.OpenHandle(path, + FileMode.Append, FileAccess.Write, FileShare.ReadWrite); + + void Act() + { + using FileSystemStream stream = + FileSystem.FileStream.New(handle, FileAccess.ReadWrite); + } + + await That(Act).DoesNotThrow() + .Because("the append mode of the handle is not re-validated against the stream access"); + } + [Test] [AutoArguments] public async Task New_WithHandle_ShouldReportAccessFromTheGivenFileAccess(