Skip to content

Commit

Permalink
More tests for FileStream edge cases (#49754)
Browse files Browse the repository at this point in the history
* add StreamConformanceTests to the solution file so we can read source code from VS

* add FileOffsetIsPreservedWhenFileStreamIsCreatedFromSafeFileHandle tests

* add WriteAsyncStartsWherePreviousReadAsyncHasFinished test
  • Loading branch information
adamsitnik authored Mar 17, 2021
1 parent 6f110f1 commit 7802727
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/libraries/System.IO.FileSystem/System.IO.FileSystem.sln
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D9FB1730-B75
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO.FileSystem.Legacy.Tests", "tests\LegacyTests\System.IO.FileSystem.Legacy.Tests.csproj", "{48E07F12-8597-40DE-8A37-CCBEB9D54012}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StreamConformanceTests", "..\Common\tests\StreamConformanceTests\StreamConformanceTests.csproj", "{FEF03BCC-509F-4646-9132-9DE27FA3DA6F}"
EndProject
Global
GlobalSection(NestedProjects) = preSolution
{D350D6E7-52F1-40A4-B646-C178F6BBB689} = {1A727AF9-4F39-4109-BB8F-813286031DC9}
Expand All @@ -40,6 +42,7 @@ Global
{877E39A8-51CB-463A-AF4C-6FAE4F438075} = {D9FB1730-B750-4C0D-8D24-8C992DEB6034}
{D7DF8034-3AE5-4DEF-BCC4-6353239391BF} = {D9FB1730-B750-4C0D-8D24-8C992DEB6034}
{48E07F12-8597-40DE-8A37-CCBEB9D54012} = {1A727AF9-4F39-4109-BB8F-813286031DC9}
{FEF03BCC-509F-4646-9132-9DE27FA3DA6F} = {1A727AF9-4F39-4109-BB8F-813286031DC9}
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -90,6 +93,10 @@ Global
{48E07F12-8597-40DE-8A37-CCBEB9D54012}.Debug|Any CPU.Build.0 = Debug|Any CPU
{48E07F12-8597-40DE-8A37-CCBEB9D54012}.Release|Any CPU.ActiveCfg = Release|Any CPU
{48E07F12-8597-40DE-8A37-CCBEB9D54012}.Release|Any CPU.Build.0 = Release|Any CPU
{FEF03BCC-509F-4646-9132-9DE27FA3DA6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FEF03BCC-509F-4646-9132-9DE27FA3DA6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FEF03BCC-509F-4646-9132-9DE27FA3DA6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FEF03BCC-509F-4646-9132-9DE27FA3DA6F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using Microsoft.Win32.SafeHandles;
using System.IO.Pipes;
using System.Linq;
using System.Threading.Tasks;
using Xunit;

Expand All @@ -29,6 +30,74 @@ private Task<Stream> CreateStream(byte[] initialData, FileAccess access)
protected override Task<Stream> CreateWriteOnlyStreamCore(byte[] initialData) => CreateStream(initialData, FileAccess.Write);

protected override bool NopFlushCompletesSynchronously => OperatingSystem.IsWindows();

[Theory]
[MemberData(nameof(AllReadWriteModes))]
public async Task FileOffsetIsPreservedWhenFileStreamIsCreatedFromSafeFileHandle_Reads(ReadWriteMode mode)
{
byte[] initialData = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
using FileStream stream = (FileStream)await CreateReadOnlyStreamCore(initialData);
byte[] buffer = new byte[5];
int bytesRead = await ReadAsync(mode, stream, buffer, 0, buffer.Length);

Assert.Equal(bytesRead, stream.Position);

using FileStream createdFromHandle = new FileStream(stream.SafeFileHandle, FileAccess.Read);

Assert.Equal(bytesRead, stream.Position); // accessing SafeFileHandle must not change the position
Assert.Equal(stream.Position, createdFromHandle.Position); // but it should sync the offset with OS
}

[Theory]
[MemberData(nameof(AllReadWriteModes))]
public async Task FileOffsetIsPreservedWhenFileStreamIsCreatedFromSafeFileHandle_Writes(ReadWriteMode mode)
{
using FileStream stream = (FileStream)await CreateWriteOnlyStreamCore(Array.Empty<byte>());
byte[] buffer = new byte[] { 0, 1, 2, 3, 4 };
await WriteAsync(mode, stream, buffer, 0, buffer.Length);

Assert.Equal(buffer.Length, stream.Position);

using FileStream createdFromHandle = new FileStream(stream.SafeFileHandle, FileAccess.Write);

Assert.Equal(buffer.Length, stream.Position);
Assert.Equal(stream.Position, createdFromHandle.Position);
}

[Theory]
[MemberData(nameof(AllReadWriteModes))]
public async Task WriteAsyncStartsWherePreviousReadAsyncHasFinished(ReadWriteMode mode)
{
if (mode == ReadWriteMode.SyncByte)
{
// it reads a single byte even if buffer.Length > 1
return;
}

byte[] initialData = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
byte[] readBuffer = new byte[initialData.Length * 2]; // the edge case: reading more than available
byte[] writeBuffer = new byte[] { 10, 11, 12, 13, 14, 15 };
string filePath;

using (FileStream stream = (FileStream)await CreateReadWriteStreamCore(initialData))
{
filePath = stream.Name;

int bytesRead = await ReadAsync(mode, stream, readBuffer, 0, readBuffer.Length);

Assert.Equal(bytesRead, initialData.Length);
Assert.Equal(initialData.Length, stream.Position);
Assert.Equal(stream.Position, stream.Length);

await WriteAsync(mode, stream, writeBuffer, 0, writeBuffer.Length);

Assert.Equal(initialData.Length + writeBuffer.Length, stream.Position);
Assert.Equal(stream.Position, stream.Length);
}

byte[] allBytes = File.ReadAllBytes(filePath);
Assert.Equal(initialData.Concat(writeBuffer), allBytes);
}
}

public class UnbufferedSyncFileStreamStandaloneConformanceTests : FileStreamStandaloneConformanceTests
Expand Down

0 comments on commit 7802727

Please sign in to comment.