Explorar el Código

Merge pull request #277 from sshnet/develop

Merge develop changes into master to prepare for 2016.1.0-beta2
Gert Driesen hace 8 años
padre
commit
bc154e6533
Se han modificado 100 ficheros con 7531 adiciones y 1497 borrados
  1. 25 9
      README.md
  2. 5 6
      appveyor.yml
  3. 12 0
      build/build.cmd
  4. 18 9
      build/build.proj
  5. 32 0
      src/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj
  6. 113 0
      src/Renci.SshNet.NETCore/Renci.SshNet.NETCore.csproj
  7. 0 19
      src/Renci.SshNet.NETCore/Renci.SshNet.NETCore.xproj
  8. 0 90
      src/Renci.SshNet.NETCore/project.json
  9. 31 1
      src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj
  10. 31 1
      src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj
  11. 263 19
      src/Renci.SshNet.Tests.NET35/Renci.SshNet.Tests.NET35.csproj
  12. 25 4
      src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs
  13. 1 1
      src/Renci.SshNet.Tests/Classes/Channels/ChannelForwardedTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs
  14. 10 3
      src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs
  15. 9 1
      src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived_SendEofInvoked.cs
  16. 18 0
      src/Renci.SshNet.Tests/Classes/Common/BigIntegerTest.cs
  17. 83 0
      src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Reverse.cs
  18. 186 0
      src/Renci.SshNet.Tests/Classes/Common/PackTest.cs
  19. 0 60
      src/Renci.SshNet.Tests/Classes/Common/SshDataTest.cs
  20. 7 3
      src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Connected.cs
  21. 7 3
      src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disconnected.cs
  22. 7 3
      src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disposed.cs
  23. 5 2
      src/Renci.SshNet.Tests/Classes/NetConfClientTest_Finalize_Connected.cs
  24. 36 53
      src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/DesCipherTest.cs
  25. 6 3
      src/Renci.SshNet.Tests/Classes/Sftp/Responses/ExtendedReplies/StatVfsReplyInfoTest.cs
  26. 38 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpDataResponseBuilder.cs
  27. 60 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTestBase.cs
  28. 148 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_DisposeShouldUnblockReadAndReadAhead.cs
  29. 162 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_LastChunkBeforeEofIsComplete.cs
  30. 161 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_LastChunkBeforeEofIsPartial.cs
  31. 300 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsNotReached.cs
  32. 190 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsReached.cs
  33. 6 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadBeginReadException.cs
  34. 207 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadEndInvokeException_DiscardsFurtherReadAheads.cs
  35. 174 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadEndInvokeException_PreventsFurtherReadAheads.cs
  36. 11 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackBeginReadException.cs
  37. 11 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackEndInvokeException.cs
  38. 138 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_ChunkAvailable.cs
  39. 122 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_NoChunkAvailable.cs
  40. 166 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReahAheadExceptionInBeginRead.cs
  41. 65 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTestBase.cs
  42. 35 36
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessRead.cs
  43. 35 36
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessReadWrite.cs
  44. 35 36
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessWrite.cs
  45. 38 39
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessRead.cs
  46. 38 39
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessReadWrite.cs
  47. 38 39
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessWrite.cs
  48. 0 73
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_SessionOpen_FileAccessRead.cs
  49. 0 73
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_SessionOpen_FileAccessReadWrite.cs
  50. 0 73
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_SessionOpen_FileAccessWrite.cs
  51. 38 39
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessRead.cs
  52. 38 39
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessReadWrite.cs
  53. 38 39
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessWrite.cs
  54. 38 39
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessRead.cs
  55. 38 39
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessReadWrite.cs
  56. 35 39
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessWrite.cs
  57. 0 73
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_SessionOpen_FileAccessRead.cs
  58. 0 73
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_SessionOpen_FileAccessReadWrite.cs
  59. 0 73
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_SessionOpen_FileAccessWrite.cs
  60. 2 5
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Closed.cs
  61. 37 41
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Disposed.cs
  62. 37 38
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionNotOpen.cs
  63. 36 36
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionOpen.cs
  64. 54 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileAccessInvalid.cs
  65. 55 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessRead.cs
  66. 55 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessReadWrite.cs
  67. 173 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessWrite.cs
  68. 55 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessRead.cs
  69. 151 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessReadWrite.cs
  70. 155 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessWrite.cs
  71. 55 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessRead.cs
  72. 154 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs
  73. 151 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileExists.cs
  74. 159 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileDoesNotExist.cs
  75. 155 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileExists.cs
  76. 54 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeInvalid.cs
  77. 174 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessRead.cs
  78. 151 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessReadWrite.cs
  79. 155 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessWrite.cs
  80. 174 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessRead.cs
  81. 151 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessReadWrite.cs
  82. 155 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessWrite.cs
  83. 55 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessRead.cs
  84. 151 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessReadWrite.cs
  85. 155 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessWrite.cs
  86. 35 39
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Closed.cs
  87. 35 39
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Disposed.cs
  88. 36 40
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionNotOpen.cs
  89. 33 36
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionOpen.cs
  90. 33 36
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Finalize_SessionOpen.cs
  91. 112 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_NotReadFromBuffer.cs
  92. 118 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_ReadFromBuffer.cs
  93. 112 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_NoDataInBuffer.cs
  94. 81 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_SessionNotOpen.cs
  95. 149 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_WriteMode_DataInBuffer.cs
  96. 117 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_WriteMode_NoDataInBuffer.cs
  97. 85 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_Eof.cs
  98. 90 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_LessDataThanReadBufferSizeAvailable.cs
  99. 155 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs
  100. 148 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs

+ 25 - 9
README.md

@@ -1,14 +1,14 @@
 SSH.NET
 =======
-SSH.NET is a Secure Shell (SSH) library for .NET, optimized for parallelism.
+SSH.NET is a Secure Shell (SSH-2) library for .NET, optimized for parallelism.
 
 [![Version](https://img.shields.io/nuget/vpre/SSH.NET.svg)](https://www.nuget.org/packages/SSH.NET)
 [![Build status](https://ci.appveyor.com/api/projects/status/ih77qu6tap3o92gu/branch/develop?svg=true)](https://ci.appveyor.com/api/projects/status/ih77qu6tap3o92gu/branch/develop)
 
-##Introduction
+## Introduction
 This project was inspired by **Sharp.SSH** library which was ported from java and it seems like was not supported for quite some time. This library is a complete rewrite, without any third party dependencies, using parallelism to achieve the best performance possible.
 
-##Features
+## Features
 * Execution of SSH command using both synchronous and asynchronous methods
 * Return command execution exit status and other information 
 * Provide SFTP functionality for both synchronous and asynchronous operations
@@ -25,7 +25,7 @@ This project was inspired by **Sharp.SSH** library which was ported from java an
 * Supports two-factor or higher authentication
 * Supports SOCKS4, SOCKS5 and HTTP Proxy
 
-##Key Exchange Method
+## Key Exchange Method
 
 **SSH.NET** supports the following key exchange methods:
 * diffie-hellman-group-exchange-sha256
@@ -33,7 +33,7 @@ This project was inspired by **Sharp.SSH** library which was ported from java an
 * diffie-hellman-group14-sha1
 * diffie-hellman-group1-sha1
 
-##Message Authentication Code
+## Message Authentication Code
 
 **SSH.NET** supports the following MAC algorithms:
 * hmac-md5
@@ -47,23 +47,39 @@ This project was inspired by **Sharp.SSH** library which was ported from java an
 * hmac-ripemd160
 * hmac-ripemd160@openssh.com
 
-##Framework Support
+## Framework Support
 **SSH.NET** supports the following target frameworks:
 * .NET Framework 3.5
 * .NET Framework 4.0 (and higher)
-* .NET Platform Standard 1.3
+* .NET Standard 1.3
 * Silverlight 4
 * Silverlight 5
 * Windows Phone 7.1
 * Windows Phone 8.0
 * Universal Windows Platform 10
 
-##Building SSH.NET
+## Usage
+Establish an SFTP connection using both password and public-key authentication:
+
+```cs
+var connectionInfo = new ConnectionInfo("sftp.foo.com",
+                                        "guest",
+                                        new PasswordAuthenticationMethod("guest", "pwd"),
+                                        new PrivateKeyAuthenticationMethod("rsa.key"));
+using (var client = new SftpClient(connectionInfo))
+{
+    client.Connect();
+}
+
+```
+
+## Building SSH.NET
 
 Software                          | net35 | net40 | netstandard1.3 | sl4 | sl5 | wp71 | wp8 | uap10.0 |
 --------------------------------- | :---: | :---: | :------------: | :-: | :-: | :--: | :-: | :-----: |
 Windows Phone SDK 8.0             |       |       |                | x   | x   | x    | x   |
 Visual Studio 2012 Update 5       | x     | x     |                | x   | x   | x    | x   |
-Visual Studio 2015 Update 3       | x     | x     | x              |     | x   |      | x   | x
+Visual Studio 2015 Update 3       | x     | x     |                |     | x   |      | x   | x
+Visual Studio 2017                |       | x     | x              |     |     |      |     | 
 
 [![NDepend](http://download-codeplex.sec.s-msft.com/Download?ProjectName=sshnet&DownloadId=629750)](http://ndepend.com)

+ 5 - 6
appveyor.yml

@@ -7,9 +7,8 @@ build:
   project: src\Renci.SshNet.VS2015.sln
   verbosity: minimal
 
-test:
-  assemblies: src\Renci.SshNet.Tests\bin\Debug\Renci.SshNet.Tests.dll
-  categories:
-    except:
-    - integration
-    - LongRunning
+test_script:
+- cmd: >-
+    vstest.console /logger:Appveyor src\Renci.SshNet.Tests\bin\Debug\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration&TestCategory!=LongRunning"
+
+    vstest.console /logger:Appveyor src\Renci.SshNet.Tests.NET35\bin\Debug\Renci.SshNet.Tests.NET35.dll /TestCaseFilter:"TestCategory!=integration&TestCategory!=LongRunning"

+ 12 - 0
build/build.cmd

@@ -0,0 +1,12 @@
+@echo off
+
+set MSBUILD14_EXE=%ProgramFiles(x86)%\MSBuild\14.0\Bin\MSBuild.exe
+set MSBUILD15_EXE=%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Enterprise\\MSBuild\15.0\bin\MSBuild.exe
+
+call "%MSBUILD14_EXE%" build.proj /t:Clean
+call "%MSBUILD15_EXE%" build.proj /t:Clean
+
+call "%MSBUILD14_EXE%" build.proj /t:Build
+call "%MSBUILD15_EXE%" build.proj /t:Build
+
+call "%MSBUILD15_EXE%" build.proj /t:Package /p:ReleaseVersion=%1

+ 18 - 9
build/build.proj

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" DefaultTargets="Clean;CreateNuGetPackage;CreateBinPackage;GenerateHelpFile" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 	<UsingTask TaskName="Zip" AssemblyFile="$(MSBuildThisFileDirectory)target\nuget\packages\$(MSBuildTasksPackageId).$(MSBuildTasksPackageVersion)\tools\MSBuild.Community.Tasks.dll"/>
 	<PropertyGroup>
 		<Configuration Condition="'$(Configuration)' == ''">Release</Configuration>
@@ -11,9 +11,17 @@
 	<ItemGroup>
 		<VisualStudioVersion Include="2012">
 			<SolutionFile>$(MSBuildThisFileDirectory)..\src\Renci.SshNet.VS2012.sln</SolutionFile>
+			<MSBuildToolsVersion>14.0</MSBuildToolsVersion>
+			<NuGetPackageRestore>true</NuGetPackageRestore>
 		</VisualStudioVersion>
 		<VisualStudioVersion Include="2015">
 			<SolutionFile>$(MSBuildThisFileDirectory)..\src\Renci.SshNet.VS2015.sln</SolutionFile>
+			<MSBuildToolsVersion>14.0</MSBuildToolsVersion>
+			<NuGetPackageRestore>true</NuGetPackageRestore>
+		</VisualStudioVersion>
+		<VisualStudioVersion Include="2017">
+			<SolutionFile>$(MSBuildThisFileDirectory)..\src\Renci.SshNet.VS2017.sln</SolutionFile>
+			<MSBuildToolsVersion>15.0</MSBuildToolsVersion>
 		</VisualStudioVersion>
 	</ItemGroup>
 	<ItemGroup>
@@ -54,11 +62,11 @@
 		<RemoveDir Directories="$(MSBuildThisFileDirectory)target"/>
 		<ItemGroup>
 			<ProjectToBuild Remove="@(ProjectToBuild)"/>
-			<ProjectToBuild Include="%(VisualStudioVersion.SolutionFile)">
+			<ProjectToBuild Include="%(VisualStudioVersion.SolutionFile)" Condition="'%(VisualStudioVersion.MSBuildToolsVersion)'=='$(MSBuildToolsVersion)'">
 				<Properties>Configuration=Release</Properties>
 			</ProjectToBuild>
 		</ItemGroup>
-		<MSBuild Projects="@(ProjectToBuild)" Targets="Clean"/>
+		<MSBuild Projects="@(ProjectToBuild)" Targets="Clean" />
 	</Target>
 	<Target Name="DownloadNuGet">
 		<MakeDir Directories="$(MSBuildThisFileDirectory)target\nuget"/>
@@ -67,22 +75,23 @@
 			FileName="$(MSBuildThisFileDirectory)target\nuget\nuget.exe"/>
 	</Target>
 	<Target Name="RestoreNuGetPackages" DependsOnTargets="DownloadNuGet" Outputs="%(VisualStudioVersion.Identity)">
-		<Message Text="Restoring nuget packages for '%(VisualStudioVersion.SolutionFile)'..." Importance="High"/>
-		<Exec Command="$(NuGetExe) restore &quot;%(VisualStudioVersion.SolutionFile)&quot;"/>
+		<Message Text="Restoring nuget packages for '%(VisualStudioVersion.SolutionFile)'..." Importance="High" Condition="'%(VisualStudioVersion.MSBuildToolsVersion)'=='$(MSBuildToolsVersion)' and '%(VisualStudioVersion.NuGetPackageRestore)'=='true'"/>
+		<Exec Command="$(NuGetExe) restore &quot;%(VisualStudioVersion.SolutionFile)&quot;" Condition="'%(VisualStudioVersion.MSBuildToolsVersion)'=='$(MSBuildToolsVersion)' and '%(VisualStudioVersion.NuGetPackageRestore)'=='true'"/>
 	</Target>
 	<Target Name="Build" DependsOnTargets="RestoreNuGetPackages" Outputs="%(VisualStudioVersion.Identity)">
 		<ItemGroup>
 			<ProjectToBuild Remove="@(ProjectToBuild)"/>
-			<ProjectToBuild Include="%(VisualStudioVersion.SolutionFile)">
+			<ProjectToBuild Include="%(VisualStudioVersion.SolutionFile)" Condition="'%(VisualStudioVersion.MSBuildToolsVersion)'=='$(MSBuildToolsVersion)'">
 				<Properties>Configuration=Release</Properties>
 			</ProjectToBuild>
 		</ItemGroup>
 		<MSBuild Projects="@(ProjectToBuild)" Targets="Rebuild"/>
 	</Target>
+	<Target Name="Package" DependsOnTargets="CreateNuGetPackage;CreateBinPackage;GenerateHelpFile"/>
 	<Target Name="CreateNuGetPackage" DependsOnTargets="CopyBuildOutputToPackage">
 		<Exec Command="$(NuGetExe) pack $(MSBuildThisFileDirectory)nuget\SSH.NET.nuspec -OutputDirectory &quot;$(MSBuildThisFileDirectory)target&quot; -BasePath &quot;$(MSBuildThisFileDirectory)target\package&quot; -NonInteractive"/>
 	</Target>
-	<Target Name="CopyBuildOutputToPackage" DependsOnTargets="Build" Outputs="%(TargetFramework.Identity)">
+	<Target Name="CopyBuildOutputToPackage" Outputs="%(TargetFramework.Identity)">
 		<ItemGroup>
 			<BuildOutput Remove="@(BuildOutput)"/>
 			<BuildOutput Include="$(MSBuildThisFileDirectory)..\src\%(TargetFramework.OutputDirectory)\Renci.SshNet.dll"/>
@@ -90,12 +99,12 @@
 		</ItemGroup>
 		<Copy SourceFiles="@(BuildOutput)" DestinationFolder="$(MSBuildThisFileDirectory)target\package\lib\%(TargetFramework.Moniker)"/>
 	</Target>
-	<Target Name="GenerateHelpFile" DependsOnTargets="Build;CheckReleaseVersion">
+	<Target Name="GenerateHelpFile" DependsOnTargets="CheckReleaseVersion">
 		<Error Text="Please install Sandcastle, and ensure the SHFBFolder environment variable is set." Condition="'$(SHFBFolder)'==''"/>
 		<MSBuild Projects="$(MSBuildThisFileDirectory)sandcastle\SSH.NET.shfbproj"/>
 		<Move SourceFiles="$(MSBuildThisFileDirectory)target\help\SshNet.Help.chm" DestinationFiles="$(MSBuildThisFileDirectory)target\SSH.NET-$(ReleaseVersion)-help.chm"/>
 	</Target>
-	<Target Name="CopyBuildOutputToBin" DependsOnTargets="Build" Outputs="%(TargetFramework.Identity)">
+	<Target Name="CopyBuildOutputToBin" Outputs="%(TargetFramework.Identity)">
 		<ItemGroup>
 			<BuildOutput Remove="@(BuildOutput)"/>
 			<BuildOutput Include="$(MSBuildThisFileDirectory)..\src\%(TargetFramework.OutputDirectory)\*.dll"/>

+ 32 - 0
src/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj

@@ -23,6 +23,7 @@
     <WarningLevel>4</WarningLevel>
     <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
     <DocumentationFile>bin\Debug\Renci.SshNet.xml</DocumentationFile>
+    <LangVersion>5</LangVersion>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <DebugType>none</DebugType>
@@ -35,6 +36,7 @@
     <NoWarn>
     </NoWarn>
     <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+    <LangVersion>5</LangVersion>
   </PropertyGroup>
   <PropertyGroup>
     <SignAssembly>true</SignAssembly>
@@ -186,6 +188,9 @@
     <Compile Include="..\Renci.SshNet\Common\ObjectIdentifier.cs">
       <Link>Common\ObjectIdentifier.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Common\Pack.cs">
+      <Link>Common\Pack.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Common\PipeStream.cs">
       <Link>Common\PipeStream.cs</Link>
     </Compile>
@@ -735,6 +740,12 @@
     <Compile Include="..\Renci.SshNet\Sftp\Flags.cs">
       <Link>Sftp\Flags.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\ISftpFileReader.cs">
+      <Link>Sftp\ISftpFileReader.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\ISftpResponseFactory.cs">
+      <Link>Sftp\ISftpResponseFactory.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Sftp\ISftpSession.cs">
       <Link>Sftp\ISftpSession.cs</Link>
     </Compile>
@@ -852,6 +863,9 @@
     <Compile Include="..\Renci.SshNet\Sftp\Responses\SftpVersionResponse.cs">
       <Link>Sftp\Responses\SftpVersionResponse.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SftpCloseAsyncResult.cs">
+      <Link>Sftp\SftpCloseAsyncResult.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Sftp\SftpDownloadAsyncResult.cs">
       <Link>Sftp\SftpDownloadAsyncResult.cs</Link>
     </Compile>
@@ -861,6 +875,9 @@
     <Compile Include="..\Renci.SshNet\Sftp\SftpFileAttributes.cs">
       <Link>Sftp\SftpFileAttributes.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SftpFileReader.cs">
+      <Link>Sftp\SftpFileReader.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Sftp\SftpFileStream.cs">
       <Link>Sftp\SftpFileStream.cs</Link>
     </Compile>
@@ -876,9 +893,24 @@
     <Compile Include="..\Renci.SshNet\Sftp\SftpMessageTypes.cs">
       <Link>Sftp\SftpMessageTypes.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SftpOpenAsyncResult.cs">
+      <Link>Sftp\SftpOpenAsyncResult.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SftpReadAsyncResult.cs">
+      <Link>Sftp\SftpReadAsyncResult.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SftpRealPathAsyncResult.cs">
+      <Link>Sftp\SftpRealPathAsyncResult.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SftpResponseFactory.cs">
+      <Link>Sftp\SftpResponseFactory.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Sftp\SftpSession.cs">
       <Link>Sftp\SftpSession.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SFtpStatAsyncResult.cs">
+      <Link>Sftp\SFtpStatAsyncResult.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Sftp\SftpSynchronizeDirectoriesAsyncResult.cs">
       <Link>Sftp\SftpSynchronizeDirectoriesAsyncResult.cs</Link>
     </Compile>

+ 113 - 0
src/Renci.SshNet.NETCore/Renci.SshNet.NETCore.csproj

@@ -0,0 +1,113 @@
+<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
+  <PropertyGroup>
+    <AssemblyTitle>SSH.NET</AssemblyTitle>
+    <TargetFramework>netstandard1.3</TargetFramework>
+	<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+    <GenerateDocumentationFile>true</GenerateDocumentationFile>
+    <AssemblyName>Renci.SshNet</AssemblyName>
+    <AssemblyOriginatorKeyFile>../Renci.SshNet.snk</AssemblyOriginatorKeyFile>
+    <LangVersion>5</LangVersion>
+    <SignAssembly>true</SignAssembly>
+    <PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
+    <GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
+    <GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
+    <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
+    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
+    <GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
+    <GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
+    <GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
+    <GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>
+    <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="..\Renci.SshNet\**\*.cs" Exclude="..\Renci.SshNet\Properties\AssemblyInfo.cs">
+      <Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <PackageReference Include="NETStandard.Library">
+      <Version>1.6.0</Version>
+    </PackageReference>
+  </ItemGroup>
+  <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
+    <PackageReference Include="Microsoft.CSharp">
+      <Version>4.0.1</Version>
+    </PackageReference>
+    <PackageReference Include="SshNet.Security.Cryptography">
+      <Version>[1.2.0]</Version>
+    </PackageReference>
+    <PackageReference Include="System.Diagnostics.Debug">
+      <Version>4.0.11</Version>
+    </PackageReference>
+    <PackageReference Include="System.Diagnostics.Tools">
+      <Version>4.0.1</Version>
+    </PackageReference>
+    <PackageReference Include="System.Diagnostics.TraceSource">
+      <Version>4.0.0</Version>
+    </PackageReference>
+    <PackageReference Include="System.Globalization">
+      <Version>4.0.11</Version>
+    </PackageReference>
+    <PackageReference Include="System.IO">
+      <Version>4.1.0</Version>
+    </PackageReference>
+    <PackageReference Include="System.IO.FileSystem">
+      <Version>4.0.1</Version>
+    </PackageReference>
+    <PackageReference Include="System.IO.FileSystem.Primitives">
+      <Version>4.0.1</Version>
+    </PackageReference>
+    <PackageReference Include="System.Linq">
+      <Version>4.1.0</Version>
+    </PackageReference>
+    <PackageReference Include="System.Net.NameResolution">
+      <Version>4.0.0</Version>
+    </PackageReference>
+    <PackageReference Include="System.Net.Sockets">
+      <Version>4.1.0</Version>
+    </PackageReference>
+    <PackageReference Include="System.Reflection.Extensions">
+      <Version>4.0.1</Version>
+    </PackageReference>
+    <PackageReference Include="System.Runtime.Extensions">
+      <Version>4.1.0</Version>
+    </PackageReference>
+    <PackageReference Include="System.Security.Cryptography.Algorithms">
+      <Version>4.2.0</Version>
+    </PackageReference>
+    <PackageReference Include="System.Text.RegularExpressions">
+      <Version>4.1.0</Version>
+    </PackageReference>
+    <PackageReference Include="System.Threading">
+      <Version>4.0.11</Version>
+    </PackageReference>
+    <PackageReference Include="System.Threading.Thread">
+      <Version>4.0.0</Version>
+    </PackageReference>
+    <PackageReference Include="System.Threading.ThreadPool">
+      <Version>4.0.10</Version>
+    </PackageReference>
+    <PackageReference Include="System.Threading.Timer">
+      <Version>4.0.1</Version>
+    </PackageReference>
+    <PackageReference Include="System.Xml.XmlDocument">
+      <Version>4.0.1</Version>
+    </PackageReference>
+    <PackageReference Include="System.Xml.XPath.XmlDocument">
+      <Version>4.0.1</Version>
+    </PackageReference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Update="..\Renci.SshNet\Sftp\ISftpMessageFactory.cs" Link="Sftp\ISftpResponseFactory.cs" />
+    <Compile Update="..\Renci.SshNet\Sftp\SftpMessageFactory.cs" Link="Sftp\SftpResponseFactory.cs" />
+  </ItemGroup>
+  <PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
+    <DefineConstants>FEATURE_ENCODING_ASCII;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_RNG_CREATE;FEATURE_SOCKET_TAP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_SELECT;FEATURE_SOCKET_POLL;FEATURE_DNS_TAP;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512</DefineConstants>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+    <DebugType>portable</DebugType>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
+    <DebugType>none</DebugType>
+  </PropertyGroup>
+</Project>

+ 0 - 19
src/Renci.SshNet.NETCore/Renci.SshNet.NETCore.xproj

@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
-    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>8e8229eb-6780-4a8a-b470-e2023fa55ab5</ProjectGuid>
-    <RootNamespace>Renci.SshNet</RootNamespace>
-    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
-    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
-    <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
-  </PropertyGroup>
-  <PropertyGroup>
-    <SchemaVersion>2.0</SchemaVersion>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
-</Project>

+ 0 - 90
src/Renci.SshNet.NETCore/project.json

@@ -1,90 +0,0 @@
-{
-  "title": "SSH.NET",
-  "configurations": {
-    "debug": {
-      "buildOptions": {
-        "debugType": "portable",
-        "define": [ "DEBUG", "TRACE" ]
-      }
-    },
-    "release": {
-      "buildOptions": {
-        "debugType": "none",
-        "define": [ "TRACE" ]
-      }
-    }
-  },
-  "buildOptions": {
-    "outputName": "Renci.SshNet",
-    "keyFile": "../Renci.SshNet.snk",
-    "compile": {
-      "include": [
-        "../Renci.SshNet/**/*.cs"
-      ],
-      "exclude": [
-        "../Renci.SshNet/Properties/AssemblyInfo.cs"
-      ]
-    },
-    "optimize": true,
-    "xmlDoc": true,
-    "warningsAsErrors": true
-  },
-  "frameworks": {
-    "netstandard1.3": {
-      "dependencies": {
-        "Microsoft.CSharp": "4.0.1",
-        "SshNet.Security.Cryptography": "[1.2.0]",
-        "System.Diagnostics.Debug": "4.0.11",
-        "System.Diagnostics.Tools": "4.0.1",
-        "System.Diagnostics.TraceSource": "4.0.0",
-        "System.Globalization": "4.0.11",
-        "System.IO": "4.1.0",
-        "System.IO.FileSystem": "4.0.1",
-        "System.IO.FileSystem.Primitives": "4.0.1",
-        "System.Linq": "4.1.0",
-        "System.Net.NameResolution": "4.0.0",
-        "System.Net.Sockets": "4.1.0",
-        "System.Reflection.Extensions": "4.0.1",
-        "System.Runtime.Extensions": "4.1.0",
-        "System.Security.Cryptography.Algorithms": "4.2.0",
-        "System.Text.RegularExpressions": "4.1.0",
-        "System.Threading": "4.0.11",
-        "System.Threading.Thread": "4.0.0",
-        "System.Threading.ThreadPool": "4.0.10",
-        "System.Threading.Timer": "4.0.1",
-        "System.Xml.XmlDocument": "4.0.1",
-        "System.Xml.XPath.XmlDocument": "4.0.1"
-      },
-      "buildOptions": {
-        "define": [
-          "FEATURE_ENCODING_ASCII",
-          "FEATURE_DIAGNOSTICS_TRACESOURCE",
-          "FEATURE_DIRECTORYINFO_ENUMERATEFILES",
-          "FEATURE_MEMORYSTREAM_TRYGETBUFFER",
-          "FEATURE_REFLECTION_TYPEINFO",
-          "FEATURE_RNG_CREATE",
-          "FEATURE_SOCKET_TAP",
-          "FEATURE_SOCKET_EAP",
-          "FEATURE_SOCKET_SYNC",
-          "FEATURE_SOCKET_SETSOCKETOPTION",
-          "FEATURE_SOCKET_POLL",
-          "FEATURE_DNS_TAP",
-          "FEATURE_STREAM_TAP",
-          "FEATURE_THREAD_COUNTDOWNEVENT",
-          "FEATURE_THREAD_THREADPOOL",
-          "FEATURE_THREAD_SLEEP",
-          "FEATURE_HASH_MD5",
-          "FEATURE_HASH_SHA1_CREATE",
-          "FEATURE_HASH_SHA256_CREATE",
-          "FEATURE_HASH_SHA384_CREATE",
-          "FEATURE_HASH_SHA512_CREATE",
-          "FEATURE_HMAC_MD5",
-          "FEATURE_HMAC_SHA1",
-          "FEATURE_HMAC_SHA256",
-          "FEATURE_HMAC_SHA384",
-          "FEATURE_HMAC_SHA512"
-        ]
-      }
-    }
-  }
-}

+ 31 - 1
src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj

@@ -200,6 +200,9 @@
     <Compile Include="..\Renci.SshNet\Common\ObjectIdentifier.cs">
       <Link>Common\ObjectIdentifier.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Common\Pack.cs">
+      <Link>Common\Pack.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Common\PipeStream.cs">
       <Link>Common\PipeStream.cs</Link>
     </Compile>
@@ -725,6 +728,12 @@
     <Compile Include="..\Renci.SshNet\Sftp\Flags.cs">
       <Link>Sftp\Flags.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\ISftpFileReader.cs">
+      <Link>Sftp\ISftpFileReader.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\ISftpResponseFactory.cs">
+      <Link>Sftp\ISftpResponseFactory.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Sftp\ISftpSession.cs">
       <Link>Sftp\ISftpSession.cs</Link>
     </Compile>
@@ -842,6 +851,9 @@
     <Compile Include="..\Renci.SshNet\Sftp\Responses\SftpVersionResponse.cs">
       <Link>Sftp\Responses\SftpVersionResponse.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SftpCloseAsyncResult.cs">
+      <Link>Sftp\SftpCloseAsyncResult.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Sftp\SftpDownloadAsyncResult.cs">
       <Link>Sftp\SftpDownloadAsyncResult.cs</Link>
     </Compile>
@@ -851,6 +863,9 @@
     <Compile Include="..\Renci.SshNet\Sftp\SftpFileAttributes.cs">
       <Link>Sftp\SftpFileAttributes.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SftpFileReader.cs">
+      <Link>Sftp\SftpFileReader.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Sftp\SftpFileStream.cs">
       <Link>Sftp\SftpFileStream.cs</Link>
     </Compile>
@@ -866,9 +881,24 @@
     <Compile Include="..\Renci.SshNet\Sftp\SftpMessageTypes.cs">
       <Link>Sftp\SftpMessageTypes.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SftpOpenAsyncResult.cs">
+      <Link>Sftp\SftpOpenAsyncResult.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SftpReadAsyncResult.cs">
+      <Link>Sftp\SftpReadAsyncResult.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SftpRealPathAsyncResult.cs">
+      <Link>Sftp\SftpRealPathAsyncResult.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SftpResponseFactory.cs">
+      <Link>Sftp\SftpResponseFactory.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Sftp\SftpSession.cs">
       <Link>Sftp\SftpSession.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SFtpStatAsyncResult.cs">
+      <Link>Sftp\SFtpStatAsyncResult.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Sftp\SftpSynchronizeDirectoriesAsyncResult.cs">
       <Link>Sftp\SftpSynchronizeDirectoriesAsyncResult.cs</Link>
     </Compile>
@@ -916,7 +946,7 @@
       <FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
         <SilverlightProjectProperties />
       </FlavorProperties>
-      <UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" />
+      <UserProperties ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
     </VisualStudio>
   </ProjectExtensions>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+ 31 - 1
src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj

@@ -209,6 +209,9 @@
     <Compile Include="..\Renci.SshNet\Common\ObjectIdentifier.cs">
       <Link>Common\ObjectIdentifier.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Common\Pack.cs">
+      <Link>Common\Pack.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Common\PipeStream.cs">
       <Link>Common\PipeStream.cs</Link>
     </Compile>
@@ -734,6 +737,12 @@
     <Compile Include="..\Renci.SshNet\Sftp\Flags.cs">
       <Link>Sftp\Flags.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\ISftpFileReader.cs">
+      <Link>Sftp\ISftpFileReader.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\ISftpResponseFactory.cs">
+      <Link>Sftp\ISftpResponseFactory.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Sftp\ISftpSession.cs">
       <Link>Sftp\ISftpSession.cs</Link>
     </Compile>
@@ -851,6 +860,9 @@
     <Compile Include="..\Renci.SshNet\Sftp\Responses\SftpVersionResponse.cs">
       <Link>Sftp\Responses\SftpVersionResponse.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SftpCloseAsyncResult.cs">
+      <Link>Sftp\SftpCloseAsyncResult.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Sftp\SftpDownloadAsyncResult.cs">
       <Link>Sftp\SftpDownloadAsyncResult.cs</Link>
     </Compile>
@@ -860,6 +872,9 @@
     <Compile Include="..\Renci.SshNet\Sftp\SftpFileAttributes.cs">
       <Link>Sftp\SftpFileAttributes.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SftpFileReader.cs">
+      <Link>Sftp\SftpFileReader.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Sftp\SftpFileStream.cs">
       <Link>Sftp\SftpFileStream.cs</Link>
     </Compile>
@@ -875,9 +890,24 @@
     <Compile Include="..\Renci.SshNet\Sftp\SftpMessageTypes.cs">
       <Link>Sftp\SftpMessageTypes.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SftpOpenAsyncResult.cs">
+      <Link>Sftp\SftpOpenAsyncResult.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SftpReadAsyncResult.cs">
+      <Link>Sftp\SftpReadAsyncResult.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SftpRealPathAsyncResult.cs">
+      <Link>Sftp\SftpRealPathAsyncResult.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SftpResponseFactory.cs">
+      <Link>Sftp\SftpResponseFactory.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Sftp\SftpSession.cs">
       <Link>Sftp\SftpSession.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Sftp\SFtpStatAsyncResult.cs">
+      <Link>Sftp\SFtpStatAsyncResult.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Sftp\SftpSynchronizeDirectoriesAsyncResult.cs">
       <Link>Sftp\SftpSynchronizeDirectoriesAsyncResult.cs</Link>
     </Compile>
@@ -922,7 +952,7 @@
       <FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
         <SilverlightProjectProperties />
       </FlavorProperties>
-      <UserProperties ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
+      <UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" />
     </VisualStudio>
   </ProjectExtensions>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+ 263 - 19
src/Renci.SshNet.Tests.NET35/Renci.SshNet.Tests.NET35.csproj

@@ -23,6 +23,7 @@
     <DefineConstants>TRACE;DEBUG</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
+    <LangVersion>5</LangVersion>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <DebugType>pdbonly</DebugType>
@@ -40,7 +41,7 @@
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
-    <Reference Include="Moq">
+    <Reference Include="Moq, Version=4.2.1409.1722, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
       <HintPath>..\..\packages\Moq.4.2.1409.1722\lib\net35\Moq.dll</HintPath>
     </Reference>
     <Reference Include="System" />
@@ -77,6 +78,9 @@
     <Compile Include="..\..\test\Renci.SshNet.Shared.Tests\ForwardedPortStatusTest_Stopping.cs">
       <Link>Classes\ForwardedPortStatusTest_Stopping.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs">
+      <Link>Classes\BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Channels\ChannelDirectTcpipTest.cs">
       <Link>Classes\Channels\ChannelDirectTcpipTest.cs</Link>
     </Compile>
@@ -839,6 +843,45 @@
     <Compile Include="..\Renci.SshNet.Tests\Classes\SessionTest.HttpProxy.cs">
       <Link>Classes\SessionTest.HttpProxy.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\SessionTest_Connected.cs">
+      <Link>Classes\SessionTest_Connected.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\SessionTest_ConnectedBase.cs">
+      <Link>Classes\SessionTest_ConnectedBase.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\SessionTest_Connected_ConnectionReset.cs">
+      <Link>Classes\SessionTest_Connected_ConnectionReset.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\SessionTest_Connected_Disconnect.cs">
+      <Link>Classes\SessionTest_Connected_Disconnect.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\SessionTest_Connected_GlobalRequestMessageAfterAuthenticationRace.cs">
+      <Link>Classes\SessionTest_Connected_GlobalRequestMessageAfterAuthenticationRace.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\SessionTest_Connected_ServerAndClientDisconnectRace.cs">
+      <Link>Classes\SessionTest_Connected_ServerAndClientDisconnectRace.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\SessionTest_Connected_ServerSendsBadPacket.cs">
+      <Link>Classes\SessionTest_Connected_ServerSendsBadPacket.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\SessionTest_Connected_ServerSendsDisconnectMessage.cs">
+      <Link>Classes\SessionTest_Connected_ServerSendsDisconnectMessage.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs">
+      <Link>Classes\SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\SessionTest_Connected_ServerShutsDownSendAfterSendingIncompletePacket.cs">
+      <Link>Classes\SessionTest_Connected_ServerShutsDownSendAfterSendingIncompletePacket.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\SessionTest_Connected_ServerShutsDownSocket.cs">
+      <Link>Classes\SessionTest_Connected_ServerShutsDownSocket.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\SessionTest_NotConnected.cs">
+      <Link>Classes\SessionTest_NotConnected.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\SessionTest_SocketConnected_BadPacketAndDispose.cs">
+      <Link>Classes\SessionTest_SocketConnected_BadPacketAndDispose.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\SftpClientTest.ChangeDirectory.cs">
       <Link>Classes\SftpClientTest.ChangeDirectory.cs</Link>
     </Compile>
@@ -974,12 +1017,60 @@
     <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\Responses\SftpVersionResponseTest.cs">
       <Link>Classes\Sftp\Responses\SftpVersionResponseTest.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpDataResponseBuilder.cs">
+      <Link>Classes\Sftp\SftpDataResponseBuilder.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpDownloadAsyncResultTest.cs">
       <Link>Classes\Sftp\SftpDownloadAsyncResultTest.cs</Link>
     </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileAttributesTest.cs">
       <Link>Classes\Sftp\SftpFileAttributesTest.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileReaderTestBase.cs">
+      <Link>Classes\Sftp\SftpFileReaderTestBase.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileReaderTest_DisposeShouldUnblockReadAndReadAhead.cs">
+      <Link>Classes\Sftp\SftpFileReaderTest_DisposeShouldUnblockReadAndReadAhead.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileReaderTest_LastChunkBeforeEofIsComplete.cs">
+      <Link>Classes\Sftp\SftpFileReaderTest_LastChunkBeforeEofIsComplete.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileReaderTest_LastChunkBeforeEofIsPartial.cs">
+      <Link>Classes\Sftp\SftpFileReaderTest_LastChunkBeforeEofIsPartial.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsNotReached.cs">
+      <Link>Classes\Sftp\SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsNotReached.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsReached.cs">
+      <Link>Classes\Sftp\SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsReached.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileReaderTest_ReadAheadBeginReadException.cs">
+      <Link>Classes\Sftp\SftpFileReaderTest_ReadAheadBeginReadException.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileReaderTest_ReadAheadEndInvokeException_DiscardsFurtherReadAheads.cs">
+      <Link>Classes\Sftp\SftpFileReaderTest_ReadAheadEndInvokeException_DiscardsFurtherReadAheads.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileReaderTest_ReadAheadEndInvokeException_PreventsFurtherReadAheads.cs">
+      <Link>Classes\Sftp\SftpFileReaderTest_ReadAheadEndInvokeException_PreventsFurtherReadAheads.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileReaderTest_ReadBackBeginReadException.cs">
+      <Link>Classes\Sftp\SftpFileReaderTest_ReadBackBeginReadException.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileReaderTest_ReadBackEndInvokeException.cs">
+      <Link>Classes\Sftp\SftpFileReaderTest_ReadBackEndInvokeException.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_ChunkAvailable.cs">
+      <Link>Classes\Sftp\SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_ChunkAvailable.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_NoChunkAvailable.cs">
+      <Link>Classes\Sftp\SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_NoChunkAvailable.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileReaderTest_Read_ReahAheadExceptionInBeginRead.cs">
+      <Link>Classes\Sftp\SftpFileReaderTest_Read_ReahAheadExceptionInBeginRead.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTestBase.cs">
+      <Link>Classes\Sftp\SftpFileStreamTestBase.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_CanRead_Closed_FileAccessRead.cs">
       <Link>Classes\Sftp\SftpFileStreamTest_CanRead_Closed_FileAccessRead.cs</Link>
     </Compile>
@@ -998,15 +1089,6 @@
     <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_CanRead_Disposed_FileAccessWrite.cs">
       <Link>Classes\Sftp\SftpFileStreamTest_CanRead_Disposed_FileAccessWrite.cs</Link>
     </Compile>
-    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_CanRead_SessionOpen_FileAccessRead.cs">
-      <Link>Classes\Sftp\SftpFileStreamTest_CanRead_SessionOpen_FileAccessRead.cs</Link>
-    </Compile>
-    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_CanRead_SessionOpen_FileAccessReadWrite.cs">
-      <Link>Classes\Sftp\SftpFileStreamTest_CanRead_SessionOpen_FileAccessReadWrite.cs</Link>
-    </Compile>
-    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_CanRead_SessionOpen_FileAccessWrite.cs">
-      <Link>Classes\Sftp\SftpFileStreamTest_CanRead_SessionOpen_FileAccessWrite.cs</Link>
-    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_CanWrite_Closed_FileAccessRead.cs">
       <Link>Classes\Sftp\SftpFileStreamTest_CanWrite_Closed_FileAccessRead.cs</Link>
     </Compile>
@@ -1025,15 +1107,6 @@
     <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_CanWrite_Disposed_FileAccessWrite.cs">
       <Link>Classes\Sftp\SftpFileStreamTest_CanWrite_Disposed_FileAccessWrite.cs</Link>
     </Compile>
-    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_CanWrite_SessionOpen_FileAccessRead.cs">
-      <Link>Classes\Sftp\SftpFileStreamTest_CanWrite_SessionOpen_FileAccessRead.cs</Link>
-    </Compile>
-    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_CanWrite_SessionOpen_FileAccessReadWrite.cs">
-      <Link>Classes\Sftp\SftpFileStreamTest_CanWrite_SessionOpen_FileAccessReadWrite.cs</Link>
-    </Compile>
-    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_CanWrite_SessionOpen_FileAccessWrite.cs">
-      <Link>Classes\Sftp\SftpFileStreamTest_CanWrite_SessionOpen_FileAccessWrite.cs</Link>
-    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Close_Closed.cs">
       <Link>Classes\Sftp\SftpFileStreamTest_Close_Closed.cs</Link>
     </Compile>
@@ -1046,6 +1119,72 @@
     <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Close_SessionOpen.cs">
       <Link>Classes\Sftp\SftpFileStreamTest_Close_SessionOpen.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileAccessInvalid.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileAccessInvalid.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileModeAppend_FileAccessRead.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileModeAppend_FileAccessRead.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileModeAppend_FileAccessReadWrite.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileModeAppend_FileAccessReadWrite.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileModeAppend_FileAccessWrite.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileModeAppend_FileAccessWrite.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessRead.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessRead.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessReadWrite.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessReadWrite.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessWrite.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessWrite.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreate_FileAccessRead.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreate_FileAccessRead.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileExists.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileExists.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileDoesNotExist.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileDoesNotExist.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileExists.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileExists.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileModeInvalid.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileModeInvalid.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessRead.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessRead.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessReadWrite.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessReadWrite.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessWrite.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessWrite.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileModeOpen_FileAccessRead.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileModeOpen_FileAccessRead.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileModeOpen_FileAccessReadWrite.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileModeOpen_FileAccessReadWrite.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileModeOpen_FileAccessWrite.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileModeOpen_FileAccessWrite.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessRead.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessRead.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessReadWrite.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessReadWrite.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessWrite.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessWrite.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Dispose_Closed.cs">
       <Link>Classes\Sftp\SftpFileStreamTest_Dispose_Closed.cs</Link>
     </Compile>
@@ -1061,9 +1200,69 @@
     <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Finalize_SessionOpen.cs">
       <Link>Classes\Sftp\SftpFileStreamTest_Finalize_SessionOpen.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Flush_ReadMode_DataInBuffer_NotReadFromBuffer.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Flush_ReadMode_DataInBuffer_NotReadFromBuffer.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Flush_ReadMode_DataInBuffer_ReadFromBuffer.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Flush_ReadMode_DataInBuffer_ReadFromBuffer.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Flush_ReadMode_NoDataInBuffer.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Flush_ReadMode_NoDataInBuffer.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Flush_SessionNotOpen.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Flush_SessionNotOpen.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Flush_WriteMode_DataInBuffer.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Flush_WriteMode_DataInBuffer.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Flush_WriteMode_NoDataInBuffer.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Flush_WriteMode_NoDataInBuffer.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_Eof.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_Eof.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_LessDataThanReadBufferSizeAvailable.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_LessDataThanReadBufferSizeAvailable.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetNegative.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetNegative.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetPositive.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetPositive.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetZero.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetZero.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_NoBuffering.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_NoBuffering.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_ReadBuffer.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_ReadBuffer.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_SetLength_Closed.cs">
       <Link>Classes\Sftp\SftpFileStreamTest_SetLength_Closed.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthGreatherThanPosition.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthGreatherThanPosition.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthLessThanPosition.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthLessThanPosition.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthGreatherThanPosition.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthGreatherThanPosition.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthLessThanPosition.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthLessThanPosition.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_SetLength_Disposed.cs">
       <Link>Classes\Sftp\SftpFileStreamTest_SetLength_Disposed.cs</Link>
     </Compile>
@@ -1079,21 +1278,57 @@
     <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_SetLength_SessionOpen_FIleAccessWrite.cs">
       <Link>Classes\Sftp\SftpFileStreamTest_SetLength_SessionOpen_FIleAccessWrite.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileStreamTest_Write_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs">
+      <Link>Classes\Sftp\SftpFileStreamTest_Write_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileSystemInformationTest.cs">
       <Link>Classes\Sftp\SftpFileSystemInformationTest.cs</Link>
     </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileTest.cs">
       <Link>Classes\Sftp\SftpFileTest.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpHandleResponseBuilder.cs">
+      <Link>Classes\Sftp\SftpHandleResponseBuilder.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpInitRequestBuilder.cs">
+      <Link>Classes\Sftp\SftpInitRequestBuilder.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpListDirectoryAsyncResultTest.cs">
       <Link>Classes\Sftp\SftpListDirectoryAsyncResultTest.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpNameResponseBuilder.cs">
+      <Link>Classes\Sftp\SftpNameResponseBuilder.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpOpenRequestBuilder.cs">
+      <Link>Classes\Sftp\SftpOpenRequestBuilder.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpReadRequestBuilder.cs">
+      <Link>Classes\Sftp\SftpReadRequestBuilder.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpRealPathRequestBuilder.cs">
+      <Link>Classes\Sftp\SftpRealPathRequestBuilder.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpSessionTest_Connected_RequestRead.cs">
       <Link>Classes\Sftp\SftpSessionTest_Connected_RequestRead.cs</Link>
     </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpSessionTest_Connected_RequestStatVfs.cs">
       <Link>Classes\Sftp\SftpSessionTest_Connected_RequestStatVfs.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpSessionTest_DataReceived_MultipleSftpMessagesInSingleSshDataMessage.cs">
+      <Link>Classes\Sftp\SftpSessionTest_DataReceived_MultipleSftpMessagesInSingleSshDataMessage.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpSessionTest_DataReceived_MultipleSftpMessagesSplitOverMultipleSshDataMessages.cs">
+      <Link>Classes\Sftp\SftpSessionTest_DataReceived_MultipleSftpMessagesSplitOverMultipleSshDataMessages.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpSessionTest_DataReceived_SingleSftpMessageInSshDataMessage.cs">
+      <Link>Classes\Sftp\SftpSessionTest_DataReceived_SingleSftpMessageInSshDataMessage.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpStatVfsRequestBuilder.cs">
+      <Link>Classes\Sftp\SftpStatVfsRequestBuilder.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpStatVfsResponseBuilder.cs">
+      <Link>Classes\Sftp\SftpStatVfsResponseBuilder.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpSynchronizeDirectoriesAsyncResultTest.cs">
       <Link>Classes\Sftp\SftpSynchronizeDirectoriesAsyncResultTest.cs</Link>
     </Compile>
@@ -1217,9 +1452,15 @@
     <Compile Include="..\Renci.SshNet.Tests\Classes\SubsystemSession_SendData_NeverConnected.cs">
       <Link>Classes\SubsystemSession_SendData_NeverConnected.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Common\ArrayBuilder.cs">
+      <Link>Common\ArrayBuilder.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Common\AsyncSocketListener.cs">
       <Link>Common\AsyncSocketListener.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Common\DictionaryAssert.cs">
+      <Link>Common\DictionaryAssert.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Common\Extensions.cs">
       <Link>Common\Extensions.cs</Link>
     </Compile>
@@ -1229,6 +1470,9 @@
     <Compile Include="..\Renci.SshNet.Tests\Common\HttpRequest.cs">
       <Link>Common\HttpRequest.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Common\SftpFileAttributesBuilder.cs">
+      <Link>Common\SftpFileAttributesBuilder.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Common\TestBase.cs">
       <Link>Common\TestBase.cs</Link>
     </Compile>

+ 25 - 4
src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs

@@ -11,8 +11,10 @@ namespace Renci.SshNet.Tests.Classes
     {
         private Mock<IServiceFactory> _serviceFactoryMock;
         private Mock<ISession> _sessionMock;
+        private MockSequence _mockSequence;
         private BaseClient _client;
         private ConnectionInfo _connectionInfo;
+        private ManualResetEvent _keepAliveSent;
 
         [TestInitialize]
         public void Setup()
@@ -24,20 +26,33 @@ namespace Renci.SshNet.Tests.Classes
         [TestCleanup]
         public void Cleanup()
         {
+            if (_client != null)
+            {
+                _sessionMock.InSequence(_mockSequence).Setup(p => p.OnDisconnecting());
+                _sessionMock.InSequence(_mockSequence).Setup(p => p.Dispose());
+                _client.Dispose();
+            }
         }
 
         protected void Arrange()
         {
             _connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd"));
+            _keepAliveSent = new ManualResetEvent(false);
 
             _serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
             _sessionMock = new Mock<ISession>(MockBehavior.Strict);
 
-            _serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo)).Returns(_sessionMock.Object);
-            _sessionMock.Setup(p => p.Connect());
-            _sessionMock.Setup(p => p.TrySendMessage(It.IsAny<IgnoreMessage>()))
+            _mockSequence = new MockSequence();
+
+            _serviceFactoryMock.InSequence(_mockSequence).Setup(p => p.CreateSession(_connectionInfo)).Returns(_sessionMock.Object);
+            _sessionMock.InSequence(_mockSequence).Setup(p => p.Connect());
+            _sessionMock.InSequence(_mockSequence).Setup(p => p.TrySendMessage(It.IsAny<IgnoreMessage>()))
                 .Returns(true)
-                .Callback(() => Thread.Sleep(300));
+                .Callback(() =>
+                    {
+                        Thread.Sleep(300);
+                        _keepAliveSent.Set();
+                    });
 
             _client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object)
                 {
@@ -51,6 +66,12 @@ namespace Renci.SshNet.Tests.Classes
             // should keep-alive message be sent concurrently, then multiple keep-alive
             // message would be sent during this sleep period
             Thread.Sleep(200);
+
+            // disable further keep-alives
+            _client.KeepAliveInterval = Session.InfiniteTimeSpan;
+
+            // wait until keep-alive has been sent at least once
+            Assert.IsTrue(_keepAliveSent.WaitOne(500));
         }
 
         [TestMethod]

+ 1 - 1
src/Renci.SshNet.Tests/Classes/Channels/ChannelForwardedTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs

@@ -171,8 +171,8 @@ namespace Renci.SshNet.Tests.Classes.Channels
         [TestMethod]
         public void BindShouldHaveFinishedWithoutException()
         {
-            Assert.IsTrue(_channelBindFinishedWaitHandle.WaitOne(0));
             Assert.IsNull(_channelException, _channelException != null ? _channelException.ToString() : null);
+            Assert.IsTrue(_channelBindFinishedWaitHandle.WaitOne(0));
         }
 
         [TestMethod]

+ 10 - 3
src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs

@@ -21,6 +21,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
         private uint _remotePacketSize;
         private ChannelStub _channel;
         private Stopwatch _closeTimer;
+        private ManualResetEvent _channelClosedWaitHandle;
         private List<ChannelEventArgs> _channelClosedRegister;
         private IList<ExceptionEventArgs> _channelExceptionRegister;
 
@@ -42,6 +43,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
             _remotePacketSize = (uint)random.Next(0, int.MaxValue);
             _closeTimer = new Stopwatch();
             _channelClosedRegister = new List<ChannelEventArgs>();
+            _channelClosedWaitHandle = new ManualResetEvent(false);
             _channelExceptionRegister = new List<ExceptionEventArgs>();
 
             _sessionMock = new Mock<ISession>(MockBehavior.Strict);
@@ -61,8 +63,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
                                 // SSH_MSG_CHANNEL_CLOSE message from server which is waited on after
                                 // sending the SSH_MSG_CHANNEL_CLOSE message to the server
                                 _sessionMock.Raise(s => s.ChannelCloseReceived += null,
-                                    new MessageEventArgs<ChannelCloseMessage>(
-                                        new ChannelCloseMessage(_localChannelNumber)));
+                                                   new MessageEventArgs<ChannelCloseMessage>(new ChannelCloseMessage(_localChannelNumber)));
                             }).Start();
                         _closeTimer.Start();
                         try
@@ -76,7 +77,11 @@ namespace Renci.SshNet.Tests.Classes.Channels
                     });
 
             _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize);
-            _channel.Closed += (sender, args) => _channelClosedRegister.Add(args);
+            _channel.Closed += (sender, args) =>
+                {
+                    _channelClosedRegister.Add(args);
+                    _channelClosedWaitHandle.Set();
+                };
             _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args);
             _channel.InitializeRemoteChannelInfo(_remoteChannelNumber, _remoteWindowSize, _remotePacketSize);
             _channel.SetIsOpen(true);
@@ -124,6 +129,8 @@ namespace Renci.SshNet.Tests.Classes.Channels
         [TestMethod]
         public void ClosedEventShouldHaveFiredOnce()
         {
+            _channelClosedWaitHandle.WaitOne(100);
+
             Assert.AreEqual(1, _channelClosedRegister.Count);
             Assert.AreEqual(_localChannelNumber, _channelClosedRegister[0].ChannelNumber);
         }

+ 9 - 1
src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived_SendEofInvoked.cs

@@ -21,6 +21,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
         private uint _remotePacketSize;
         private ChannelStub _channel;
         private Stopwatch _closeTimer;
+        private ManualResetEvent _channelClosedWaitHandle;
         private List<ChannelEventArgs> _channelClosedRegister;
         private IList<ExceptionEventArgs> _channelExceptionRegister;
 
@@ -41,6 +42,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
             _remoteWindowSize = (uint)random.Next(0, int.MaxValue);
             _remotePacketSize = (uint)random.Next(0, int.MaxValue);
             _closeTimer = new Stopwatch();
+            _channelClosedWaitHandle = new ManualResetEvent(false);
             _channelClosedRegister = new List<ChannelEventArgs>();
             _channelExceptionRegister = new List<ExceptionEventArgs>();
 
@@ -75,7 +77,11 @@ namespace Renci.SshNet.Tests.Classes.Channels
                 });
 
             _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize);
-            _channel.Closed += (sender, args) => _channelClosedRegister.Add(args);
+            _channel.Closed += (sender, args) =>
+                {
+                    _channelClosedRegister.Add(args);
+                    _channelClosedWaitHandle.Set();
+                };
             _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args);
             _channel.InitializeRemoteChannelInfo(_remoteChannelNumber, _remoteWindowSize, _remotePacketSize);
             _channel.SetIsOpen(true);
@@ -124,6 +130,8 @@ namespace Renci.SshNet.Tests.Classes.Channels
         [TestMethod]
         public void ClosedEventShouldHaveFiredOnce()
         {
+            _channelClosedWaitHandle.WaitOne(100);
+
             Assert.AreEqual(1, _channelClosedRegister.Count);
             Assert.AreEqual(_localChannelNumber, _channelClosedRegister[0].ChannelNumber);
         }

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 18 - 0
src/Renci.SshNet.Tests/Classes/Common/BigIntegerTest.cs


+ 83 - 0
src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Reverse.cs

@@ -0,0 +1,83 @@
+using System;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Renci.SshNet.Tests.Classes.Common
+{
+    [TestClass]
+    [SuppressMessage("ReSharper", "InvokeAsExtensionMethod")]
+    public class ExtensionsTest_Reverse
+    {
+        [TestMethod]
+        public void Empty()
+        {
+            var value = new byte[0];
+
+            var actual = Extensions.Reverse(value);
+
+            Assert.IsNotNull(actual);
+            Assert.AreEqual(0, actual.Length);
+        }
+
+        [TestInitialize]
+        public void Null()
+        {
+            const byte[] value = null;
+
+            try
+            {
+                Extensions.Reverse(value);
+                Assert.Fail();
+            }
+            catch (ArgumentNullException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("array", ex.ParamName);
+            }
+        }
+
+        [TestMethod]
+        public void Small()
+        {
+            var value = new[] {0, 1, 4, 3, 7, 9};
+
+            var actual = Extensions.Reverse(value);
+
+            Assert.IsNotNull(actual);
+            Assert.AreEqual(6, actual.Length);
+            Assert.AreEqual(9, actual[0]);
+            Assert.AreEqual(7, actual[1]);
+            Assert.AreEqual(3, actual[2]);
+            Assert.AreEqual(4, actual[3]);
+            Assert.AreEqual(1, actual[4]);
+            Assert.AreEqual(0, actual[5]);
+
+            Assert.AreEqual(9, value[0]);
+            Assert.AreEqual(7, value[1]);
+            Assert.AreEqual(3, value[2]);
+            Assert.AreEqual(4, value[3]);
+            Assert.AreEqual(1, value[4]);
+            Assert.AreEqual(0, value[5]);
+        }
+
+        [TestMethod]
+        [Ignore]
+        public void Perf_Large()
+        {
+            var value = new byte[2048];
+            new Random().NextBytes(value);
+
+            var stopwatch = Stopwatch.StartNew();
+
+            for (var i = 0; i < 1000000; i++)
+            {
+                Extensions.Reverse(value);
+            }
+
+            stopwatch.Stop();
+            Console.WriteLine(stopwatch.ElapsedMilliseconds);
+        }
+    }
+}
+

+ 186 - 0
src/Renci.SshNet.Tests/Classes/Common/PackTest.cs

@@ -0,0 +1,186 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
+
+namespace Renci.SshNet.Tests.Classes.Common
+{
+    [TestClass]
+    public class PackTest
+    {
+        [TestMethod]
+        public void BigEndianToUInt16()
+        {
+            Assert.AreEqual(0, Pack.BigEndianToUInt16(new byte[] {0, 0}));
+            Assert.AreEqual(1, Pack.BigEndianToUInt16(new byte[] {0, 1}));
+            Assert.AreEqual(256, Pack.BigEndianToUInt16(new byte[] {1, 0}));
+            Assert.AreEqual(257, Pack.BigEndianToUInt16(new byte[] {1, 1}));
+            Assert.AreEqual(1025, Pack.BigEndianToUInt16(new byte[] {4, 1}));
+            Assert.AreEqual(ushort.MaxValue, Pack.BigEndianToUInt16(new byte[] {255, 255}));
+        }
+
+        [TestMethod]
+        public void BigEndianToUInt32()
+        {
+            Assert.AreEqual(0U, Pack.BigEndianToUInt32(new byte[] {0, 0, 0, 0}));
+            Assert.AreEqual(1U, Pack.BigEndianToUInt32(new byte[] {0, 0, 0, 1}));
+            Assert.AreEqual(256U, Pack.BigEndianToUInt32(new byte[] {0, 0, 1, 0}));
+            Assert.AreEqual(257U, Pack.BigEndianToUInt32(new byte[] {0, 0, 1, 1}));
+            Assert.AreEqual(1025U, Pack.BigEndianToUInt32(new byte[] {0, 0, 4, 1}));
+            Assert.AreEqual(65536U, Pack.BigEndianToUInt32(new byte[] {0, 1, 0, 0}));
+            Assert.AreEqual(133124U, Pack.BigEndianToUInt32(new byte[] {0, 2, 8, 4}));
+            Assert.AreEqual(16777216U, Pack.BigEndianToUInt32(new byte[] {1, 0, 0, 0}));
+            Assert.AreEqual(uint.MaxValue, Pack.BigEndianToUInt32(new byte[] {255, 255, 255, 255}));
+        }
+
+        [TestMethod]
+        public void BigEndianToUInt64()
+        {
+            Assert.AreEqual(0UL, Pack.BigEndianToUInt64(new byte[] {0, 0, 0, 0, 0, 0, 0, 0}));
+            Assert.AreEqual(1UL, Pack.BigEndianToUInt64(new byte[] {0, 0, 0, 0, 0, 0, 0, 1}));
+            Assert.AreEqual(256UL, Pack.BigEndianToUInt64(new byte[] {0, 0, 0, 0, 0, 0, 1, 0}));
+            Assert.AreEqual(257UL, Pack.BigEndianToUInt64(new byte[] {0, 0, 0, 0, 0, 0, 1, 1}));
+            Assert.AreEqual(65536UL, Pack.BigEndianToUInt64(new byte[] {0, 0, 0, 0, 0, 1, 0, 0}));
+            Assert.AreEqual(133124UL, Pack.BigEndianToUInt64(new byte[] {0, 0, 0, 0, 0, 2, 8, 4}));
+            Assert.AreEqual(16777216UL, Pack.BigEndianToUInt64(new byte[] {0, 0, 0, 0, 1, 0, 0, 0}));
+            Assert.AreEqual(4294967296UL, Pack.BigEndianToUInt64(new byte[] {0, 0, 0, 1, 0, 0, 0, 0}));
+            Assert.AreEqual(1099511627776UL, Pack.BigEndianToUInt64(new byte[] {0, 0, 1, 0, 0, 0, 0, 0}));
+            Assert.AreEqual(1099511892096UL, Pack.BigEndianToUInt64(new byte[] {0, 0, 1, 0, 0, 4, 8, 128}));
+            Assert.AreEqual(1099511627776UL * 256, Pack.BigEndianToUInt64(new byte[] {0, 1, 0, 0, 0, 0, 0, 0}));
+            Assert.AreEqual(1099511627776UL * 256 * 256, Pack.BigEndianToUInt64(new byte[] {1, 0, 0, 0, 0, 0, 0, 0}));
+            Assert.AreEqual(ulong.MaxValue, Pack.BigEndianToUInt64(new byte[] {255, 255, 255, 255, 255, 255, 255, 255}));
+        }
+
+        [TestMethod]
+        public void LittleEndianToUInt16()
+        {
+            Assert.AreEqual((ushort) 0, Pack.LittleEndianToUInt16(new byte[] {0, 0}));
+            Assert.AreEqual((ushort) 1, Pack.LittleEndianToUInt16(new byte[] {1, 0}));
+            Assert.AreEqual((ushort) 256, Pack.LittleEndianToUInt16(new byte[] {0, 1}));
+            Assert.AreEqual((ushort) 257, Pack.LittleEndianToUInt16(new byte[] {1, 1}));
+            Assert.AreEqual((ushort) 1025, Pack.LittleEndianToUInt16(new byte[] {1, 4}));
+            Assert.AreEqual(ushort.MaxValue, Pack.LittleEndianToUInt16(new byte[] {255, 255}));
+        }
+
+        [TestMethod]
+        public void LittleEndianToUInt32()
+        {
+            Assert.AreEqual(0U, Pack.LittleEndianToUInt32(new byte[] {0, 0, 0, 0}));
+            Assert.AreEqual(1U, Pack.LittleEndianToUInt32(new byte[] {1, 0, 0, 0}));
+            Assert.AreEqual(256U, Pack.LittleEndianToUInt32(new byte[] {0, 1, 0, 0}));
+            Assert.AreEqual(257U, Pack.LittleEndianToUInt32(new byte[] {1, 1, 0, 0}));
+            Assert.AreEqual(1025U, Pack.LittleEndianToUInt32(new byte[] {1, 4, 0, 0}));
+            Assert.AreEqual(65536U, Pack.LittleEndianToUInt32(new byte[] {0, 0, 1, 0}));
+            Assert.AreEqual(133124U, Pack.LittleEndianToUInt32(new byte[] {4, 8, 2, 0}));
+            Assert.AreEqual(16777216U, Pack.LittleEndianToUInt32(new byte[] {0, 0, 0, 1}));
+            Assert.AreEqual(uint.MaxValue, Pack.LittleEndianToUInt32(new byte[] {255, 255, 255, 255}));
+        }
+
+        [TestMethod]
+        public void LittleEndianToUInt64()
+        {
+            Assert.AreEqual(0UL, Pack.LittleEndianToUInt64(new byte[] {0, 0, 0, 0, 0, 0, 0, 0}));
+            Assert.AreEqual(1UL, Pack.LittleEndianToUInt64(new byte[] {1, 0, 0, 0, 0, 0, 0, 0}));
+            Assert.AreEqual(256UL, Pack.LittleEndianToUInt64(new byte[] {0, 1, 0, 0, 0, 0, 0, 0}));
+            Assert.AreEqual(257UL, Pack.LittleEndianToUInt64(new byte[] {1, 1, 0, 0, 0, 0, 0, 0}));
+            Assert.AreEqual(65536UL, Pack.LittleEndianToUInt64(new byte[] {0, 0, 1, 0, 0, 0, 0, 0}));
+            Assert.AreEqual(133124UL, Pack.LittleEndianToUInt64(new byte[] {4, 8, 2, 0, 0, 0, 0, 0}));
+            Assert.AreEqual(16777216UL, Pack.LittleEndianToUInt64(new byte[] {0, 0, 0, 1, 0, 0, 0, 0}));
+            Assert.AreEqual(4294967296UL, Pack.LittleEndianToUInt64(new byte[] {0, 0, 0, 0, 1, 0, 0, 0}));
+            Assert.AreEqual(1099511627776UL, Pack.LittleEndianToUInt64(new byte[] {0, 0, 0, 0, 0, 1, 0, 0}));
+            Assert.AreEqual(1099511892096UL, Pack.LittleEndianToUInt64(new byte[] {128, 8, 4, 0, 0, 1, 0, 0}));
+            Assert.AreEqual(1099511627776UL * 256, Pack.LittleEndianToUInt64(new byte[] {0, 0, 0, 0, 0, 0, 1, 0}));
+            Assert.AreEqual(1099511627776UL * 256 * 256, Pack.LittleEndianToUInt64(new byte[] {0, 0, 0, 0, 0, 0, 0, 1}));
+            Assert.AreEqual(ulong.MaxValue, Pack.LittleEndianToUInt64(new byte[] {255, 255, 255, 255, 255, 255, 255, 255}));
+        }
+
+        [TestMethod]
+        public void UInt16ToLittleEndian()
+        {
+            AssertEqual(new byte[] {0, 0}, Pack.UInt16ToLittleEndian(0));
+            AssertEqual(new byte[] {1, 0}, Pack.UInt16ToLittleEndian(1));
+            AssertEqual(new byte[] {0, 1}, Pack.UInt16ToLittleEndian(256));
+            AssertEqual(new byte[] {1, 1}, Pack.UInt16ToLittleEndian(257));
+            AssertEqual(new byte[] {1, 4}, Pack.UInt16ToLittleEndian(1025));
+            AssertEqual(new byte[] {255, 255}, Pack.UInt16ToLittleEndian(ushort.MaxValue));
+        }
+
+        [TestMethod]
+        public void UInt32ToLittleEndian()
+        {
+            AssertEqual(new byte[] {0, 0, 0, 0}, Pack.UInt32ToLittleEndian(0));
+            AssertEqual(new byte[] {1, 0, 0, 0}, Pack.UInt32ToLittleEndian(1));
+            AssertEqual(new byte[] {0, 1, 0, 0}, Pack.UInt32ToLittleEndian(256));
+            AssertEqual(new byte[] {1, 1, 0, 0}, Pack.UInt32ToLittleEndian(257));
+            AssertEqual(new byte[] {1, 4, 0, 0}, Pack.UInt32ToLittleEndian(1025));
+            AssertEqual(new byte[] {0, 0, 1, 0}, Pack.UInt32ToLittleEndian(65536));
+            AssertEqual(new byte[] {4, 8, 2, 0}, Pack.UInt32ToLittleEndian(133124));
+            AssertEqual(new byte[] {0, 0, 0, 1}, Pack.UInt32ToLittleEndian(16777216));
+            AssertEqual(new byte[] {255, 255, 255, 255}, Pack.UInt32ToLittleEndian(uint.MaxValue));
+        }
+
+        [TestMethod]
+        public void UInt64ToLittleEndian()
+        {
+            AssertEqual(new byte[] {0, 0, 0, 0, 0, 0, 0, 0}, Pack.UInt64ToLittleEndian(0UL));
+            AssertEqual(new byte[] {1, 0, 0, 0, 0, 0, 0, 0}, Pack.UInt64ToLittleEndian(1UL));
+            AssertEqual(new byte[] {0, 1, 0, 0, 0, 0, 0, 0}, Pack.UInt64ToLittleEndian(256UL));
+            AssertEqual(new byte[] {1, 1, 0, 0, 0, 0, 0, 0}, Pack.UInt64ToLittleEndian(257UL));
+            AssertEqual(new byte[] {0, 0, 1, 0, 0, 0, 0, 0}, Pack.UInt64ToLittleEndian(65536UL));
+            AssertEqual(new byte[] {4, 8, 2, 0, 0, 0, 0, 0}, Pack.UInt64ToLittleEndian(133124UL));
+            AssertEqual(new byte[] {0, 0, 0, 1, 0, 0, 0, 0}, Pack.UInt64ToLittleEndian(16777216UL));
+            AssertEqual(new byte[] {0, 0, 0, 0, 1, 0, 0, 0}, Pack.UInt64ToLittleEndian(4294967296UL));
+            AssertEqual(new byte[] {0, 0, 0, 0, 0, 1, 0, 0}, Pack.UInt64ToLittleEndian(1099511627776UL));
+            AssertEqual(new byte[] {128, 8, 4, 0, 0, 1, 0, 0}, Pack.UInt64ToLittleEndian(1099511892096UL));
+            AssertEqual(new byte[] {0, 0, 0, 0, 0, 0, 1, 0}, Pack.UInt64ToLittleEndian(1099511627776UL * 256));
+            AssertEqual(new byte[] {0, 0, 0, 0, 0, 0, 0, 1}, Pack.UInt64ToLittleEndian(1099511627776UL * 256 * 256));
+            AssertEqual(new byte[] {255, 255, 255, 255, 255, 255, 255, 255}, Pack.UInt64ToLittleEndian(ulong.MaxValue));
+        }
+
+        [TestMethod]
+        public void UInt16ToBigEndian()
+        {
+            AssertEqual(new byte[] {0, 0}, Pack.UInt16ToBigEndian(0));
+            AssertEqual(new byte[] {0, 1}, Pack.UInt16ToBigEndian(1));
+            AssertEqual(new byte[] {1, 0}, Pack.UInt16ToBigEndian(256));
+            AssertEqual(new byte[] {1, 1}, Pack.UInt16ToBigEndian(257));
+            AssertEqual(new byte[] {4, 1}, Pack.UInt16ToBigEndian(1025));
+            AssertEqual(new byte[] {255, 255}, Pack.UInt16ToBigEndian(ushort.MaxValue));
+        }
+
+        [TestMethod]
+        public void UInt32ToBigEndian()
+        {
+            AssertEqual(new byte[] {0, 0, 0, 0}, Pack.UInt32ToBigEndian(0));
+            AssertEqual(new byte[] {0, 0, 0, 1}, Pack.UInt32ToBigEndian(1));
+            AssertEqual(new byte[] {0, 0, 1, 0}, Pack.UInt32ToBigEndian(256));
+            AssertEqual(new byte[] {0, 0, 1, 1}, Pack.UInt32ToBigEndian(257));
+            AssertEqual(new byte[] {0, 0, 4, 1}, Pack.UInt32ToBigEndian(1025));
+            AssertEqual(new byte[] {0, 1, 0, 0}, Pack.UInt32ToBigEndian(65536));
+            AssertEqual(new byte[] {0, 2, 8, 4}, Pack.UInt32ToBigEndian(133124));
+            AssertEqual(new byte[] {1, 0, 0, 0}, Pack.UInt32ToBigEndian(16777216));
+            AssertEqual(new byte[] {255, 255, 255, 255}, Pack.UInt32ToBigEndian(uint.MaxValue));
+        }
+
+        [TestMethod]
+        public void UInt64ToBigEndian()
+        {
+            AssertEqual(new byte[] {0, 0, 0, 0, 0, 0, 0, 0}, Pack.UInt64ToBigEndian(0UL));
+            AssertEqual(new byte[] {0, 0, 0, 0, 0, 0, 0, 1}, Pack.UInt64ToBigEndian(1UL));
+            AssertEqual(new byte[] {0, 0, 0, 0, 0, 0, 1, 0}, Pack.UInt64ToBigEndian(256UL));
+            AssertEqual(new byte[] {0, 0, 0, 0, 0, 0, 1, 1}, Pack.UInt64ToBigEndian(257UL));
+            AssertEqual(new byte[] {0, 0, 0, 0, 0, 1, 0, 0}, Pack.UInt64ToBigEndian(65536UL));
+            AssertEqual(new byte[] {0, 0, 0, 0, 0, 2, 8, 4}, Pack.UInt64ToBigEndian(133124UL));
+            AssertEqual(new byte[] {0, 0, 0, 0, 1, 0, 0, 0}, Pack.UInt64ToBigEndian(16777216UL));
+            AssertEqual(new byte[] {0, 0, 0, 1, 0, 0, 0, 0}, Pack.UInt64ToBigEndian(4294967296UL));
+            AssertEqual(new byte[] {0, 0, 1, 0, 0, 0, 0, 0}, Pack.UInt64ToBigEndian(1099511627776UL));
+            AssertEqual(new byte[] {0, 0, 1, 0, 0, 4, 8, 128}, Pack.UInt64ToBigEndian(1099511892096UL));
+            AssertEqual(new byte[] {0, 1, 0, 0, 0, 0, 0, 0}, Pack.UInt64ToBigEndian(1099511627776UL * 256));
+            AssertEqual(new byte[] {1, 0, 0, 0, 0, 0, 0, 0}, Pack.UInt64ToBigEndian(1099511627776UL * 256 * 256));
+            AssertEqual(new byte[] {255, 255, 255, 255, 255, 255, 255, 255}, Pack.UInt64ToBigEndian(ulong.MaxValue));
+        }
+
+        private static void AssertEqual(byte[] expected, byte[] actual)
+        {
+            Assert.IsTrue(expected.IsEqualTo(actual));
+        }
+    }
+}

+ 0 - 60
src/Renci.SshNet.Tests/Classes/Common/SshDataTest.cs

@@ -86,66 +86,6 @@ namespace Renci.SshNet.Tests.Classes.Common
             Assert.AreEqual(two, request.ValueTwo);
         }
 
-
-        [TestMethod]
-        public void OfType()
-        {
-            const uint one = 123456u;
-            const uint two = 456789u;
-
-            var sshDataStream = new SshDataStream(8);
-            sshDataStream.Write(one);
-            sshDataStream.Write(two);
-
-            var sshData = sshDataStream.ToArray();
-
-            var request = new RequestSshData();
-            request.Load(sshData);
-
-            var reply = request.OfType<ReplySshData>();
-            Assert.IsNotNull(reply);
-            Assert.AreEqual(one, reply.ValueOne);
-        }
-
-        [TestMethod]
-        public void OfType_LoadWithOffset()
-        {
-            const uint one = 123456u;
-            const uint two = 456789u;
-
-            var sshDataStream = new SshDataStream(11);
-            sshDataStream.WriteByte(0x05);
-            sshDataStream.WriteByte(0x07);
-            sshDataStream.WriteByte(0x0f);
-            sshDataStream.Write(one);
-            sshDataStream.Write(two);
-
-            var sshData = sshDataStream.ToArray();
-
-            var request = new RequestSshData();
-            request.Load(sshData, 3, sshData.Length - 3);
-            var reply = request.OfType<ReplySshData>();
-            Assert.IsNotNull(reply);
-            Assert.AreEqual(one, reply.ValueOne);
-        }
-
-        [TestMethod]
-        public void OfType_ShouldThrowArgumentNullExceptionWhenNoDataIsLoaded()
-        {
-            var request = new RequestSshData();
-
-            try
-            {
-                request.OfType<ReplySshData>();
-                Assert.Fail();
-            }
-            catch (ArgumentNullException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual("data", ex.ParamName);
-            }
-        }
-
         private class BoolSshData : SshData
         {
             private readonly bool _value;

+ 7 - 3
src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Connected.cs

@@ -1,6 +1,7 @@
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
 using Renci.SshNet.NetConf;
+using System;
 
 namespace Renci.SshNet.Tests.Classes
 {
@@ -9,9 +10,10 @@ namespace Renci.SshNet.Tests.Classes
     {
         private Mock<IServiceFactory> _serviceFactoryMock;
         private Mock<ISession> _sessionMock;
+        private Mock<INetConfSession> _netConfSessionMock;
         private NetConfClient _netConfClient;
         private ConnectionInfo _connectionInfo;
-        private Mock<INetConfSession> _netConfSessionMock;
+        private int _operationTimeout;
 
         [TestInitialize]
         public void Setup()
@@ -32,7 +34,9 @@ namespace Renci.SshNet.Tests.Classes
             _netConfSessionMock = new Mock<INetConfSession>(MockBehavior.Strict);
 
             _connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth"));
+            _operationTimeout = new Random().Next(1000, 10000);
             _netConfClient = new NetConfClient(_connectionInfo, false, _serviceFactoryMock.Object);
+            _netConfClient.OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout);
 
             var sequence = new MockSequence();
             _serviceFactoryMock.InSequence(sequence)
@@ -40,7 +44,7 @@ namespace Renci.SshNet.Tests.Classes
                 .Returns(_sessionMock.Object);
             _sessionMock.InSequence(sequence).Setup(p => p.Connect());
             _serviceFactoryMock.InSequence(sequence)
-                .Setup(p => p.CreateNetConfSession(_sessionMock.Object, _netConfClient.OperationTimeout))
+                .Setup(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout))
                 .Returns(_netConfSessionMock.Object);
             _netConfSessionMock.InSequence(sequence).Setup(p => p.Connect());
             _sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting());
@@ -59,7 +63,7 @@ namespace Renci.SshNet.Tests.Classes
         [TestMethod]
         public void CreateNetConfSessionOnServiceFactoryShouldBeInvokedOnce()
         {
-            _serviceFactoryMock.Verify(p => p.CreateNetConfSession(_sessionMock.Object, _netConfClient.OperationTimeout), Times.Once);
+            _serviceFactoryMock.Verify(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout), Times.Once);
         }
 
         [TestMethod]

+ 7 - 3
src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disconnected.cs

@@ -1,6 +1,7 @@
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
 using Renci.SshNet.NetConf;
+using System;
 
 namespace Renci.SshNet.Tests.Classes
 {
@@ -9,9 +10,10 @@ namespace Renci.SshNet.Tests.Classes
     {
         private Mock<IServiceFactory> _serviceFactoryMock;
         private Mock<ISession> _sessionMock;
+        private Mock<INetConfSession> _netConfSessionMock;
         private NetConfClient _netConfClient;
         private ConnectionInfo _connectionInfo;
-        private Mock<INetConfSession> _netConfSessionMock;
+        private int _operationTimeout;
 
         [TestInitialize]
         public void Setup()
@@ -32,7 +34,9 @@ namespace Renci.SshNet.Tests.Classes
             _netConfSessionMock = new Mock<INetConfSession>(MockBehavior.Strict);
 
             _connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth"));
+            _operationTimeout = new Random().Next(1000, 10000);
             _netConfClient = new NetConfClient(_connectionInfo, false, _serviceFactoryMock.Object);
+            _netConfClient.OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout);
 
             var sequence = new MockSequence();
             _serviceFactoryMock.InSequence(sequence)
@@ -40,7 +44,7 @@ namespace Renci.SshNet.Tests.Classes
                 .Returns(_sessionMock.Object);
             _sessionMock.InSequence(sequence).Setup(p => p.Connect());
             _serviceFactoryMock.InSequence(sequence)
-                .Setup(p => p.CreateNetConfSession(_sessionMock.Object, _netConfClient.OperationTimeout))
+                .Setup(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout))
                 .Returns(_netConfSessionMock.Object);
             _netConfSessionMock.InSequence(sequence).Setup(p => p.Connect());
             _sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting());
@@ -61,7 +65,7 @@ namespace Renci.SshNet.Tests.Classes
         [TestMethod]
         public void CreateNetConfSessionOnServiceFactoryShouldBeInvokedOnce()
         {
-            _serviceFactoryMock.Verify(p => p.CreateNetConfSession(_sessionMock.Object, _netConfClient.OperationTimeout), Times.Once);
+            _serviceFactoryMock.Verify(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout), Times.Once);
         }
 
         [TestMethod]

+ 7 - 3
src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disposed.cs

@@ -1,6 +1,7 @@
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
 using Renci.SshNet.NetConf;
+using System;
 
 namespace Renci.SshNet.Tests.Classes
 {
@@ -9,9 +10,10 @@ namespace Renci.SshNet.Tests.Classes
     {
         private Mock<IServiceFactory> _serviceFactoryMock;
         private Mock<ISession> _sessionMock;
+        private Mock<INetConfSession> _netConfSessionMock;
         private NetConfClient _netConfClient;
         private ConnectionInfo _connectionInfo;
-        private Mock<INetConfSession> _netConfSessionMock;
+        private int _operationTimeout;
 
         [TestInitialize]
         public void Setup()
@@ -32,7 +34,9 @@ namespace Renci.SshNet.Tests.Classes
             _netConfSessionMock = new Mock<INetConfSession>(MockBehavior.Strict);
 
             _connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth"));
+            _operationTimeout = new Random().Next(1000, 10000);
             _netConfClient = new NetConfClient(_connectionInfo, false, _serviceFactoryMock.Object);
+            _netConfClient.OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout);
 
             var sequence = new MockSequence();
             _serviceFactoryMock.InSequence(sequence)
@@ -40,7 +44,7 @@ namespace Renci.SshNet.Tests.Classes
                 .Returns(_sessionMock.Object);
             _sessionMock.InSequence(sequence).Setup(p => p.Connect());
             _serviceFactoryMock.InSequence(sequence)
-                .Setup(p => p.CreateNetConfSession(_sessionMock.Object, _netConfClient.OperationTimeout))
+                .Setup(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout))
                 .Returns(_netConfSessionMock.Object);
             _netConfSessionMock.InSequence(sequence).Setup(p => p.Connect());
             _sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting());
@@ -60,7 +64,7 @@ namespace Renci.SshNet.Tests.Classes
         [TestMethod]
         public void CreateNetConfSessionOnServiceFactoryShouldBeInvokedOnce()
         {
-            _serviceFactoryMock.Verify(p => p.CreateNetConfSession(_sessionMock.Object, _netConfClient.OperationTimeout), Times.Once);
+            _serviceFactoryMock.Verify(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout), Times.Once);
         }
 
         [TestMethod]

+ 5 - 2
src/Renci.SshNet.Tests/Classes/NetConfClientTest_Finalize_Connected.cs

@@ -10,9 +10,10 @@ namespace Renci.SshNet.Tests.Classes
     {
         private Mock<IServiceFactory> _serviceFactoryMock;
         private Mock<ISession> _sessionMock;
+        private Mock<INetConfSession> _netConfSessionMock;
         private NetConfClient _netConfClient;
         private ConnectionInfo _connectionInfo;
-        private Mock<INetConfSession> _netConfSessionMock;
+        private int _operationTimeout;
 
         [TestInitialize]
         public void Setup()
@@ -28,7 +29,9 @@ namespace Renci.SshNet.Tests.Classes
             _netConfSessionMock = new Mock<INetConfSession>(MockBehavior.Loose);
 
             _connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth"));
+            _operationTimeout = new Random().Next(1000, 10000);
             _netConfClient = new NetConfClient(_connectionInfo, false, _serviceFactoryMock.Object);
+            _netConfClient.OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout);
 
             var sequence = new MockSequence();
             _serviceFactoryMock.InSequence(sequence)
@@ -36,7 +39,7 @@ namespace Renci.SshNet.Tests.Classes
                 .Returns(_sessionMock.Object);
             _sessionMock.InSequence(sequence).Setup(p => p.Connect());
             _serviceFactoryMock.InSequence(sequence)
-                .Setup(p => p.CreateNetConfSession(_sessionMock.Object, _netConfClient.OperationTimeout))
+                .Setup(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout))
                 .Returns(_netConfSessionMock.Object);
             _netConfSessionMock.InSequence(sequence).Setup(p => p.Connect());
 

+ 36 - 53
src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/DesCipherTest.cs

@@ -1,5 +1,8 @@
-using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System.Text;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Renci.SshNet.Security.Cryptography.Ciphers;
+using Renci.SshNet.Security.Cryptography.Ciphers.Modes;
+using Renci.SshNet.Security.Cryptography.Ciphers.Paddings;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers
@@ -10,64 +13,44 @@ namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers
     [TestClass]
     public class DesCipherTest : TestBase
     {
-        /// <summary>
-        ///A test for DesCipher Constructor
-        ///</summary>
         [TestMethod]
-        [Ignore] // placeholder for actual test
-        public void DesCipherConstructorTest()
+        public void Cbc_Encrypt()
         {
-            byte[] key = null; // TODO: Initialize to an appropriate value
-            CipherMode mode = null; // TODO: Initialize to an appropriate value
-            CipherPadding padding = null; // TODO: Initialize to an appropriate value
-            DesCipher target = new DesCipher(key, mode, padding);
-            Assert.Inconclusive("TODO: Implement code to verify target");
-        }
+            var expectedCypher = new byte[]
+                {
+                    0x15, 0x43, 0x3e, 0x97, 0x65, 0x66, 0xea, 0x81, 0x22, 0xab, 0xe3,
+                    0x11, 0x0f, 0x7d, 0xcb, 0x78, 0x56, 0x91, 0x22, 0x3d, 0xd6, 0xca,
+                    0xe3, 0xbd
+                };
 
-        /// <summary>
-        ///A test for DecryptBlock
-        ///</summary>
-        [TestMethod]
-        [Ignore] // placeholder for actual test
-        public void DecryptBlockTest()
-        {
-            byte[] key = null; // TODO: Initialize to an appropriate value
-            CipherMode mode = null; // TODO: Initialize to an appropriate value
-            CipherPadding padding = null; // TODO: Initialize to an appropriate value
-            DesCipher target = new DesCipher(key, mode, padding); // TODO: Initialize to an appropriate value
-            byte[] inputBuffer = null; // TODO: Initialize to an appropriate value
-            int inputOffset = 0; // TODO: Initialize to an appropriate value
-            int inputCount = 0; // TODO: Initialize to an appropriate value
-            byte[] outputBuffer = null; // TODO: Initialize to an appropriate value
-            int outputOffset = 0; // TODO: Initialize to an appropriate value
-            int expected = 0; // TODO: Initialize to an appropriate value
-            int actual;
-            actual = target.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
-            Assert.AreEqual(expected, actual);
-            Assert.Inconclusive("Verify the correctness of this test method.");
+            var input = Encoding.ASCII.GetBytes("www.javaCODEgeeks.com!!!");
+            var key = new byte[] {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+            var iv = new byte[] {0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00};
+
+            var des = new DesCipher(key, new CbcCipherMode(iv), new PKCS7Padding());
+            var actualCypher = des.Encrypt(input);
+
+            Assert.IsTrue((expectedCypher.IsEqualTo(actualCypher)));
         }
 
-        /// <summary>
-        ///A test for EncryptBlock
-        ///</summary>
         [TestMethod]
-        [Ignore] // placeholder for actual test
-        public void EncryptBlockTest()
+        public void Cbc_Decrypt()
         {
-            byte[] key = null; // TODO: Initialize to an appropriate value
-            CipherMode mode = null; // TODO: Initialize to an appropriate value
-            CipherPadding padding = null; // TODO: Initialize to an appropriate value
-            DesCipher target = new DesCipher(key, mode, padding); // TODO: Initialize to an appropriate value
-            byte[] inputBuffer = null; // TODO: Initialize to an appropriate value
-            int inputOffset = 0; // TODO: Initialize to an appropriate value
-            int inputCount = 0; // TODO: Initialize to an appropriate value
-            byte[] outputBuffer = null; // TODO: Initialize to an appropriate value
-            int outputOffset = 0; // TODO: Initialize to an appropriate value
-            int expected = 0; // TODO: Initialize to an appropriate value
-            int actual;
-            actual = target.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
-            Assert.AreEqual(expected, actual);
-            Assert.Inconclusive("Verify the correctness of this test method.");
+            var expectedPlain = Encoding.ASCII.GetBytes("www.javaCODEgeeks.com!!!");
+
+            var key = new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
+            var iv = new byte[] { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
+            var cypher = new byte[]
+                {
+                    0x15, 0x43, 0x3e, 0x97, 0x65, 0x66, 0xea, 0x81, 0x22, 0xab, 0xe3,
+                    0x11, 0x0f, 0x7d, 0xcb, 0x78, 0x56, 0x91, 0x22, 0x3d, 0xd6, 0xca,
+                    0xe3, 0xbd
+                };
+
+            var des = new DesCipher(key, new CbcCipherMode(iv), new PKCS7Padding());
+            var plain = des.Decrypt(cypher);
+
+            Assert.IsTrue(expectedPlain.IsEqualTo(plain));
         }
-    }
+   }
 }

+ 6 - 3
src/Renci.SshNet.Tests/Classes/Sftp/Responses/ExtendedReplies/StatVfsReplyInfoTest.cs

@@ -50,8 +50,6 @@ namespace Renci.SshNet.Tests.Classes.Sftp.Responses
         [TestMethod]
         public void Load()
         {
-            var target = new StatVfsReplyInfo();
-
             var sshDataStream = new SshDataStream(4 + 1 + 4 + 88);
             sshDataStream.Write(_responseId);
             sshDataStream.Write(_bsize);
@@ -66,7 +64,12 @@ namespace Renci.SshNet.Tests.Classes.Sftp.Responses
             sshDataStream.Write((ulong) 0x1);
             sshDataStream.Write(_namemax);
 
-            target.Load(sshDataStream.ToArray());
+            var extendedReplyResponse = new SftpExtendedReplyResponse(SftpSession.MaximumSupportedVersion);
+            extendedReplyResponse.Load(sshDataStream.ToArray());
+
+            Assert.AreEqual(_responseId, extendedReplyResponse.ResponseId);
+
+            var target = extendedReplyResponse.GetReply<StatVfsReplyInfo>();
 
             Assert.IsNotNull(target.Information);
 

+ 38 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpDataResponseBuilder.cs

@@ -0,0 +1,38 @@
+using Renci.SshNet.Sftp.Responses;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    internal class SftpDataResponseBuilder
+    {
+        private uint _protocolVersion;
+        private uint _responseId;
+        private byte[] _data;
+
+        public SftpDataResponseBuilder WithProtocolVersion(uint protocolVersion)
+        {
+            _protocolVersion = protocolVersion;
+            return this;
+        }
+
+        public SftpDataResponseBuilder WithResponseId(uint responseId)
+        {
+            _responseId = responseId;
+            return this;
+        }
+
+        public SftpDataResponseBuilder WithData(byte[] data)
+        {
+            _data = data;
+            return this;
+        }
+
+        public SftpDataResponse Build()
+        {
+            return new SftpDataResponse(_protocolVersion)
+                {
+                    ResponseId = _responseId,
+                    Data = _data
+                };
+        }
+    }
+}

+ 60 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTestBase.cs

@@ -0,0 +1,60 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Common;
+using Renci.SshNet.Sftp;
+using System;
+using System.Threading;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    public abstract class SftpFileReaderTestBase
+    {
+        internal Mock<ISftpSession> SftpSessionMock {  get; private set;}
+
+        protected abstract void SetupData();
+
+        protected void CreateMocks()
+        {
+            SftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        }
+
+        protected abstract void SetupMocks();
+
+        protected virtual void Arrange()
+        {
+            SetupData();
+            CreateMocks();
+            SetupMocks();
+        }
+
+        [TestInitialize]
+        public void SetUp()
+        {
+            Arrange();
+            Act();
+        }
+
+        protected abstract void Act();
+
+        protected static SftpFileAttributes CreateSftpFileAttributes(long size)
+        {
+            return new SftpFileAttributes(default(DateTime), default(DateTime), size, default(int), default(int), default(uint), null);
+        }
+
+        protected static byte[] CreateByteArray(Random random, int length)
+        {
+            var chunk = new byte[length];
+            random.NextBytes(chunk);
+            return chunk;
+        }
+
+        protected static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout)
+        {
+            var result = WaitHandle.WaitAny(waitHandles, millisecondsTimeout);
+
+            if (result == WaitHandle.WaitTimeout)
+                throw new SshOperationTimeoutException();
+            return result;
+        }
+    }
+}

+ 148 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_DisposeShouldUnblockReadAndReadAhead.cs

@@ -0,0 +1,148 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Abstractions;
+using Renci.SshNet.Sftp;
+using System;
+using System.Diagnostics;
+using System.Threading;
+using BufferedRead = Renci.SshNet.Sftp.SftpFileReader.BufferedRead;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileReaderTest_DisposeShouldUnblockReadAndReadAhead : SftpFileReaderTestBase
+    {
+        private const int ChunkLength = 32 * 1024;
+
+        private MockSequence _seq;
+        private byte[] _handle;
+        private int _fileSize;
+        private WaitHandle[] _waitHandleArray;
+        private int _operationTimeout;
+        private SftpCloseAsyncResult _closeAsyncResult;
+        private SftpFileReader _reader;
+        private ObjectDisposedException _actualException;
+        private ManualResetEvent _disposeCompleted;
+
+        [TestCleanup]
+        public void TearDown()
+        {
+            if (_disposeCompleted != null)
+            {
+                _disposeCompleted.Dispose();
+            }
+        }
+
+        protected override void SetupData()
+        {
+            var random = new Random();
+
+            _handle = CreateByteArray(random, 5);
+            _fileSize = 5000;
+            _waitHandleArray = new WaitHandle[2];
+            _operationTimeout = random.Next(10000, 20000);
+            _closeAsyncResult = new SftpCloseAsyncResult(null, null);
+            _disposeCompleted = new ManualResetEvent(false);
+        }
+
+        protected override void SetupMocks()
+        {
+            _seq = new MockSequence();
+
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.CreateWaitHandleArray(It.IsNotNull<WaitHandle>(), It.IsNotNull<WaitHandle>()))
+                           .Returns<WaitHandle, WaitHandle>((disposingWaitHandle, semaphoreAvailableWaitHandle) =>
+                           {
+                               _waitHandleArray[0] = disposingWaitHandle;
+                               _waitHandleArray[1] = semaphoreAvailableWaitHandle;
+                               return _waitHandleArray;
+                           });
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                           .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult));
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _reader = new SftpFileReader(_handle, SftpSessionMock.Object, ChunkLength, 1, _fileSize);
+        }
+
+        protected override void Act()
+        {
+            ThreadAbstraction.ExecuteThread(() =>
+            {
+                Thread.Sleep(500);
+                _reader.Dispose();
+                _disposeCompleted.Set();
+            });
+
+            try
+            {
+                _reader.Read();
+                Assert.Fail();
+            }
+            catch (ObjectDisposedException ex)
+            {
+                _actualException = ex;
+            }
+
+            // Dispose may unblock Read() before the dispose has fully completed, so
+            // let's wait until it has completed
+            _disposeCompleted.WaitOne(500);
+        }
+
+        [TestMethod]
+        public void ReadShouldHaveThrownObjectDisposedException()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.AreEqual(typeof(SftpFileReader).FullName, _actualException.ObjectName);
+        }
+
+        [TestMethod]
+        public void ReadAfterDisposeShouldThrowObjectDisposedException()
+        {
+            try
+            {
+                _reader.Read();
+                Assert.Fail();
+            }
+            catch (ObjectDisposedException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual(typeof(SftpFileReader).FullName, ex.ObjectName);
+            }
+        }
+
+        [TestMethod]
+        public void HandleShouldHaveBeenClosed()
+        {
+            SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
+            SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
+        }
+
+        [TestMethod]
+        public void DisposeShouldCompleteImmediatelyAndNotAttemptToCloseHandleAgain()
+        {
+            var stopwatch = Stopwatch.StartNew();
+            _reader.Dispose();
+            stopwatch.Stop();
+
+            Assert.IsTrue(stopwatch.ElapsedMilliseconds < 200, "Dispose took too long to complete: " + stopwatch.ElapsedMilliseconds);
+
+            SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
+            SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
+        }
+    }
+}

+ 162 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_LastChunkBeforeEofIsComplete.cs

@@ -0,0 +1,162 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Common;
+using Renci.SshNet.Sftp;
+using System;
+using System.Diagnostics;
+using System.Threading;
+using BufferedRead = Renci.SshNet.Sftp.SftpFileReader.BufferedRead;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileReaderTest_LastChunkBeforeEofIsComplete : SftpFileReaderTestBase
+    {
+        private const int ChunkLength = 32 * 1024;
+
+        private MockSequence _seq;
+        private byte[] _handle;
+        private int _fileSize;
+        private WaitHandle[] _waitHandleArray;
+        private int _operationTimeout;
+        private SftpCloseAsyncResult _closeAsyncResult;
+        private byte[] _chunk1;
+        private byte[] _chunk2;
+        private byte[] _chunk3;
+        private SftpFileReader _reader;
+        private byte[] _actualChunk1;
+        private byte[] _actualChunk2;
+        private byte[] _actualChunk3;
+
+        protected override void SetupData()
+        {
+            var random = new Random();
+
+            _handle = CreateByteArray(random, 5);
+            _chunk1 = CreateByteArray(random, ChunkLength);
+            // chunk is less than the requested length, but - together with chunk 1 - contains all data up to the EOF
+            _chunk2 = CreateByteArray(random, ChunkLength - 10);
+            _chunk3 = new byte[0];
+            _fileSize = _chunk1.Length + _chunk2.Length;
+            _waitHandleArray = new WaitHandle[2];
+            _operationTimeout = random.Next(10000, 20000);
+            _closeAsyncResult = new SftpCloseAsyncResult(null, null);
+        }
+
+        protected override void SetupMocks()
+        {
+            _seq = new MockSequence();
+
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.CreateWaitHandleArray(It.IsNotNull<WaitHandle>(), It.IsNotNull<WaitHandle>()))
+                           .Returns<WaitHandle, WaitHandle>((disposingWaitHandle, semaphoreAvailableWaitHandle) =>
+                           {
+                               _waitHandleArray[0] = disposingWaitHandle;
+                               _waitHandleArray[1] = semaphoreAvailableWaitHandle;
+                               return _waitHandleArray;
+                           });
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                            .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                            {
+                                var asyncResult = new SftpReadAsyncResult(callback, state);
+                                asyncResult.SetAsCompleted(_chunk1, false);
+                            })
+                            .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.BeginRead(_handle, ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                            .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                            {
+                                var asyncResult = new SftpReadAsyncResult(callback, state);
+                                asyncResult.SetAsCompleted(_chunk2, false);
+                            })
+                            .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.BeginRead(_handle, 2 * ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                            .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                            {
+                                var asyncResult = new SftpReadAsyncResult(callback, state);
+                                asyncResult.SetAsCompleted(_chunk3, false);
+                            })
+                            .Returns((SftpReadAsyncResult)null);
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _reader = new SftpFileReader(_handle, SftpSessionMock.Object, ChunkLength, 15, _fileSize);
+        }
+
+        protected override void Act()
+        {
+            _actualChunk1 = _reader.Read();
+            _actualChunk2 = _reader.Read();
+            _actualChunk3 = _reader.Read();
+        }
+
+        [TestMethod]
+        public void FirstReadShouldReturnChunk1()
+        {
+            Assert.IsNotNull(_actualChunk1);
+            Assert.AreSame(_chunk1, _actualChunk1);
+        }
+
+        [TestMethod]
+        public void SecondReadShouldReturnChunk2()
+        {
+            Assert.IsNotNull(_actualChunk2);
+            Assert.AreSame(_chunk2, _actualChunk2);
+        }
+
+        [TestMethod]
+        public void ThirdReadShouldReturnChunk3()
+        {
+            Assert.IsNotNull(_actualChunk3);
+            Assert.AreSame(_chunk3, _actualChunk3);
+        }
+
+        [TestMethod]
+        public void ReadAfterEndOfFileShouldThrowSshException()
+        {
+            try
+            {
+                _reader.Read();
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Attempting to read beyond the end of the file.", ex.Message);
+            }
+        }
+
+        [TestMethod]
+        public void DisposeShouldCloseHandleAndCompleteImmediately()
+        {
+            SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult));
+
+            var stopwatch = Stopwatch.StartNew();
+            _reader.Dispose();
+            stopwatch.Stop();
+
+            Assert.IsTrue(stopwatch.ElapsedMilliseconds < 200, "Dispose took too long to complete: " + stopwatch.ElapsedMilliseconds);
+
+            SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
+            SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
+        }
+    }
+}

+ 161 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_LastChunkBeforeEofIsPartial.cs

@@ -0,0 +1,161 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Common;
+using Renci.SshNet.Sftp;
+using System;
+using System.Diagnostics;
+using System.Threading;
+using BufferedRead = Renci.SshNet.Sftp.SftpFileReader.BufferedRead;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileReaderTest_LastChunkBeforeEofIsPartial : SftpFileReaderTestBase
+    {
+        private const int ChunkLength = 32 * 1024;
+
+        private MockSequence _seq;
+        private byte[] _handle;
+        private int _fileSize;
+        private WaitHandle[] _waitHandleArray;
+        private int _operationTimeout;
+        private SftpCloseAsyncResult _closeAsyncResult;
+        private byte[] _chunk1;
+        private byte[] _chunk2;
+        private byte[] _chunk3;
+        private SftpFileReader _reader;
+        private byte[] _actualChunk1;
+        private byte[] _actualChunk2;
+        private byte[] _actualChunk3;
+
+        protected override void SetupData()
+        {
+            var random = new Random();
+
+            _handle = CreateByteArray(random, 5);
+            _chunk1 = CreateByteArray(random, ChunkLength);
+            _chunk2 = CreateByteArray(random, ChunkLength);
+            _chunk3 = new byte[0];
+            _fileSize = _chunk1.Length + _chunk2.Length;
+            _waitHandleArray = new WaitHandle[2];
+            _operationTimeout = random.Next(10000, 20000);
+            _closeAsyncResult = new SftpCloseAsyncResult(null, null);
+        }
+
+        protected override void SetupMocks()
+        {
+            _seq = new MockSequence();
+
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.CreateWaitHandleArray(It.IsNotNull<WaitHandle>(), It.IsNotNull<WaitHandle>()))
+                           .Returns<WaitHandle, WaitHandle>((disposingWaitHandle, semaphoreAvailableWaitHandle) =>
+                           {
+                               _waitHandleArray[0] = disposingWaitHandle;
+                               _waitHandleArray[1] = semaphoreAvailableWaitHandle;
+                               return _waitHandleArray;
+                           });
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                            .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                            {
+                                var asyncResult = new SftpReadAsyncResult(callback, state);
+                                asyncResult.SetAsCompleted(_chunk1, false);
+                            })
+                            .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.BeginRead(_handle, ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                            .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                            {
+                                var asyncResult = new SftpReadAsyncResult(callback, state);
+                                asyncResult.SetAsCompleted(_chunk2, false);
+                            })
+                            .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.BeginRead(_handle, 2 * ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                            .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                            {
+                                var asyncResult = new SftpReadAsyncResult(callback, state);
+                                asyncResult.SetAsCompleted(_chunk3, false);
+                            })
+                            .Returns((SftpReadAsyncResult)null);
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _reader = new SftpFileReader(_handle, SftpSessionMock.Object, ChunkLength, 15, _fileSize);
+        }
+
+        protected override void Act()
+        {
+            _actualChunk1 = _reader.Read();
+            _actualChunk2 = _reader.Read();
+            _actualChunk3 = _reader.Read();
+        }
+
+        [TestMethod]
+        public void FirstReadShouldReturnChunk1()
+        {
+            Assert.IsNotNull(_actualChunk1);
+            Assert.AreSame(_chunk1, _actualChunk1);
+        }
+
+        [TestMethod]
+        public void SecondReadShouldReturnChunk2()
+        {
+            Assert.IsNotNull(_actualChunk2);
+            Assert.AreSame(_chunk2, _actualChunk2);
+        }
+
+        [TestMethod]
+        public void ThirdReadShouldReturnChunk3()
+        {
+            Assert.IsNotNull(_actualChunk3);
+            Assert.AreSame(_chunk3, _actualChunk3);
+        }
+
+        [TestMethod]
+        public void ReadAfterEndOfFileShouldThrowSshException()
+        {
+            try
+            {
+                _reader.Read();
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Attempting to read beyond the end of the file.", ex.Message);
+            }
+        }
+
+        [TestMethod]
+        public void DisposeShouldCloseHandleAndCompleteImmediately()
+        {
+            SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult));
+
+            var stopwatch = Stopwatch.StartNew();
+            _reader.Dispose();
+            stopwatch.Stop();
+
+            Assert.IsTrue(stopwatch.ElapsedMilliseconds < 200, "Dispose took too long to complete: " + stopwatch.ElapsedMilliseconds);
+
+            SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
+            SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
+        }
+    }
+}

+ 300 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsNotReached.cs

@@ -0,0 +1,300 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Common;
+using Renci.SshNet.Sftp;
+using System;
+using System.Diagnostics;
+using System.Threading;
+using BufferedRead = Renci.SshNet.Sftp.SftpFileReader.BufferedRead;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsNotReached : SftpFileReaderTestBase
+    {
+        private const int ChunkLength = 32 * 1024;
+
+        private MockSequence _seq;
+        private byte[] _handle;
+        private int _fileSize;
+        private WaitHandle[] _waitHandleArray;
+        private int _operationTimeout;
+        private SftpCloseAsyncResult _closeAsyncResult;
+        private byte[] _chunk1;
+        private byte[] _chunk2;
+        private byte[] _chunk2CatchUp1;
+        private byte[] _chunk2CatchUp2;
+        private byte[] _chunk3;
+        private byte[] _chunk4;
+        private byte[] _chunk5;
+        private SftpFileReader _reader;
+        private byte[] _actualChunk1;
+        private byte[] _actualChunk2;
+        private byte[] _actualChunk3;
+        private ManualResetEvent _chunk1BeginRead;
+        private ManualResetEvent _chunk2BeginRead;
+        private ManualResetEvent _chunk3BeginRead;
+        private ManualResetEvent _chunk4BeginRead;
+        private ManualResetEvent _chunk5BeginRead;
+        private ManualResetEvent _waitBeforeChunk6;
+        private ManualResetEvent _chunk6BeginRead;
+        private byte[] _actualChunk4;
+        private byte[] _actualChunk2CatchUp1;
+        private byte[] _actualChunk2CatchUp2;
+        private byte[] _chunk6;
+        private byte[] _actualChunk5;
+        private byte[] _actualChunk6;
+
+        protected override void SetupData()
+        {
+            var random = new Random();
+
+            _handle = CreateByteArray(random, 3);
+            _chunk1 = CreateByteArray(random, ChunkLength);
+            _chunk2 = CreateByteArray(random, ChunkLength - 17);
+            _chunk2CatchUp1 = CreateByteArray(random, 10);
+            _chunk2CatchUp2 = CreateByteArray(random, 7);
+            _chunk3 = CreateByteArray(random, ChunkLength);
+            _chunk4 = CreateByteArray(random, ChunkLength);
+            _chunk5 = CreateByteArray(random, ChunkLength);
+            _chunk6 = new byte[0];
+            _chunk1BeginRead = new ManualResetEvent(false);
+            _chunk2BeginRead = new ManualResetEvent(false);
+            _chunk3BeginRead = new ManualResetEvent(false);
+            _chunk4BeginRead = new ManualResetEvent(false);
+            _chunk5BeginRead = new ManualResetEvent(false);
+            _waitBeforeChunk6 = new ManualResetEvent(false);
+            _chunk6BeginRead = new ManualResetEvent(false);
+            _fileSize = _chunk1.Length + _chunk2.Length + _chunk2CatchUp1.Length + _chunk2CatchUp2.Length + _chunk3.Length + _chunk4.Length + _chunk5.Length;
+            _waitHandleArray = new WaitHandle[2];
+            _operationTimeout = random.Next(10000, 20000);
+            _closeAsyncResult = new SftpCloseAsyncResult(null, null);
+        }
+
+        protected override void SetupMocks()
+        {
+            _seq = new MockSequence();
+
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.CreateWaitHandleArray(It.IsNotNull<WaitHandle>(), It.IsNotNull<WaitHandle>()))
+                           .Returns<WaitHandle, WaitHandle>((disposingWaitHandle, semaphoreAvailableWaitHandle) =>
+                           {
+                               _waitHandleArray[0] = disposingWaitHandle;
+                               _waitHandleArray[1] = semaphoreAvailableWaitHandle;
+                               return _waitHandleArray;
+                           });
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                            .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                            {
+                                _chunk1BeginRead.Set();
+                                var asyncResult = new SftpReadAsyncResult(callback, state);
+                                asyncResult.SetAsCompleted(_chunk1, false);
+                            })
+                            .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.BeginRead(_handle, ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                            .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                            {
+                                _chunk2BeginRead.Set();
+                                var asyncResult = new SftpReadAsyncResult(callback, state);
+                                asyncResult.SetAsCompleted(_chunk2, false);
+                            })
+                            .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.BeginRead(_handle, 2 * ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                            .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                            {
+                                _chunk3BeginRead.Set();
+                                var asyncResult = new SftpReadAsyncResult(callback, state);
+                                asyncResult.SetAsCompleted(_chunk3, false);
+                            })
+                            .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.BeginRead(_handle, 3 * ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                            .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                            {
+                                _chunk4BeginRead.Set();
+                                var asyncResult = new SftpReadAsyncResult(callback, state);
+                                asyncResult.SetAsCompleted(_chunk4, false);
+                            })
+                            .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.BeginRead(_handle, 4 * ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                            .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                            {
+                                _chunk5BeginRead.Set();
+                                var asyncResult = new SftpReadAsyncResult(callback, state);
+                                asyncResult.SetAsCompleted(_chunk5, false);
+                            })
+                            .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Callback(() => _waitBeforeChunk6.Set())
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.RequestRead(_handle, 2 * ChunkLength - 17, 17))
+                            .Returns(_chunk2CatchUp1);
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.RequestRead(_handle, 2 * ChunkLength - 7, 7))
+                            .Returns(_chunk2CatchUp2);
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.BeginRead(_handle, 5 * ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                            .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                            {
+                                _chunk6BeginRead.Set();
+                                var asyncResult = new SftpReadAsyncResult(callback, state);
+                                asyncResult.SetAsCompleted(_chunk6, false);
+                            })
+                            .Returns((SftpReadAsyncResult)null);
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _reader = new SftpFileReader(_handle, SftpSessionMock.Object, ChunkLength, 3, _fileSize);
+        }
+
+        protected override void Act()
+        {
+            // reader is configured to read-ahead max. 3 chunks, so chunk4 should not have been read
+            Assert.IsFalse(_chunk4BeginRead.WaitOne(0));
+            // consume chunk 1
+            _actualChunk1 = _reader.Read();
+            // consuming chunk1 allows chunk4 to be read-ahead
+            Assert.IsTrue(_chunk4BeginRead.WaitOne(200));
+            // verify that chunk5 has not yet been read-ahead
+            Assert.IsFalse(_chunk5BeginRead.WaitOne(0));
+            // consume chunk 2
+            _actualChunk2 = _reader.Read();
+            // consuming chunk2 allows chunk5 to be read-ahead
+            Assert.IsTrue(_chunk5BeginRead.WaitOne(200));
+            // pauze until the read-ahead has started waiting a semaphore to become available
+            Assert.IsTrue(_waitBeforeChunk6.WaitOne(200));
+            // consume remaining parts of chunk 2
+            _actualChunk2CatchUp1 = _reader.Read();
+            _actualChunk2CatchUp2 = _reader.Read();
+            // verify that chunk6 has not yet been read-ahead
+            Assert.IsFalse(_chunk6BeginRead.WaitOne(0));
+            // consume chunk 3
+            _actualChunk3 = _reader.Read();
+            // consuming chunk3 allows chunk6 to be read-ahead
+            Assert.IsTrue(_chunk6BeginRead.WaitOne(200));
+            // consume chunk 4
+            _actualChunk4 = _reader.Read();
+            // consume chunk 5
+            _actualChunk5 = _reader.Read();
+            // consume chunk 6
+            _actualChunk6 = _reader.Read();
+        }
+
+        [TestMethod]
+        public void FirstReadShouldReturnChunk1()
+        {
+            Assert.IsNotNull(_actualChunk1);
+            Assert.AreSame(_chunk1, _actualChunk1);
+        }
+
+        [TestMethod]
+        public void SecondReadShouldReturnChunk2()
+        {
+            Assert.IsNotNull(_actualChunk2);
+            Assert.AreSame(_chunk2, _actualChunk2);
+        }
+
+        [TestMethod]
+        public void ThirdReadShouldReturnChunk2CatchUp1()
+        {
+            Assert.IsNotNull(_actualChunk2CatchUp1);
+            Assert.AreSame(_chunk2CatchUp1, _actualChunk2CatchUp1);
+        }
+
+        [TestMethod]
+        public void FourthReadShouldReturnChunk2CatchUp2()
+        {
+            Assert.IsNotNull(_actualChunk2CatchUp2);
+            Assert.AreSame(_chunk2CatchUp2, _actualChunk2CatchUp2);
+        }
+
+        [TestMethod]
+        public void FifthReadShouldReturnChunk3()
+        {
+            Assert.IsNotNull(_actualChunk3);
+            Assert.AreSame(_chunk3, _actualChunk3);
+        }
+
+        [TestMethod]
+        public void SixthReadShouldReturnChunk4()
+        {
+            Assert.IsNotNull(_actualChunk4);
+            Assert.AreSame(_chunk4, _actualChunk4);
+        }
+
+        [TestMethod]
+        public void SeventhReadShouldReturnChunk5()
+        {
+            Assert.IsNotNull(_actualChunk5);
+            Assert.AreSame(_chunk5, _actualChunk5);
+        }
+
+        [TestMethod]
+        public void EightReadShouldReturnChunk6()
+        {
+            Assert.IsNotNull(_actualChunk6);
+            Assert.AreSame(_chunk6, _actualChunk6);
+        }
+
+        [TestMethod]
+        public void ReadAfterEndOfFileShouldThrowSshException()
+        {
+            try
+            {
+                _reader.Read();
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Attempting to read beyond the end of the file.", ex.Message);
+            }
+        }
+
+        [TestMethod]
+        public void DisposeShouldCloseHandleAndCompleteImmediately()
+        {
+            SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult));
+
+            var stopwatch = Stopwatch.StartNew();
+            _reader.Dispose();
+            stopwatch.Stop();
+
+            Assert.IsTrue(stopwatch.ElapsedMilliseconds < 200, "Dispose took too long to complete: " + stopwatch.ElapsedMilliseconds);
+
+            SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
+            SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
+        }
+    }
+}

+ 190 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsReached.cs

@@ -0,0 +1,190 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Common;
+using Renci.SshNet.Sftp;
+using System;
+using System.Diagnostics;
+using System.Threading;
+using BufferedRead = Renci.SshNet.Sftp.SftpFileReader.BufferedRead;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsReached : SftpFileReaderTestBase
+    {
+        private const int ChunkLength = 32 * 1024;
+
+        private MockSequence _seq;
+        private byte[] _handle;
+        private int _fileSize;
+        private WaitHandle[] _waitHandleArray;
+        private int _operationTimeout;
+        private SftpCloseAsyncResult _closeAsyncResult;
+        private byte[] _chunk1;
+        private byte[] _chunk2;
+        private byte[] _chunk2CatchUp;
+        private byte[] _chunk3;
+        private SftpFileReader _reader;
+        private byte[] _actualChunk1;
+        private byte[] _actualChunk2;
+        private byte[] _actualChunk2CatchUp;
+        private byte[] _actualChunk3;
+        private ManualResetEvent _chunk1BeginRead;
+        private ManualResetEvent _chunk2BeginRead;
+        private ManualResetEvent _chunk3BeginRead;
+
+        protected override void SetupData()
+        {
+            var random = new Random();
+
+            _handle = CreateByteArray(random, 3);
+            _chunk1 = CreateByteArray(random, ChunkLength);
+            _chunk2 = CreateByteArray(random, ChunkLength - 10);
+            _chunk2CatchUp = CreateByteArray(random, 10);
+            _chunk3 = new byte[0];
+            _chunk1BeginRead = new ManualResetEvent(false);
+            _chunk2BeginRead = new ManualResetEvent(false);
+            _chunk3BeginRead = new ManualResetEvent(false);
+            _fileSize = _chunk1.Length + _chunk2.Length + _chunk2CatchUp.Length + _chunk3.Length;
+            _waitHandleArray = new WaitHandle[2];
+            _operationTimeout = random.Next(10000, 20000);
+            _closeAsyncResult = new SftpCloseAsyncResult(null, null);
+        }
+
+        protected override void SetupMocks()
+        {
+            _seq = new MockSequence();
+
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.CreateWaitHandleArray(It.IsNotNull<WaitHandle>(), It.IsNotNull<WaitHandle>()))
+                           .Returns<WaitHandle, WaitHandle>((disposingWaitHandle, semaphoreAvailableWaitHandle) =>
+                           {
+                               _waitHandleArray[0] = disposingWaitHandle;
+                               _waitHandleArray[1] = semaphoreAvailableWaitHandle;
+                               return _waitHandleArray;
+                           });
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                            .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                            {
+                                _chunk1BeginRead.Set();
+                                var asyncResult = new SftpReadAsyncResult(callback, state);
+                                asyncResult.SetAsCompleted(_chunk1, false);
+                            })
+                            .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.BeginRead(_handle, ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                            .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                            {
+                                _chunk2BeginRead.Set();
+                                var asyncResult = new SftpReadAsyncResult(callback, state);
+                                asyncResult.SetAsCompleted(_chunk2, false);
+                            })
+                            .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.BeginRead(_handle, 2 * ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                            .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                            {
+                                _chunk3BeginRead.Set();
+                                var asyncResult = new SftpReadAsyncResult(callback, state);
+                                asyncResult.SetAsCompleted(_chunk3, false);
+                            })
+                            .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.RequestRead(_handle, 2 * ChunkLength - 10, 10))
+                            .Returns(_chunk2CatchUp);
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _reader = new SftpFileReader(_handle, SftpSessionMock.Object, ChunkLength, 3, _fileSize);
+        }
+
+        protected override void Act()
+        {
+            // consume chunk 1
+            _actualChunk1 = _reader.Read();
+            // consume chunk 2
+            _actualChunk2 = _reader.Read();
+            // wait until chunk3 has been read-ahead
+            Assert.IsTrue(_chunk3BeginRead.WaitOne(200));
+            // consume remaining parts of chunk 2
+            _actualChunk2CatchUp = _reader.Read();
+            // consume chunk 3
+            _actualChunk3 = _reader.Read();
+        }
+
+        [TestMethod]
+        public void FirstReadShouldReturnChunk1()
+        {
+            Assert.IsNotNull(_actualChunk1);
+            Assert.AreSame(_chunk1, _actualChunk1);
+        }
+
+        [TestMethod]
+        public void SecondReadShouldReturnChunk2()
+        {
+            Assert.IsNotNull(_actualChunk2);
+            Assert.AreSame(_chunk2, _actualChunk2);
+        }
+
+        [TestMethod]
+        public void ThirdReadShouldReturnChunk2CatchUp()
+        {
+            Assert.IsNotNull(_actualChunk2CatchUp);
+            Assert.AreSame(_chunk2CatchUp, _actualChunk2CatchUp);
+        }
+
+        [TestMethod]
+        public void FourthReadShouldReturnChunk3()
+        {
+            Assert.IsNotNull(_actualChunk3);
+            Assert.AreSame(_chunk3, _actualChunk3);
+        }
+
+        [TestMethod]
+        public void ReadAfterEndOfFileShouldThrowSshException()
+        {
+            try
+            {
+                _reader.Read();
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Attempting to read beyond the end of the file.", ex.Message);
+            }
+        }
+
+        [TestMethod]
+        public void DisposeShouldCloseHandleAndCompleteImmediately()
+        {
+            SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult));
+
+            var stopwatch = Stopwatch.StartNew();
+            _reader.Dispose();
+            stopwatch.Stop();
+
+            Assert.IsTrue(stopwatch.ElapsedMilliseconds < 200, "Dispose took too long to complete: " + stopwatch.ElapsedMilliseconds);
+
+            SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
+            SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
+        }
+    }
+}

+ 6 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadBeginReadException.cs

@@ -0,0 +1,6 @@
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    class SftpFileReaderTest_ReadAheadBeginReadException
+    {
+    }
+}

+ 207 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadEndInvokeException_DiscardsFurtherReadAheads.cs

@@ -0,0 +1,207 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Abstractions;
+using Renci.SshNet.Common;
+using Renci.SshNet.Sftp;
+using System;
+using System.Diagnostics;
+using System.Threading;
+using BufferedRead = Renci.SshNet.Sftp.SftpFileReader.BufferedRead;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    /// <summary>
+    /// Runs a reader with max. 2 pending reads.
+    /// The read-ahead of chunk1 starts followed by the read-ahead of chunk2.
+    /// The read-ahead of chunk1 completes successfully and the resulting chunk is read.
+    /// The read of this first chunk allows a third ahead-head to start.
+    /// The second read-ahead uses signals to forcefully block a failure completion until the read
+    /// ahead of the third chunk has completed and the semaphore is waiting for a slot to start
+    /// the read-ahead of chunk4.
+    /// The second read does not consume check3 as it is out of order, but instead waits for
+    /// the outcome of the read-ahead of chunk2.
+    /// 
+    /// The completion with exception of chunk2 causes the second read to throw that same exception, and
+    /// signals the semaphore that was waiting to start the read-ahead of chunk4. However, due to the fact
+    /// that chunk2 completed with an exception, the read-ahead loop is stopped.
+    /// </summary>
+    [TestClass]
+    public class SftpFileReaderTest_ReadAheadEndInvokeException_DiscardsFurtherReadAheads : SftpFileReaderTestBase
+    {
+        private const int ChunkLength = 32 * 1024;
+
+        private MockSequence _seq;
+        private byte[] _handle;
+        private int _fileSize;
+        private WaitHandle[] _waitHandleArray;
+        private int _operationTimeout;
+        private SftpCloseAsyncResult _closeAsyncResult;
+        private byte[] _chunk1;
+        private byte[] _chunk3;
+        private ManualResetEvent _readAheadChunk2Completed;
+        private ManualResetEvent _readAheadChunk3Completed;
+        private ManualResetEvent _waitingForSemaphoreAfterCompletingChunk3;
+        private SftpFileReader _reader;
+        private SshException _exception;
+        private SshException _actualException;
+
+        protected override void SetupData()
+        {
+            var random = new Random();
+
+            _handle = CreateByteArray(random, 5);
+            _chunk1 = CreateByteArray(random, ChunkLength);
+            _chunk3 = CreateByteArray(random, ChunkLength);
+            _fileSize = 4 * ChunkLength;
+            _waitHandleArray = new WaitHandle[2];
+            _operationTimeout = random.Next(10000, 20000);
+            _closeAsyncResult = new SftpCloseAsyncResult(null, null);
+
+            _readAheadChunk2Completed = new ManualResetEvent(false);
+            _readAheadChunk3Completed = new ManualResetEvent(false);
+            _waitingForSemaphoreAfterCompletingChunk3 = new ManualResetEvent(false);
+
+            _exception = new SshException();
+        }
+
+        protected override void SetupMocks()
+        {
+            _seq = new MockSequence();
+
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.CreateWaitHandleArray(It.IsNotNull<WaitHandle>(), It.IsNotNull<WaitHandle>()))
+                           .Returns<WaitHandle, WaitHandle>((disposingWaitHandle, semaphoreAvailableWaitHandle) =>
+                           {
+                               _waitHandleArray[0] = disposingWaitHandle;
+                               _waitHandleArray[1] = semaphoreAvailableWaitHandle;
+                               return _waitHandleArray;
+                           });
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                           .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                           {
+                               var asyncResult = new SftpReadAsyncResult(callback, state);
+                               asyncResult.SetAsCompleted(_chunk1, false);
+                           })
+                           .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.BeginRead(_handle, ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                            .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                            {
+                                ThreadAbstraction.ExecuteThread(() =>
+                                {
+                                    // wait until the read-ahead for chunk3 has completed; this should allow
+                                    // the read-ahead of chunk4 to start
+                                    _readAheadChunk3Completed.WaitOne(TimeSpan.FromSeconds(3));
+                                    // wait until the semaphore wait to start with chunk4 has started
+                                    _waitingForSemaphoreAfterCompletingChunk3.WaitOne(TimeSpan.FromSeconds(7));
+                                    // complete async read of chunk2 with exception
+                                    var asyncResult = new SftpReadAsyncResult(callback, state);
+                                    asyncResult.SetAsCompleted(_exception, false);
+                                    // signal that read-ahead of chunk 2 has completed
+                                    _readAheadChunk2Completed.Set();
+                                });
+                            })
+                           .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.BeginRead(_handle, 2 * ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                            .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                            {
+                                var asyncResult = new SftpReadAsyncResult(callback, state);
+                                asyncResult.SetAsCompleted(_chunk3, false);
+                                // signal that we've completed the read-ahead for chunk3
+                                _readAheadChunk3Completed.Set();
+                            })
+                            .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Callback(() => _waitingForSemaphoreAfterCompletingChunk3.Set())
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _reader = new SftpFileReader(_handle, SftpSessionMock.Object, ChunkLength, 2, _fileSize);
+        }
+
+        protected override void Act()
+        {
+            _reader.Read();
+
+            try
+            {
+                _reader.Read();
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void ReadOfSecondChunkShouldThrowExceptionThatOccurredInReadAhead()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.AreSame(_exception, _actualException);
+        }
+
+        [TestMethod]
+        public void ReahAheadOfChunk3ShouldHaveStarted()
+        {
+            SftpSessionMock.Verify(p => p.BeginRead(_handle, 2 * ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()), Times.Once);
+        }
+
+        [TestMethod]
+        public void ReadAfterReadAheadExceptionShouldRethrowExceptionThatOccurredInReadAhead()
+        {
+            try
+            {
+                _reader.Read();
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.AreSame(_exception, ex);
+            }
+        }
+
+        [TestMethod]
+        public void WaitAnyOFSftpSessionShouldHaveBeenInvokedFourTimes()
+        {
+            SftpSessionMock.Verify(p => p.WaitAny(_waitHandleArray, _operationTimeout), Times.Exactly(4));
+        }
+
+        [TestMethod]
+        public void DisposeShouldCloseHandleAndCompleteImmediately()
+        {
+            SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult));
+
+            var stopwatch = Stopwatch.StartNew();
+            _reader.Dispose();
+            stopwatch.Stop();
+
+            Assert.IsTrue(stopwatch.ElapsedMilliseconds < 200, "Dispose took too long to complete: " + stopwatch.ElapsedMilliseconds);
+
+            SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
+            SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
+        }
+    }
+}

+ 174 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadEndInvokeException_PreventsFurtherReadAheads.cs

@@ -0,0 +1,174 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Abstractions;
+using Renci.SshNet.Common;
+using Renci.SshNet.Sftp;
+using System;
+using System.Diagnostics;
+using System.Threading;
+using BufferedRead = Renci.SshNet.Sftp.SftpFileReader.BufferedRead;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileReaderTest_ReadAheadEndInvokeException_PreventsFurtherReadAheads : SftpFileReaderTestBase
+    {
+        private const int ChunkLength = 32 * 1024;
+
+        private MockSequence _seq;
+        private byte[] _handle;
+        private int _fileSize;
+        private WaitHandle[] _waitHandleArray;
+        private int _operationTimeout;
+        private SftpCloseAsyncResult _closeAsyncResult;
+        private byte[] _chunk1;
+        private byte[] _chunk3;
+        private SftpFileReader _reader;
+        private ManualResetEvent _readAheadChunk2;
+        private ManualResetEvent _readChunk2;
+        private SshException _exception;
+        private SshException _actualException;
+
+        protected override void SetupData()
+        {
+            var random = new Random();
+
+            _handle = CreateByteArray(random, 5);
+            _chunk1 = CreateByteArray(random, ChunkLength);
+            _chunk3 = CreateByteArray(random, ChunkLength);
+            _fileSize = 3 * _chunk1.Length;
+            _waitHandleArray = new WaitHandle[2];
+            _operationTimeout = random.Next(10000, 20000);
+            _closeAsyncResult = new SftpCloseAsyncResult(null, null);
+
+            _readAheadChunk2 = new ManualResetEvent(false);
+            _readChunk2 = new ManualResetEvent(false);
+
+            _exception = new SshException();
+        }
+
+        protected override void SetupMocks()
+        {
+            _seq = new MockSequence();
+
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.CreateWaitHandleArray(It.IsNotNull<WaitHandle>(), It.IsNotNull<WaitHandle>()))
+                           .Returns<WaitHandle, WaitHandle>((disposingWaitHandle, semaphoreAvailableWaitHandle) =>
+                           {
+                               _waitHandleArray[0] = disposingWaitHandle;
+                               _waitHandleArray[1] = semaphoreAvailableWaitHandle;
+                               return _waitHandleArray;
+                           });
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                           .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                           {
+                               var asyncResult = new SftpReadAsyncResult(callback, state);
+                               asyncResult.SetAsCompleted(_chunk1, false);
+                           })
+                           .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.BeginRead(_handle, ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                            .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                            {
+                                ThreadAbstraction.ExecuteThread(() =>
+                                {
+                                    // signal that we're in the read-ahead for chunk2
+                                    _readAheadChunk2.Set();
+                                    // wait for client to start reading this chunk
+                                    _readChunk2.WaitOne(TimeSpan.FromSeconds(5));
+                                    // sleep a short time to make sure the client is in the blocking wait
+                                    Thread.Sleep(500);
+                                    // complete async read of chunk2 with exception
+                                    var asyncResult = new SftpReadAsyncResult(callback, state);
+                                    asyncResult.SetAsCompleted(_exception, false);
+                                });
+                            })
+                           .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            // use a max. read-ahead of 1 to allow us to verify that the next read-ahead is not done
+            // when a read-ahead has failed
+            _reader = new SftpFileReader(_handle, SftpSessionMock.Object, ChunkLength, 1, _fileSize);
+        }
+
+        protected override void Act()
+        {
+            _reader.Read();
+
+            // wait until SftpFileReader has starting reading ahead chunk 2
+            Assert.IsTrue(_readAheadChunk2.WaitOne(TimeSpan.FromSeconds(5)));
+            // signal that we are about to read chunk 2
+            _readChunk2.Set();
+
+            try
+            {
+                _reader.Read();
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void ReadOfSecondChunkShouldThrowExceptionThatOccurredInReadAhead()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.AreSame(_exception, _actualException);
+        }
+
+        [TestMethod]
+        public void ReadAfterReadAheadExceptionShouldRethrowExceptionThatOccurredInReadAhead()
+        {
+            try
+            {
+                _reader.Read();
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.AreSame(_exception, ex);
+            }
+        }
+
+        [TestMethod]
+        public void DisposeShouldCloseHandleAndCompleteImmediately()
+        {
+            SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult));
+
+            var stopwatch = Stopwatch.StartNew();
+            _reader.Dispose();
+            stopwatch.Stop();
+
+            Assert.IsTrue(stopwatch.ElapsedMilliseconds < 200, "Dispose took too long to complete: " + stopwatch.ElapsedMilliseconds);
+
+            SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
+            SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
+        }
+
+        [TestMethod]
+        public void ExceptionInReadAheadShouldPreventFurtherReadAheads()
+        {
+            SftpSessionMock.Verify(p => p.BeginRead(_handle, 2 * ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()), Times.Never);
+        }
+    }
+}

+ 11 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackBeginReadException.cs

@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    class SftpFileReaderTest_ReadBackBeginReadException
+    {
+    }
+}

+ 11 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackEndInvokeException.cs

@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    class SftpFileReaderTest_ReadBackEndInvokeException
+    {
+    }
+}

+ 138 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_ChunkAvailable.cs

@@ -0,0 +1,138 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Common;
+using Renci.SshNet.Sftp;
+using System;
+using System.Diagnostics;
+using System.Threading;
+using BufferedRead = Renci.SshNet.Sftp.SftpFileReader.BufferedRead;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_ChunkAvailable : SftpFileReaderTestBase
+    {
+        private const int ChunkLength = 32 * 1024;
+
+        private MockSequence _seq;
+        private byte[] _handle;
+        private int _fileSize;
+        private WaitHandle[] _waitHandleArray;
+        private int _operationTimeout;
+        private SftpCloseAsyncResult _closeAsyncResult;
+        private byte[] _chunk1;
+        private byte[] _chunk2;
+        private SftpFileReader _reader;
+        private SshException _exception;
+        private ManualResetEvent _exceptionSignaled;
+        private SshException _actualException;
+
+        protected override void SetupData()
+        {
+            var random = new Random();
+
+            _handle = CreateByteArray(random, 5);
+            _chunk1 = CreateByteArray(random, ChunkLength);
+            _chunk2 = CreateByteArray(random, ChunkLength);
+            _fileSize = _chunk1.Length + _chunk2.Length + 1;
+            _waitHandleArray = new WaitHandle[2];
+            _operationTimeout = random.Next(10000, 20000);
+            _closeAsyncResult = new SftpCloseAsyncResult(null, null);
+
+            _exception = new SshException();
+            _exceptionSignaled = new ManualResetEvent(false);
+        }
+
+        protected override void SetupMocks()
+        {
+            _seq = new MockSequence();
+
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.CreateWaitHandleArray(It.IsNotNull<WaitHandle>(), It.IsNotNull<WaitHandle>()))
+                           .Returns<WaitHandle, WaitHandle>((disposingWaitHandle, semaphoreAvailableWaitHandle) =>
+                               {
+                                   _waitHandleArray[0] = disposingWaitHandle;
+                                   _waitHandleArray[1] = semaphoreAvailableWaitHandle;
+                                   return _waitHandleArray;
+                               });
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                            .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                            {
+                                var asyncResult = new SftpReadAsyncResult(callback, state);
+                                asyncResult.SetAsCompleted(_chunk1, false);
+                            })
+                           .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Callback(() => _exceptionSignaled.Set())
+                           .Throws(_exception);
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _reader = new SftpFileReader(_handle, SftpSessionMock.Object, ChunkLength, 2, _fileSize);
+        }
+
+        protected override void Act()
+        {
+            // wait for the exception to be signaled by the second call to WaitAny
+            _exceptionSignaled.WaitOne(5000);
+            // allow a little time to allow SftpFileReader to process exception
+            Thread.Sleep(100);
+            try
+            {
+                _reader.Read();
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void ReadShouldHaveRethrownExceptionThrownByWaitAny()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.AreSame(_exception, _actualException);
+        }
+
+        [TestMethod]
+        public void ReadShouldRethrowExceptionThrownByWaitAny()
+        {
+            try
+            {
+                _reader.Read();
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.AreSame(_exception, ex);
+            }
+        }
+
+        [TestMethod]
+        public void DisposeShouldCloseHandleAndCompleteImmediately()
+        {
+            SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult));
+
+            var stopwatch = Stopwatch.StartNew();
+            _reader.Dispose();
+            stopwatch.Stop();
+
+            Assert.IsTrue(stopwatch.ElapsedMilliseconds < 200, "Dispose took too long to complete: " + stopwatch.ElapsedMilliseconds);
+
+            SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
+            SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
+        }
+    }
+}

+ 122 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_NoChunkAvailable.cs

@@ -0,0 +1,122 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Common;
+using Renci.SshNet.Sftp;
+using System;
+using System.Diagnostics;
+using System.Threading;
+using BufferedRead = Renci.SshNet.Sftp.SftpFileReader.BufferedRead;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_NoChunkAvailable : SftpFileReaderTestBase
+    {
+        private const int ChunkLength = 32 * 1024;
+
+        private MockSequence _seq;
+        private byte[] _handle;
+        private int _fileSize;
+        private WaitHandle[] _waitHandleArray;
+        private int _operationTimeout;
+        private SftpCloseAsyncResult _closeAsyncResult;
+        private SftpFileReader _reader;
+        private SshException _exception;
+        private SshException _actualException;
+
+        protected override void SetupData()
+        {
+            var random = new Random();
+
+            _handle = CreateByteArray(random, 5);
+            _fileSize = random.Next();
+            _waitHandleArray = new WaitHandle[2];
+            _operationTimeout = random.Next(10000, 20000);
+            _closeAsyncResult = new SftpCloseAsyncResult(null, null);
+
+            _exception = new SshException();
+        }
+
+        protected override void SetupMocks()
+        {
+            _seq = new MockSequence();
+
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.CreateWaitHandleArray(It.IsNotNull<WaitHandle>(), It.IsNotNull<WaitHandle>()))
+                           .Returns<WaitHandle, WaitHandle>((disposingWaitHandle, semaphoreAvailableWaitHandle) =>
+                           {
+                               _waitHandleArray[0] = disposingWaitHandle;
+                               _waitHandleArray[1] = semaphoreAvailableWaitHandle;
+                               return _waitHandleArray;
+                           });
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                           .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Throws(_exception);
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _reader = new SftpFileReader(_handle, SftpSessionMock.Object, ChunkLength, 1, _fileSize);
+        }
+
+        protected override void Act()
+        {
+            try
+            {
+                _reader.Read();
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void ReadShouldHaveRethrownExceptionThrownByWaitOnHandle()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.AreSame(_exception, _actualException);
+        }
+
+        [TestMethod]
+        public void ReadShouldRethrowExceptionThrownByWaitOnHandle()
+        {
+            try
+            {
+                _reader.Read();
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.AreSame(_exception, ex);
+            }
+        }
+
+        [TestMethod]
+        public void DisposeShouldCloseHandleAndCompleteImmediately()
+        {
+            SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult));
+
+            var stopwatch = Stopwatch.StartNew();
+            _reader.Dispose();
+            stopwatch.Stop();
+
+            Assert.IsTrue(stopwatch.ElapsedMilliseconds < 200, "Dispose took too long to complete: " + stopwatch.ElapsedMilliseconds);
+
+            SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
+            SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
+        }
+    }
+}

+ 166 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReahAheadExceptionInBeginRead.cs

@@ -0,0 +1,166 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Common;
+using Renci.SshNet.Sftp;
+using System;
+using System.Diagnostics;
+using System.Threading;
+using BufferedRead = Renci.SshNet.Sftp.SftpFileReader.BufferedRead;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileReaderTest_Read_ReahAheadExceptionInBeginRead : SftpFileReaderTestBase
+    {
+        private const int ChunkLength = 32 * 1024;
+
+        private MockSequence _seq;
+        private byte[] _handle;
+        private int _fileSize;
+        private WaitHandle[] _waitHandleArray;
+        private int _operationTimeout;
+        private SftpCloseAsyncResult _closeAsyncResult;
+        private byte[] _chunk1;
+        private byte[] _chunk2;
+        private SftpFileReader _reader;
+        private ManualResetEvent _readAheadChunk3;
+        private ManualResetEvent _readChunk3;
+        private SshException _exception;
+        private SshException _actualException;
+
+        protected override void SetupData()
+        {
+            var random = new Random();
+
+            _handle = CreateByteArray(random, 5);
+            _chunk1 = CreateByteArray(random, ChunkLength);
+            _chunk2 = CreateByteArray(random, ChunkLength);
+            _fileSize = _chunk1.Length + _chunk2.Length + 1;
+            _waitHandleArray = new WaitHandle[2];
+            _operationTimeout = random.Next(10000, 20000);
+            _closeAsyncResult = new SftpCloseAsyncResult(null, null);
+
+            _readAheadChunk3 = new ManualResetEvent(false);
+            _readChunk3 = new ManualResetEvent(false);
+
+            _exception = new SshException();
+        }
+
+        protected override void SetupMocks()
+        {
+            _seq = new MockSequence();
+
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.CreateWaitHandleArray(It.IsNotNull<WaitHandle>(), It.IsNotNull<WaitHandle>()))
+                           .Returns<WaitHandle, WaitHandle>((disposingWaitHandle, semaphoreAvailableWaitHandle) =>
+                           {
+                               _waitHandleArray[0] = disposingWaitHandle;
+                               _waitHandleArray[1] = semaphoreAvailableWaitHandle;
+                               return _waitHandleArray;
+                           });
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                           .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                                {
+                                    var asyncResult = new SftpReadAsyncResult(callback, state);
+                                    asyncResult.SetAsCompleted(_chunk1, false);
+                                })
+                           .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.BeginRead(_handle, ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                            .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                            {
+                                var asyncResult = new SftpReadAsyncResult(callback, state);
+                                asyncResult.SetAsCompleted(_chunk2, false);
+                            })
+                            .Returns((SftpReadAsyncResult)null);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout))
+                           .Returns(() => WaitAny(_waitHandleArray, _operationTimeout));
+            SftpSessionMock.InSequence(_seq)
+                            .Setup(p => p.BeginRead(_handle, 2 * ChunkLength, ChunkLength, It.IsNotNull<AsyncCallback>(), It.IsAny<BufferedRead>()))
+                            .Callback<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                            {
+                                _readAheadChunk3.Set();
+                                _readChunk3.WaitOne(TimeSpan.FromSeconds(5));
+                                // sleep a short time to make sure the client is in the blocking wait
+                                Thread.Sleep(500);
+                            })
+                            .Throws(_exception);
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _reader = new SftpFileReader(_handle, SftpSessionMock.Object, ChunkLength, 3, _fileSize);
+        }
+
+        protected override void Act()
+        {
+            _reader.Read();
+            _reader.Read();
+
+            // wait until we've the SftpFileReader has starting reading ahead chunk 3
+            Assert.IsTrue(_readAheadChunk3.WaitOne(TimeSpan.FromSeconds(5)));
+            // signal that we are about to read chunk 3
+            _readChunk3.Set();
+
+            try
+            {
+                _reader.Read();
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void ReadOfThirdChunkShouldThrowExceptionThatOccurredInReadAhead()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.AreSame(_exception, _actualException);
+        }
+
+        [TestMethod]
+        public void ReadAfterReadAheadExceptionShouldRethrowExceptionThatOccurredInReadAhead()
+        {
+            try
+            {
+                _reader.Read();
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.AreSame(_exception, ex);
+            }
+        }
+
+        [TestMethod]
+        public void DisposeShouldCloseHandleAndCompleteImmediately()
+        {
+            SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult);
+            SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult));
+
+            var stopwatch = Stopwatch.StartNew();
+            _reader.Dispose();
+            stopwatch.Stop();
+
+            Assert.IsTrue(stopwatch.ElapsedMilliseconds < 200, "Dispose took too long to complete: " + stopwatch.ElapsedMilliseconds);
+
+            SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
+            SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
+        }
+    }
+}

+ 65 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTestBase.cs

@@ -0,0 +1,65 @@
+using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    public abstract class SftpFileStreamTestBase
+    {
+        internal Mock<ISftpSession> SftpSessionMock;
+        protected MockSequence MockSequence;
+
+        protected virtual void Arrange()
+        {
+            SetupData();
+            CreateMocks();
+            SetupMocks();
+        }
+
+        protected virtual void SetupData()
+        {
+            MockSequence = new MockSequence();
+        }
+
+        protected abstract void SetupMocks();
+
+        private void CreateMocks()
+        {
+            SftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        }
+
+        [TestInitialize]
+        public void SetUp()
+        {
+            Arrange();
+            Act();
+        }
+
+        protected abstract void Act();
+
+        protected byte[] GenerateRandom(int length)
+        {
+            return GenerateRandom(length, new Random());
+        }
+
+        protected byte[] GenerateRandom(int length, Random random)
+        {
+            var buffer = new byte[length];
+            random.NextBytes(buffer);
+            return buffer;
+        }
+
+        protected byte[] GenerateRandom(uint length)
+        {
+            return GenerateRandom(length, new Random());
+        }
+
+        protected byte[] GenerateRandom(uint length, Random random)
+        {
+            var buffer = new byte[length];
+            random.NextBytes(buffer);
+            return buffer;
+        }
+    }
+}

+ 35 - 36
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessRead.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Globalization;
 using System.IO;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
@@ -8,61 +7,61 @@ using Renci.SshNet.Sftp;
 namespace Renci.SshNet.Tests.Classes.Sftp
 {
     [TestClass]
-    public class SftpFileStreamTest_CanRead_Closed_FileAccessRead
+    public class SftpFileStreamTest_CanRead_Closed_FileAccessRead : SftpFileStreamTestBase
     {
-        private Mock<ISftpSession> _sftpSessionMock;
+        private SftpFileStream _target;
         private string _path;
-        private SftpFileStream _sftpFileStream;
         private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
         private uint _bufferSize;
         private uint _readBufferSize;
         private uint _writeBufferSize;
         private bool _actual;
 
-        [TestInitialize]
-        public void Setup()
+        protected override void SetupData()
         {
-            Arrange();
-            Act();
-        }
+            base.SetupData();
 
-        protected void Arrange()
-        {
             var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] {(byte) random.Next(byte.MinValue, byte.MaxValue)};
-            _fileAttributes = SftpFileAttributes.Empty;
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(3, random);
             _bufferSize = (uint) random.Next(0, 1000);
             _readBufferSize = (uint) random.Next(0, 1000);
             _writeBufferSize = (uint) random.Next(0, 1000);
+        }
 
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestClose(_handle));
+        }
 
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
+        protected override void Arrange()
+        {
+            base.Arrange();
 
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Read, (int)_bufferSize);
-            _sftpFileStream.Close();
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.Read,
+                                         (int) _bufferSize);
+            _target.Close();
         }
 
-        protected void Act()
+        protected override void Act()
         {
-            _actual = _sftpFileStream.CanRead;
+            _actual = _target.CanRead;
         }
 
         [TestMethod]

+ 35 - 36
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessReadWrite.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Globalization;
 using System.IO;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
@@ -8,61 +7,61 @@ using Renci.SshNet.Sftp;
 namespace Renci.SshNet.Tests.Classes.Sftp
 {
     [TestClass]
-    public class SftpFileStreamTest_CanRead_Closed_FileAccessReadWrite
+    public class SftpFileStreamTest_CanRead_Closed_FileAccessReadWrite : SftpFileStreamTestBase
     {
-        private Mock<ISftpSession> _sftpSessionMock;
+        private SftpFileStream _target;
         private string _path;
-        private SftpFileStream _sftpFileStream;
         private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
         private uint _bufferSize;
         private uint _readBufferSize;
         private uint _writeBufferSize;
         private bool _actual;
 
-        [TestInitialize]
-        public void Setup()
+        protected override void SetupData()
         {
-            Arrange();
-            Act();
-        }
+            base.SetupData();
 
-        protected void Arrange()
-        {
             var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] {(byte) random.Next(byte.MinValue, byte.MaxValue)};
-            _fileAttributes = SftpFileAttributes.Empty;
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(3, random);
             _bufferSize = (uint) random.Next(0, 1000);
             _readBufferSize = (uint) random.Next(0, 1000);
             _writeBufferSize = (uint) random.Next(0, 1000);
+        }
 
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestClose(_handle));
+        }
 
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
+        protected override void Arrange()
+        {
+            base.Arrange();
 
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.ReadWrite, (int)_bufferSize);
-            _sftpFileStream.Close();
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.ReadWrite,
+                                         (int) _bufferSize);
+            _target.Close();
         }
 
-        protected void Act()
+        protected override void Act()
         {
-            _actual = _sftpFileStream.CanRead;
+            _actual = _target.CanRead;
         }
 
         [TestMethod]

+ 35 - 36
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessWrite.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Globalization;
 using System.IO;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
@@ -8,61 +7,61 @@ using Renci.SshNet.Sftp;
 namespace Renci.SshNet.Tests.Classes.Sftp
 {
     [TestClass]
-    public class SftpFileStreamTest_CanRead_Closed_FileAccessWrite
+    public class SftpFileStreamTest_CanRead_Closed_FileAccessWrite : SftpFileStreamTestBase
     {
-        private Mock<ISftpSession> _sftpSessionMock;
+        private SftpFileStream _target;
         private string _path;
-        private SftpFileStream _sftpFileStream;
         private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
         private uint _bufferSize;
         private uint _readBufferSize;
         private uint _writeBufferSize;
         private bool _actual;
 
-        [TestInitialize]
-        public void Setup()
+        protected override void SetupData()
         {
-            Arrange();
-            Act();
-        }
+            base.SetupData();
 
-        protected void Arrange()
-        {
             var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] {(byte) random.Next(byte.MinValue, byte.MaxValue)};
-            _fileAttributes = SftpFileAttributes.Empty;
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(3, random);
             _bufferSize = (uint) random.Next(0, 1000);
             _readBufferSize = (uint) random.Next(0, 1000);
             _writeBufferSize = (uint) random.Next(0, 1000);
+        }
 
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Write, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestClose(_handle));
+        }
 
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
+        protected override void Arrange()
+        {
+            base.Arrange();
 
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Write, (int)_bufferSize);
-            _sftpFileStream.Close();
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.Write,
+                                         (int) _bufferSize);
+            _target.Close();
         }
 
-        protected void Act()
+        protected override void Act()
         {
-            _actual = _sftpFileStream.CanRead;
+            _actual = _target.CanRead;
         }
 
         [TestMethod]

+ 38 - 39
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessRead.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Globalization;
 using System.IO;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
@@ -8,61 +7,61 @@ using Renci.SshNet.Sftp;
 namespace Renci.SshNet.Tests.Classes.Sftp
 {
     [TestClass]
-    public class SftpFileStreamTest_CanRead_Disposed_FileAccessRead
+    public class SftpFileStreamTest_CanRead_Disposed_FileAccessRead : SftpFileStreamTestBase
     {
-        private Mock<ISftpSession> _sftpSessionMock;
+        private SftpFileStream _target;
         private string _path;
-        private SftpFileStream _sftpFileStream;
         private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
         private uint _bufferSize;
         private uint _readBufferSize;
         private uint _writeBufferSize;
         private bool _actual;
 
-        [TestInitialize]
-        public void Setup()
+        protected override void SetupData()
         {
-            Arrange();
-            Act();
-        }
+            base.SetupData();
 
-        protected void Arrange()
-        {
             var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] { (byte)random.Next(byte.MinValue, byte.MaxValue) };
-            _fileAttributes = SftpFileAttributes.Empty;
-            _bufferSize = (uint)random.Next(0, 1000);
-            _readBufferSize = (uint)random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(1, random);
+            _bufferSize = (uint) random.Next(0, 1000);
+            _readBufferSize = (uint) random.Next(0, 1000);
+            _writeBufferSize = (uint) random.Next(0, 1000);
+        }
 
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestClose(_handle));
+        }
 
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
+        protected override void Arrange()
+        {
+            base.Arrange();
 
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Read, (int)_bufferSize);
-            _sftpFileStream.Dispose();
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.Read,
+                                         (int) _bufferSize);
+            _target.Dispose();
         }
 
-        protected void Act()
+        protected override void Act()
         {
-            _actual = _sftpFileStream.CanRead;
+            _actual = _target.CanRead;
         }
 
         [TestMethod]

+ 38 - 39
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessReadWrite.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Globalization;
 using System.IO;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
@@ -8,61 +7,61 @@ using Renci.SshNet.Sftp;
 namespace Renci.SshNet.Tests.Classes.Sftp
 {
     [TestClass]
-    public class SftpFileStreamTest_CanRead_Disposed_FileAccessReadWrite
+    public class SftpFileStreamTest_CanRead_Disposed_FileAccessReadWrite : SftpFileStreamTestBase
     {
-        private Mock<ISftpSession> _sftpSessionMock;
+        private SftpFileStream _target;
         private string _path;
-        private SftpFileStream _sftpFileStream;
         private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
         private uint _bufferSize;
         private uint _readBufferSize;
         private uint _writeBufferSize;
         private bool _actual;
 
-        [TestInitialize]
-        public void Setup()
+        protected override void SetupData()
         {
-            Arrange();
-            Act();
-        }
+            base.SetupData();
 
-        protected void Arrange()
-        {
             var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] { (byte)random.Next(byte.MinValue, byte.MaxValue) };
-            _fileAttributes = SftpFileAttributes.Empty;
-            _bufferSize = (uint)random.Next(0, 1000);
-            _readBufferSize = (uint)random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(1, random);
+            _bufferSize = (uint) random.Next(0, 1000);
+            _readBufferSize = (uint) random.Next(0, 1000);
+            _writeBufferSize = (uint) random.Next(0, 1000);
+        }
 
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestClose(_handle));
+        }
 
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
+        protected override void Arrange()
+        {
+            base.Arrange();
 
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.ReadWrite, (int)_bufferSize);
-            _sftpFileStream.Dispose();
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.ReadWrite,
+                                         (int) _bufferSize);
+            _target.Dispose();
         }
 
-        protected void Act()
+        protected override void Act()
         {
-            _actual = _sftpFileStream.CanRead;
+            _actual = _target.CanRead;
         }
 
         [TestMethod]

+ 38 - 39
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessWrite.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Globalization;
 using System.IO;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
@@ -8,61 +7,61 @@ using Renci.SshNet.Sftp;
 namespace Renci.SshNet.Tests.Classes.Sftp
 {
     [TestClass]
-    public class SftpFileStreamTest_CanRead_Disposed_FileAccessWrite
+    public class SftpFileStreamTest_CanRead_Disposed_FileAccessWrite : SftpFileStreamTestBase
     {
-        private Mock<ISftpSession> _sftpSessionMock;
+        private SftpFileStream _target;
         private string _path;
-        private SftpFileStream _sftpFileStream;
         private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
         private uint _bufferSize;
         private uint _readBufferSize;
         private uint _writeBufferSize;
         private bool _actual;
 
-        [TestInitialize]
-        public void Setup()
+        protected override void SetupData()
         {
-            Arrange();
-            Act();
-        }
+            base.SetupData();
 
-        protected void Arrange()
-        {
             var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] { (byte)random.Next(byte.MinValue, byte.MaxValue) };
-            _fileAttributes = SftpFileAttributes.Empty;
-            _bufferSize = (uint)random.Next(0, 1000);
-            _readBufferSize = (uint)random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(1, random);
+            _bufferSize = (uint) random.Next(0, 1000);
+            _readBufferSize = (uint) random.Next(0, 1000);
+            _writeBufferSize = (uint) random.Next(0, 1000);
+        }
 
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Write, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestClose(_handle));
+        }
 
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
+        protected override void Arrange()
+        {
+            base.Arrange();
 
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Write, (int)_bufferSize);
-            _sftpFileStream.Dispose();
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.Write,
+                                         (int) _bufferSize);
+            _target.Dispose();
         }
 
-        protected void Act()
+        protected override void Act()
         {
-            _actual = _sftpFileStream.CanRead;
+            _actual = _target.CanRead;
         }
 
         [TestMethod]

+ 0 - 73
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_SessionOpen_FileAccessRead.cs

@@ -1,73 +0,0 @@
-using System;
-using System.Globalization;
-using System.IO;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Moq;
-using Renci.SshNet.Sftp;
-
-namespace Renci.SshNet.Tests.Classes.Sftp
-{
-    [TestClass]
-    public class SftpFileStreamTest_CanRead_SessionOpen_FileAccessRead
-    {
-        private Mock<ISftpSession> _sftpSessionMock;
-        private string _path;
-        private SftpFileStream _sftpFileStream;
-        private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
-        private uint _bufferSize;
-        private uint _readBufferSize;
-        private uint _writeBufferSize;
-        private bool _actual;
-
-        [TestInitialize]
-        public void Setup()
-        {
-            Arrange();
-            Act();
-        }
-
-        protected void Arrange()
-        {
-            var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] { (byte)random.Next(byte.MinValue, byte.MaxValue) };
-            _fileAttributes = SftpFileAttributes.Empty;
-            _bufferSize = (uint)random.Next(0, 1000);
-            _readBufferSize = (uint)random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
-
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
-
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
-
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Read, (int)_bufferSize);
-        }
-
-        protected void Act()
-        {
-            _actual = _sftpFileStream.CanRead;
-        }
-
-        [TestMethod]
-        public void CanReadShouldReturnTrue()
-        {
-            Assert.IsTrue(_actual);
-        }
-    }
-}

+ 0 - 73
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_SessionOpen_FileAccessReadWrite.cs

@@ -1,73 +0,0 @@
-using System;
-using System.Globalization;
-using System.IO;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Moq;
-using Renci.SshNet.Sftp;
-
-namespace Renci.SshNet.Tests.Classes.Sftp
-{
-    [TestClass]
-    public class SftpFileStreamTest_CanRead_SessionOpen_FileAccessReadWrite
-    {
-        private Mock<ISftpSession> _sftpSessionMock;
-        private string _path;
-        private SftpFileStream _sftpFileStream;
-        private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
-        private uint _bufferSize;
-        private uint _readBufferSize;
-        private uint _writeBufferSize;
-        private bool _actual;
-
-        [TestInitialize]
-        public void Setup()
-        {
-            Arrange();
-            Act();
-        }
-
-        protected void Arrange()
-        {
-            var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] { (byte)random.Next(byte.MinValue, byte.MaxValue) };
-            _fileAttributes = SftpFileAttributes.Empty;
-            _bufferSize = (uint)random.Next(0, 1000);
-            _readBufferSize = (uint)random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
-
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
-
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
-
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.ReadWrite, (int)_bufferSize);
-        }
-
-        protected void Act()
-        {
-            _actual = _sftpFileStream.CanRead;
-        }
-
-        [TestMethod]
-        public void CanReadShouldReturnTrue()
-        {
-            Assert.IsTrue(_actual);
-        }
-    }
-}

+ 0 - 73
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_SessionOpen_FileAccessWrite.cs

@@ -1,73 +0,0 @@
-using System;
-using System.Globalization;
-using System.IO;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Moq;
-using Renci.SshNet.Sftp;
-
-namespace Renci.SshNet.Tests.Classes.Sftp
-{
-    [TestClass]
-    public class SftpFileStreamTest_CanRead_SessionOpen_FileAccessWrite
-    {
-        private Mock<ISftpSession> _sftpSessionMock;
-        private string _path;
-        private SftpFileStream _sftpFileStream;
-        private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
-        private uint _bufferSize;
-        private uint _readBufferSize;
-        private uint _writeBufferSize;
-        private bool _actual;
-
-        [TestInitialize]
-        public void Setup()
-        {
-            Arrange();
-            Act();
-        }
-
-        protected void Arrange()
-        {
-            var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] { (byte)random.Next(byte.MinValue, byte.MaxValue) };
-            _fileAttributes = SftpFileAttributes.Empty;
-            _bufferSize = (uint)random.Next(0, 1000);
-            _readBufferSize = (uint)random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
-
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
-
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
-
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Write, (int)_bufferSize);
-        }
-
-        protected void Act()
-        {
-            _actual = _sftpFileStream.CanRead;
-        }
-
-        [TestMethod]
-        public void CanReadShouldReturnFalse()
-        {
-            Assert.IsFalse(_actual);
-        }
-    }
-}

+ 38 - 39
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessRead.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Globalization;
 using System.IO;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
@@ -8,61 +7,61 @@ using Renci.SshNet.Sftp;
 namespace Renci.SshNet.Tests.Classes.Sftp
 {
     [TestClass]
-    public class SftpFileStreamTest_CanWrite_Closed_FileAccessRead
+    public class SftpFileStreamTest_CanWrite_Closed_FileAccessRead : SftpFileStreamTestBase
     {
-        private Mock<ISftpSession> _sftpSessionMock;
+        private SftpFileStream _target;
         private string _path;
-        private SftpFileStream _sftpFileStream;
         private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
         private uint _bufferSize;
         private uint _readBufferSize;
         private uint _writeBufferSize;
         private bool _actual;
 
-        [TestInitialize]
-        public void Setup()
+        protected override void SetupData()
         {
-            Arrange();
-            Act();
-        }
+            base.SetupData();
 
-        protected void Arrange()
-        {
             var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] { (byte)random.Next(byte.MinValue, byte.MaxValue) };
-            _fileAttributes = SftpFileAttributes.Empty;
-            _bufferSize = (uint)random.Next(0, 1000);
-            _readBufferSize = (uint)random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(1, random);
+            _bufferSize = (uint) random.Next(0, 1000);
+            _readBufferSize = (uint) random.Next(0, 1000);
+            _writeBufferSize = (uint) random.Next(0, 1000);
+        }
 
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestClose(_handle));
+        }
 
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
+        protected override void Arrange()
+        {
+            base.Arrange();
 
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Read, (int)_bufferSize);
-            _sftpFileStream.Close();
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.Read,
+                                         (int) _bufferSize);
+            _target.Close();
         }
 
-        protected void Act()
+        protected override void Act()
         {
-            _actual = _sftpFileStream.CanWrite;
+            _actual = _target.CanWrite;
         }
 
         [TestMethod]

+ 38 - 39
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessReadWrite.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Globalization;
 using System.IO;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
@@ -8,61 +7,61 @@ using Renci.SshNet.Sftp;
 namespace Renci.SshNet.Tests.Classes.Sftp
 {
     [TestClass]
-    public class SftpFileStreamTest_CanWrite_Closed_FileAccessReadWrite
+    public class SftpFileStreamTest_CanWrite_Closed_FileAccessReadWrite : SftpFileStreamTestBase
     {
-        private Mock<ISftpSession> _sftpSessionMock;
+        private SftpFileStream _target;
         private string _path;
-        private SftpFileStream _sftpFileStream;
         private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
         private uint _bufferSize;
         private uint _readBufferSize;
         private uint _writeBufferSize;
         private bool _actual;
 
-        [TestInitialize]
-        public void Setup()
+        protected override void SetupData()
         {
-            Arrange();
-            Act();
-        }
+            base.SetupData();
 
-        protected void Arrange()
-        {
             var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] {(byte) random.Next(byte.MinValue, byte.MaxValue)};
-            _fileAttributes = SftpFileAttributes.Empty;
-            _bufferSize = (uint)random.Next(0, 1000);
-            _readBufferSize = (uint)random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(1, random);
+            _bufferSize = (uint) random.Next(0, 1000);
+            _readBufferSize = (uint) random.Next(0, 1000);
+            _writeBufferSize = (uint) random.Next(0, 1000);
+        }
 
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestClose(_handle));
+        }
 
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
+        protected override void Arrange()
+        {
+            base.Arrange();
 
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.ReadWrite, (int)_bufferSize);
-            _sftpFileStream.Close();
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.ReadWrite,
+                                         (int) _bufferSize);
+            _target.Close();
         }
 
-        protected void Act()
+        protected override void Act()
         {
-            _actual = _sftpFileStream.CanWrite;
+            _actual = _target.CanWrite;
         }
 
         [TestMethod]

+ 38 - 39
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessWrite.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Globalization;
 using System.IO;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
@@ -8,61 +7,61 @@ using Renci.SshNet.Sftp;
 namespace Renci.SshNet.Tests.Classes.Sftp
 {
     [TestClass]
-    public class SftpFileStreamTest_CanWrite_Closed_FileAccessWrite
+    public class SftpFileStreamTest_CanWrite_Closed_FileAccessWrite : SftpFileStreamTestBase
     {
-        private Mock<ISftpSession> _sftpSessionMock;
+        private SftpFileStream _target;
         private string _path;
-        private SftpFileStream _sftpFileStream;
         private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
         private uint _bufferSize;
         private uint _readBufferSize;
         private uint _writeBufferSize;
         private bool _actual;
 
-        [TestInitialize]
-        public void Setup()
+        protected override void SetupData()
         {
-            Arrange();
-            Act();
-        }
+            base.SetupData();
 
-        protected void Arrange()
-        {
             var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] { (byte)random.Next(byte.MinValue, byte.MaxValue) };
-            _fileAttributes = SftpFileAttributes.Empty;
-            _bufferSize = (uint)random.Next(0, 1000);
-            _readBufferSize = (uint)random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(1, random);
+            _bufferSize = (uint) random.Next(0, 1000);
+            _readBufferSize = (uint) random.Next(0, 1000);
+            _writeBufferSize = (uint) random.Next(0, 1000);
+        }
 
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Write, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestClose(_handle));
+        }
 
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
+        protected override void Arrange()
+        {
+            base.Arrange();
 
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Write, (int)_bufferSize);
-            _sftpFileStream.Close();
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.Write,
+                                         (int) _bufferSize);
+            _target.Close();
         }
 
-        protected void Act()
+        protected override void Act()
         {
-            _actual = _sftpFileStream.CanWrite;
+            _actual = _target.CanWrite;
         }
 
         [TestMethod]

+ 38 - 39
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessRead.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Globalization;
 using System.IO;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
@@ -8,61 +7,61 @@ using Renci.SshNet.Sftp;
 namespace Renci.SshNet.Tests.Classes.Sftp
 {
     [TestClass]
-    public class SftpFileStreamTest_CanWrite_Disposed_FileAccessRead
+    public class SftpFileStreamTest_CanWrite_Disposed_FileAccessRead : SftpFileStreamTestBase
     {
-        private Mock<ISftpSession> _sftpSessionMock;
+        private SftpFileStream _target;
         private string _path;
-        private SftpFileStream _sftpFileStream;
         private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
         private uint _bufferSize;
         private uint _readBufferSize;
         private uint _writeBufferSize;
         private bool _actual;
 
-        [TestInitialize]
-        public void Setup()
+        protected override void SetupData()
         {
-            Arrange();
-            Act();
-        }
+            base.SetupData();
 
-        protected void Arrange()
-        {
             var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] { (byte)random.Next(byte.MinValue, byte.MaxValue) };
-            _fileAttributes = SftpFileAttributes.Empty;
-            _bufferSize = (uint)random.Next(0, 1000);
-            _readBufferSize = (uint)random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(1, random);
+            _bufferSize = (uint) random.Next(0, 1000);
+            _readBufferSize = (uint) random.Next(0, 1000);
+            _writeBufferSize = (uint) random.Next(0, 1000);
+        }
 
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestClose(_handle));
+        }
 
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
+        protected override void Arrange()
+        {
+            base.Arrange();
 
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Read, (int)_bufferSize);
-            _sftpFileStream.Dispose();
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.Read,
+                                         (int) _bufferSize);
+            _target.Dispose();
         }
 
-        protected void Act()
+        protected override void Act()
         {
-            _actual = _sftpFileStream.CanWrite;
+            _actual = _target.CanWrite;
         }
 
         [TestMethod]

+ 38 - 39
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessReadWrite.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Globalization;
 using System.IO;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
@@ -8,61 +7,61 @@ using Renci.SshNet.Sftp;
 namespace Renci.SshNet.Tests.Classes.Sftp
 {
     [TestClass]
-    public class SftpFileStreamTest_CanWrite_Disposed_FileAccessReadWrite
+    public class SftpFileStreamTest_CanWrite_Disposed_FileAccessReadWrite : SftpFileStreamTestBase
     {
-        private Mock<ISftpSession> _sftpSessionMock;
+        private SftpFileStream _target;
         private string _path;
-        private SftpFileStream _sftpFileStream;
         private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
         private uint _bufferSize;
         private uint _readBufferSize;
         private uint _writeBufferSize;
         private bool _actual;
 
-        [TestInitialize]
-        public void Setup()
+        protected override void SetupData()
         {
-            Arrange();
-            Act();
-        }
+            base.SetupData();
 
-        protected void Arrange()
-        {
             var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] { (byte)random.Next(byte.MinValue, byte.MaxValue) };
-            _fileAttributes = SftpFileAttributes.Empty;
-            _bufferSize = (uint)random.Next(0, 1000);
-            _readBufferSize = (uint)random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(1, random);
+            _bufferSize = (uint) random.Next(0, 1000);
+            _readBufferSize = (uint) random.Next(0, 1000);
+            _writeBufferSize = (uint) random.Next(0, 1000);
+        }
 
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read |Flags.Write, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestClose(_handle));
+        }
 
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
+        protected override void Arrange()
+        {
+            base.Arrange();
 
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.ReadWrite, (int)_bufferSize);
-            _sftpFileStream.Dispose();
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.ReadWrite,
+                                         (int) _bufferSize);
+            _target.Dispose();
         }
 
-        protected void Act()
+        protected override void Act()
         {
-            _actual = _sftpFileStream.CanWrite;
+            _actual = _target.CanWrite;
         }
 
         [TestMethod]

+ 35 - 39
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessWrite.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Globalization;
 using System.IO;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
@@ -8,61 +7,58 @@ using Renci.SshNet.Sftp;
 namespace Renci.SshNet.Tests.Classes.Sftp
 {
     [TestClass]
-    public class SftpFileStreamTest_CanWrite_Disposed_FileAccessWrite
+    public class SftpFileStreamTest_CanWrite_Disposed_FileAccessWrite : SftpFileStreamTestBase
     {
-        private Mock<ISftpSession> _sftpSessionMock;
+        private SftpFileStream _target;
         private string _path;
-        private SftpFileStream _sftpFileStream;
         private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
         private uint _bufferSize;
         private uint _readBufferSize;
         private uint _writeBufferSize;
         private bool _actual;
 
-        [TestInitialize]
-        public void Setup()
+        protected override void SetupData()
         {
-            Arrange();
-            Act();
-        }
+            base.SetupData();
 
-        protected void Arrange()
-        {
             var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] { (byte)random.Next(byte.MinValue, byte.MaxValue) };
-            _fileAttributes = SftpFileAttributes.Empty;
-            _bufferSize = (uint)random.Next(0, 1000);
-            _readBufferSize = (uint)random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(1, random);
+            _bufferSize = (uint) random.Next(0, 1000);
+            _readBufferSize = (uint) random.Next(0, 1000);
+            _writeBufferSize = (uint) random.Next(0, 1000);
+        }
 
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Write, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestClose(_handle));
+        }
 
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
+        protected override void Arrange()
+        {
+            base.Arrange();
 
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Write, (int)_bufferSize);
-            _sftpFileStream.Dispose();
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.Write,
+                                         (int) _bufferSize);
+            _target.Dispose();
         }
 
-        protected void Act()
+        protected override void Act()
         {
-            _actual = _sftpFileStream.CanWrite;
+            _actual = _target.CanWrite;
         }
 
         [TestMethod]

+ 0 - 73
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_SessionOpen_FileAccessRead.cs

@@ -1,73 +0,0 @@
-using System;
-using System.Globalization;
-using System.IO;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Moq;
-using Renci.SshNet.Sftp;
-
-namespace Renci.SshNet.Tests.Classes.Sftp
-{
-    [TestClass]
-    public class SftpFileStreamTest_CanWrite_SessionOpen_FileAccessRead
-    {
-        private Mock<ISftpSession> _sftpSessionMock;
-        private string _path;
-        private SftpFileStream _sftpFileStream;
-        private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
-        private uint _bufferSize;
-        private uint _readBufferSize;
-        private uint _writeBufferSize;
-        private bool _actual;
-
-        [TestInitialize]
-        public void Setup()
-        {
-            Arrange();
-            Act();
-        }
-
-        protected void Arrange()
-        {
-            var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] {(byte) random.Next(byte.MinValue, byte.MaxValue)};
-            _fileAttributes = SftpFileAttributes.Empty;
-            _bufferSize = (uint)random.Next(0, 1000);
-            _readBufferSize = (uint)random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
-
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
-
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
-
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Read, (int)_bufferSize);
-        }
-
-        protected void Act()
-        {
-            _actual = _sftpFileStream.CanWrite;
-        }
-
-        [TestMethod]
-        public void CaWriteShouldReturnFalse()
-        {
-            Assert.IsFalse(_actual);
-        }
-    }
-}

+ 0 - 73
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_SessionOpen_FileAccessReadWrite.cs

@@ -1,73 +0,0 @@
-using System;
-using System.Globalization;
-using System.IO;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Moq;
-using Renci.SshNet.Sftp;
-
-namespace Renci.SshNet.Tests.Classes.Sftp
-{
-    [TestClass]
-    public class SftpFileStreamTest_CanWrite_SessionOpen_FileAccessReadWrite
-    {
-        private Mock<ISftpSession> _sftpSessionMock;
-        private string _path;
-        private SftpFileStream _sftpFileStream;
-        private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
-        private uint _bufferSize;
-        private uint _readBufferSize;
-        private uint _writeBufferSize;
-        private bool _actual;
-
-        [TestInitialize]
-        public void Setup()
-        {
-            Arrange();
-            Act();
-        }
-
-        protected void Arrange()
-        {
-            var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] {(byte) random.Next(byte.MinValue, byte.MaxValue)};
-            _fileAttributes = SftpFileAttributes.Empty;
-            _bufferSize = (uint)random.Next(0, 1000);
-            _readBufferSize = (uint)random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
-
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
-
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
-
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.ReadWrite, (int)_bufferSize);
-        }
-
-        protected void Act()
-        {
-            _actual = _sftpFileStream.CanWrite;
-        }
-
-        [TestMethod]
-        public void CanWriteShouldReturnTrue()
-        {
-            Assert.IsTrue(_actual);
-        }
-    }
-}

+ 0 - 73
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_SessionOpen_FileAccessWrite.cs

@@ -1,73 +0,0 @@
-using System;
-using System.Globalization;
-using System.IO;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Moq;
-using Renci.SshNet.Sftp;
-
-namespace Renci.SshNet.Tests.Classes.Sftp
-{
-    [TestClass]
-    public class SftpFileStreamTest_CanWrite_SessionOpen_FileAccessWrite
-    {
-        private Mock<ISftpSession> _sftpSessionMock;
-        private string _path;
-        private SftpFileStream _sftpFileStream;
-        private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
-        private uint _bufferSize;
-        private uint _readBufferSize;
-        private uint _writeBufferSize;
-        private bool _actual;
-
-        [TestInitialize]
-        public void Setup()
-        {
-            Arrange();
-            Act();
-        }
-
-        protected void Arrange()
-        {
-            var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] { (byte)random.Next(byte.MinValue, byte.MaxValue) };
-            _fileAttributes = SftpFileAttributes.Empty;
-            _bufferSize = (uint)random.Next(0, 1000);
-            _readBufferSize = (uint)random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
-
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
-
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
-
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Write, (int)_bufferSize);
-        }
-
-        protected void Act()
-        {
-            _actual = _sftpFileStream.CanWrite;
-        }
-
-        [TestMethod]
-        public void CanWriteShouldReturnTrue()
-        {
-            Assert.IsTrue(_actual);
-        }
-    }
-}

+ 2 - 5
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Closed.cs

@@ -14,7 +14,6 @@ namespace Renci.SshNet.Tests.Classes.Sftp
         private string _path;
         private SftpFileStream _sftpFileStream;
         private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
         private uint _bufferSize;
         private uint _readBufferSize;
         private uint _writeBufferSize;
@@ -31,7 +30,6 @@ namespace Renci.SshNet.Tests.Classes.Sftp
             var random = new Random();
             _path = random.Next().ToString(CultureInfo.InvariantCulture);
             _handle = new[] { (byte)random.Next(byte.MinValue, byte.MaxValue) };
-            _fileAttributes = SftpFileAttributes.Empty;
             _bufferSize = (uint)random.Next(1, 1000);
             _readBufferSize = (uint)random.Next(0, 1000);
             _writeBufferSize = (uint)random.Next(0, 1000);
@@ -40,9 +38,8 @@ namespace Renci.SshNet.Tests.Classes.Sftp
 
             var sequence = new MockSequence();
             _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Truncate, true))
+                .Setup(p => p.RequestOpen(_path, Flags.Read, false))
                 .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
             _sftpSessionMock.InSequence(sequence)
                 .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
                 .Returns(_readBufferSize);
@@ -55,7 +52,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
             _sftpSessionMock.InSequence(sequence)
                 .Setup(p => p.RequestClose(_handle));
 
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Read, (int)_bufferSize);
+            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Open, FileAccess.Read, (int)_bufferSize);
             _sftpFileStream.Close();
         }
 

+ 37 - 41
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Disposed.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Globalization;
 using System.IO;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
@@ -8,72 +7,69 @@ using Renci.SshNet.Sftp;
 namespace Renci.SshNet.Tests.Classes.Sftp
 {
     [TestClass]
-    public class SftpFileStreamTest_Close_Disposed
+    public class SftpFileStreamTest_Close_Disposed : SftpFileStreamTestBase
     {
-        private Mock<ISftpSession> _sftpSessionMock;
+        private SftpFileStream _target;
         private string _path;
-        private SftpFileStream _sftpFileStream;
         private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
         private uint _bufferSize;
         private uint _readBufferSize;
         private uint _writeBufferSize;
 
-        [TestInitialize]
-        public void Setup()
+        protected override void SetupData()
         {
-            Arrange();
-            Act();
-        }
+            base.SetupData();
 
-        protected void Arrange()
-        {
             var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] { (byte)random.Next(byte.MinValue, byte.MaxValue) };
-            _fileAttributes = SftpFileAttributes.Empty;
-            _bufferSize = (uint)random.Next(1, 1000);
-            _readBufferSize = (uint)random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(2, random);
+            _bufferSize = (uint) random.Next(1, 1000);
+            _readBufferSize = (uint) random.Next(0, 1000);
+            _writeBufferSize = (uint) random.Next(0, 1000);
+        }
 
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestClose(_handle));
+        }
 
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
+        protected override void Arrange()
+        {
+            base.Arrange();
 
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Read, (int)_bufferSize);
-            _sftpFileStream.Dispose();
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.Read,
+                                         (int) _bufferSize);
+            _target.Dispose();
         }
 
-        protected void Act()
+        protected override void Act()
         {
-            _sftpFileStream.Close();
+            _target.Close();
         }
 
         [TestMethod]
         public void IsOpenOnSftpSessionShouldBeInvokedOnce()
         {
-            _sftpSessionMock.Verify(p => p.IsOpen, Times.Once);
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Once);
         }
 
         [TestMethod]
         public void RequestCloseOnSftpSessionShouldBeInvokedOnce()
         {
-            _sftpSessionMock.Verify(p => p.RequestClose(_handle), Times.Once);
+            SftpSessionMock.Verify(p => p.RequestClose(_handle), Times.Once);
         }
     }
 }

+ 37 - 38
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionNotOpen.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Globalization;
 using System.IO;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
@@ -8,69 +7,69 @@ using Renci.SshNet.Sftp;
 namespace Renci.SshNet.Tests.Classes.Sftp
 {
     [TestClass]
-    public class SftpFileStreamTest_Close_SessionNotOpen
+    public class SftpFileStreamTest_Close_SessionNotOpen : SftpFileStreamTestBase
     {
-        private Mock<ISftpSession> _sftpSessionMock;
+        private SftpFileStream _target;
         private string _path;
-        private SftpFileStream _sftpFileStream;
         private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
         private uint _bufferSize;
         private uint _readBufferSize;
         private uint _writeBufferSize;
 
-        [TestInitialize]
-        public void Setup()
+        protected override void SetupData()
         {
-            Arrange();
-            Act();
-        }
+            base.SetupData();
 
-        protected void Arrange()
-        {
             var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] { (byte)random.Next(byte.MinValue, byte.MaxValue) };
-            _fileAttributes = SftpFileAttributes.Empty;
-            _bufferSize = (uint)random.Next(1, 1000);
-            _readBufferSize = (uint)random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(2, random);
+            _bufferSize = (uint) random.Next(1, 1000);
+            _readBufferSize = (uint) random.Next(0, 1000);
+            _writeBufferSize = (uint) random.Next(0, 1000);
+        }
 
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(false);
+        }
 
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(false);
+        protected override void Arrange()
+        {
+            base.Arrange();
 
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Read, (int)_bufferSize);
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.Read,
+                                         (int) _bufferSize);
         }
 
-        protected void Act()
+        protected override void Act()
         {
-            _sftpFileStream.Close();
+            _target.Close();
         }
 
         [TestMethod]
         public void IsOpenOnSftpSessionShouldBeInvokedOnce()
         {
-            _sftpSessionMock.Verify(p => p.IsOpen, Times.Once);
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Once);
         }
 
         [TestMethod]
         public void RequestCloseOnSftpSessionShouldNeverBeInvoked()
         {
-            _sftpSessionMock.Verify(p => p.RequestClose(_handle), Times.Never);
+            SftpSessionMock.Verify(p => p.RequestClose(_handle), Times.Never);
         }
     }
 }

+ 36 - 36
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionOpen.cs

@@ -8,71 +8,71 @@ using Renci.SshNet.Sftp;
 namespace Renci.SshNet.Tests.Classes.Sftp
 {
     [TestClass]
-    public class SftpFileStreamTest_Close_SessionOpen
+    public class SftpFileStreamTest_Close_SessionOpen : SftpFileStreamTestBase
     {
-        private Mock<ISftpSession> _sftpSessionMock;
+        private SftpFileStream _target;
         private string _path;
-        private SftpFileStream _sftpFileStream;
         private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
         private uint _bufferSize;
         private uint _readBufferSize;
         private uint _writeBufferSize;
 
-        [TestInitialize]
-        public void Setup()
+        protected override void SetupData()
         {
-            Arrange();
-            Act();
-        }
+            base.SetupData();
 
-        protected void Arrange()
-        {
             var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] {(byte) random.Next(byte.MinValue, byte.MaxValue)};
-            _fileAttributes = SftpFileAttributes.Empty;
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(2, random);
             _bufferSize = (uint) random.Next(1, 1000);
             _readBufferSize = (uint) random.Next(0, 1000);
             _writeBufferSize = (uint) random.Next(0, 1000);
+        }
 
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestClose(_handle));
+        }
 
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
+        protected override void Arrange()
+        {
+            base.Arrange();
 
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Read, (int) _bufferSize);
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.Read,
+                                         (int) _bufferSize);
         }
 
-        protected void Act()
+        protected override void Act()
         {
-            _sftpFileStream.Close();
+            _target.Close();
         }
 
         [TestMethod]
         public void IsOpenOnSftpSessionShouldBeInvokedOnce()
         {
-            _sftpSessionMock.Verify(p => p.IsOpen, Times.Once);
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Once);
         }
 
         [TestMethod]
         public void RequestCloseOnSftpSessionShouldBeInvokedOnce()
         {
-            _sftpSessionMock.Verify(p => p.RequestClose(_handle), Times.Once);
+            SftpSessionMock.Verify(p => p.RequestClose(_handle), Times.Once);
         }
     }
 }

+ 54 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileAccessInvalid.cs

@@ -0,0 +1,54 @@
+using System;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileAccessInvalid : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private ArgumentOutOfRangeException _actualException;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = FileMode.Open;
+            _fileAccess = 0;
+            _bufferSize = _random.Next(5, 1000);
+        }
+
+        protected override void SetupMocks()
+        {
+        }
+
+        protected override void Act()
+        {
+            try
+            {
+                new SftpFileStream(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize);
+                Assert.Fail();
+            }
+            catch (ArgumentOutOfRangeException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void CtorShouldHaveThrownArgumentException()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.IsNull(_actualException.InnerException);
+            Assert.AreEqual("access", _actualException.ParamName);
+        }
+    }
+}

+ 55 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessRead.cs

@@ -0,0 +1,55 @@
+using System;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileModeAppend_FileAccessRead : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private ArgumentException _actualException;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = FileMode.Append;
+            _fileAccess = FileAccess.Read;
+            _bufferSize = _random.Next(5, 1000);
+        }
+
+        protected override void SetupMocks()
+        {
+        }
+
+        protected override void Act()
+        {
+            try
+            {
+                new SftpFileStream(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize);
+                Assert.Fail();
+            }
+            catch (ArgumentException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void CtorShouldHaveThrownArgumentException()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.IsNull(_actualException.InnerException);
+            Assert.AreEqual(string.Format("{0} mode can be requested only when combined with write-only access.", _fileMode), _actualException.Message);
+            Assert.IsNull(_actualException.ParamName);
+        }
+    }
+}

+ 55 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessReadWrite.cs

@@ -0,0 +1,55 @@
+using System;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileModeAppend_FileAccessReadWrite : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private ArgumentException _actualException;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = FileMode.Append;
+            _fileAccess = FileAccess.ReadWrite;
+            _bufferSize = _random.Next(5, 1000);
+        }
+
+        protected override void SetupMocks()
+        {
+        }
+
+        protected override void Act()
+        {
+            try
+            {
+                new SftpFileStream(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize);
+                Assert.Fail();
+            }
+            catch (ArgumentException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void CtorShouldHaveThrownArgumentException()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.IsNull(_actualException.InnerException);
+            Assert.AreEqual(string.Format("{0} mode can be requested only when combined with write-only access.", _fileMode), _actualException.Message);
+            Assert.IsNull(_actualException.ParamName);
+        }
+    }
+}

+ 173 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessWrite.cs

@@ -0,0 +1,173 @@
+using System;
+using System.IO;
+using System.Threading;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+using Renci.SshNet.Tests.Common;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileModeAppend_FileAccessWrite : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private byte[] _handle;
+        private SftpFileStream _target;
+        private SftpFileAttributes _fileAttributes;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = FileMode.Append;
+            _fileAccess = FileAccess.Write;
+            _bufferSize = _random.Next(5, 1000);
+            _readBufferSize = (uint) _random.Next(5, 1000);
+            _writeBufferSize = (uint) _random.Next(5, 1000);
+            _handle = GenerateRandom(_random.Next(1, 10), _random);
+            _fileAttributes = new SftpFileAttributesBuilder().WithLastAccessTime(DateTime.Now.AddSeconds(_random.Next()))
+                                                             .WithLastWriteTime(DateTime.Now.AddSeconds(_random.Next()))
+                                                             .WithSize(_random.Next())
+                                                             .WithUserId(_random.Next())
+                                                             .WithGroupId(_random.Next())
+                                                             .WithPermissions((uint) _random.Next())
+                                                             .Build();
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.Append | Flags.CreateNewOrOpen, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestFStat(_handle, false))
+                           .Returns(_fileAttributes);
+        }
+
+        protected override void Act()
+        {
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         _fileMode,
+                                         _fileAccess,
+                                         _bufferSize);
+        }
+
+        [TestMethod]
+        public void CanReadShouldReturnFalse()
+        {
+            Assert.IsFalse(_target.CanRead);
+        }
+
+        [TestMethod]
+        public void CanSeekShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanSeek);
+        }
+
+        [TestMethod]
+        public void CanWriteShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanWrite);
+        }
+
+        [TestMethod]
+        public void CanTimeoutShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanTimeout);
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnSizeOfFile()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            var actual = _target.Position;
+
+            Assert.AreEqual(_fileAttributes.Size, actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadShouldThrowNotSupportedException()
+        {
+            var buffer = new byte[_readBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            try
+            {
+                _target.Read(buffer, 0, buffer.Length);
+                Assert.Fail();
+            }
+            catch (NotSupportedException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Read not supported.", ex.Message);
+            }
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadByteShouldThrowNotSupportedException()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            try
+            {
+                _target.ReadByte();
+                Assert.Fail();
+            }
+            catch (NotSupportedException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Read not supported.", ex.Message);
+            }
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void WriteShouldStartWritingAtEndOfFile()
+        {
+            var buffer = new byte[_writeBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWrite(_handle, (ulong) _fileAttributes.Size, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null));
+
+            _target.Write(buffer, 0, buffer.Length);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestWrite(_handle, (ulong)_fileAttributes.Size, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null), Times.Once);
+        }
+
+        [TestMethod]
+        public void RequestOpenOnSftpSessionShouldBeInvokedOnce()
+        {
+            SftpSessionMock.Verify(p => p.RequestOpen(_path, Flags.Write | Flags.Append | Flags.CreateNewOrOpen, false), Times.Once);
+        }
+
+        [TestMethod]
+        public void RequestFStatOnSftpSessionShouldBeInvokedOnce()
+        {
+            SftpSessionMock.Verify(p => p.RequestFStat(_handle, false), Times.Once);
+        }
+    }
+}

+ 55 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessRead.cs

@@ -0,0 +1,55 @@
+using System;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessRead : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private ArgumentException _actualException;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = FileMode.CreateNew;
+            _fileAccess = FileAccess.Read;
+            _bufferSize = _random.Next(5, 1000);
+        }
+
+        protected override void SetupMocks()
+        {
+        }
+
+        protected override void Act()
+        {
+            try
+            {
+                new SftpFileStream(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize);
+                Assert.Fail();
+            }
+            catch (ArgumentException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void CtorShouldHaveThrownArgumentException()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.IsNull(_actualException.InnerException);
+            Assert.AreEqual(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", typeof(FileMode).Name, _fileMode, typeof(FileAccess).Name, _fileAccess), _actualException.Message);
+            Assert.IsNull(_actualException.ParamName);
+        }
+    }
+}

+ 151 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessReadWrite.cs

@@ -0,0 +1,151 @@
+using System;
+using System.IO;
+using System.Threading;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessReadWrite : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private byte[] _handle;
+        private SftpFileStream _target;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = FileMode.CreateNew;
+            _fileAccess = FileAccess.ReadWrite;
+            _bufferSize = _random.Next(5, 1000);
+            _readBufferSize = (uint)_random.Next(5, 1000);
+            _writeBufferSize = (uint)_random.Next(5, 1000);
+            _handle = GenerateRandom(_random.Next(1, 10), _random);
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.CreateNew, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+        }
+
+        protected override void Act()
+        {
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         _fileMode,
+                                         _fileAccess,
+                                         _bufferSize);
+        }
+
+        [TestMethod]
+        public void CanReadShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanRead);
+        }
+
+        [TestMethod]
+        public void CanSeekShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanSeek);
+        }
+
+        [TestMethod]
+        public void CanWriteShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanWrite);
+        }
+
+        [TestMethod]
+        public void CanTimeoutShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanTimeout);
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnZero()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            var actual = _target.Position;
+
+            Assert.AreEqual(0L, actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadShouldStartReadingAtBeginningOfFile()
+        {
+            var buffer = new byte[8];
+            var data = new byte[] { 5, 4, 3, 2, 1 };
+            var expected = new byte[] { 0, 5, 4, 3, 2, 1, 0, 0 };
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)).Returns(data);
+
+            var actual = _target.Read(buffer, 1, data.Length);
+
+            Assert.AreEqual(data.Length, actual);
+            Assert.IsTrue(buffer.IsEqualTo(expected));
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, 0UL, _readBufferSize), Times.Once);
+        }
+
+        [TestMethod]
+        public void ReadByteShouldStartReadingAtBeginningOfFile()
+        {
+            var data = GenerateRandom(5, _random);
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize))
+                .Returns(data);
+
+            var actual = _target.ReadByte();
+
+            Assert.AreEqual(data[0], actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, 0UL, _readBufferSize), Times.Once);
+        }
+
+        [TestMethod]
+        public void WriteShouldStartWritingAtBeginningOfFile()
+        {
+            var buffer = new byte[_writeBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null));
+
+            _target.Write(buffer, 0, buffer.Length);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null), Times.Once);
+        }
+
+        [TestMethod]
+        public void RequestOpenOnSftpSessionShouldBeInvokedOnce()
+        {
+            SftpSessionMock.Verify(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.CreateNew, false), Times.Once);
+        }
+    }
+}

+ 155 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessWrite.cs

@@ -0,0 +1,155 @@
+using System;
+using System.IO;
+using System.Threading;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessWrite : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private byte[] _handle;
+        private SftpFileStream _target;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = FileMode.CreateNew;
+            _fileAccess = FileAccess.Write;
+            _bufferSize = _random.Next(5, 1000);
+            _readBufferSize = (uint) _random.Next(5, 1000);
+            _writeBufferSize = (uint) _random.Next(5, 1000);
+            _handle = GenerateRandom(_random.Next(1, 10), _random);
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.CreateNew, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+        }
+
+        protected override void Act()
+        {
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         _fileMode,
+                                         _fileAccess,
+                                         _bufferSize);
+        }
+
+        [TestMethod]
+        public void CanReadShouldReturnFalse()
+        {
+            Assert.IsFalse(_target.CanRead);
+        }
+
+        [TestMethod]
+        public void CanSeekShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanSeek);
+        }
+
+        [TestMethod]
+        public void CanWriteShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanWrite);
+        }
+
+        [TestMethod]
+        public void CanTimeoutShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanTimeout);
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnZero()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            var actual = _target.Position;
+
+            Assert.AreEqual(0L, actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadShouldThrowNotSupportedException()
+        {
+            var buffer = new byte[_readBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            try
+            {
+                _target.Read(buffer, 0, buffer.Length);
+                Assert.Fail();
+            }
+            catch (NotSupportedException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Read not supported.", ex.Message);
+            }
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadByteShouldThrowNotSupportedException()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            try
+            {
+                _target.ReadByte();
+                Assert.Fail();
+            }
+            catch (NotSupportedException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Read not supported.", ex.Message);
+            }
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void WriteShouldStartWritingAtBeginningOfFile()
+        {
+            var buffer = new byte[_writeBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null));
+
+            _target.Write(buffer, 0, buffer.Length);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null), Times.Once);
+        }
+
+        [TestMethod]
+        public void RequestOpenOnSftpSessionShouldBeInvokedOnce()
+        {
+            SftpSessionMock.Verify(p => p.RequestOpen(_path, Flags.Write | Flags.CreateNew, false), Times.Once);
+        }
+    }
+}

+ 55 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessRead.cs

@@ -0,0 +1,55 @@
+using System;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileModeCreate_FileAccessRead : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private ArgumentException _actualException;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = FileMode.Create;
+            _fileAccess = FileAccess.Read;
+            _bufferSize = _random.Next(5, 1000);
+        }
+
+        protected override void SetupMocks()
+        {
+        }
+
+        protected override void Act()
+        {
+            try
+            {
+                new SftpFileStream(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize);
+                Assert.Fail();
+            }
+            catch (ArgumentException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void CtorShouldHaveThrownArgumentException()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.IsNull(_actualException.InnerException);
+            Assert.AreEqual(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", typeof(FileMode).Name, _fileMode, typeof(FileAccess).Name, _fileAccess), _actualException.Message);
+            Assert.IsNull(_actualException.ParamName);
+        }
+    }
+}

+ 154 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs

@@ -0,0 +1,154 @@
+using System;
+using System.IO;
+using System.Threading;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileDoesNotExist : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private byte[] _handle;
+        private SftpFileStream _target;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = FileMode.Create;
+            _fileAccess = FileAccess.ReadWrite;
+            _bufferSize = _random.Next(5, 1000);
+            _readBufferSize = (uint)_random.Next(5, 1000);
+            _writeBufferSize = (uint)_random.Next(5, 1000);
+            _handle = GenerateRandom(_random.Next(1, 10), _random);
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.Truncate, true))
+                           .Returns((byte[]) null);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.CreateNew, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+        }
+
+        protected override void Act()
+        {
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         _fileMode,
+                                         _fileAccess,
+                                         _bufferSize);
+        }
+
+        [TestMethod]
+        public void CanReadShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanRead);
+        }
+
+        [TestMethod]
+        public void CanSeekShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanSeek);
+        }
+
+        [TestMethod]
+        public void CanWriteShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanWrite);
+        }
+
+        [TestMethod]
+        public void CanTimeoutShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanTimeout);
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnZero()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            var actual = _target.Position;
+
+            Assert.AreEqual(0L, actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadShouldStartReadingAtBeginningOfFile()
+        {
+            var buffer = new byte[8];
+            var data = new byte[] { 5, 4, 3, 2, 1 };
+            var expected = new byte[] { 0, 5, 4, 3, 2, 1, 0, 0 };
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)).Returns(data);
+
+            var actual = _target.Read(buffer, 1, data.Length);
+
+            Assert.AreEqual(data.Length, actual);
+            Assert.IsTrue(buffer.IsEqualTo(expected));
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, 0UL, _readBufferSize), Times.Once);
+        }
+
+        [TestMethod]
+        public void ReadByteShouldStartReadingAtBeginningOfFile()
+        {
+            var data = GenerateRandom(5, _random);
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize))
+                .Returns(data);
+
+            var actual = _target.ReadByte();
+
+            Assert.AreEqual(data[0], actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, 0UL, _readBufferSize), Times.Once);
+        }
+
+        [TestMethod]
+        public void WriteShouldStartWritingAtBeginningOfFile()
+        {
+            var buffer = new byte[_writeBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null));
+
+            _target.Write(buffer, 0, buffer.Length);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null), Times.Once);
+        }
+
+        [TestMethod]
+        public void RequestOpenOnSftpSessionShouldBeInvokedOnce()
+        {
+            SftpSessionMock.Verify(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.Truncate, true), Times.Once);
+        }
+    }
+}

+ 151 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileExists.cs

@@ -0,0 +1,151 @@
+using System;
+using System.IO;
+using System.Threading;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileExists : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private byte[] _handle;
+        private SftpFileStream _target;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = FileMode.Create;
+            _fileAccess = FileAccess.ReadWrite;
+            _bufferSize = _random.Next(5, 1000);
+            _readBufferSize = (uint)_random.Next(5, 1000);
+            _writeBufferSize = (uint)_random.Next(5, 1000);
+            _handle = GenerateRandom(_random.Next(1, 10), _random);
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.Truncate, true))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+        }
+
+        protected override void Act()
+        {
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         _fileMode,
+                                         _fileAccess,
+                                         _bufferSize);
+        }
+
+        [TestMethod]
+        public void CanReadShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanRead);
+        }
+
+        [TestMethod]
+        public void CanSeekShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanSeek);
+        }
+
+        [TestMethod]
+        public void CanWriteShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanWrite);
+        }
+
+        [TestMethod]
+        public void CanTimeoutShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanTimeout);
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnZero()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            var actual = _target.Position;
+
+            Assert.AreEqual(0L, actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadShouldStartReadingAtBeginningOfFile()
+        {
+            var buffer = new byte[8];
+            var data = new byte[] { 5, 4, 3, 2, 1 };
+            var expected = new byte[] { 0, 5, 4, 3, 2, 1, 0, 0 };
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)).Returns(data);
+
+            var actual = _target.Read(buffer, 1, data.Length);
+
+            Assert.AreEqual(data.Length, actual);
+            Assert.IsTrue(buffer.IsEqualTo(expected));
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, 0UL, _readBufferSize), Times.Once);
+        }
+
+        [TestMethod]
+        public void ReadByteShouldStartReadingAtBeginningOfFile()
+        {
+            var data = GenerateRandom(5, _random);
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize))
+                .Returns(data);
+
+            var actual = _target.ReadByte();
+
+            Assert.AreEqual(data[0], actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, 0UL, _readBufferSize), Times.Once);
+        }
+
+        [TestMethod]
+        public void WriteShouldStartWritingAtBeginningOfFile()
+        {
+            var buffer = new byte[_writeBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null));
+
+            _target.Write(buffer, 0, buffer.Length);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null), Times.Once);
+        }
+
+        [TestMethod]
+        public void RequestOpenOnSftpSessionShouldBeInvokedOnce()
+        {
+            SftpSessionMock.Verify(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.Truncate, true), Times.Once);
+        }
+    }
+}

+ 159 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileDoesNotExist.cs

@@ -0,0 +1,159 @@
+using System;
+using System.IO;
+using System.Threading;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileDoesNotExist : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private byte[] _handle;
+        private SftpFileStream _target;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = FileMode.Create;
+            _fileAccess = FileAccess.Write;
+            _bufferSize = _random.Next(5, 1000);
+            _readBufferSize = (uint)_random.Next(5, 1000);
+            _writeBufferSize = (uint)_random.Next(5, 1000);
+            _handle = GenerateRandom(_random.Next(1, 10), _random);
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.Truncate, true))
+                           .Returns((byte[]) null);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.CreateNew, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+        }
+
+        protected override void Act()
+        {
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         _fileMode,
+                                         _fileAccess,
+                                         _bufferSize);
+        }
+
+        [TestMethod]
+        public void CanReadShouldReturnFalse()
+        {
+            Assert.IsFalse(_target.CanRead);
+        }
+
+        [TestMethod]
+        public void CanSeekShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanSeek);
+        }
+
+        [TestMethod]
+        public void CanWriteShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanWrite);
+        }
+
+        [TestMethod]
+        public void CanTimeoutShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanTimeout);
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnZero()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            var actual = _target.Position;
+
+            Assert.AreEqual(0L, actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadShouldThrowNotSupportedException()
+        {
+            var buffer = new byte[_readBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            try
+            {
+                _target.Read(buffer, 0, buffer.Length);
+                Assert.Fail();
+            }
+            catch (NotSupportedException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Read not supported.", ex.Message);
+            }
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadByteShouldThrowNotSupportedException()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            try
+            {
+                _target.ReadByte();
+                Assert.Fail();
+            }
+            catch (NotSupportedException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Read not supported.", ex.Message);
+            }
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void WriteShouldStartWritingAtBeginningOfFile()
+        {
+            var buffer = new byte[_writeBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null));
+
+            _target.Write(buffer, 0, buffer.Length);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null), Times.Once);
+        }
+
+        [TestMethod]
+        public void RequestOpenOnSftpSessionShouldBeInvokedOnceWithTruncateAndOnceWithCreateNew()
+        {
+            SftpSessionMock.Verify(p => p.RequestOpen(_path, Flags.Write | Flags.Truncate, true), Times.Once);
+            SftpSessionMock.Verify(p => p.RequestOpen(_path, Flags.Write | Flags.CreateNew, false), Times.Once);
+        }
+    }
+}

+ 155 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileExists.cs

@@ -0,0 +1,155 @@
+using System;
+using System.IO;
+using System.Threading;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileExists : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private byte[] _handle;
+        private SftpFileStream _target;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = FileMode.Create;
+            _fileAccess = FileAccess.Write;
+            _bufferSize = _random.Next(5, 1000);
+            _readBufferSize = (uint) _random.Next(5, 1000);
+            _writeBufferSize = (uint) _random.Next(5, 1000);
+            _handle = GenerateRandom(_random.Next(1, 10), _random);
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.Truncate, true))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+        }
+
+        protected override void Act()
+        {
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         _fileMode,
+                                         _fileAccess,
+                                         _bufferSize);
+        }
+
+        [TestMethod]
+        public void CanReadShouldReturnFalse()
+        {
+            Assert.IsFalse(_target.CanRead);
+        }
+
+        [TestMethod]
+        public void CanSeekShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanSeek);
+        }
+
+        [TestMethod]
+        public void CanWriteShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanWrite);
+        }
+
+        [TestMethod]
+        public void CanTimeoutShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanTimeout);
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnZero()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            var actual = _target.Position;
+
+            Assert.AreEqual(0L, actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadShouldThrowNotSupportedException()
+        {
+            var buffer = new byte[_readBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            try
+            {
+                _target.Read(buffer, 0, buffer.Length);
+                Assert.Fail();
+            }
+            catch (NotSupportedException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Read not supported.", ex.Message);
+            }
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadByteShouldThrowNotSupportedException()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            try
+            {
+                _target.ReadByte();
+                Assert.Fail();
+            }
+            catch (NotSupportedException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Read not supported.", ex.Message);
+            }
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void WriteShouldStartWritingAtBeginningOfFile()
+        {
+            var buffer = new byte[_writeBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null));
+
+            _target.Write(buffer, 0, buffer.Length);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null), Times.Once);
+        }
+
+        [TestMethod]
+        public void RequestOpenOnSftpSessionShouldBeInvokedOnce()
+        {
+            SftpSessionMock.Verify(p => p.RequestOpen(_path, Flags.Write | Flags.Truncate, true), Times.Once);
+        }
+    }
+}

+ 54 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeInvalid.cs

@@ -0,0 +1,54 @@
+using System;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileModeInvalid : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private ArgumentOutOfRangeException _actualException;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = 0;
+            _fileAccess = FileAccess.Read;
+            _bufferSize = _random.Next(5, 1000);
+        }
+
+        protected override void SetupMocks()
+        {
+        }
+
+        protected override void Act()
+        {
+            try
+            {
+                new SftpFileStream(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize);
+                Assert.Fail();
+            }
+            catch (ArgumentOutOfRangeException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void CtorShouldHaveThrownArgumentException()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.IsNull(_actualException.InnerException);
+            Assert.AreEqual("mode", _actualException.ParamName);
+        }
+    }
+}

+ 174 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessRead.cs

@@ -0,0 +1,174 @@
+using System;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessRead : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private byte[] _handle;
+        private SftpFileStream _target;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = FileMode.OpenOrCreate;
+            _fileAccess = FileAccess.Read;
+            _bufferSize = _random.Next(5, 1000);
+            _readBufferSize = (uint) _random.Next(5, 1000);
+            _writeBufferSize = (uint) _random.Next(5, 1000);
+            _handle = GenerateRandom(_random.Next(1, 10), _random);
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.CreateNewOrOpen, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+        }
+
+        protected override void Act()
+        {
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         _fileMode,
+                                         _fileAccess,
+                                         _bufferSize);
+        }
+
+        [TestMethod]
+        public void CanReadShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanRead);
+        }
+
+        [TestMethod]
+        public void CanSeekShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanSeek);
+        }
+
+        [TestMethod]
+        public void CanWriteShouldReturnFalse()
+        {
+            Assert.IsFalse(_target.CanWrite);
+        }
+
+        [TestMethod]
+        public void CanTimeoutShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanTimeout);
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnZero()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            var actual = _target.Position;
+
+            Assert.AreEqual(0L, actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadShouldStartReadingAtBeginningOfFile()
+        {
+            var buffer = new byte[8];
+            var data = new byte[] { 5, 4, 3, 2, 1 };
+            var expected = new byte[] { 0, 5, 4, 3, 2, 1, 0, 0 };
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)).Returns(data);
+
+            var actual = _target.Read(buffer, 1, data.Length);
+
+            Assert.AreEqual(data.Length, actual);
+            Assert.IsTrue(buffer.IsEqualTo(expected));
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, 0UL, _readBufferSize), Times.Once);
+        }
+
+        [TestMethod]
+        public void ReadByteShouldStartReadingAtBeginningOfFile()
+        {
+            var data = GenerateRandom(5, _random);
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize))
+                .Returns(data);
+
+            var actual = _target.ReadByte();
+
+            Assert.AreEqual(data[0], actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, 0UL, _readBufferSize), Times.Once);
+        }
+
+        [TestMethod]
+        public void WriteShouldThrowNotSupportedException()
+        {
+            var buffer = new byte[_writeBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            try
+            {
+                _target.Write(buffer, 0, buffer.Length);
+            }
+            catch (NotSupportedException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Write not supported.", ex.Message);
+            }
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void WriteByteShouldThrowNotSupportedException()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            try
+            {
+                _target.WriteByte(0x0a);
+            }
+            catch (NotSupportedException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Write not supported.", ex.Message);
+            }
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void RequestOpenOnSftpSessionShouldBeInvokedOnce()
+        {
+            SftpSessionMock.Verify(p => p.RequestOpen(_path, Flags.Read | Flags.CreateNewOrOpen, false), Times.Once);
+        }
+    }
+}

+ 151 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessReadWrite.cs

@@ -0,0 +1,151 @@
+using System;
+using System.IO;
+using System.Threading;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessReadWrite : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private byte[] _handle;
+        private SftpFileStream _target;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = FileMode.OpenOrCreate;
+            _fileAccess = FileAccess.ReadWrite;
+            _bufferSize = _random.Next(5, 1000);
+            _readBufferSize = (uint)_random.Next(5, 1000);
+            _writeBufferSize = (uint)_random.Next(5, 1000);
+            _handle = GenerateRandom(_random.Next(1, 10), _random);
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.CreateNewOrOpen, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+        }
+
+        protected override void Act()
+        {
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         _fileMode,
+                                         _fileAccess,
+                                         _bufferSize);
+        }
+
+        [TestMethod]
+        public void CanReadShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanRead);
+        }
+
+        [TestMethod]
+        public void CanSeekShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanSeek);
+        }
+
+        [TestMethod]
+        public void CanWriteShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanWrite);
+        }
+
+        [TestMethod]
+        public void CanTimeoutShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanTimeout);
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnZero()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            var actual = _target.Position;
+
+            Assert.AreEqual(0L, actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadShouldStartReadingAtBeginningOfFile()
+        {
+            var buffer = new byte[8];
+            var data = new byte[] { 5, 4, 3, 2, 1 };
+            var expected = new byte[] { 0, 5, 4, 3, 2, 1, 0, 0 };
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)).Returns(data);
+
+            var actual = _target.Read(buffer, 1, data.Length);
+
+            Assert.AreEqual(data.Length, actual);
+            Assert.IsTrue(buffer.IsEqualTo(expected));
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, 0UL, _readBufferSize), Times.Once);
+        }
+
+        [TestMethod]
+        public void ReadByteShouldStartReadingAtBeginningOfFile()
+        {
+            var data = GenerateRandom(5, _random);
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize))
+                .Returns(data);
+
+            var actual = _target.ReadByte();
+
+            Assert.AreEqual(data[0], actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, 0UL, _readBufferSize), Times.Once);
+        }
+
+        [TestMethod]
+        public void WriteShouldStartWritingAtBeginningOfFile()
+        {
+            var buffer = new byte[_writeBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null));
+
+            _target.Write(buffer, 0, buffer.Length);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null), Times.Once);
+        }
+
+        [TestMethod]
+        public void RequestOpenOnSftpSessionShouldBeInvokedOnce()
+        {
+            SftpSessionMock.Verify(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.CreateNewOrOpen, false), Times.Once);
+        }
+    }
+}

+ 155 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessWrite.cs

@@ -0,0 +1,155 @@
+using System;
+using System.IO;
+using System.Threading;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessWrite : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private byte[] _handle;
+        private SftpFileStream _target;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = FileMode.OpenOrCreate;
+            _fileAccess = FileAccess.Write;
+            _bufferSize = _random.Next(5, 1000);
+            _readBufferSize = (uint) _random.Next(5, 1000);
+            _writeBufferSize = (uint) _random.Next(5, 1000);
+            _handle = GenerateRandom(_random.Next(1, 10), _random);
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.CreateNewOrOpen, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+        }
+
+        protected override void Act()
+        {
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         _fileMode,
+                                         _fileAccess,
+                                         _bufferSize);
+        }
+
+        [TestMethod]
+        public void CanReadShouldReturnFalse()
+        {
+            Assert.IsFalse(_target.CanRead);
+        }
+
+        [TestMethod]
+        public void CanSeekShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanSeek);
+        }
+
+        [TestMethod]
+        public void CanWriteShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanWrite);
+        }
+
+        [TestMethod]
+        public void CanTimeoutShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanTimeout);
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnZero()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            var actual = _target.Position;
+
+            Assert.AreEqual(0L, actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadShouldThrowNotSupportedException()
+        {
+            var buffer = new byte[_readBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            try
+            {
+                _target.Read(buffer, 0, buffer.Length);
+                Assert.Fail();
+            }
+            catch (NotSupportedException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Read not supported.", ex.Message);
+            }
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadByteShouldThrowNotSupportedException()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            try
+            {
+                _target.ReadByte();
+                Assert.Fail();
+            }
+            catch (NotSupportedException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Read not supported.", ex.Message);
+            }
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void WriteShouldStartWritingAtBeginningOfFile()
+        {
+            var buffer = new byte[_writeBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null));
+
+            _target.Write(buffer, 0, buffer.Length);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null), Times.Once);
+        }
+
+        [TestMethod]
+        public void RequestOpenOnSftpSessionShouldBeInvokedOnce()
+        {
+            SftpSessionMock.Verify(p => p.RequestOpen(_path, Flags.Write | Flags.CreateNewOrOpen, false), Times.Once);
+        }
+    }
+}

+ 174 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessRead.cs

@@ -0,0 +1,174 @@
+using System;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileModeOpen_FileAccessRead : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private byte[] _handle;
+        private SftpFileStream _target;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = FileMode.Open;
+            _fileAccess = FileAccess.Read;
+            _bufferSize = _random.Next(5, 1000);
+            _readBufferSize = (uint)_random.Next(5, 1000);
+            _writeBufferSize = (uint)_random.Next(5, 1000);
+            _handle = GenerateRandom(_random.Next(1, 10), _random);
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+        }
+
+        protected override void Act()
+        {
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         _fileMode,
+                                         _fileAccess,
+                                         _bufferSize);
+        }
+
+        [TestMethod]
+        public void CanReadShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanRead);
+        }
+
+        [TestMethod]
+        public void CanSeekShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanSeek);
+        }
+
+        [TestMethod]
+        public void CanWriteShouldReturnFalse()
+        {
+            Assert.IsFalse(_target.CanWrite);
+        }
+
+        [TestMethod]
+        public void CanTimeoutShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanTimeout);
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnZero()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            var actual = _target.Position;
+
+            Assert.AreEqual(0L, actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadShouldStartReadingAtBeginningOfFile()
+        {
+            var buffer = new byte[8];
+            var data = new byte[] { 5, 4, 3, 2, 1 };
+            var expected = new byte[] { 0, 5, 4, 3, 2, 1, 0, 0 };
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)).Returns(data);
+
+            var actual = _target.Read(buffer, 1, data.Length);
+
+            Assert.AreEqual(data.Length, actual);
+            Assert.IsTrue(buffer.IsEqualTo(expected));
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, 0UL, _readBufferSize), Times.Once);
+        }
+
+        [TestMethod]
+        public void ReadByteShouldStartReadingAtBeginningOfFile()
+        {
+            var data = GenerateRandom(5, _random);
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize))
+                .Returns(data);
+
+            var actual = _target.ReadByte();
+
+            Assert.AreEqual(data[0], actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, 0UL, _readBufferSize), Times.Once);
+        }
+
+        [TestMethod]
+        public void WriteShouldThrowNotSupportedException()
+        {
+            var buffer = new byte[_writeBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            try
+            {
+                _target.Write(buffer, 0, buffer.Length);
+            }
+            catch (NotSupportedException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Write not supported.", ex.Message);
+            }
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void WriteByteShouldThrowNotSupportedException()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            try
+            {
+                _target.WriteByte(0x0a);
+            }
+            catch (NotSupportedException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Write not supported.", ex.Message);
+            }
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void RequestOpenOnSftpSessionShouldBeInvokedOnce()
+        {
+            SftpSessionMock.Verify(p => p.RequestOpen(_path, Flags.Read, false), Times.Once);
+        }
+    }
+}

+ 151 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessReadWrite.cs

@@ -0,0 +1,151 @@
+using System;
+using System.IO;
+using System.Threading;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileModeOpen_FileAccessReadWrite : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private byte[] _handle;
+        private SftpFileStream _target;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = FileMode.Open;
+            _fileAccess = FileAccess.ReadWrite;
+            _bufferSize = _random.Next(5, 1000);
+            _readBufferSize = (uint) _random.Next(5, 1000);
+            _writeBufferSize = (uint) _random.Next(5, 1000);
+            _handle = GenerateRandom(_random.Next(1, 10), _random);
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+        }
+
+        protected override void Act()
+        {
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         _fileMode,
+                                         _fileAccess,
+                                         _bufferSize);
+        }
+
+        [TestMethod]
+        public void CanReadShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanRead);
+        }
+
+        [TestMethod]
+        public void CanSeekShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanSeek);
+        }
+
+        [TestMethod]
+        public void CanWriteShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanWrite);
+        }
+
+        [TestMethod]
+        public void CanTimeoutShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanTimeout);
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnZero()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            var actual = _target.Position;
+
+            Assert.AreEqual(0L, actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadShouldStartReadingAtBeginningOfFile()
+        {
+            var buffer = new byte[8];
+            var data = new byte[] { 5, 4, 3, 2, 1 };
+            var expected = new byte[] { 0, 5, 4, 3, 2, 1, 0, 0 };
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)).Returns(data);
+
+            var actual = _target.Read(buffer, 1, data.Length);
+
+            Assert.AreEqual(data.Length, actual);
+            Assert.IsTrue(buffer.IsEqualTo(expected));
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, 0UL, _readBufferSize), Times.Once);
+        }
+
+        [TestMethod]
+        public void ReadByteShouldStartReadingAtBeginningOfFile()
+        {
+            var data = GenerateRandom(5, _random);
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize))
+                .Returns(data);
+
+            var actual = _target.ReadByte();
+
+            Assert.AreEqual(data[0], actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, 0UL, _readBufferSize), Times.Once);
+        }
+
+        [TestMethod]
+        public void WriteShouldStartWritingAtBeginningOfFile()
+        {
+            var buffer = new byte[_writeBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null));
+
+            _target.Write(buffer, 0, buffer.Length);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null), Times.Once);
+        }
+
+        [TestMethod]
+        public void RequestOpenOnSftpSessionShouldBeInvokedOnce()
+        {
+            SftpSessionMock.Verify(p => p.RequestOpen(_path, Flags.Read | Flags.Write, false), Times.Once);
+        }
+    }
+}

+ 155 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessWrite.cs

@@ -0,0 +1,155 @@
+using System;
+using System.IO;
+using System.Threading;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileModeOpen_FileAccessWrite : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private byte[] _handle;
+        private SftpFileStream _target;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = FileMode.Open;
+            _fileAccess = FileAccess.Write;
+            _bufferSize = _random.Next(5, 1000);
+            _readBufferSize = (uint) _random.Next(5, 1000);
+            _writeBufferSize = (uint) _random.Next(5, 1000);
+            _handle = GenerateRandom(_random.Next(1, 10), _random);
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Write, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+        }
+
+        protected override void Act()
+        {
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         _fileMode,
+                                         _fileAccess,
+                                         _bufferSize);
+        }
+
+        [TestMethod]
+        public void CanReadShouldReturnFalse()
+        {
+            Assert.IsFalse(_target.CanRead);
+        }
+
+        [TestMethod]
+        public void CanSeekShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanSeek);
+        }
+
+        [TestMethod]
+        public void CanWriteShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanWrite);
+        }
+
+        [TestMethod]
+        public void CanTimeoutShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanTimeout);
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnZero()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            var actual = _target.Position;
+
+            Assert.AreEqual(0L, actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadShouldThrowNotSupportedException()
+        {
+            var buffer = new byte[_readBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            try
+            {
+                _target.Read(buffer, 0, buffer.Length);
+                Assert.Fail();
+            }
+            catch (NotSupportedException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Read not supported.", ex.Message);
+            }
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadByteShouldThrowNotSupportedException()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            try
+            {
+                _target.ReadByte();
+                Assert.Fail();
+            }
+            catch (NotSupportedException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Read not supported.", ex.Message);
+            }
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void WriteShouldStartWritingAtBeginningOfFile()
+        {
+            var buffer = new byte[_writeBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null));
+
+            _target.Write(buffer, 0, buffer.Length);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null), Times.Once);
+        }
+
+        [TestMethod]
+        public void RequestOpenOnSftpSessionShouldBeInvokedOnce()
+        {
+            SftpSessionMock.Verify(p => p.RequestOpen(_path, Flags.Write, false), Times.Once);
+        }
+    }
+}

+ 55 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessRead.cs

@@ -0,0 +1,55 @@
+using System;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessRead : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private ArgumentException _actualException;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = FileMode.Truncate;
+            _fileAccess = FileAccess.Read;
+            _bufferSize = _random.Next(5, 1000);
+        }
+
+        protected override void SetupMocks()
+        {
+        }
+
+        protected override void Act()
+        {
+            try
+            {
+                new SftpFileStream(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize);
+                Assert.Fail();
+            }
+            catch (ArgumentException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void CtorShouldHaveThrownArgumentException()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.IsNull(_actualException.InnerException);
+            Assert.AreEqual(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", typeof(FileMode).Name, _fileMode, typeof(FileAccess).Name, _fileAccess), _actualException.Message);
+            Assert.IsNull(_actualException.ParamName);
+        }
+    }
+}

+ 151 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessReadWrite.cs

@@ -0,0 +1,151 @@
+using System;
+using System.IO;
+using System.Threading;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessReadWrite : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private byte[] _handle;
+        private SftpFileStream _target;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = FileMode.Truncate;
+            _fileAccess = FileAccess.ReadWrite;
+            _bufferSize = _random.Next(5, 1000);
+            _readBufferSize = (uint) _random.Next(5, 1000);
+            _writeBufferSize = (uint) _random.Next(5, 1000);
+            _handle = GenerateRandom(_random.Next(1, 10), _random);
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.Truncate, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+        }
+
+        protected override void Act()
+        {
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         _fileMode,
+                                         _fileAccess,
+                                         _bufferSize);
+        }
+
+        [TestMethod]
+        public void CanReadShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanRead);
+        }
+
+        [TestMethod]
+        public void CanSeekShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanSeek);
+        }
+
+        [TestMethod]
+        public void CanWriteShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanWrite);
+        }
+
+        [TestMethod]
+        public void CanTimeoutShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanTimeout);
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnZero()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            var actual = _target.Position;
+
+            Assert.AreEqual(0L, actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadShouldStartReadingAtBeginningOfFile()
+        {
+            var buffer = new byte[8];
+            var data = new byte[] { 5, 4, 3, 2, 1 };
+            var expected = new byte[] { 0, 5, 4, 3, 2, 1, 0, 0 };
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)).Returns(data);
+
+            var actual = _target.Read(buffer, 1, data.Length);
+
+            Assert.AreEqual(data.Length, actual);
+            Assert.IsTrue(buffer.IsEqualTo(expected));
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, 0UL, _readBufferSize), Times.Once);
+        }
+
+        [TestMethod]
+        public void ReadByteShouldStartReadingAtBeginningOfFile()
+        {
+            var data = GenerateRandom(5, _random);
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize))
+                .Returns(data);
+
+            var actual = _target.ReadByte();
+
+            Assert.AreEqual(data[0], actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, 0UL, _readBufferSize), Times.Once);
+        }
+
+        [TestMethod]
+        public void WriteShouldStartWritingAtBeginningOfFile()
+        {
+            var buffer = new byte[_writeBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null));
+
+            _target.Write(buffer, 0, buffer.Length);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null), Times.Once);
+        }
+
+        [TestMethod]
+        public void RequestOpenOnSftpSessionShouldBeInvokedOnce()
+        {
+            SftpSessionMock.Verify(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.Truncate, false), Times.Once);
+        }
+    }
+}

+ 155 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessWrite.cs

@@ -0,0 +1,155 @@
+using System;
+using System.IO;
+using System.Threading;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessWrite : SftpFileStreamTestBase
+    {
+        private Random _random;
+        private string _path;
+        private FileMode _fileMode;
+        private FileAccess _fileAccess;
+        private int _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private byte[] _handle;
+        private SftpFileStream _target;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            _random = new Random();
+            _path = _random.Next().ToString();
+            _fileMode = FileMode.Truncate;
+            _fileAccess = FileAccess.Write;
+            _bufferSize = _random.Next(5, 1000);
+            _readBufferSize = (uint) _random.Next(5, 1000);
+            _writeBufferSize = (uint) _random.Next(5, 1000);
+            _handle = GenerateRandom(_random.Next(1, 10), _random);
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.Truncate, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+        }
+
+        protected override void Act()
+        {
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         _fileMode,
+                                         _fileAccess,
+                                         _bufferSize);
+        }
+
+        [TestMethod]
+        public void CanReadShouldReturnFalse()
+        {
+            Assert.IsFalse(_target.CanRead);
+        }
+
+        [TestMethod]
+        public void CanSeekShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanSeek);
+        }
+
+        [TestMethod]
+        public void CanWriteShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanWrite);
+        }
+
+        [TestMethod]
+        public void CanTimeoutShouldReturnTrue()
+        {
+            Assert.IsTrue(_target.CanTimeout);
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnZero()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            var actual = _target.Position;
+
+            Assert.AreEqual(0L, actual);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadShouldThrowNotSupportedException()
+        {
+            var buffer = new byte[_readBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            try
+            {
+                _target.Read(buffer, 0, buffer.Length);
+                Assert.Fail();
+            }
+            catch (NotSupportedException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Read not supported.", ex.Message);
+            }
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void ReadByteShouldThrowNotSupportedException()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            try
+            {
+                _target.ReadByte();
+                Assert.Fail();
+            }
+            catch (NotSupportedException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Read not supported.", ex.Message);
+            }
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+        }
+
+        [TestMethod]
+        public void WriteShouldStartWritingAtBeginningOfFile()
+        {
+            var buffer = new byte[_writeBufferSize];
+
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null));
+
+            _target.Write(buffer, 0, buffer.Length);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(1));
+            SftpSessionMock.Verify(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull<AutoResetEvent>(), null), Times.Once);
+        }
+
+        [TestMethod]
+        public void RequestOpenOnSftpSessionShouldBeInvokedOnce()
+        {
+            SftpSessionMock.Verify(p => p.RequestOpen(_path, Flags.Write | Flags.Truncate, false), Times.Once);
+        }
+    }
+}

+ 35 - 39
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Closed.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Globalization;
 using System.IO;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
@@ -8,72 +7,69 @@ using Renci.SshNet.Sftp;
 namespace Renci.SshNet.Tests.Classes.Sftp
 {
     [TestClass]
-    public class SftpFileStreamTest_Dispose_Closed
+    public class SftpFileStreamTest_Dispose_Closed : SftpFileStreamTestBase
     {
-        private Mock<ISftpSession> _sftpSessionMock;
+        private SftpFileStream _target;
         private string _path;
-        private SftpFileStream _sftpFileStream;
         private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
         private uint _bufferSize;
         private uint _readBufferSize;
         private uint _writeBufferSize;
 
-        [TestInitialize]
-        public void Setup()
+        protected override void SetupData()
         {
-            Arrange();
-            Act();
-        }
+            base.SetupData();
 
-        protected void Arrange()
-        {
             var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] {(byte) random.Next(byte.MinValue, byte.MaxValue)};
-            _fileAttributes = SftpFileAttributes.Empty;
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(random.Next(1, 5), random);
             _bufferSize = (uint) random.Next(1, 1000);
             _readBufferSize = (uint) random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
+            _writeBufferSize = (uint) random.Next(0, 1000);
+        }
 
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestClose(_handle));
+        }
 
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
+        protected override void Arrange()
+        {
+            base.Arrange();
 
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Read, (int) _bufferSize);
-            _sftpFileStream.Close();
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.Read,
+                                         (int) _bufferSize);
+            _target.Close();
         }
 
-        protected void Act()
+        protected override void Act()
         {
-            _sftpFileStream.Dispose();
+            _target.Dispose();
         }
 
         [TestMethod]
         public void IsOpenOnSftpSessionShouldBeInvokedOnce()
         {
-            _sftpSessionMock.Verify(p => p.IsOpen, Times.Once);
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Once);
         }
 
         [TestMethod]
         public void RequestCloseOnSftpSessionShouldBeInvokedOnce()
         {
-            _sftpSessionMock.Verify(p => p.RequestClose(_handle), Times.Once);
+            SftpSessionMock.Verify(p => p.RequestClose(_handle), Times.Once);
         }
     }
 }

+ 35 - 39
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Disposed.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Globalization;
 using System.IO;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
@@ -8,72 +7,69 @@ using Renci.SshNet.Sftp;
 namespace Renci.SshNet.Tests.Classes.Sftp
 {
     [TestClass]
-    public class SftpFileStreamTest_Dispose_Disposed
+    public class SftpFileStreamTest_Dispose_Disposed : SftpFileStreamTestBase
     {
-        private Mock<ISftpSession> _sftpSessionMock;
+        private SftpFileStream _target;
         private string _path;
-        private SftpFileStream _sftpFileStream;
         private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
         private uint _bufferSize;
         private uint _readBufferSize;
         private uint _writeBufferSize;
 
-        [TestInitialize]
-        public void Setup()
+        protected override void SetupData()
         {
-            Arrange();
-            Act();
-        }
+            base.SetupData();
 
-        protected void Arrange()
-        {
             var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] {(byte) random.Next(byte.MinValue, byte.MaxValue)};
-            _fileAttributes = SftpFileAttributes.Empty;
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(1, random);
             _bufferSize = (uint) random.Next(1, 1000);
             _readBufferSize = (uint) random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
+            _writeBufferSize = (uint) random.Next(0, 1000);
+        }
 
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.CreateNewOrOpen, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestClose(_handle));
+        }
 
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
+        protected override void Arrange()
+        {
+            base.Arrange();
 
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Read, (int) _bufferSize);
-            _sftpFileStream.Dispose();
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.OpenOrCreate,
+                                         FileAccess.Write,
+                                         (int) _bufferSize);
+            _target.Dispose();
         }
 
-        protected void Act()
+        protected override void Act()
         {
-            _sftpFileStream.Dispose();
+            _target.Dispose();
         }
 
         [TestMethod]
         public void IsOpenOnSftpSessionShouldBeInvokedOnce()
         {
-            _sftpSessionMock.Verify(p => p.IsOpen, Times.Once);
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Once);
         }
 
         [TestMethod]
         public void RequestCloseOnSftpSessionShouldBeInvokedOnce()
         {
-            _sftpSessionMock.Verify(p => p.RequestClose(_handle), Times.Once);
+            SftpSessionMock.Verify(p => p.RequestClose(_handle), Times.Once);
         }
     }
 }

+ 36 - 40
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionNotOpen.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Globalization;
 using System.IO;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
@@ -8,71 +7,68 @@ using Renci.SshNet.Sftp;
 namespace Renci.SshNet.Tests.Classes.Sftp
 {
     [TestClass]
-    public class SftpFileStreamTest_Dispose_SessionNotOpen
+    public class SftpFileStreamTest_Dispose_SessionNotOpen : SftpFileStreamTestBase
     {
-        private Mock<ISftpSession> _sftpSessionMock;
+        private SftpFileStream _target;
         private string _path;
-        private SftpFileStream _sftpFileStream;
         private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
         private uint _bufferSize;
         private uint _readBufferSize;
         private uint _writeBufferSize;
 
-        [TestInitialize]
-        public void Setup()
+        protected override void SetupData()
         {
-            Arrange();
-            Act();
-        }
+            base.SetupData();
 
-        protected void Arrange()
-        {
             var random = new Random();
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] { (byte)random.Next(byte.MinValue, byte.MaxValue) };
-            _fileAttributes = SftpFileAttributes.Empty;
-            _bufferSize = (uint)random.Next(1, 1000);
-            _readBufferSize = (uint)random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(2, random);
+            _bufferSize = (uint) random.Next(1, 1000);
+            _readBufferSize = (uint) random.Next(0, 1000);
+            _writeBufferSize = (uint) random.Next(0, 1000);
+        }
 
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.CreateNew, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(false);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestClose(_handle));
+        }
 
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(false);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
+        protected override void Arrange()
+        {
+            base.Arrange();
 
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Read, (int)_bufferSize);
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.CreateNew,
+                                         FileAccess.Write,
+                                         (int) _bufferSize);
         }
 
-        protected void Act()
+        protected override void Act()
         {
-            _sftpFileStream.Dispose();
+            _target.Dispose();
         }
 
         [TestMethod]
         public void IsOpenOnSftpSessionShouldBeInvokedOnce()
         {
-            _sftpSessionMock.Verify(p => p.IsOpen, Times.Once);
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Once);
         }
 
         [TestMethod]
         public void RequestCloseOnSftpSessionShouldNeverBeInvoked()
         {
-            _sftpSessionMock.Verify(p => p.RequestClose(_handle), Times.Never);
+            SftpSessionMock.Verify(p => p.RequestClose(_handle), Times.Never);
         }
     }
 }

+ 33 - 36
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionOpen.cs

@@ -8,71 +8,68 @@ using Renci.SshNet.Sftp;
 namespace Renci.SshNet.Tests.Classes.Sftp
 {
     [TestClass]
-    public class SftpFileStreamTest_Dispose_SessionOpen
+    public class SftpFileStreamTest_Dispose_SessionOpen : SftpFileStreamTestBase
     {
-        private Mock<ISftpSession> _sftpSessionMock;
+        private SftpFileStream _target;
         private string _path;
-        private SftpFileStream _sftpFileStream;
         private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
         private uint _bufferSize;
         private uint _readBufferSize;
         private uint _writeBufferSize;
 
-        [TestInitialize]
-        public void Setup()
+        protected override void SetupData()
         {
-            Arrange();
-            Act();
-        }
+            base.SetupData();
 
-        protected void Arrange()
-        {
             var random = new Random();
             _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] {(byte) random.Next(byte.MinValue, byte.MaxValue)};
-            _fileAttributes = SftpFileAttributes.Empty;
+            _handle = GenerateRandom(2, random);
             _bufferSize = (uint) random.Next(1, 1000);
             _readBufferSize = (uint) random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
+            _writeBufferSize = (uint) random.Next(0, 1000);
+        }
 
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.Truncate, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestClose(_handle));
+        }
 
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
+        protected override void Arrange()
+        {
+            base.Arrange();
 
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Read, (int) _bufferSize);
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Truncate,
+                                         FileAccess.Write,
+                                         (int) _bufferSize);
         }
 
-        protected void Act()
+        protected override void Act()
         {
-            _sftpFileStream.Dispose();
+            _target.Dispose();
         }
 
         [TestMethod]
         public void IsOpenOnSftpSessionShouldBeInvokedOnce()
         {
-            _sftpSessionMock.Verify(p => p.IsOpen, Times.Once);
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Once);
         }
 
         [TestMethod]
         public void RequestCloseOnSftpSessionShouldBeInvokedOnce()
         {
-            _sftpSessionMock.Verify(p => p.RequestClose(_handle), Times.Once);
+            SftpSessionMock.Verify(p => p.RequestClose(_handle), Times.Once);
         }
     }
 }

+ 33 - 36
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Finalize_SessionOpen.cs

@@ -8,58 +8,55 @@ using Renci.SshNet.Sftp;
 namespace Renci.SshNet.Tests.Classes.Sftp
 {
     [TestClass]
-    public class SftpFileStreamTest_Finalize_SessionOpen
+    public class SftpFileStreamTest_Finalize_SessionOpen : SftpFileStreamTestBase
     {
-        private Mock<ISftpSession> _sftpSessionMock;
+        private SftpFileStream _target;
         private string _path;
-        private SftpFileStream _sftpFileStream;
         private byte[] _handle;
-        private SftpFileAttributes _fileAttributes;
         private uint _bufferSize;
         private uint _readBufferSize;
         private uint _writeBufferSize;
 
-        [TestInitialize]
-        public void Setup()
+        protected override void SetupData()
         {
-            Arrange();
-            Act();
-        }
+            base.SetupData();
 
-        protected void Arrange()
-        {
             var random = new Random();
             _path = random.Next().ToString(CultureInfo.InvariantCulture);
-            _handle = new[] {(byte) random.Next(byte.MinValue, byte.MaxValue)};
-            _fileAttributes = SftpFileAttributes.Empty;
+            _handle = GenerateRandom(7, random);
             _bufferSize = (uint) random.Next(1, 1000);
             _readBufferSize = (uint) random.Next(0, 1000);
-            _writeBufferSize = (uint)random.Next(0, 1000);
+            _writeBufferSize = (uint) random.Next(0, 1000);
+        }
 
-            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.CreateNewOrOpen, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestClose(_handle));
+        }
 
-            var sequence = new MockSequence();
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Truncate, true))
-                .Returns(_handle);
-            _sftpSessionMock.InSequence(sequence).Setup(p => p.RequestFStat(_handle)).Returns(_fileAttributes);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
-                .Returns(_readBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
-                .Returns(_writeBufferSize);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.IsOpen)
-                .Returns(true);
-            _sftpSessionMock.InSequence(sequence)
-                .Setup(p => p.RequestClose(_handle));
+        protected override void Arrange()
+        {
+            base.Arrange();
 
-            _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Read, (int) _bufferSize);
-            _sftpFileStream = null;
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.OpenOrCreate,
+                                         FileAccess.ReadWrite,
+                                         (int) _bufferSize);
+            _target = null;
         }
 
-        protected void Act()
+        protected override void Act()
         {
             GC.Collect();
             GC.WaitForPendingFinalizers();
@@ -68,13 +65,13 @@ namespace Renci.SshNet.Tests.Classes.Sftp
         [TestMethod]
         public void IsOpenOnSftpSessionShouldNeverBeInvoked()
         {
-            _sftpSessionMock.Verify(p => p.IsOpen, Times.Never);
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Never);
         }
 
         [TestMethod]
         public void RequestCloseOnSftpSessionShouldNeverBeInvoked()
         {
-            _sftpSessionMock.Verify(p => p.RequestClose(_handle), Times.Never);
+            SftpSessionMock.Verify(p => p.RequestClose(_handle), Times.Never);
         }
     }
 }

+ 112 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_NotReadFromBuffer.cs

@@ -0,0 +1,112 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+using Renci.SshNet.Tests.Common;
+using System;
+using System.IO;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Flush_ReadMode_DataInBuffer_NotReadFromBuffer : SftpFileStreamTestBase
+    {
+        private SftpFileStream _target;
+        private string _path;
+        private byte[] _handle;
+        private uint _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private byte[] _readBytes;
+        private byte[] _serverBytes;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            var random = new Random();
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(5, random);
+            _bufferSize = (uint) random.Next(1, 1000);
+            _readBufferSize = 100;
+            _writeBufferSize = 500;
+            _readBytes = new byte[random.Next(1, (int) _readBufferSize - 10)];
+            _serverBytes = GenerateRandom(_readBytes.Length + 5); // store 5 bytes in read buffer
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize))
+                           .Returns(_serverBytes);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.Read,
+                                         (int)_bufferSize);
+            _target.Read(_readBytes, 0, _readBytes.Length);
+        }
+
+        protected override void Act()
+        {
+            _target.Flush();
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnSameValueAsBeforeFlush()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+
+            Assert.AreEqual(_readBytes.Length, _target.Position);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(3));
+        }
+
+        [TestMethod]
+        public void ReadShouldReadFromServer()
+        {
+            var serverBytes2 = GenerateRandom(5);
+            var readBytes2 = new byte[5];
+            var expectedReadBytes = new ArrayBuilder<byte>().Add(new byte[2])
+                                                            .Add(serverBytes2.Take(0, 3))
+                                                            .Build();
+
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestRead(_handle, (ulong)_readBytes.Length, _readBufferSize))
+                           .Returns(serverBytes2);
+
+            var bytesRead = _target.Read(readBytes2, 2, 3);
+
+            Assert.AreEqual(3, bytesRead);
+            CollectionAssert.AreEqual(expectedReadBytes, readBytes2);
+
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, (ulong)_readBytes.Length, _readBufferSize), Times.Once);
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(3));
+        }
+    }
+}

+ 118 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_ReadFromBuffer.cs

@@ -0,0 +1,118 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+using Renci.SshNet.Tests.Common;
+using System;
+using System.IO;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Flush_ReadMode_DataInBuffer_ReadFromBuffer : SftpFileStreamTestBase
+    {
+        private SftpFileStream _target;
+        private string _path;
+        private byte[] _handle;
+        private uint _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private byte[] _readBytes1;
+        private byte[] _readBytes2;
+        private byte[] _serverBytes;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            var random = new Random();
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(5, random);
+            _bufferSize = (uint)random.Next(1, 1000);
+            _readBufferSize = 100;
+            _writeBufferSize = 500;
+            _readBytes1 = new byte[random.Next(1, (int) _readBufferSize - 10)];
+            _readBytes2 = new byte[random.Next(1, 3)];
+            _serverBytes = GenerateRandom(_readBytes1.Length + 10); // store 5 bytes in read buffer
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize))
+                           .Returns(_serverBytes);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.Read,
+                                         (int)_bufferSize);
+            _target.Read(_readBytes1, 0, _readBytes1.Length);
+            _target.Read(_readBytes2, 0, _readBytes2.Length);
+        }
+
+        protected override void Act()
+        {
+            _target.Flush();
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnSameValueAsBeforeFlush()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+
+            Assert.AreEqual(_readBytes1.Length + _readBytes2.Length, _target.Position);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(4));
+        }
+
+        [TestMethod]
+        public void ReadShouldReadFromServer()
+        {
+            var serverBytes3 = GenerateRandom(5);
+            var readBytes3 = new byte[3];
+            var expectedReadBytes = new ArrayBuilder<byte>().Add(new byte[1])
+                                                            .Add(serverBytes3.Take(0, 2))
+                                                            .Build();
+
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestRead(_handle, (ulong) (_readBytes1.Length + _readBytes2.Length), _readBufferSize))
+                           .Returns(serverBytes3);
+
+            var bytesRead = _target.Read(readBytes3, 1, 2);
+
+            Assert.AreEqual(2, bytesRead);
+            CollectionAssert.AreEqual(expectedReadBytes, readBytes3);
+
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, (ulong)(_readBytes1.Length + _readBytes2.Length), _readBufferSize), Times.Once);
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(4));
+        }
+    }
+}

+ 112 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_NoDataInBuffer.cs

@@ -0,0 +1,112 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+using Renci.SshNet.Tests.Common;
+using System;
+using System.IO;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Flush_ReadMode_NoDataInBuffer : SftpFileStreamTestBase
+    {
+        private SftpFileStream _target;
+        private string _path;
+        private byte[] _handle;
+        private uint _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private byte[] _readBytes;
+        private byte[] _serverBytes;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            var random = new Random();
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(5, random);
+            _bufferSize = (uint) random.Next(1, 1000);
+            _readBufferSize = 100;
+            _writeBufferSize = 500;
+            _readBytes = new byte[random.Next(1, (int) _readBufferSize)];
+            _serverBytes = GenerateRandom(_readBytes.Length);
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize))
+                           .Returns(_serverBytes);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.Read,
+                                         (int) _bufferSize);
+            _target.Read(_readBytes, 0, _readBytes.Length);
+        }
+
+        protected override void Act()
+        {
+            _target.Flush();
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnSameValueAsBeforeFlush()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+
+            Assert.AreEqual(_readBytes.Length, _target.Position);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(3));
+        }
+
+        [TestMethod]
+        public void ReadShouldReadFromServer()
+        {
+            var serverBytes2 = GenerateRandom(5);
+            var readBytes2 = new byte[5];
+            var expectedReadBytes = new ArrayBuilder<byte>().Add(new byte[2])
+                                                            .Add(serverBytes2.Take(0, 3))
+                                                            .Build();
+
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestRead(_handle, (ulong) _readBytes.Length, _readBufferSize))
+                           .Returns(serverBytes2);
+
+            var bytesRead = _target.Read(readBytes2, 2, 3);
+
+            Assert.AreEqual(3, bytesRead);
+            CollectionAssert.AreEqual(expectedReadBytes, readBytes2);
+
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, (ulong)_readBytes.Length, _readBufferSize), Times.Once);
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(3));
+        }
+    }
+}

+ 81 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_SessionNotOpen.cs

@@ -0,0 +1,81 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+using System;
+using System.IO;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Flush_SessionNotOpen : SftpFileStreamTestBase
+    {
+        private SftpFileStream _target;
+        private string _path;
+        private byte[] _handle;
+        private uint _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private ObjectDisposedException _actualException;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            var random = new Random();
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(5, random);
+            _bufferSize = (uint) random.Next(1, 1000);
+            _readBufferSize = 20;
+            _writeBufferSize = 500;
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(false);
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.Read,
+                                         (int) _bufferSize);
+        }
+
+        protected override void Act()
+        {
+            try
+            {
+                _target.Flush();
+                Assert.Fail();
+            }
+            catch (ObjectDisposedException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void FlushShouldHaveThrownObjectDisposedException()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.IsNull(_actualException.InnerException);
+            Assert.AreEqual(string.Format("Cannot access a closed SFTP session.{0}Object name: '{1}'.", Environment.NewLine, _actualException.ObjectName), _actualException.Message);
+            Assert.AreEqual(typeof(SftpFileStream).FullName, _actualException.ObjectName);
+        }
+    }
+}

+ 149 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_WriteMode_DataInBuffer.cs

@@ -0,0 +1,149 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+using Renci.SshNet.Sftp.Responses;
+using Renci.SshNet.Tests.Common;
+using System;
+using System.IO;
+using System.Threading;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Flush_WriteMode_DataInBuffer : SftpFileStreamTestBase
+    {
+        private SftpFileStream _target;
+        private string _path;
+        private byte[] _handle;
+        private uint _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private byte[] _writeBytes1;
+        private byte[] _writeBytes2;
+        private byte[] _writeBytes3;
+        private byte[] _flushedBytes;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            var random = new Random();
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(5, random);
+            _bufferSize = (uint)random.Next(1, 1000);
+            _readBufferSize = 100;
+            _writeBufferSize = 500;
+            _writeBytes1 = GenerateRandom(_writeBufferSize);
+            _writeBytes2 = GenerateRandom(2);
+            _writeBytes3 = GenerateRandom(3);
+            _flushedBytes = null;
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestWrite(_handle, 0UL, It.IsAny<byte[]>(), 0, _writeBytes1.Length, It.IsAny<AutoResetEvent>(), null))
+                           .Callback<byte[], ulong, byte[], int, int, AutoResetEvent, Action<SftpStatusResponse>>((handle, serverOffset, data, offset, length, wait, writeCompleted)
+                               =>
+                           {
+                               wait.Set();
+                           });
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestWrite(_handle, (ulong) _writeBytes1.Length, It.IsAny<byte[]>(), 0, _writeBytes2.Length + _writeBytes3.Length, It.IsAny<AutoResetEvent>(), null))
+                           .Callback<byte[], ulong, byte[], int, int, AutoResetEvent, Action<SftpStatusResponse>>((handle, serverOffset, data, offset, length, wait, writeCompleted)
+                               =>
+                           {
+                               _flushedBytes = data.Take(offset, length);
+                               wait.Set();
+                           });
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.ReadWrite,
+                                         (int)_bufferSize);
+            _target.Write(_writeBytes1, 0, _writeBytes1.Length);
+            _target.Write(_writeBytes2, 0, _writeBytes2.Length);
+            _target.Write(_writeBytes3, 0, _writeBytes3.Length);
+        }
+
+        protected override void Act()
+        {
+            _target.Flush();
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnSameValueAsBeforeFlush()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+
+            Assert.AreEqual(_writeBytes1.Length + _writeBytes2.Length + _writeBytes3.Length, _target.Position);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(5));
+        }
+
+        [TestMethod]
+        public void BufferedBytesShouldHaveBeenWrittenToTheServer()
+        {
+            var expected = new ArrayBuilder<byte>().Add(_writeBytes2)
+                                                   .Add(_writeBytes3)
+                                                   .Build();
+
+            Assert.IsNotNull(_flushedBytes);
+            CollectionAssert.AreEqual(expected, _flushedBytes);
+        }
+
+        [TestMethod]
+        public void ReadShouldReadFromServer()
+        {
+            var serverBytes = GenerateRandom(5);
+            var readBytes = new byte[5];
+            var expectedReadBytes = new ArrayBuilder<byte>().Add(new byte[2])
+                                                            .Add(serverBytes.Take(0, 3))
+                                                            .Build();
+
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestRead(_handle, (ulong) (_writeBytes1.Length + _writeBytes2.Length + _writeBytes3.Length), _readBufferSize))
+                           .Returns(serverBytes);
+
+            var bytesRead = _target.Read(readBytes, 2, 3);
+
+            Assert.AreEqual(3, bytesRead);
+            CollectionAssert.AreEqual(expectedReadBytes, readBytes);
+
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, (ulong)(_writeBytes1.Length + _writeBytes2.Length + _writeBytes3.Length), _readBufferSize), Times.Once);
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(5));
+        }
+    }
+}

+ 117 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_WriteMode_NoDataInBuffer.cs

@@ -0,0 +1,117 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+using Renci.SshNet.Sftp.Responses;
+using Renci.SshNet.Tests.Common;
+using System;
+using System.IO;
+using System.Threading;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Flush_WriteMode_NoDataInBuffer : SftpFileStreamTestBase
+    {
+        private SftpFileStream _target;
+        private string _path;
+        private byte[] _handle;
+        private uint _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private byte[] _writeBytes;
+        private byte[] _requestWriteBytes;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            var random = new Random();
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(5, random);
+            _bufferSize = (uint)random.Next(1, 1000);
+            _readBufferSize = 100;
+            _writeBufferSize = 500;
+            _writeBytes = GenerateRandom(_writeBufferSize);
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestWrite(_handle, 0UL, It.IsAny<byte[]>(), 0, _writeBytes.Length, It.IsAny<AutoResetEvent>(), null))
+                           .Callback<byte[], ulong, byte[], int, int, AutoResetEvent, Action<SftpStatusResponse>>((handle, serverOffset, data, offset, length, wait, writeCompleted)
+                               =>
+                           {
+                               wait.Set();
+                           });
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.ReadWrite,
+                                         (int) _bufferSize);
+            _target.Write(_writeBytes, 0, _writeBytes.Length);
+        }
+
+        protected override void Act()
+        {
+            _target.Flush();
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnSameValueAsBeforeFlush()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+
+            Assert.AreEqual(_writeBytes.Length, _target.Position);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(3));
+        }
+
+        [TestMethod]
+        public void ReadShouldReadFromServer()
+        {
+            var serverBytes = GenerateRandom(5);
+            var readBytes = new byte[5];
+            var expectedReadBytes = new ArrayBuilder<byte>().Add(new byte[2])
+                                                            .Add(serverBytes.Take(0, 3))
+                                                            .Build();
+
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestRead(_handle, (ulong) _writeBytes.Length, _readBufferSize))
+                           .Returns(serverBytes);
+
+            var bytesRead = _target.Read(readBytes, 2, 3);
+
+            Assert.AreEqual(3, bytesRead);
+            CollectionAssert.AreEqual(expectedReadBytes, readBytes);
+
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, (ulong) _writeBytes.Length, _readBufferSize), Times.Once);
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(3));
+        }
+    }
+}

+ 85 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_Eof.cs

@@ -0,0 +1,85 @@
+using System;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_Eof : SftpFileStreamTestBase
+    {
+        private SftpFileStream _target;
+        private string _path;
+        private byte[] _handle;
+        private uint _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private int _actual;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            var random = new Random();
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(1, random);
+            _bufferSize = (uint) random.Next(1, 1000);
+            _readBufferSize = (uint) random.Next(0, 1000);
+            _writeBufferSize = (uint) random.Next(0, 1000);
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize))
+                           .Returns(new byte[0]);
+        }
+
+        [TestCleanup]
+        public void TearDown()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestClose(_handle));
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.Read,
+                                         (int)_bufferSize);
+        }
+
+        protected override void Act()
+        {
+            _actual = _target.ReadByte();
+        }
+
+        [TestMethod]
+        public void ReadByteShouldReturnMinusOne()
+        {
+            Assert.AreEqual(-1, _actual);
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnZero()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            Assert.AreEqual(0L, _target.Position);
+        }
+    }
+}

+ 90 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_LessDataThanReadBufferSizeAvailable.cs

@@ -0,0 +1,90 @@
+using System;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    /// <summary>
+    /// Test for issue #173.
+    /// </summary>
+    [TestClass]
+    public class SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_LessDataThanReadBufferSizeAvailable : SftpFileStreamTestBase
+    {
+        private SftpFileStream _target;
+        private string _path;
+        private byte[] _handle;
+        private uint _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private int _actual;
+        private byte[] _data;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            var random = new Random();
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(5, random);
+            _bufferSize = (uint) random.Next(5, 1000);
+            _readBufferSize = (uint) random.Next(10, 100);
+            _writeBufferSize = (uint) random.Next(10, 100);
+            _data = GenerateRandom((int) _readBufferSize - 2, random);
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestOpen(_path, Flags.Read, false))
+                           .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                           .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                           .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize))
+                           .Returns(_data);
+        }
+
+        [TestCleanup]
+        public void TearDown()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestClose(_handle));
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.Read,
+                                         (int)_bufferSize);
+        }
+
+        protected override void Act()
+        {
+            _actual = _target.ReadByte();
+        }
+
+        [TestMethod]
+        public void ReadByteShouldReturnFirstByteThatWasReadFromServer()
+        {
+            Assert.AreEqual(_data[0], _actual);
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnOne()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            Assert.AreEqual(1L, _target.Position);
+        }
+    }
+}

+ 155 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs

@@ -0,0 +1,155 @@
+using System;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Common;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize : SftpFileStreamTestBase
+    {
+        private string _path;
+        private SftpFileStream _target;
+        private byte[] _handle;
+        private uint _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private int _actual;
+        private byte[] _buffer;
+        private byte[] _serverData1;
+        private byte[] _serverData2;
+        private int _serverData1Length;
+        private int _serverData2Length;
+        private int _numberOfBytesToRead;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            var random = new Random();
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(5, random);
+            _bufferSize = (uint)random.Next(1, 1000);
+            _readBufferSize = 20;
+            _writeBufferSize = 500;
+
+            _numberOfBytesToRead = (int) _readBufferSize + 5; // greather than read buffer size
+            _buffer = new byte[_numberOfBytesToRead];
+            _serverData1Length = (int) _readBufferSize; // equal to read buffer size
+            _serverData1 = GenerateRandom(_serverData1Length, random);
+            _serverData2Length = (int) _readBufferSize; // equal to read buffer size
+            _serverData2 = GenerateRandom(_serverData2Length, random);
+
+            Assert.IsTrue(_serverData1Length < _numberOfBytesToRead && _serverData1Length == _readBufferSize);
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                .Setup(p => p.RequestOpen(_path, Flags.Read, false))
+                .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                .Setup(p => p.IsOpen)
+                .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                .Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize))
+                .Returns(_serverData1);
+            SftpSessionMock.InSequence(MockSequence)
+                .Setup(p => p.RequestRead(_handle, (ulong)_serverData1.Length, _readBufferSize))
+                .Returns(_serverData2);
+        }
+
+        [TestCleanup]
+        public void TearDown()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestClose(_handle));
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.Read,
+                                         (int)_bufferSize);
+        }
+
+        protected override void Act()
+        {
+            _actual = _target.Read(_buffer, 0, _numberOfBytesToRead);
+        }
+
+        [TestMethod]
+        public void ReadShouldHaveReturnedTheNumberOfBytesRequested()
+        {
+            Assert.AreEqual(_numberOfBytesToRead, _actual);
+        }
+
+        [TestMethod]
+        public void ReadShouldHaveWrittenBytesToTheCallerSuppliedBuffer()
+        {
+            Assert.IsTrue(_serverData1.IsEqualTo(_buffer.Take(_serverData1Length)));
+
+            var bytesWrittenFromSecondRead = _numberOfBytesToRead - _serverData1Length;
+            Assert.IsTrue(_serverData2.Take(bytesWrittenFromSecondRead).IsEqualTo(_buffer.Take(_serverData1Length, bytesWrittenFromSecondRead)));
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnNumberOfBytesWrittenToCallerProvidedBuffer()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            Assert.AreEqual(_actual, _target.Position);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(2));
+        }
+
+        [TestMethod]
+        public void ReadShouldReturnAllRemaningBytesFromReadBufferWhenCountIsEqualToNumberOfRemainingBytes()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            var numberOfBytesRemainingInReadBuffer = _serverData1Length + _serverData2Length - _numberOfBytesToRead;
+
+            _buffer = new byte[numberOfBytesRemainingInReadBuffer];
+
+            var actual = _target.Read(_buffer, 0, _buffer.Length);
+
+            Assert.AreEqual(_buffer.Length, actual);
+            Assert.IsTrue(_serverData2.Take(_numberOfBytesToRead - _serverData1Length, _buffer.Length).IsEqualTo(_buffer));
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(2));
+        }
+
+        [TestMethod]
+        public void ReadShouldReturnAllRemaningBytesFromReadBufferAndReadAgainWhenCountIsGreaterThanNumberOfRemainingBytesAndNewReadReturnsZeroBytes()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, (ulong)(_serverData1Length + _serverData2Length), _readBufferSize)).Returns(Array<byte>.Empty);
+
+            var numberOfBytesRemainingInReadBuffer = _serverData1Length + _serverData2Length - _numberOfBytesToRead;
+
+            _buffer = new byte[numberOfBytesRemainingInReadBuffer + 1];
+
+            var actual = _target.Read(_buffer, 0, _buffer.Length);
+
+            Assert.AreEqual(numberOfBytesRemainingInReadBuffer, actual);
+            Assert.IsTrue(_serverData2.Take(_numberOfBytesToRead - _serverData1Length, numberOfBytesRemainingInReadBuffer).IsEqualTo(_buffer.Take(numberOfBytesRemainingInReadBuffer)));
+            Assert.AreEqual(0, _buffer[numberOfBytesRemainingInReadBuffer]);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(2));
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, (ulong)(_serverData1Length + _serverData2Length), _readBufferSize));
+        }
+    }
+}

+ 148 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs

@@ -0,0 +1,148 @@
+using System;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Common;
+using Renci.SshNet.Sftp;
+using Renci.SshNet.Tests.Common;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize : SftpFileStreamTestBase
+    {
+        private string _path;
+        private SftpFileStream _target;
+        private byte[] _handle;
+        private uint _bufferSize;
+        private uint _readBufferSize;
+        private uint _writeBufferSize;
+        private int _actual;
+        private byte[] _buffer;
+        private byte[] _serverData;
+        private int _serverDataLength;
+        private int _numberOfBytesToRead;
+        private byte[] _originalBuffer;
+
+        protected override void SetupData()
+        {
+            base.SetupData();
+
+            var random = new Random();
+            _path = random.Next().ToString();
+            _handle = GenerateRandom(5, random);
+            _bufferSize = (uint)random.Next(1, 1000);
+            _readBufferSize = 20;
+            _writeBufferSize = 500;
+
+            _numberOfBytesToRead = (int) _readBufferSize + 2; // greater than read buffer size
+            _originalBuffer = GenerateRandom(_numberOfBytesToRead, random);
+            _buffer = _originalBuffer.Copy();
+
+            _serverDataLength = (int) _readBufferSize - 1; // less than read buffer size
+            _serverData = GenerateRandom(_serverDataLength, random);
+
+            Assert.IsTrue(_serverDataLength < _numberOfBytesToRead && _serverDataLength < _readBufferSize);
+        }
+
+        protected override void SetupMocks()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                .Setup(p => p.RequestOpen(_path, Flags.Read, false))
+                .Returns(_handle);
+            SftpSessionMock.InSequence(MockSequence)
+                .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                .Returns(_readBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
+                .Returns(_writeBufferSize);
+            SftpSessionMock.InSequence(MockSequence)
+                .Setup(p => p.IsOpen)
+                .Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                .Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize))
+                .Returns(_serverData);
+        }
+
+        [TestCleanup]
+        public void TearDown()
+        {
+            SftpSessionMock.InSequence(MockSequence)
+                           .Setup(p => p.RequestClose(_handle));
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _target = new SftpFileStream(SftpSessionMock.Object,
+                                         _path,
+                                         FileMode.Open,
+                                         FileAccess.Read,
+                                         (int)_bufferSize);
+        }
+
+        protected override void Act()
+        {
+            _actual = _target.Read(_buffer, 0, _numberOfBytesToRead);
+        }
+
+        [TestMethod]
+        public void ReadShouldHaveReturnedTheNumberOfBytesReturnedByTheReadFromTheServer()
+        {
+            Assert.AreEqual(_serverDataLength, _actual);
+        }
+
+        [TestMethod]
+        public void ReadShouldHaveWrittenBytesToTheCallerSuppliedBufferAndRemainingBytesShouldRemainUntouched()
+        {
+            Assert.IsTrue(_serverData.IsEqualTo(_buffer.Take(_serverDataLength)));
+            Assert.IsTrue(_originalBuffer.Take(_serverDataLength, _originalBuffer.Length - _serverDataLength).IsEqualTo(_buffer.Take(_serverDataLength, _buffer.Length - _serverDataLength)));
+        }
+
+        [TestMethod]
+        public void PositionShouldReturnNumberOfBytesWrittenToCallerProvidedBuffer()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            Assert.AreEqual(_actual, _target.Position);
+
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(2));
+        }
+
+        [TestMethod]
+        public void SubsequentReadShouldReadAgainFromCurrentPositionFromServerAndReturnZeroWhenServerReturnsZeroBytes()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                .Setup(p => p.RequestRead(_handle, (ulong) _actual, _readBufferSize))
+                .Returns(Array<byte>.Empty);
+
+            var buffer = _originalBuffer.Copy();
+            var actual = _target.Read(buffer, 0, buffer.Length);
+
+            Assert.AreEqual(0, actual);
+            Assert.IsTrue(_originalBuffer.IsEqualTo(buffer));
+
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, (ulong)_actual, _readBufferSize), Times.Once);
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(2));
+        }
+
+        [TestMethod]
+        public void SubsequentReadShouldReadAgainFromCurrentPositionFromServerAndNotUpdatePositionWhenServerReturnsZeroBytes()
+        {
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+            SftpSessionMock.InSequence(MockSequence)
+                .Setup(p => p.RequestRead(_handle, (ulong)_actual, _readBufferSize))
+                .Returns(Array<byte>.Empty);
+            SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true);
+
+            _target.Read(new byte[10], 0, 10);
+
+            Assert.AreEqual(_actual, _target.Position);
+
+            SftpSessionMock.Verify(p => p.RequestRead(_handle, (ulong)_actual, _readBufferSize), Times.Once);
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Exactly(3));
+        }
+    }
+}

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio