Quellcode durchsuchen

Merge remote-tracking branch 'refs/remotes/origin/develop'

Gert Driesen vor 8 Jahren
Ursprung
Commit
cdf50d2a37
100 geänderte Dateien mit 5691 neuen und 486 gelöschten Zeilen
  1. 38 1
      README.md
  2. 2 2
      build/nuget/SSH.NET.nuspec
  3. 1 29
      src/Renci.SshNet.NET35/Common/Extensions.NET35.cs
  4. 19 1
      src/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj
  5. 1 1
      src/Renci.SshNet.NETCore/Renci.SshNet.NETCore.csproj
  6. 20 2
      src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj
  7. 20 2
      src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj
  8. 120 0
      src/Renci.SshNet.Tests.NET35/Renci.SshNet.Tests.NET35.csproj
  9. 3 2
      src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs
  10. 85 37
      src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived.cs
  11. 11 11
      src/Renci.SshNet.Tests/Classes/Common/AsyncResultTest.cs
  12. 4 5
      src/Renci.SshNet.Tests/Classes/Common/AuthenticationBannerEventArgsTest.cs
  13. 5 6
      src/Renci.SshNet.Tests/Classes/Common/AuthenticationPasswordChangeEventArgsTest.cs
  14. 4 5
      src/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptEventArgsTest.cs
  15. 5 6
      src/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptTest.cs
  16. 11 12
      src/Renci.SshNet.Tests/Classes/Common/BigIntegerTest.cs
  17. 136 5
      src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest.cs
  18. 109 0
      src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_NotSet.cs
  19. 107 0
      src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_Set.cs
  20. 16 17
      src/Renci.SshNet.Tests/Classes/Common/DerDataTest.cs
  21. 4 4
      src/Renci.SshNet.Tests/Classes/Common/ExceptionEventArgsTest.cs
  22. 2 1
      src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Concat.cs
  23. 9 8
      src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_IsEqualTo_ByteArray.cs
  24. 1 0
      src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Reverse.cs
  25. 3 1
      src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Take_Count.cs
  26. 1 0
      src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Take_OffsetAndCount.cs
  27. 1 0
      src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_TrimLeadingZeros.cs
  28. 5 5
      src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs
  29. 6 6
      src/Renci.SshNet.Tests/Classes/Common/NetConfServerExceptionTest.cs
  30. 4 5
      src/Renci.SshNet.Tests/Classes/Common/ObjectIdentifierTest.cs
  31. 3 3
      src/Renci.SshNet.Tests/Classes/Common/PipeStreamTest.cs
  32. 3 3
      src/Renci.SshNet.Tests/Classes/Common/PortForwardEventArgsTest.cs
  33. 157 0
      src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetFileName.cs
  34. 6 6
      src/Renci.SshNet.Tests/Classes/Common/ProxyExceptionTest.cs
  35. 4 5
      src/Renci.SshNet.Tests/Classes/Common/ScpDownloadEventArgsTest.cs
  36. 6 6
      src/Renci.SshNet.Tests/Classes/Common/ScpExceptionTest.cs
  37. 4 5
      src/Renci.SshNet.Tests/Classes/Common/ScpUploadEventArgsTest.cs
  38. 9 9
      src/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs
  39. 6 6
      src/Renci.SshNet.Tests/Classes/Common/SftpPathNotFoundExceptionTest.cs
  40. 6 6
      src/Renci.SshNet.Tests/Classes/Common/SftpPermissionDeniedExceptionTest.cs
  41. 5 6
      src/Renci.SshNet.Tests/Classes/Common/ShellDataEventArgsTest.cs
  42. 6 6
      src/Renci.SshNet.Tests/Classes/Common/SshAuthenticationExceptionTest.cs
  43. 9 9
      src/Renci.SshNet.Tests/Classes/Common/SshConnectionExceptionTest.cs
  44. 0 55
      src/Renci.SshNet.Tests/Classes/Common/SshDataTest.cs
  45. 8 8
      src/Renci.SshNet.Tests/Classes/Common/SshExceptionTest.cs
  46. 6 6
      src/Renci.SshNet.Tests/Classes/Common/SshOperationTimeoutExceptionTest.cs
  47. 6 6
      src/Renci.SshNet.Tests/Classes/Common/SshPassPhraseNullOrEmptyExceptionTest.cs
  48. 1188 0
      src/Renci.SshNet.Tests/Classes/RemotePathDoubleQuoteTransformationTest.cs
  49. 1188 0
      src/Renci.SshNet.Tests/Classes/RemotePathShellQuoteTransformationTest.cs
  50. 229 78
      src/Renci.SshNet.Tests/Classes/ScpClientTest.cs
  51. 45 0
      src/Renci.SshNet.Tests/Classes/ScpClientTestBase.cs
  52. 111 0
      src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs
  53. 110 0
      src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs
  54. 120 0
      src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs
  55. 111 0
      src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs
  56. 29 29
      src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs
  57. 22 39
      src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs
  58. 120 0
      src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs
  59. 1 0
      src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs
  60. 1 0
      src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Arc4CipherTest.cs
  61. 1 0
      src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/DesCipherTest.cs
  62. 1 0
      src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Paddings/PKCS5PaddingTest.cs
  63. 1 0
      src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Paddings/PKCS7PaddingTest.cs
  64. 95 0
      src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_EndLStatThrowsSshException.cs
  65. 98 0
      src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsAlmostSixTimesGreaterThanChunkSize.cs
  66. 98 0
      src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsEqualToChunkSize.cs
  67. 98 0
      src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsExactlyFiveTimesGreaterThanChunkSize.cs
  68. 98 0
      src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLessThanChunkSize.cs
  69. 98 0
      src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLittleMoreThanFiveTimesGreaterThanChunkSize.cs
  70. 98 0
      src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanTenTimesGreaterThanChunkSize.cs
  71. 98 0
      src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsZero.cs
  72. 134 0
      src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream.cs
  73. 35 10
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_DisposeShouldUnblockReadAndReadAhead.cs
  74. 138 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsNotOpen.cs
  75. 141 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_BeginCloseThrowsException.cs
  76. 146 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_EndCloseThrowsException.cs
  77. 10 8
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_LastChunkBeforeEofIsComplete.cs
  78. 2 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_LastChunkBeforeEofIsPartial.cs
  79. 2 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsNotReached.cs
  80. 3 1
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsReached.cs
  81. 2 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadEndInvokeException_DiscardsFurtherReadAheads.cs
  82. 2 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadEndInvokeException_PreventsFurtherReadAheads.cs
  83. 2 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_ChunkAvailable.cs
  84. 2 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_NoChunkAvailable.cs
  85. 2 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReahAheadExceptionInBeginRead.cs
  86. 1 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessReadWrite.cs
  87. 1 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs
  88. 1 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileExists.cs
  89. 1 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessRead.cs
  90. 1 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessReadWrite.cs
  91. 1 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessRead.cs
  92. 1 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessReadWrite.cs
  93. 1 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessReadWrite.cs
  94. 1 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_NotReadFromBuffer.cs
  95. 1 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_ReadFromBuffer.cs
  96. 1 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_NoDataInBuffer.cs
  97. 1 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_WriteMode_DataInBuffer.cs
  98. 1 1
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_WriteMode_NoDataInBuffer.cs
  99. 0 1
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetPositive.cs
  100. 1 0
      src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_ReadBuffer.cs

+ 38 - 1
README.md

@@ -59,7 +59,10 @@ This project was inspired by **Sharp.SSH** library which was ported from java an
 * Universal Windows Platform 10
 
 ## Usage
-Establish an SFTP connection using both password and public-key authentication:
+
+### Multi-factor authentication
+
+Establish a SFTP connection using both password and public-key authentication:
 
 ```cs
 var connectionInfo = new ConnectionInfo("sftp.foo.com",
@@ -73,6 +76,40 @@ using (var client = new SftpClient(connectionInfo))
 
 ```
 
+### Verify host identify
+
+Establish a SSH connection using user name and password, and reject the connection if the fingerprint of the server does not match the expected fingerprint:
+
+```cs
+byte[] expectedFingerPrint = new byte[] {
+                                            0x66, 0x31, 0xaf, 0x00, 0x54, 0xb9, 0x87, 0x31,
+                                            0xff, 0x58, 0x1c, 0x31, 0xb1, 0xa2, 0x4c, 0x6b
+                                        };
+
+using (var client = new SshClient("sftp.foo.com", "guest", "pwd"))
+{
+    client.HostKeyReceived += (sender, e) =>
+        {
+            if (expectedFingerPrint.Length == e.FingerPrint.Length)
+            {
+                for (var i = 0; i < expectedFingerPrint.Length; i++)
+                {
+                    if (expectedFingerPrint[i] != e.FingerPrint[i])
+                    {
+                        e.CanTrust = false;
+                        break;
+                    }
+                }
+            }
+            else
+            {
+                e.CanTrust = false;
+            }
+        };
+    client.Connect();
+}
+```
+
 ## Building SSH.NET
 
 Software                          | net35 | net40 | netstandard1.3 | sl4 | sl5 | wp71 | wp8 | uap10.0 |

+ 2 - 2
build/nuget/SSH.NET.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
         <id>SSH.NET</id>
-        <version>2016.1.0-beta2</version>
+        <version>2016.1.0-beta3</version>
         <title>SSH.NET</title>
         <authors>Renci</authors>
         <owners>olegkap,drieseng</owners>
@@ -10,7 +10,7 @@
         <projectUrl>https://github.com/sshnet/SSH.NET/</projectUrl>
         <requireLicenseAcceptance>false</requireLicenseAcceptance>
         <description>SSH.NET is a Secure Shell (SSH) library for .NET, optimized for parallelism and with broad framework support.</description>
-        <releaseNotes>https://github.com/sshnet/SSH.NET/releases/tag/2016.1.0-beta2</releaseNotes>
+        <releaseNotes>https://github.com/sshnet/SSH.NET/releases/tag/2016.1.0-beta3</releaseNotes>
         <summary>A Secure Shell (SSH) library for .NET, optimized for parallelism.</summary>
         <copyright>2012-2017, RENCI</copyright>
         <language>en-US</language>

+ 1 - 29
src/Renci.SshNet.NET35/Common/Extensions.NET35.cs

@@ -1,43 +1,15 @@
 using System;
 using System.Diagnostics;
-using System.Net.Sockets;
 using System.Security.Cryptography;
 using System.Text;
-using System.Threading;
 
-namespace Renci.SshNet
+namespace Renci.SshNet.Common
 {
     /// <summary>
     /// Collection of different extension method specific for .NET 3.5
     /// </summary>
     internal static partial class Extensions
     {
-        /// <summary>
-        /// Disposes the specified socket.
-        /// </summary>
-        /// <param name="socket">The socket.</param>
-        [DebuggerNonUserCode]
-        internal static void Dispose(this Socket socket)
-        {
-            if (socket == null)
-                throw new NullReferenceException();
-
-            socket.Close();
-        }
-
-        /// <summary>
-        /// Disposes the specified handle.
-        /// </summary>
-        /// <param name="handle">The handle.</param>
-        [DebuggerNonUserCode]
-        internal static void Dispose(this WaitHandle handle)
-        {
-            if (handle == null)
-                throw new NullReferenceException();
-
-            handle.Close();
-        }
-
         /// <summary>
         /// Disposes the specified algorithm.
         /// </summary>

+ 19 - 1
src/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj

@@ -197,6 +197,9 @@
     <Compile Include="..\Renci.SshNet\Common\PortForwardEventArgs.cs">
       <Link>Common\PortForwardEventArgs.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Common\PosixPath.cs">
+      <Link>Common\PosixPath.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Common\ProxyException.cs">
       <Link>Common\ProxyException.cs</Link>
     </Compile>
@@ -305,6 +308,9 @@
     <Compile Include="..\Renci.SshNet\IForwardedPort.cs">
       <Link>IForwardedPort.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\IRemotePathTransformation.cs">
+      <Link>IRemotePathTransformation.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\IServiceFactory.cs">
       <Link>IServiceFactory.cs</Link>
     </Compile>
@@ -575,6 +581,18 @@
     <Compile Include="..\Renci.SshNet\ProxyTypes.cs">
       <Link>ProxyTypes.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\RemotePathDoubleQuoteTransformation.cs">
+      <Link>RemotePathDoubleQuoteTransformation.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\RemotePathNoneTransformation.cs">
+      <Link>RemotePathNoneTransformation.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\RemotePathShellQuoteTransformation.cs">
+      <Link>RemotePathShellQuoteTransformation.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\RemotePathTransformation.cs">
+      <Link>RemotePathTransformation.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\ScpClient.cs">
       <Link>ScpClient.cs</Link>
     </Compile>
@@ -953,7 +971,7 @@
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <ProjectExtensions>
     <VisualStudio>
-      <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. 

+ 1 - 1
src/Renci.SshNet.NETCore/Renci.SshNet.NETCore.csproj

@@ -102,7 +102,7 @@
     <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>
+    <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_SOCKET_DISPOSE;FEATURE_DNS_TAP;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;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>

+ 20 - 2
src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj

@@ -29,7 +29,7 @@
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
     <OutputPath>Bin\Debug</OutputPath>
-    <DefineConstants>TRACE;DEBUG;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_MEMORYSTREAM_GETBUFFER</DefineConstants>
+    <DefineConstants>TRACE;DEBUG;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_MEMORYSTREAM_GETBUFFER</DefineConstants>
     <NoStdLib>true</NoStdLib>
     <NoConfig>true</NoConfig>
     <ErrorReport>prompt</ErrorReport>
@@ -40,7 +40,7 @@
     <DebugType>none</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>Bin\Release</OutputPath>
-    <DefineConstants>TRACE;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_MEMORYSTREAM_GETBUFFER</DefineConstants>
+    <DefineConstants>TRACE;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_MEMORYSTREAM_GETBUFFER</DefineConstants>
     <NoStdLib>true</NoStdLib>
     <NoConfig>true</NoConfig>
     <ErrorReport>prompt</ErrorReport>
@@ -209,6 +209,9 @@
     <Compile Include="..\Renci.SshNet\Common\PortForwardEventArgs.cs">
       <Link>Common\PortForwardEventArgs.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Common\PosixPath.cs">
+      <Link>Common\PosixPath.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Common\ProxyException.cs">
       <Link>Common\ProxyException.cs</Link>
     </Compile>
@@ -311,6 +314,9 @@
     <Compile Include="..\Renci.SshNet\IForwardedPort.cs">
       <Link>IForwardedPort.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\IRemotePathTransformation.cs">
+      <Link>IRemotePathTransformation.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\IServiceFactory.cs">
       <Link>IServiceFactory.cs</Link>
     </Compile>
@@ -569,6 +575,18 @@
     <Compile Include="..\Renci.SshNet\ProxyTypes.cs">
       <Link>ProxyTypes.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\RemotePathDoubleQuoteTransformation.cs">
+      <Link>RemotePathDoubleQuoteTransformation.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\RemotePathNoneTransformation.cs">
+      <Link>RemotePathNoneTransformation.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\RemotePathShellQuoteTransformation.cs">
+      <Link>RemotePathShellQuoteTransformation.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\RemotePathTransformation.cs">
+      <Link>RemotePathTransformation.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\ScpClient.cs">
       <Link>ScpClient.cs</Link>
     </Compile>

+ 20 - 2
src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj

@@ -29,7 +29,7 @@
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
     <OutputPath>Bin\Debug</OutputPath>
-    <DefineConstants>TRACE;DEBUG;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256</DefineConstants>
+    <DefineConstants>TRACE;DEBUG;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256</DefineConstants>
     <NoStdLib>true</NoStdLib>
     <NoConfig>true</NoConfig>
     <ErrorReport>prompt</ErrorReport>
@@ -42,7 +42,7 @@
     <DebugType>none</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>Bin\Release</OutputPath>
-    <DefineConstants>TRACE;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256</DefineConstants>
+    <DefineConstants>TRACE;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256</DefineConstants>
     <NoStdLib>true</NoStdLib>
     <NoConfig>true</NoConfig>
     <ErrorReport>prompt</ErrorReport>
@@ -218,6 +218,9 @@
     <Compile Include="..\Renci.SshNet\Common\PortForwardEventArgs.cs">
       <Link>Common\PortForwardEventArgs.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\Common\PosixPath.cs">
+      <Link>Common\PosixPath.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\Common\ProxyException.cs">
       <Link>Common\ProxyException.cs</Link>
     </Compile>
@@ -320,6 +323,9 @@
     <Compile Include="..\Renci.SshNet\IForwardedPort.cs">
       <Link>IForwardedPort.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\IRemotePathTransformation.cs">
+      <Link>IRemotePathTransformation.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\IServiceFactory.cs">
       <Link>IServiceFactory.cs</Link>
     </Compile>
@@ -578,6 +584,18 @@
     <Compile Include="..\Renci.SshNet\ProxyTypes.cs">
       <Link>ProxyTypes.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet\RemotePathDoubleQuoteTransformation.cs">
+      <Link>RemotePathDoubleQuoteTransformation.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\RemotePathNoneTransformation.cs">
+      <Link>RemotePathNoneTransformation.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\RemotePathShellQuoteTransformation.cs">
+      <Link>RemotePathShellQuoteTransformation.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet\RemotePathTransformation.cs">
+      <Link>RemotePathTransformation.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet\ScpClient.cs">
       <Link>ScpClient.cs</Link>
     </Compile>

+ 120 - 0
src/Renci.SshNet.Tests.NET35/Renci.SshNet.Tests.NET35.csproj

@@ -273,12 +273,36 @@
     <Compile Include="..\Renci.SshNet.Tests\Classes\Common\CountdownEventTest.cs">
       <Link>Classes\Common\CountdownEventTest.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Common\CountdownEventTest_Dispose_NotSet.cs">
+      <Link>Classes\Common\CountdownEventTest_Dispose_NotSet.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Common\CountdownEventTest_Dispose_Set.cs">
+      <Link>Classes\Common\CountdownEventTest_Dispose_Set.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Common\DerDataTest.cs">
       <Link>Classes\Common\DerDataTest.cs</Link>
     </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Common\ExceptionEventArgsTest.cs">
       <Link>Classes\Common\ExceptionEventArgsTest.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Common\ExtensionsTest_Concat.cs">
+      <Link>Classes\Common\ExtensionsTest_Concat.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Common\ExtensionsTest_IsEqualTo_ByteArray.cs">
+      <Link>Classes\Common\ExtensionsTest_IsEqualTo_ByteArray.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Common\ExtensionsTest_Reverse.cs">
+      <Link>Classes\Common\ExtensionsTest_Reverse.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Common\ExtensionsTest_Take_Count.cs">
+      <Link>Classes\Common\ExtensionsTest_Take_Count.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Common\ExtensionsTest_Take_OffsetAndCount.cs">
+      <Link>Classes\Common\ExtensionsTest_Take_OffsetAndCount.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Common\ExtensionsTest_TrimLeadingZeros.cs">
+      <Link>Classes\Common\ExtensionsTest_TrimLeadingZeros.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Common\HostKeyEventArgsTest.cs">
       <Link>Classes\Common\HostKeyEventArgsTest.cs</Link>
     </Compile>
@@ -306,6 +330,9 @@
     <Compile Include="..\Renci.SshNet.Tests\Classes\Common\PortForwardEventArgsTest.cs">
       <Link>Classes\Common\PortForwardEventArgsTest.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Common\PosixPathTest_GetFileName.cs">
+      <Link>Classes\Common\PosixPathTest_GetFileName.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Common\ProxyExceptionTest.cs">
       <Link>Classes\Common\ProxyExceptionTest.cs</Link>
     </Compile>
@@ -744,15 +771,39 @@
     <Compile Include="..\Renci.SshNet.Tests\Classes\PrivateKeyFileTest.cs">
       <Link>Classes\PrivateKeyFileTest.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\RemotePathDoubleQuoteTransformationTest.cs">
+      <Link>Classes\RemotePathDoubleQuoteTransformationTest.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\RemotePathShellQuoteTransformationTest.cs">
+      <Link>Classes\RemotePathShellQuoteTransformationTest.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\ScpClientTest.cs">
       <Link>Classes\ScpClientTest.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ScpClientTestBase.cs">
+      <Link>Classes\ScpClientTestBase.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs">
+      <Link>Classes\ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs">
+      <Link>Classes\ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs">
+      <Link>Classes\ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs">
+      <Link>Classes\ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs">
       <Link>Classes\ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs</Link>
     </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\ScpClientTest_Upload_FileInfoAndPath_Success.cs">
       <Link>Classes\ScpClientTest_Upload_FileInfoAndPath_Success.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs">
+      <Link>Classes\ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Security\CertificateHostAlgorithmTest.cs">
       <Link>Classes\Security\CertificateHostAlgorithmTest.cs</Link>
     </Compile>
@@ -837,6 +888,33 @@
     <Compile Include="..\Renci.SshNet.Tests\Classes\Security\KeyHostAlgorithmTest.cs">
       <Link>Classes\Security\KeyHostAlgorithmTest.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ServiceFactoryTest_CreateSftpFileReader_EndLStatThrowsSshException.cs">
+      <Link>Classes\ServiceFactoryTest_CreateSftpFileReader_EndLStatThrowsSshException.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsAlmostSixTimesGreaterThanChunkSize.cs">
+      <Link>Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsAlmostSixTimesGreaterThanChunkSize.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsEqualToChunkSize.cs">
+      <Link>Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsEqualToChunkSize.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsExactlyFiveTimesGreaterThanChunkSize.cs">
+      <Link>Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsExactlyFiveTimesGreaterThanChunkSize.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLessThanChunkSize.cs">
+      <Link>Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLessThanChunkSize.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLittleMoreThanFiveTimesGreaterThanChunkSize.cs">
+      <Link>Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLittleMoreThanFiveTimesGreaterThanChunkSize.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanTenTimesGreaterThanChunkSize.cs">
+      <Link>Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanTenTimesGreaterThanChunkSize.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsZero.cs">
+      <Link>Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsZero.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ServiceFactoryTest_CreateShellStream.cs">
+      <Link>Classes\ServiceFactoryTest_CreateShellStream.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\SessionTest.cs">
       <Link>Classes\SessionTest.cs</Link>
     </Compile>
@@ -1032,6 +1110,15 @@
     <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_Dispose_SftpSessionIsNotOpen.cs">
+      <Link>Classes\Sftp\SftpFileReaderTest_Dispose_SftpSessionIsNotOpen.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileReaderTest_Dispose_SftpSessionIsOpen_BeginCloseThrowsException.cs">
+      <Link>Classes\Sftp\SftpFileReaderTest_Dispose_SftpSessionIsOpen_BeginCloseThrowsException.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileReaderTest_Dispose_SftpSessionIsOpen_EndCloseThrowsException.cs">
+      <Link>Classes\Sftp\SftpFileReaderTest_Dispose_SftpSessionIsOpen_EndCloseThrowsException.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\Sftp\SftpFileReaderTest_LastChunkBeforeEofIsComplete.cs">
       <Link>Classes\Sftp\SftpFileReaderTest_LastChunkBeforeEofIsComplete.cs</Link>
     </Compile>
@@ -1341,12 +1428,45 @@
     <Compile Include="..\Renci.SshNet.Tests\Classes\ShellStreamTest.cs">
       <Link>Classes\ShellStreamTest.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteLessBytesThanBufferSize.cs">
+      <Link>Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteLessBytesThanBufferSize.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteMoreBytesThanBufferSize.cs">
+      <Link>Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteMoreBytesThanBufferSize.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteNumberOfBytesEqualToBufferSize.cs">
+      <Link>Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteNumberOfBytesEqualToBufferSize.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteZeroBytes.cs">
+      <Link>Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteZeroBytes.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ShellStreamTest_Write_WriteBufferFullAndWriteLessBytesThanBufferSize.cs">
+      <Link>Classes\ShellStreamTest_Write_WriteBufferFullAndWriteLessBytesThanBufferSize.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ShellStreamTest_Write_WriteBufferFullAndWriteZeroBytes.cs">
+      <Link>Classes\ShellStreamTest_Write_WriteBufferFullAndWriteZeroBytes.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ShellStreamTest_Write_WriteBufferNotEmptyAndWriteLessBytesThanBufferCanContain.cs">
+      <Link>Classes\ShellStreamTest_Write_WriteBufferNotEmptyAndWriteLessBytesThanBufferCanContain.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ShellStreamTest_Write_WriteBufferNotEmptyAndWriteMoreBytesThanBufferCanContain.cs">
+      <Link>Classes\ShellStreamTest_Write_WriteBufferNotEmptyAndWriteMoreBytesThanBufferCanContain.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\ShellStreamTest_Write_WriteBufferNotEmptyAndWriteZeroBytes.cs">
+      <Link>Classes\ShellStreamTest_Write_WriteBufferNotEmptyAndWriteZeroBytes.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\ShellTestTest.cs">
       <Link>Classes\ShellTestTest.cs</Link>
     </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\SshClientTest.cs">
       <Link>Classes\SshClientTest.cs</Link>
     </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSizeAndTerminalModes_Connected.cs">
+      <Link>Classes\SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSizeAndTerminalModes_Connected.cs</Link>
+    </Compile>
+    <Compile Include="..\Renci.SshNet.Tests\Classes\SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSize_Connected.cs">
+      <Link>Classes\SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSize_Connected.cs</Link>
+    </Compile>
     <Compile Include="..\Renci.SshNet.Tests\Classes\SshClientTest_Disconnect_ForwardedPortStarted.cs">
       <Link>Classes\SshClientTest_Disconnect_ForwardedPortStarted.cs</Link>
     </Compile>

+ 3 - 2
src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs

@@ -5,6 +5,9 @@ using System.Net.Sockets;
 using System.Threading;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
+#if !FEATURE_SOCKET_DISPOSE
+using Renci.SshNet.Common;
+#endif // !FEATURE_SOCKET_DISPOSE
 using Renci.SshNet.Channels;
 using Renci.SshNet.Messages.Connection;
 using Renci.SshNet.Tests.Common;
@@ -16,7 +19,6 @@ namespace Renci.SshNet.Tests.Classes.Channels
     {
         private Mock<ISession> _sessionMock;
         private Mock<IForwardedPort> _forwardedPortMock;
-        private Mock<IConnectionInfo> _connectionInfoMock;
         private ChannelDirectTcpip _channel;
         private uint _localChannelNumber;
         private uint _localWindowSize;
@@ -73,7 +75,6 @@ namespace Renci.SshNet.Tests.Classes.Channels
 
             _sessionMock = new Mock<ISession>(MockBehavior.Strict);
             _forwardedPortMock = new Mock<IForwardedPort>(MockBehavior.Strict);
-            _connectionInfoMock = new Mock<IConnectionInfo>(MockBehavior.Strict);
 
             var sequence = new MockSequence();
             _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true);

+ 85 - 37
src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived.cs

@@ -1,6 +1,5 @@
 using System;
 using System.Collections.Generic;
-using System.Diagnostics;
 using System.Threading;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
@@ -21,8 +20,68 @@ namespace Renci.SshNet.Tests.Classes.Channels
         private uint _remotePacketSize;
         private ChannelStub _channel;
         private List<ChannelEventArgs> _channelClosedRegister;
+        private List<ChannelEventArgs> _channelEndOfDataRegister;
         private IList<ExceptionEventArgs> _channelExceptionRegister;
         private ManualResetEvent _channelClosedReceived;
+        private Thread _raiseChannelCloseReceivedThread;
+
+        private void SetupData()
+        {
+            var random = new Random();
+
+            _localChannelNumber = (uint) random.Next(0, int.MaxValue);
+            _localWindowSize = (uint) random.Next(0, int.MaxValue);
+            _localPacketSize = (uint) random.Next(0, int.MaxValue);
+            _remoteChannelNumber = (uint) random.Next(0, int.MaxValue);
+            _remoteWindowSize = (uint) random.Next(0, int.MaxValue);
+            _remotePacketSize = (uint) random.Next(0, int.MaxValue);
+            _channelClosedRegister = new List<ChannelEventArgs>();
+            _channelEndOfDataRegister = new List<ChannelEventArgs>();
+            _channelExceptionRegister = new List<ExceptionEventArgs>();
+            _channelClosedReceived = new ManualResetEvent(false);
+            _raiseChannelCloseReceivedThread = null;
+        }
+
+        private void CreateMocks()
+        {
+            _sessionMock = new Mock<ISession>(MockBehavior.Strict);
+        }
+
+        private void SetupMocks()
+        {
+            var sequence = new MockSequence();
+
+            _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true);
+            _sessionMock.InSequence(sequence).Setup(p => p.TrySendMessage(It.Is<ChannelCloseMessage>(c => c.LocalChannelNumber == _remoteChannelNumber))).Returns(true);
+            _sessionMock.InSequence(sequence).Setup(p => p.WaitOnHandle(It.IsAny<EventWaitHandle>()))
+                .Callback<WaitHandle>(w =>
+                {
+                    _raiseChannelCloseReceivedThread = new Thread(() =>
+                    {
+                        Thread.Sleep(100);
+
+                        // signal that the ChannelCloseMessage was received; we use this to verify whether we've actually
+                        // waited on the EventWaitHandle to be set; this needs to be set before we raise the ChannelCloseReceived
+                        // to make sure the waithandle is signaled when the Dispose method completes (or else the assert that
+                        // checks whether the handle has been signaled, will sometimes fail)
+                        _channelClosedReceived.Set();
+
+                        // raise ChannelCloseReceived event to set waithandle for receiving SSH_MSG_CHANNEL_CLOSE message
+                        // from server which is waited on after sending the SSH_MSG_CHANNEL_CLOSE message to the server
+                        //
+                        // this will cause a new invocation of Close() that will block until the Close() that was invoked
+                        // as part of Dispose() has released the lock; as such, this thread cannot be joined until that
+                        // lock is released
+                        //
+                        // we're mocking the wait on the ChannelCloseMessage, but we still want
+                        // to get the channel in the state that it would have after actually receiving
+                        // the ChannelCloseMessage
+                        _sessionMock.Raise(s => s.ChannelCloseReceived += null, new MessageEventArgs<ChannelCloseMessage>(new ChannelCloseMessage(_localChannelNumber)));
+                    });
+                    _raiseChannelCloseReceivedThread.Start();
+                    w.WaitOne();
+                });
+        }
 
         [TestInitialize]
         public void Initialize()
@@ -39,49 +98,25 @@ namespace Renci.SshNet.Tests.Classes.Channels
                 _channelClosedReceived.Dispose();
                 _channelClosedReceived = null;
             }
+
+            if (_raiseChannelCloseReceivedThread != null && _raiseChannelCloseReceivedThread.IsAlive)
+            {
+                if (!_raiseChannelCloseReceivedThread.Join(1000))
+                {
+                    _raiseChannelCloseReceivedThread.Abort();
+                }
+            }
         }
 
         private void Arrange()
         {
-            var random = new Random();
-            _localChannelNumber = (uint)random.Next(0, int.MaxValue);
-            _localWindowSize = (uint)random.Next(0, int.MaxValue);
-            _localPacketSize = (uint)random.Next(0, int.MaxValue);
-            _remoteChannelNumber = (uint)random.Next(0, int.MaxValue);
-            _remoteWindowSize = (uint)random.Next(0, int.MaxValue);
-            _remotePacketSize = (uint)random.Next(0, int.MaxValue);
-            _channelClosedRegister = new List<ChannelEventArgs>();
-            _channelExceptionRegister = new List<ExceptionEventArgs>();
-            _channelClosedReceived = new ManualResetEvent(false);
-
-            _sessionMock = new Mock<ISession>(MockBehavior.Strict);
-
-            var sequence = new MockSequence();
-            _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true);
-            _sessionMock.InSequence(sequence).Setup(p => p.TrySendMessage(It.Is<ChannelCloseMessage>(c => c.LocalChannelNumber == _remoteChannelNumber))).Returns(true);
-            _sessionMock.InSequence(sequence).Setup(p => p.WaitOnHandle(It.IsAny<EventWaitHandle>()))
-                .Callback<WaitHandle>(w =>
-                    {
-                        new Thread(() =>
-                            {
-                                Thread.Sleep(100);
-                                // signal that the ChannelCloseMessage was received; we use this to verify whether we've actually
-                                // waited on the EventWaitHandle to be set
-                                _channelClosedReceived.Set();
-                                // raise ChannelCloseReceived event to set waithandle for receiving
-                                // SSH_MSG_CHANNEL_CLOSE message from server which is waited on after
-                                // sending the SSH_MSG_CHANNEL_CLOSE message to the server
-                                // 
-                                // we're mocking the wait on the ChannelCloseMessage, but we still want
-                                // to get the channel in the state that it would have after actually receiving
-                                // the ChannelCloseMessage
-                                _sessionMock.Raise(s => s.ChannelCloseReceived += null, new MessageEventArgs<ChannelCloseMessage>(new ChannelCloseMessage(_localChannelNumber)));
-                            }).Start();
-                        w.WaitOne();
-                    });
+            SetupData();
+            CreateMocks();
+            SetupMocks();
 
             _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize);
             _channel.Closed += (sender, args) => _channelClosedRegister.Add(args);
+            _channel.EndOfData += (sender, args) => _channelEndOfDataRegister.Add(args);
             _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args);
             _channel.InitializeRemoteChannelInfo(_remoteChannelNumber, _remoteWindowSize, _remotePacketSize);
             _channel.SetIsOpen(true);
@@ -137,10 +172,23 @@ namespace Renci.SshNet.Tests.Classes.Channels
             Assert.AreEqual(_localChannelNumber, _channelClosedRegister[0].ChannelNumber);
         }
 
+        [TestMethod]
+        public void EndOfDataEventShouldHaveFiredOnce()
+        {
+            Assert.AreEqual(1, _channelEndOfDataRegister.Count);
+            Assert.AreEqual(_localChannelNumber, _channelEndOfDataRegister[0].ChannelNumber);
+        }
+
         [TestMethod]
         public void ExceptionShouldNeverHaveFired()
         {
             Assert.AreEqual(0, _channelExceptionRegister.Count);
         }
+
+        [TestMethod]
+        public void ThreadThatRaisedChannelCloseReceivedShouldComplete()
+        {
+            _raiseChannelCloseReceivedThread.Join();
+        }
     }
 }

+ 11 - 11
src/Renci.SshNet.Tests/Classes/Common/AsyncResultTest.cs

@@ -1,7 +1,7 @@
-using Renci.SshNet.Common;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
+using System;
 using System.Threading;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
@@ -34,7 +34,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             return target;
         }
 
-        [TestMethod()]
+        [TestMethod]
         public void EndInvokeTest1()
         {
             EndInvokeTest1Helper<GenericParameterHelper>();
@@ -52,7 +52,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             Assert.Inconclusive("A method that does not return a value cannot be verified.");
         }
 
-        [TestMethod()]
+        [TestMethod]
         public void SetAsCompletedTest1()
         {
             SetAsCompletedTest1Helper<GenericParameterHelper>();
@@ -68,7 +68,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for EndInvoke
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void EndInvokeTest()
         {
             AsyncResult target = CreateAsyncResult(); // TODO: Initialize to an appropriate value
@@ -79,7 +79,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for SetAsCompleted
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SetAsCompletedTest()
         {
             AsyncResult target = CreateAsyncResult(); // TODO: Initialize to an appropriate value
@@ -92,7 +92,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for AsyncState
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void AsyncStateTest()
         {
             AsyncResult target = CreateAsyncResult(); // TODO: Initialize to an appropriate value
@@ -104,7 +104,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for AsyncWaitHandle
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void AsyncWaitHandleTest()
         {
             AsyncResult target = CreateAsyncResult(); // TODO: Initialize to an appropriate value
@@ -116,7 +116,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for CompletedSynchronously
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void CompletedSynchronouslyTest()
         {
             AsyncResult target = CreateAsyncResult(); // TODO: Initialize to an appropriate value
@@ -128,7 +128,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for IsCompleted
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void IsCompletedTest()
         {
             AsyncResult target = CreateAsyncResult(); // TODO: Initialize to an appropriate value

+ 4 - 5
src/Renci.SshNet.Tests/Classes/Common/AuthenticationBannerEventArgsTest.cs

@@ -1,6 +1,5 @@
-using Renci.SshNet.Common;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
@@ -11,13 +10,13 @@ namespace Renci.SshNet.Tests.Classes.Common
     ///This is a test class for AuthenticationBannerEventArgsTest and is intended
     ///to contain all AuthenticationBannerEventArgsTest Unit Tests
     ///</summary>
-    [TestClass()]
+    [TestClass]
     public class AuthenticationBannerEventArgsTest : TestBase
     {
         /// <summary>
         ///A test for AuthenticationBannerEventArgs Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void AuthenticationBannerEventArgsConstructorTest()
         {
             string username = string.Empty; // TODO: Initialize to an appropriate value

+ 5 - 6
src/Renci.SshNet.Tests/Classes/Common/AuthenticationPasswordChangeEventArgsTest.cs

@@ -1,6 +1,5 @@
-using Renci.SshNet.Common;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
@@ -11,13 +10,13 @@ namespace Renci.SshNet.Tests.Classes.Common
     ///This is a test class for AuthenticationPasswordChangeEventArgsTest and is intended
     ///to contain all AuthenticationPasswordChangeEventArgsTest Unit Tests
     ///</summary>
-    [TestClass()]
+    [TestClass]
     public class AuthenticationPasswordChangeEventArgsTest : TestBase
     {
         /// <summary>
         ///A test for AuthenticationPasswordChangeEventArgs Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void AuthenticationPasswordChangeEventArgsConstructorTest()
         {
             string username = string.Empty; // TODO: Initialize to an appropriate value
@@ -28,7 +27,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for NewPassword
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void NewPasswordTest()
         {
             string username = string.Empty; // TODO: Initialize to an appropriate value

+ 4 - 5
src/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptEventArgsTest.cs

@@ -1,7 +1,6 @@
-using Renci.SshNet.Common;
+using System.Collections.Generic;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
-using System.Collections.Generic;
+using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
@@ -12,13 +11,13 @@ namespace Renci.SshNet.Tests.Classes.Common
     ///This is a test class for AuthenticationPromptEventArgsTest and is intended
     ///to contain all AuthenticationPromptEventArgsTest Unit Tests
     ///</summary>
-    [TestClass()]
+    [TestClass]
     public class AuthenticationPromptEventArgsTest : TestBase
     {
         /// <summary>
         ///A test for AuthenticationPromptEventArgs Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void AuthenticationPromptEventArgsConstructorTest()
         {
             string username = string.Empty; // TODO: Initialize to an appropriate value

+ 5 - 6
src/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptTest.cs

@@ -1,6 +1,5 @@
-using Renci.SshNet.Common;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
@@ -9,13 +8,13 @@ namespace Renci.SshNet.Tests.Classes.Common
     ///This is a test class for AuthenticationPromptTest and is intended
     ///to contain all AuthenticationPromptTest Unit Tests
     ///</summary>
-    [TestClass()]
+    [TestClass]
     public class AuthenticationPromptTest : TestBase
     {
         /// <summary>
         ///A test for AuthenticationPrompt Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void AuthenticationPromptConstructorTest()
         {
             int id = 0; // TODO: Initialize to an appropriate value
@@ -28,7 +27,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for Response
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void ResponseTest()
         {
             int id = 0; // TODO: Initialize to an appropriate value

+ 11 - 12
src/Renci.SshNet.Tests/Classes/Common/BigIntegerTest.cs

@@ -16,7 +16,6 @@ using System.Globalization;
 using System.Threading;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Renci.SshNet.Common;
-using System.Text.RegularExpressions;
 #if FEATURE_NUMERICS_BIGINTEGER
 using BigInteger = System.Numerics.BigInteger;
 #else
@@ -34,7 +33,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             0x1D, 0x33, 0xFB, 0xFE, 0xB1, 0x2, 0x85, 0x44, 0xCA, 0xDC, 0xFB, 0x70, 0xD, 0x39,
             0xB1, 0x47, 0xB6, 0xE6, 0xA2, 0xD1, 0x19, 0x1E, 0x9F, 0xE4, 0x3C, 0x1E, 0x16, 0x56, 0x13, 0x9C, 0x4D, 0xD3,
             0x5C, 0x74, 0xC9, 0xBD, 0xFA, 0x56, 0x40, 0x58, 0xAC, 0x20, 0x6B, 0x55, 0xA2, 0xD5, 0x41, 0x38, 0xA4, 0x6D,
-            0xF6, 0x8C,
+            0xF6, 0x8C
         };
 
         private static readonly byte[] huge_b =
@@ -42,7 +41,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             0x96, 0x5, 0xDA, 0xFE, 0x93, 0x17, 0xC1, 0x93, 0xEC, 0x2F, 0x30, 0x2D, 0x8F,
             0x28, 0x13, 0x99, 0x70, 0xF4, 0x4C, 0x60, 0xA6, 0x49, 0x24, 0xF9, 0xB3, 0x4A, 0x41, 0x67, 0xDC, 0xDD, 0xB1,
             0xA5, 0xA6, 0xC0, 0x3D, 0x57, 0x9A, 0xCB, 0x29, 0xE2, 0x94, 0xAC, 0x6C, 0x7D, 0xEF, 0x3E, 0xC6, 0x7A, 0xC1,
-            0xA8, 0xC8, 0xB0, 0x20, 0x95, 0xE6, 0x4C, 0xE1, 0xE0, 0x4B, 0x49, 0xD5, 0x5A, 0xB7,
+            0xA8, 0xC8, 0xB0, 0x20, 0x95, 0xE6, 0x4C, 0xE1, 0xE0, 0x4B, 0x49, 0xD5, 0x5A, 0xB7
         };
 
         private static readonly byte[] huge_add =
@@ -50,7 +49,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             0xB3, 0x38, 0xD5, 0xFD, 0x45, 0x1A, 0x46, 0xD8, 0xB6, 0xC, 0x2C, 0x9E, 0x9C,
             0x61, 0xC4, 0xE0, 0x26, 0xDB, 0xEF, 0x31, 0xC0, 0x67, 0xC3, 0xDD, 0xF0, 0x68, 0x57, 0xBD, 0xEF, 0x79, 0xFF,
             0x78, 0x3, 0x35, 0x7, 0x15, 0x95, 0x22, 0x6A, 0x3A, 0x41, 0xCD, 0xD7, 0xD2, 0x91, 0x14, 0x8, 0xB3, 0x65,
-            0x16, 0xBF, 0x3D, 0x20, 0x95, 0xE6, 0x4C, 0xE1, 0xE0, 0x4B, 0x49, 0xD5, 0x5A, 0xB7,
+            0x16, 0xBF, 0x3D, 0x20, 0x95, 0xE6, 0x4C, 0xE1, 0xE0, 0x4B, 0x49, 0xD5, 0x5A, 0xB7
         };
 
         private static readonly byte[] a_m_b =
@@ -58,7 +57,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             0x87, 0x2D, 0x21, 0x0, 0x1E, 0xEB, 0xC3, 0xB0, 0xDD, 0xAC, 0xCB, 0x43, 0x7E, 0x10,
             0x9E, 0xAE, 0x45, 0xF2, 0x55, 0x71, 0x73, 0xD4, 0x7A, 0xEB, 0x88, 0xD3, 0xD4, 0xEE, 0x36, 0xBE, 0x9B, 0x2D,
             0xB6, 0xB3, 0x8B, 0x66, 0x60, 0x8B, 0x16, 0x76, 0x17, 0x74, 0xFE, 0xD7, 0xB2, 0x96, 0x7B, 0xBD, 0xE2, 0xC4,
-            0x2D, 0xDC, 0xDE, 0x6A, 0x19, 0xB3, 0x1E, 0x1F, 0xB4, 0xB6, 0x2A, 0xA5, 0x48,
+            0x2D, 0xDC, 0xDE, 0x6A, 0x19, 0xB3, 0x1E, 0x1F, 0xB4, 0xB6, 0x2A, 0xA5, 0x48
         };
 
         private static readonly byte[] b_m_a =
@@ -66,7 +65,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             0x79, 0xD2, 0xDE, 0xFF, 0xE1, 0x14, 0x3C, 0x4F, 0x22, 0x53, 0x34, 0xBC, 0x81,
             0xEF, 0x61, 0x51, 0xBA, 0xD, 0xAA, 0x8E, 0x8C, 0x2B, 0x85, 0x14, 0x77, 0x2C, 0x2B, 0x11, 0xC9, 0x41, 0x64,
             0xD2, 0x49, 0x4C, 0x74, 0x99, 0x9F, 0x74, 0xE9, 0x89, 0xE8, 0x8B, 0x1, 0x28, 0x4D, 0x69, 0x84, 0x42, 0x1D,
-            0x3B, 0xD2, 0x23, 0x21, 0x95, 0xE6, 0x4C, 0xE1, 0xE0, 0x4B, 0x49, 0xD5, 0x5A, 0xB7,
+            0x3B, 0xD2, 0x23, 0x21, 0x95, 0xE6, 0x4C, 0xE1, 0xE0, 0x4B, 0x49, 0xD5, 0x5A, 0xB7
         };
 
         private static readonly byte[] huge_mul =
@@ -77,17 +76,17 @@ namespace Renci.SshNet.Tests.Classes.Common
             0xBC, 0xCA, 0x3E, 0x94, 0x95, 0xDA, 0x49, 0xE2, 0xA8, 0x33, 0xA2, 0x6A, 0x33, 0xB1, 0xF2, 0xEA, 0x99, 0x32,
             0xD0, 0xB2, 0xAE, 0x55, 0x75, 0xBD, 0x19, 0xFC, 0x9A, 0xEC, 0x54, 0x87, 0x2A, 0x6, 0xCC, 0x78, 0xDA, 0x88,
             0xBB, 0xAB, 0xA5, 0x47, 0xEF, 0xC7, 0x2B, 0xC7, 0x5B, 0x32, 0x31, 0xCD, 0xD9, 0x53, 0x96, 0x1A, 0x9D, 0x9A,
-            0x57, 0x40, 0x51, 0xB6, 0x5D, 0xC, 0x17, 0xD1, 0x86, 0xE9, 0xA4, 0x20,
+            0x57, 0x40, 0x51, 0xB6, 0x5D, 0xC, 0x17, 0xD1, 0x86, 0xE9, 0xA4, 0x20
         };
 
-        private static readonly byte[] huge_div = {0x0,};
+        private static readonly byte[] huge_div = {0x0};
 
         private static readonly byte[] huge_rem =
         {
             0x1D, 0x33, 0xFB, 0xFE, 0xB1, 0x2, 0x85, 0x44, 0xCA, 0xDC, 0xFB, 0x70, 0xD,
             0x39, 0xB1, 0x47, 0xB6, 0xE6, 0xA2, 0xD1, 0x19, 0x1E, 0x9F, 0xE4, 0x3C, 0x1E, 0x16, 0x56, 0x13, 0x9C, 0x4D,
             0xD3, 0x5C, 0x74, 0xC9, 0xBD, 0xFA, 0x56, 0x40, 0x58, 0xAC, 0x20, 0x6B, 0x55, 0xA2, 0xD5, 0x41, 0x38, 0xA4,
-            0x6D, 0xF6, 0x8C,
+            0x6D, 0xF6, 0x8C
         };
         private static readonly byte[][] add_a = {new byte[] {1}, new byte[] {0xFF}, huge_a};
         private static readonly byte[][] add_b = {new byte[] {1}, new byte[] {1}, huge_b};
@@ -726,7 +725,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             arr = new byte[] { 0xFF, 00 };
             AssertEqual(arr, new BigInteger(arr).ToByteArray());
 
-            arr = new byte[] { 1, 0, 0, 0, 0, 0, };
+            arr = new byte[] { 1, 0, 0, 0, 0, 0 };
             AssertEqual(new byte[] { 1 }, new BigInteger(arr).ToByteArray());
         }
 
@@ -927,8 +926,8 @@ namespace Renci.SshNet.Tests.Classes.Common
         [TestMethod]
         public void ShortOperators()
         {
-            Assert.AreEqual(22, (int)new BigInteger((short)22), "#1");
-            Assert.AreEqual(-22, (int)new BigInteger((short)-22), "#2");
+            Assert.AreEqual(22, (int)new BigInteger(22), "#1");
+            Assert.AreEqual(-22, (int)new BigInteger(-22), "#2");
 
             try
             {

+ 136 - 5
src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest.cs

@@ -26,6 +26,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             var countdownEvent = CreateCountdownEvent(initialCount);
             Assert.AreEqual(initialCount, countdownEvent.CurrentCount);
             Assert.IsFalse(countdownEvent.IsSet);
+            Assert.IsFalse(countdownEvent.WaitHandle.WaitOne(0));
             countdownEvent.Dispose();
         }
 
@@ -37,6 +38,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             var countdownEvent = CreateCountdownEvent(0);
             Assert.AreEqual(initialCount, countdownEvent.CurrentCount);
             Assert.IsTrue(countdownEvent.IsSet);
+            Assert.IsTrue(countdownEvent.WaitHandle.WaitOne(0));
             countdownEvent.Dispose();
         }
 
@@ -49,6 +51,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             Assert.IsFalse(countdownEvent.Signal());
             Assert.AreEqual(--initialCount, countdownEvent.CurrentCount);
             Assert.IsFalse(countdownEvent.IsSet);
+            Assert.IsFalse(countdownEvent.WaitHandle.WaitOne(0));
             countdownEvent.Dispose();
         }
 
@@ -59,6 +62,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             Assert.IsTrue(countdownEvent.Signal());
             Assert.AreEqual(0, countdownEvent.CurrentCount);
             Assert.IsTrue(countdownEvent.IsSet);
+            Assert.IsTrue(countdownEvent.WaitHandle.WaitOne(0));
             countdownEvent.Dispose();
         }
 
@@ -82,10 +86,6 @@ namespace Renci.SshNet.Tests.Classes.Common
             }
         }
 
-        public void CurrentCountShouldReturnZeroAfterAttemptToDecrementCountBelowZero()
-        {
-        }
-
         [TestMethod]
         public void Wait_TimeoutInfinite_ShouldBlockUntilCountdownEventIsSet()
         {
@@ -118,6 +118,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             Assert.IsTrue(actual);
             Assert.AreEqual(expectedSignalCount, signalCount);
             Assert.IsTrue(countdownEvent.IsSet);
+            Assert.IsTrue(countdownEvent.WaitHandle.WaitOne(0));
             Assert.IsTrue(elapsedTime >= sleep);
             Assert.IsTrue(elapsedTime <= sleep.Add(TimeSpan.FromMilliseconds(100)));
 
@@ -156,6 +157,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             Assert.IsTrue(actual);
             Assert.AreEqual(expectedSignalCount, signalCount);
             Assert.IsTrue(countdownEvent.IsSet);
+            Assert.IsTrue(countdownEvent.WaitHandle.WaitOne(0));
             Assert.IsTrue(elapsedTime >= sleep);
             Assert.IsTrue(elapsedTime <= timeout);
 
@@ -163,7 +165,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         }
 
         [TestMethod]
-        public void Wait_ShouldReturnFalseTimeoutExpiresBeforeCountdownEventIsSet()
+        public void Wait_ShouldReturnFalseWhenTimeoutExpiresBeforeCountdownEventIsSet()
         {
             var sleep = TimeSpan.FromMilliseconds(100);
             var timeout = TimeSpan.FromMilliseconds(30);
@@ -193,6 +195,135 @@ namespace Renci.SshNet.Tests.Classes.Common
 
             Assert.IsFalse(actual);
             Assert.IsFalse(countdownEvent.IsSet);
+            Assert.IsFalse(countdownEvent.WaitHandle.WaitOne(0));
+            Assert.IsTrue(elapsedTime >= timeout);
+
+            countdownEvent.Wait(Session.InfiniteTimeSpan);
+            countdownEvent.Dispose();
+        }
+
+        [TestMethod]
+        public void WaitHandle_ShouldAlwaysReturnSameInstance()
+        {
+            var countdownEvent = CreateCountdownEvent(1);
+
+            var waitHandleA = countdownEvent.WaitHandle;
+            Assert.IsNotNull(waitHandleA);
+
+            var waitHandleB = countdownEvent.WaitHandle;
+            Assert.AreSame(waitHandleA, waitHandleB);
+        }
+
+        [TestMethod]
+        public void WaitHandle_WaitOne_TimeoutInfinite_ShouldBlockUntilCountdownEventIsSet()
+        {
+            var sleep = TimeSpan.FromMilliseconds(100);
+            var timeout = Session.InfiniteTimeSpan;
+
+            var countdownEvent = CreateCountdownEvent(1);
+            var signalCount = 0;
+            var expectedSignalCount = _random.Next(5, 20);
+
+            for (var i = 0; i < (expectedSignalCount - 1); i++)
+                countdownEvent.AddCount();
+
+            var threads = new Thread[expectedSignalCount];
+            for (var i = 0; i < expectedSignalCount; i++)
+            {
+                threads[i] = new Thread(() =>
+                {
+                    Thread.Sleep(sleep);
+                    Interlocked.Increment(ref signalCount);
+                    countdownEvent.Signal();
+                });
+                threads[i].Start();
+            }
+
+            var start = DateTime.Now;
+            var actual = countdownEvent.WaitHandle.WaitOne(timeout);
+            var elapsedTime = DateTime.Now - start;
+
+            Assert.IsTrue(actual);
+            Assert.AreEqual(expectedSignalCount, signalCount);
+            Assert.IsTrue(countdownEvent.IsSet);
+            Assert.IsTrue(countdownEvent.WaitHandle.WaitOne(0));
+            Assert.IsTrue(elapsedTime >= sleep);
+            Assert.IsTrue(elapsedTime <= sleep.Add(TimeSpan.FromMilliseconds(100)));
+
+            countdownEvent.Dispose();
+        }
+
+        [TestMethod]
+        public void WaitHandle_WaitOne_ShouldReturnTrueWhenCountdownEventIsSetBeforeTimeoutExpires()
+        {
+            var sleep = TimeSpan.FromMilliseconds(100);
+            var timeout = sleep.Add(TimeSpan.FromSeconds(2));
+
+            var countdownEvent = CreateCountdownEvent(1);
+            var signalCount = 0;
+            var expectedSignalCount = _random.Next(5, 20);
+
+            for (var i = 0; i < (expectedSignalCount - 1); i++)
+                countdownEvent.AddCount();
+
+            var threads = new Thread[expectedSignalCount];
+            for (var i = 0; i < expectedSignalCount; i++)
+            {
+                threads[i] = new Thread(() =>
+                {
+                    Thread.Sleep(sleep);
+                    Interlocked.Increment(ref signalCount);
+                    countdownEvent.Signal();
+                });
+                threads[i].Start();
+            }
+
+            var start = DateTime.Now;
+            var actual = countdownEvent.Wait(timeout);
+            var elapsedTime = DateTime.Now - start;
+
+            Assert.IsTrue(actual);
+            Assert.AreEqual(expectedSignalCount, signalCount);
+            Assert.IsTrue(countdownEvent.IsSet);
+            Assert.IsTrue(countdownEvent.WaitHandle.WaitOne(0));
+            Assert.IsTrue(elapsedTime >= sleep);
+            Assert.IsTrue(elapsedTime <= timeout);
+
+            countdownEvent.Dispose();
+        }
+
+        [TestMethod]
+        public void WaitHandle_WaitOne_ShouldReturnFalseWhenTimeoutExpiresBeforeCountdownEventIsSet()
+        {
+            var sleep = TimeSpan.FromMilliseconds(100);
+            var timeout = TimeSpan.FromMilliseconds(30);
+
+            var countdownEvent = CreateCountdownEvent(1);
+            var signalCount = 0;
+            var expectedSignalCount = _random.Next(5, 20);
+
+            for (var i = 0; i < (expectedSignalCount - 1); i++)
+                countdownEvent.AddCount();
+
+            var threads = new Thread[expectedSignalCount];
+            for (var i = 0; i < expectedSignalCount; i++)
+            {
+                threads[i] = new Thread(() =>
+                {
+                    Thread.Sleep(sleep);
+                    countdownEvent.Signal();
+                    Interlocked.Increment(ref signalCount);
+                });
+                threads[i].Start();
+            }
+
+            var start = DateTime.Now;
+            var actual = countdownEvent.WaitHandle.WaitOne(timeout);
+            var elapsedTime = DateTime.Now - start;
+
+            Assert.IsFalse(actual);
+            Assert.IsFalse(countdownEvent.IsSet);
+            Assert.IsFalse(countdownEvent.WaitHandle.WaitOne(0));
             Assert.IsTrue(elapsedTime >= timeout);
 
             countdownEvent.Wait(Session.InfiniteTimeSpan);

+ 109 - 0
src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_NotSet.cs

@@ -0,0 +1,109 @@
+using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+#if !FEATURE_THREAD_COUNTDOWNEVENT
+using CountdownEvent = Renci.SshNet.Common.CountdownEvent;
+#else
+using System.Threading;
+#endif
+
+namespace Renci.SshNet.Tests.Classes.Common
+{
+    [TestClass]
+    public class CountdownEventTest_Dispose_NotSet
+    {
+        private int _signalsRequired;
+        private CountdownEvent _countdownEvent;
+
+        [TestInitialize]
+        public void Initialize()
+        {
+            Arrange();
+            Act();
+        }
+
+        private void Arrange()
+        {
+            _signalsRequired = new Random().Next(1, 20);
+            _countdownEvent = new CountdownEvent(_signalsRequired);
+        }
+
+        private void Act()
+        {
+            _countdownEvent.Dispose();
+        }
+
+        [TestMethod]
+        public void AddCount_ShouldThrowObjectDisposedException()
+        {
+            try
+            {
+                _countdownEvent.AddCount();
+                Assert.Fail();
+            }
+            catch (ObjectDisposedException)
+            {
+            }
+        }
+
+        [TestMethod]
+        public void CurrentCount_ShouldReturnRemainingSignalsRequiredToSetEvent()
+        {
+            var actual = _countdownEvent.CurrentCount;
+
+            Assert.AreEqual(_signalsRequired, actual);
+        }
+
+        [TestMethod]
+        public void Dispose_ShouldNotThrow()
+        {
+            _countdownEvent.Dispose();
+        }
+
+        [TestMethod]
+        public void IsSet_ShouldReturnFalse()
+        {
+            var actual = _countdownEvent.IsSet;
+
+            Assert.IsFalse(actual);
+        }
+
+        [TestMethod]
+        public void Signal_ShouldThrowObjectDisposedException()
+        {
+            try
+            {
+                var set = _countdownEvent.Signal();
+                Assert.Fail("Should have thrown ObjectDisposedException, but returned: " + set);
+            }
+            catch (ObjectDisposedException)
+            {
+            }
+        }
+
+        [TestMethod]
+        public void Wait_TimeSpan_ShouldThrowObjectDisposedException()
+        {
+            try
+            {
+                var set = _countdownEvent.Wait(TimeSpan.FromSeconds(5));
+                Assert.Fail("Should have thrown ObjectDisposedException, but returned: " + set);
+            }
+            catch (ObjectDisposedException)
+            {
+            }
+        }
+
+        [TestMethod]
+        public void WaitHandle_ShouldThrowObjectDisposedException()
+        {
+            try
+            {
+                var waitHandle = _countdownEvent.WaitHandle;
+                Assert.Fail("Should have thrown ObjectDisposedException, but returned: " + waitHandle);
+            }
+            catch (ObjectDisposedException)
+            {
+            }
+        }
+    }
+}

+ 107 - 0
src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_Set.cs

@@ -0,0 +1,107 @@
+using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+#if !FEATURE_THREAD_COUNTDOWNEVENT
+using CountdownEvent = Renci.SshNet.Common.CountdownEvent;
+#else
+using System.Threading;
+#endif
+
+namespace Renci.SshNet.Tests.Classes.Common
+{
+    [TestClass]
+    public class CountdownEventTest_Dispose_Set
+    {
+        private CountdownEvent _countdownEvent;
+
+        [TestInitialize]
+        public void Initialize()
+        {
+            Arrange();
+            Act();
+        }
+
+        private void Arrange()
+        {
+            _countdownEvent = new CountdownEvent(0);
+        }
+
+        private void Act()
+        {
+            _countdownEvent.Dispose();
+        }
+
+        [TestMethod]
+        public void AddCount_ShouldThrowObjectDisposedException()
+        {
+            try
+            {
+                _countdownEvent.AddCount();
+                Assert.Fail();
+            }
+            catch (ObjectDisposedException)
+            {
+            }
+        }
+
+        [TestMethod]
+        public void CurrentCount_ShouldReturnZero()
+        {
+            var actual = _countdownEvent.CurrentCount;
+
+            Assert.AreEqual(0, actual);
+        }
+
+        [TestMethod]
+        public void Dispose_ShouldNotThrow()
+        {
+            _countdownEvent.Dispose();
+        }
+
+        [TestMethod]
+        public void IsSet_ShouldReturnTrue()
+        {
+            var actual = _countdownEvent.IsSet;
+
+            Assert.IsTrue(actual);
+        }
+
+        [TestMethod]
+        public void Signal_ShouldThrowObjectDisposedException()
+        {
+            try
+            {
+                var set = _countdownEvent.Signal();
+                Assert.Fail("Should have thrown ObjectDisposedException, but returned: " + set);
+            }
+            catch (ObjectDisposedException)
+            {
+            }
+        }
+
+        [TestMethod]
+        public void Wait_TimeSpan_ShouldThrowObjectDisposedException()
+        {
+            try
+            {
+                var set = _countdownEvent.Wait(TimeSpan.FromSeconds(5));
+                Assert.Fail("Should have thrown ObjectDisposedException, but returned: " + set);
+            }
+            catch (ObjectDisposedException)
+            {
+            }
+        }
+
+        [TestMethod]
+        public void WaitHandle_ShouldThrowObjectDisposedException()
+        {
+            try
+            {
+                var waitHandle = _countdownEvent.WaitHandle;
+                Assert.Fail("Should have thrown ObjectDisposedException, but returned: " + waitHandle);
+            }
+            catch (ObjectDisposedException)
+            {
+            }
+        }
+    }
+}

+ 16 - 17
src/Renci.SshNet.Tests/Classes/Common/DerDataTest.cs

@@ -1,6 +1,5 @@
-using Renci.SshNet.Common;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
@@ -9,14 +8,14 @@ namespace Renci.SshNet.Tests.Classes.Common
     ///This is a test class for DerDataTest and is intended
     ///to contain all DerDataTest Unit Tests
     ///</summary>
-    [TestClass()]
+    [TestClass]
     [Ignore] // placeholder for actual test
     public class DerDataTest : TestBase
     {
         /// <summary>
         ///A test for DerData Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void DerDataConstructorTest()
         {
             DerData target = new DerData();
@@ -26,7 +25,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for DerData Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void DerDataConstructorTest1()
         {
             byte[] data = null; // TODO: Initialize to an appropriate value
@@ -37,7 +36,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for Encode
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void EncodeTest()
         {
             DerData target = new DerData(); // TODO: Initialize to an appropriate value
@@ -51,7 +50,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for ReadBigInteger
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void ReadBigIntegerTest()
         {
             DerData target = new DerData(); // TODO: Initialize to an appropriate value
@@ -65,7 +64,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for ReadInteger
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void ReadIntegerTest()
         {
             DerData target = new DerData(); // TODO: Initialize to an appropriate value
@@ -79,7 +78,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for Write
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void WriteTest()
         {
             DerData target = new DerData(); // TODO: Initialize to an appropriate value
@@ -91,7 +90,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for Write
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void WriteTest1()
         {
             DerData target = new DerData(); // TODO: Initialize to an appropriate value
@@ -103,7 +102,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for Write
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void WriteTest2()
         {
             DerData target = new DerData(); // TODO: Initialize to an appropriate value
@@ -115,7 +114,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for Write
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void WriteTest3()
         {
             DerData target = new DerData(); // TODO: Initialize to an appropriate value
@@ -127,7 +126,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for Write
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void WriteTest4()
         {
             DerData target = new DerData(); // TODO: Initialize to an appropriate value
@@ -139,7 +138,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for Write
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void WriteTest5()
         {
             DerData target = new DerData(); // TODO: Initialize to an appropriate value
@@ -151,7 +150,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for WriteNull
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void WriteNullTest()
         {
             DerData target = new DerData(); // TODO: Initialize to an appropriate value
@@ -162,7 +161,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for IsEndOfData
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void IsEndOfDataTest()
         {
             DerData target = new DerData(); // TODO: Initialize to an appropriate value

+ 4 - 4
src/Renci.SshNet.Tests/Classes/Common/ExceptionEventArgsTest.cs

@@ -1,6 +1,6 @@
-using Renci.SshNet.Common;
+using System;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
+using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
@@ -9,13 +9,13 @@ namespace Renci.SshNet.Tests.Classes.Common
     ///This is a test class for ExceptionEventArgsTest and is intended
     ///to contain all ExceptionEventArgsTest Unit Tests
     ///</summary>
-    [TestClass()]
+    [TestClass]
     public class ExceptionEventArgsTest : TestBase
     {
         /// <summary>
         ///A test for ExceptionEventArgs Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void ExceptionEventArgsConstructorTest()
         {
             Exception exception = null; // TODO: Initialize to an appropriate value

+ 2 - 1
src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Concat.cs

@@ -157,7 +157,8 @@ namespace Renci.SshNet.Tests.Classes.Common
 
             Console.WriteLine(stopWatch.ElapsedMilliseconds);
 
-            stopWatch.Restart();
+            stopWatch.Reset();
+            stopWatch.Start();
 
             for (var i = 0; i < runs; i++)
             {

+ 9 - 8
src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_IsEqualTo_ByteArray.cs

@@ -1,8 +1,8 @@
 using System;
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
-using System.Linq;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
 {
@@ -76,7 +76,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         public void ShouldReturnFalseWhenLeftIsNotEqualToRight()
         {
             Assert.IsFalse(Extensions.IsEqualTo(new byte[] {0x0a}, new byte[] {0x0a, 0x0d}));
-            Assert.IsFalse(Extensions.IsEqualTo(new byte[] { 0x0a, 0x0d }, new byte[] { 0x0a }));
+            Assert.IsFalse(Extensions.IsEqualTo(new byte[] {0x0a, 0x0d}, new byte[] {0x0a}));
             Assert.IsFalse(Extensions.IsEqualTo(new byte[0], new byte[] { 0x0a }));
             Assert.IsFalse(Extensions.IsEqualTo(new byte[] { 0x0a, 0x0d }, new byte[0]));
         }
@@ -103,7 +103,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         {
             var buffer = CreateBuffer(50000);
             var left = buffer.Concat(new byte[] {0x0a});
-            var right = buffer.Concat(new byte[] { 0x0a });
+            var right = buffer.Concat(new byte[] {0x0a});
             const int runs = 10000;
 
             Performance(left, right, runs);
@@ -126,8 +126,8 @@ namespace Renci.SshNet.Tests.Classes.Common
         public void Performance_LargeArray_NotEqual_SameLength()
         {
             var buffer = CreateBuffer(50000);
-            var left = buffer.Concat(new byte[] { 0x0a });
-            var right = buffer.Concat(new byte[] { 0x0b });
+            var left = buffer.Concat(new byte[] {0x0a});
+            var right = buffer.Concat(new byte[] {0x0b});
             const int runs = 10000;
 
             Performance(left, right, runs);
@@ -139,7 +139,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         public void Performance_LargeArray_Same()
         {
             var left = CreateBuffer(50000);
-            var right = left.Concat(new byte[] { 0x0a });
+            var right = left.Concat(new byte[] {0x0a});
             const int runs = 10000;
 
             Performance(left, right, runs);
@@ -168,11 +168,12 @@ namespace Renci.SshNet.Tests.Classes.Common
 
             Console.WriteLine(stopWatch.ElapsedMilliseconds);
 
-            stopWatch.Restart();
+            stopWatch.Reset();
+            stopWatch.Start();
 
             for (var i = 0; i < runs; i++)
             {
-                var result = Enumerable.SequenceEqual(left, right);
+                var result = System.Linq.Enumerable.SequenceEqual(left, right);
             }
 
             GC.Collect();

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

@@ -2,6 +2,7 @@
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
 {

+ 3 - 1
src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Take_Count.cs

@@ -3,6 +3,7 @@ using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
 {
@@ -164,7 +165,8 @@ namespace Renci.SshNet.Tests.Classes.Common
 
             Console.WriteLine(stopWatch.ElapsedMilliseconds);
 
-            stopWatch.Restart();
+            stopWatch.Reset();
+            stopWatch.Start();
 
             for (var i = 0; i < runs; i++)
             {

+ 1 - 0
src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Take_OffsetAndCount.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Diagnostics.CodeAnalysis;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
 {

+ 1 - 0
src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_TrimLeadingZeros.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Diagnostics.CodeAnalysis;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
 {

+ 5 - 5
src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs

@@ -1,5 +1,5 @@
-using Renci.SshNet.Common;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 using Renci.SshNet.Security;
 using Renci.SshNet.Tests.Common;
 
@@ -9,14 +9,14 @@ namespace Renci.SshNet.Tests.Classes.Common
     ///This is a test class for HostKeyEventArgsTest and is intended
     ///to contain all HostKeyEventArgsTest Unit Tests
     ///</summary>
-    [TestClass()]
+    [TestClass]
     [Ignore] // placeholder for actual test
     public class HostKeyEventArgsTest : TestBase
     {
         /// <summary>
         ///A test for HostKeyEventArgs Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void HostKeyEventArgsConstructorTest()
         {
             KeyHostAlgorithm host = null; // TODO: Initialize to an appropriate value
@@ -27,7 +27,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for CanTrust
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void CanTrustTest()
         {
             KeyHostAlgorithm host = null; // TODO: Initialize to an appropriate value

+ 6 - 6
src/Renci.SshNet.Tests/Classes/Common/NetConfServerExceptionTest.cs

@@ -1,6 +1,6 @@
-using Renci.SshNet.Common;
+using System;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
+using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
@@ -9,13 +9,13 @@ namespace Renci.SshNet.Tests.Classes.Common
     ///This is a test class for NetConfServerExceptionTest and is intended
     ///to contain all NetConfServerExceptionTest Unit Tests
     ///</summary>
-    [TestClass()]
+    [TestClass]
     public class NetConfServerExceptionTest : TestBase
     {
         /// <summary>
         ///A test for NetConfServerException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void NetConfServerExceptionConstructorTest()
         {
             NetConfServerException target = new NetConfServerException();
@@ -25,7 +25,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for NetConfServerException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void NetConfServerExceptionConstructorTest1()
         {
             string message = string.Empty; // TODO: Initialize to an appropriate value
@@ -36,7 +36,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for NetConfServerException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void NetConfServerExceptionConstructorTest2()
         {
             string message = string.Empty; // TODO: Initialize to an appropriate value

+ 4 - 5
src/Renci.SshNet.Tests/Classes/Common/ObjectIdentifierTest.cs

@@ -1,6 +1,5 @@
-using Renci.SshNet.Common;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
@@ -9,14 +8,14 @@ namespace Renci.SshNet.Tests.Classes.Common
     ///This is a test class for ObjectIdentifierTest and is intended
     ///to contain all ObjectIdentifierTest Unit Tests
     ///</summary>
-    [TestClass()]
+    [TestClass]
     [Ignore] // placeholder for actual test
     public class ObjectIdentifierTest : TestBase
     {
         /// <summary>
         ///A test for ObjectIdentifier Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void ObjectIdentifierConstructorTest()
         {
             ulong[] identifiers = null; // TODO: Initialize to an appropriate value

+ 3 - 3
src/Renci.SshNet.Tests/Classes/Common/PipeStreamTest.cs

@@ -1,9 +1,9 @@
-using System.Threading;
+using System;
+using System.IO;
+using System.Threading;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
-using System;
-using System.IO;
 
 namespace Renci.SshNet.Tests.Classes.Common
 {

+ 3 - 3
src/Renci.SshNet.Tests/Classes/Common/PortForwardEventArgsTest.cs

@@ -1,8 +1,8 @@
-using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Net;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
-using System;
-using System.Net;
 using Renci.SshNet.Tests.Properties;
 
 namespace Renci.SshNet.Tests.Classes.Common

+ 157 - 0
src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetFileName.cs

@@ -0,0 +1,157 @@
+using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
+
+namespace Renci.SshNet.Tests.Classes.Common
+{
+    [TestClass]
+    public class PosixPathTest_GetFileName
+    {
+        [TestMethod]
+        public void Path_Null()
+        {
+            const string path = null;
+
+            try
+            {
+                PosixPath.GetFileName(path);
+                Assert.Fail();
+            }
+            catch (NullReferenceException)
+            {
+            }
+        }
+
+        [TestMethod]
+        public void Path_Empty()
+        {
+            var path = string.Empty;
+
+            var actual = PosixPath.GetFileName(path);
+
+            Assert.IsNotNull(actual);
+            Assert.AreSame(path, actual);
+        }
+
+        [TestMethod]
+        public void Path_TrailingForwardSlash()
+        {
+            var path = "/abc/";
+
+            var actual = PosixPath.GetFileName(path);
+
+            Assert.IsNotNull(actual);
+            Assert.AreEqual(string.Empty, actual);
+        }
+
+        [TestMethod]
+        public void Path_FileWithoutNoDirectory()
+        {
+            var path = "abc.log";
+
+            var actual = PosixPath.GetFileName(path);
+
+            Assert.IsNotNull(actual);
+            Assert.AreSame(path, actual);
+        }
+
+        [TestMethod]
+        public void Path_FileInRootDirectory()
+        {
+            var path = "/abc.log";
+
+            var actual = PosixPath.GetFileName(path);
+
+            Assert.IsNotNull(actual);
+            Assert.AreEqual("abc.log", actual);
+        }
+
+        [TestMethod]
+        public void Path_RootDirectoryOnly()
+        {
+            var path = "/";
+
+            var actual = PosixPath.GetFileName(path);
+
+            Assert.IsNotNull(actual);
+            Assert.AreEqual(string.Empty, actual);
+        }
+
+        [TestMethod]
+        public void Path_FileInNonRootDirectory()
+        {
+            var path = "/home/sshnet/xyz";
+
+            var actual = PosixPath.GetFileName(path);
+
+            Assert.IsNotNull(actual);
+            Assert.AreEqual("xyz", actual);
+        }
+
+        [TestMethod]
+        public void Path_BackslashIsNotConsideredDirectorySeparator()
+        {
+            var path = "/home\\abc.log";
+
+            var actual = PosixPath.GetFileName(path);
+
+            Assert.IsNotNull(actual);
+            Assert.AreEqual("home\\abc.log", actual);
+        }
+
+        [TestMethod]
+        public void Path_ColonIsNotConsideredPathSeparator()
+        {
+            var path = "/home:abc.log";
+
+            var actual = PosixPath.GetFileName(path);
+
+            Assert.IsNotNull(actual);
+            Assert.AreEqual("home:abc.log", actual);
+        }
+
+        [TestMethod]
+        public void Path_LeadingWhitespace()
+        {
+            var path = "  / \tabc";
+
+            var actual = PosixPath.GetFileName(path);
+
+            Assert.IsNotNull(actual);
+            Assert.AreEqual(" \tabc", actual);
+        }
+
+        [TestMethod]
+        public void Path_TrailingWhitespace()
+        {
+            var path = "/abc \t ";
+
+            var actual = PosixPath.GetFileName(path);
+
+            Assert.IsNotNull(actual);
+            Assert.AreEqual("abc \t ", actual);
+        }
+
+        [TestMethod]
+        public void Path_OnlyWhitespace()
+        {
+            var path = " ";
+
+            var actual = PosixPath.GetFileName(path);
+
+            Assert.IsNotNull(actual);
+            Assert.AreEqual(" ", actual);
+        }
+
+        [TestMethod]
+        public void Path_FileNameOnlyWhitespace()
+        {
+            var path = "/home/\t ";
+
+            var actual = PosixPath.GetFileName(path);
+
+            Assert.IsNotNull(actual);
+            Assert.AreEqual("\t ", actual);
+        }
+    }
+}

+ 6 - 6
src/Renci.SshNet.Tests/Classes/Common/ProxyExceptionTest.cs

@@ -1,6 +1,6 @@
-using Renci.SshNet.Common;
+using System;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
+using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
@@ -9,13 +9,13 @@ namespace Renci.SshNet.Tests.Classes.Common
     ///This is a test class for ProxyExceptionTest and is intended
     ///to contain all ProxyExceptionTest Unit Tests
     ///</summary>
-    [TestClass()]
+    [TestClass]
     public class ProxyExceptionTest : TestBase
     {
         /// <summary>
         ///A test for ProxyException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void ProxyExceptionConstructorTest()
         {
             ProxyException target = new ProxyException();
@@ -25,7 +25,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for ProxyException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void ProxyExceptionConstructorTest1()
         {
             string message = string.Empty; // TODO: Initialize to an appropriate value
@@ -36,7 +36,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for ProxyException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void ProxyExceptionConstructorTest2()
         {
             string message = string.Empty; // TODO: Initialize to an appropriate value

+ 4 - 5
src/Renci.SshNet.Tests/Classes/Common/ScpDownloadEventArgsTest.cs

@@ -1,6 +1,5 @@
-using Renci.SshNet.Common;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
@@ -9,13 +8,13 @@ namespace Renci.SshNet.Tests.Classes.Common
     ///This is a test class for ScpDownloadEventArgsTest and is intended
     ///to contain all ScpDownloadEventArgsTest Unit Tests
     ///</summary>
-    [TestClass()]
+    [TestClass]
     public class ScpDownloadEventArgsTest : TestBase
     {
         /// <summary>
         ///A test for ScpDownloadEventArgs Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void ScpDownloadEventArgsConstructorTest()
         {
             string filename = string.Empty; // TODO: Initialize to an appropriate value

+ 6 - 6
src/Renci.SshNet.Tests/Classes/Common/ScpExceptionTest.cs

@@ -1,6 +1,6 @@
-using Renci.SshNet.Common;
+using System;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
+using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
@@ -9,13 +9,13 @@ namespace Renci.SshNet.Tests.Classes.Common
     ///This is a test class for ScpExceptionTest and is intended
     ///to contain all ScpExceptionTest Unit Tests
     ///</summary>
-    [TestClass()]
+    [TestClass]
     public class ScpExceptionTest : TestBase
     {
         /// <summary>
         ///A test for ScpException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void ScpExceptionConstructorTest()
         {
             ScpException target = new ScpException();
@@ -25,7 +25,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for ScpException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void ScpExceptionConstructorTest1()
         {
             string message = string.Empty; // TODO: Initialize to an appropriate value
@@ -36,7 +36,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for ScpException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void ScpExceptionConstructorTest2()
         {
             string message = string.Empty; // TODO: Initialize to an appropriate value

+ 4 - 5
src/Renci.SshNet.Tests/Classes/Common/ScpUploadEventArgsTest.cs

@@ -1,6 +1,5 @@
-using Renci.SshNet.Common;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
@@ -9,13 +8,13 @@ namespace Renci.SshNet.Tests.Classes.Common
     ///This is a test class for ScpUploadEventArgsTest and is intended
     ///to contain all ScpUploadEventArgsTest Unit Tests
     ///</summary>
-    [TestClass()]
+    [TestClass]
     public class ScpUploadEventArgsTest : TestBase
     {
         /// <summary>
         ///A test for ScpUploadEventArgs Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void ScpUploadEventArgsConstructorTest()
         {
             string filename = string.Empty; // TODO: Initialize to an appropriate value

+ 9 - 9
src/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs

@@ -1,15 +1,15 @@
-using System.Threading;
-using Renci.SshNet.Common;
+using System;
+using System.Threading;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
+using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
 {
-    [TestClass()]
+    [TestClass]
     public class SemaphoreLightTest : TestBase
     {
-        [TestMethod()]
+        [TestMethod]
         public void SemaphoreLightConstructorTest()
         {
             var initialCount = new Random().Next(1, 10);
@@ -17,7 +17,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             Assert.AreEqual(initialCount, target.CurrentCount);
         }
 
-        [TestMethod()]
+        [TestMethod]
         public void Release()
         {
             var initialCount = new Random().Next(1, 10);
@@ -33,7 +33,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for Release
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void Release_ReleaseCount()
         {
             var initialCount = new Random().Next(1, 10);
@@ -51,7 +51,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for Wait
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void WaitTest()
         {
             const int sleepTime = 200; 
@@ -82,7 +82,7 @@ namespace Renci.SshNet.Tests.Classes.Common
             Assert.IsTrue(elapsed.TotalMilliseconds < 250);
         }
 
-        [TestMethod()]
+        [TestMethod]
         public void CurrentCountTest()
         {
             var initialCount = new Random().Next(1, 20);

+ 6 - 6
src/Renci.SshNet.Tests/Classes/Common/SftpPathNotFoundExceptionTest.cs

@@ -1,6 +1,6 @@
-using Renci.SshNet.Common;
+using System;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
+using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
@@ -9,13 +9,13 @@ namespace Renci.SshNet.Tests.Classes.Common
     ///This is a test class for SftpPathNotFoundExceptionTest and is intended
     ///to contain all SftpPathNotFoundExceptionTest Unit Tests
     ///</summary>
-    [TestClass()]
+    [TestClass]
     public class SftpPathNotFoundExceptionTest : TestBase
     {
         /// <summary>
         ///A test for SftpPathNotFoundException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SftpPathNotFoundExceptionConstructorTest()
         {
             SftpPathNotFoundException target = new SftpPathNotFoundException();
@@ -25,7 +25,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for SftpPathNotFoundException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SftpPathNotFoundExceptionConstructorTest1()
         {
             string message = string.Empty; // TODO: Initialize to an appropriate value
@@ -36,7 +36,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for SftpPathNotFoundException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SftpPathNotFoundExceptionConstructorTest2()
         {
             string message = string.Empty; // TODO: Initialize to an appropriate value

+ 6 - 6
src/Renci.SshNet.Tests/Classes/Common/SftpPermissionDeniedExceptionTest.cs

@@ -1,6 +1,6 @@
-using Renci.SshNet.Common;
+using System;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
+using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
@@ -9,13 +9,13 @@ namespace Renci.SshNet.Tests.Classes.Common
     ///This is a test class for SftpPermissionDeniedExceptionTest and is intended
     ///to contain all SftpPermissionDeniedExceptionTest Unit Tests
     ///</summary>
-    [TestClass()]
+    [TestClass]
     public class SftpPermissionDeniedExceptionTest : TestBase
     {
         /// <summary>
         ///A test for SftpPermissionDeniedException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SftpPermissionDeniedExceptionConstructorTest()
         {
             SftpPermissionDeniedException target = new SftpPermissionDeniedException();
@@ -25,7 +25,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for SftpPermissionDeniedException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SftpPermissionDeniedExceptionConstructorTest1()
         {
             string message = string.Empty; // TODO: Initialize to an appropriate value
@@ -36,7 +36,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for SftpPermissionDeniedException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SftpPermissionDeniedExceptionConstructorTest2()
         {
             string message = string.Empty; // TODO: Initialize to an appropriate value

+ 5 - 6
src/Renci.SshNet.Tests/Classes/Common/ShellDataEventArgsTest.cs

@@ -1,6 +1,5 @@
-using Renci.SshNet.Common;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
 {
@@ -8,13 +7,13 @@ namespace Renci.SshNet.Tests.Classes.Common
     ///This is a test class for ShellDataEventArgsTest and is intended
     ///to contain all ShellDataEventArgsTest Unit Tests
     ///</summary>
-    [TestClass()]
+    [TestClass]
     public class ShellDataEventArgsTest
     {
         /// <summary>
         ///A test for ShellDataEventArgs Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void ShellDataEventArgsConstructorTest()
         {
             byte[] data = null; // TODO: Initialize to an appropriate value
@@ -25,7 +24,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for ShellDataEventArgs Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void ShellDataEventArgsConstructorTest1()
         {
             string line = string.Empty; // TODO: Initialize to an appropriate value

+ 6 - 6
src/Renci.SshNet.Tests/Classes/Common/SshAuthenticationExceptionTest.cs

@@ -1,6 +1,6 @@
-using Renci.SshNet.Common;
+using System;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
+using Renci.SshNet.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
 {
@@ -8,13 +8,13 @@ namespace Renci.SshNet.Tests.Classes.Common
     ///This is a test class for SshAuthenticationExceptionTest and is intended
     ///to contain all SshAuthenticationExceptionTest Unit Tests
     ///</summary>
-    [TestClass()]
+    [TestClass]
     public class SshAuthenticationExceptionTest
     {
         /// <summary>
         ///A test for SshAuthenticationException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SshAuthenticationExceptionConstructorTest()
         {
             SshAuthenticationException target = new SshAuthenticationException();
@@ -24,7 +24,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for SshAuthenticationException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SshAuthenticationExceptionConstructorTest1()
         {
             string message = string.Empty; // TODO: Initialize to an appropriate value
@@ -35,7 +35,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for SshAuthenticationException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SshAuthenticationExceptionConstructorTest2()
         {
             string message = string.Empty; // TODO: Initialize to an appropriate value

+ 9 - 9
src/Renci.SshNet.Tests/Classes/Common/SshConnectionExceptionTest.cs

@@ -1,8 +1,8 @@
-using Renci.SshNet.Common;
+using System;
+using System.Runtime.Serialization;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
+using Renci.SshNet.Common;
 using Renci.SshNet.Messages.Transport;
-using System.Runtime.Serialization;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
@@ -11,13 +11,13 @@ namespace Renci.SshNet.Tests.Classes.Common
     ///This is a test class for SshConnectionExceptionTest and is intended
     ///to contain all SshConnectionExceptionTest Unit Tests
     ///</summary>
-    [TestClass()]
+    [TestClass]
     public class SshConnectionExceptionTest : TestBase
     {
         /// <summary>
         ///A test for SshConnectionException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SshConnectionExceptionConstructorTest()
         {
             SshConnectionException target = new SshConnectionException();
@@ -27,7 +27,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for SshConnectionException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SshConnectionExceptionConstructorTest1()
         {
             string message = string.Empty; // TODO: Initialize to an appropriate value
@@ -38,7 +38,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for SshConnectionException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SshConnectionExceptionConstructorTest2()
         {
             string message = string.Empty; // TODO: Initialize to an appropriate value
@@ -50,7 +50,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for SshConnectionException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SshConnectionExceptionConstructorTest3()
         {
             string message = string.Empty; // TODO: Initialize to an appropriate value
@@ -63,7 +63,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for GetObjectData
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         [Ignore] // placeholder for actual test
         public void GetObjectDataTest()
         {

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

@@ -95,16 +95,6 @@ namespace Renci.SshNet.Tests.Classes.Common
                 _value = value;
             }
 
-            public new bool IsEndOfData
-            {
-                get { return base.IsEndOfData; }
-            }
-
-            public new byte ReadByte()
-            {
-                return base.ReadByte();
-            }
-
             protected override void LoadData()
             {
             }
@@ -120,16 +110,6 @@ namespace Renci.SshNet.Tests.Classes.Common
             private uint _valueOne;
             private uint _valueTwo;
 
-            public RequestSshData()
-            {
-            }
-
-            public RequestSshData(uint one, uint two)
-            {
-                _valueOne = one;
-                _valueTwo = two;
-            }
-
             protected override int BufferCapacity
             {
                 get
@@ -165,40 +145,5 @@ namespace Renci.SshNet.Tests.Classes.Common
                 Write(ValueTwo);
             }
         }
-
-        private class ReplySshData : SshData
-        {
-            private uint _valueOne;
-
-            public ReplySshData()
-            {
-            }
-
-            protected override int BufferCapacity
-            {
-                get
-                {
-                    var capacity = base.BufferCapacity;
-                    capacity += 4; // ValueOne
-                    return capacity;
-                }
-            }
-
-            public uint ValueOne
-            {
-                get { return _valueOne; }
-                set { _valueOne = value; }
-            }
-
-            protected override void LoadData()
-            {
-                _valueOne = ReadUInt32();
-            }
-
-            protected override void SaveData()
-            {
-                Write(ValueOne);
-            }
-        }
     }
 }

+ 8 - 8
src/Renci.SshNet.Tests/Classes/Common/SshExceptionTest.cs

@@ -1,7 +1,7 @@
-using Renci.SshNet.Common;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
+using System;
 using System.Runtime.Serialization;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
@@ -10,13 +10,13 @@ namespace Renci.SshNet.Tests.Classes.Common
     ///This is a test class for SshExceptionTest and is intended
     ///to contain all SshExceptionTest Unit Tests
     ///</summary>
-    [TestClass()]
+    [TestClass]
     public class SshExceptionTest : TestBase
     {
         /// <summary>
         ///A test for SshException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SshExceptionConstructorTest()
         {
             SshException target = new SshException();
@@ -26,7 +26,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for SshException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SshExceptionConstructorTest1()
         {
             string message = string.Empty; // TODO: Initialize to an appropriate value
@@ -37,7 +37,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for SshException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SshExceptionConstructorTest2()
         {
             string message = string.Empty; // TODO: Initialize to an appropriate value
@@ -49,7 +49,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for GetObjectData
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         [Ignore] // placeholder for actual test
         public void GetObjectDataTest()
         {

+ 6 - 6
src/Renci.SshNet.Tests/Classes/Common/SshOperationTimeoutExceptionTest.cs

@@ -1,6 +1,6 @@
-using Renci.SshNet.Common;
+using System;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
+using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
@@ -9,13 +9,13 @@ namespace Renci.SshNet.Tests.Classes.Common
     ///This is a test class for SshOperationTimeoutExceptionTest and is intended
     ///to contain all SshOperationTimeoutExceptionTest Unit Tests
     ///</summary>
-    [TestClass()]
+    [TestClass]
     public class SshOperationTimeoutExceptionTest : TestBase
     {
         /// <summary>
         ///A test for SshOperationTimeoutException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SshOperationTimeoutExceptionConstructorTest()
         {
             SshOperationTimeoutException target = new SshOperationTimeoutException();
@@ -25,7 +25,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for SshOperationTimeoutException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SshOperationTimeoutExceptionConstructorTest1()
         {
             string message = string.Empty; // TODO: Initialize to an appropriate value
@@ -36,7 +36,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for SshOperationTimeoutException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SshOperationTimeoutExceptionConstructorTest2()
         {
             string message = string.Empty; // TODO: Initialize to an appropriate value

+ 6 - 6
src/Renci.SshNet.Tests/Classes/Common/SshPassPhraseNullOrEmptyExceptionTest.cs

@@ -1,6 +1,6 @@
-using Renci.SshNet.Common;
+using System;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
+using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
 
 namespace Renci.SshNet.Tests.Classes.Common
@@ -9,13 +9,13 @@ namespace Renci.SshNet.Tests.Classes.Common
     ///This is a test class for SshPassPhraseNullOrEmptyExceptionTest and is intended
     ///to contain all SshPassPhraseNullOrEmptyExceptionTest Unit Tests
     ///</summary>
-    [TestClass()]
+    [TestClass]
     public class SshPassPhraseNullOrEmptyExceptionTest : TestBase
     {
         /// <summary>
         ///A test for SshPassPhraseNullOrEmptyException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SshPassPhraseNullOrEmptyExceptionConstructorTest()
         {
             SshPassPhraseNullOrEmptyException target = new SshPassPhraseNullOrEmptyException();
@@ -25,7 +25,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for SshPassPhraseNullOrEmptyException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SshPassPhraseNullOrEmptyExceptionConstructorTest1()
         {
             string message = string.Empty; // TODO: Initialize to an appropriate value
@@ -36,7 +36,7 @@ namespace Renci.SshNet.Tests.Classes.Common
         /// <summary>
         ///A test for SshPassPhraseNullOrEmptyException Constructor
         ///</summary>
-        [TestMethod()]
+        [TestMethod]
         public void SshPassPhraseNullOrEmptyExceptionConstructorTest2()
         {
             string message = string.Empty; // TODO: Initialize to an appropriate value

+ 1188 - 0
src/Renci.SshNet.Tests/Classes/RemotePathDoubleQuoteTransformationTest.cs

@@ -0,0 +1,1188 @@
+using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class RemotePathDoubleQuoteTransformationTest
+    {
+        private IRemotePathTransformation _transformation;
+
+        [TestInitialize]
+        public void SetUp()
+        {
+            _transformation = new RemotePathDoubleQuoteTransformation();
+        }
+
+        /// <summary>
+        /// Test cases from triple-slash comments
+        /// </summary>
+        [TestMethod]
+        public void Mixed()
+        {
+            Assert.AreEqual("\"/var/log/auth.log\"", _transformation.Transform("/var/log/auth.log"));
+            Assert.AreEqual("\"/var/mp3/Guns N' Roses\"", _transformation.Transform("/var/mp3/Guns N' Roses"));
+            Assert.AreEqual("\"/var/garbage!/temp\"", _transformation.Transform("/var/garbage!/temp"));
+            Assert.AreEqual("\"/var/would be 'kewl'!, not?\"", _transformation.Transform("/var/would be 'kewl'!, not?"));
+            Assert.AreEqual("\"\"", _transformation.Transform(string.Empty));
+            Assert.AreEqual("\"Hello \\\"World\\\"\"", _transformation.Transform("Hello \"World\""));
+        }
+
+        [TestMethod]
+        public void Null()
+        {
+            const string path = null;
+
+            try
+            {
+                _transformation.Transform(path);
+                Assert.Fail();
+            }
+            catch (ArgumentNullException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("path", ex.ParamName);
+            }
+        }
+
+        [TestMethod]
+        public void Ampersand_Embedded()
+        {
+            const string path = "You&Me";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"You&Me\"", actual);
+        }
+
+        [TestMethod]
+        public void Ampersand_Leading()
+        {
+            const string path = "&Or";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"&Or\"", actual);
+        }
+
+        [TestMethod]
+        public void Ampersand_LeadingAndTrailing()
+        {
+            const string path = "&Or&";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"&Or&\"", actual);
+        }
+
+        [TestMethod]
+        public void Ampersand_Trailing()
+        {
+            const string path = "And&";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"And&\"", actual);
+        }
+
+        [TestMethod]
+        public void Asterisk_Embedded()
+        {
+            const string path = "Love*Hate";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Love*Hate\"", actual);
+        }
+
+        [TestMethod]
+        public void Asterisk_Leading()
+        {
+            const string path = "*Times";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"*Times\"", actual);
+        }
+
+        [TestMethod]
+        public void Asterisk_LeadingAndTrailing()
+        {
+            const string path = "*WAR*";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"*WAR*\"", actual);
+        }
+
+        [TestMethod]
+        public void Asterisk_Trailing()
+        {
+            const string path = "Censor*";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Censor*\"", actual);
+        }
+
+        [TestMethod]
+        public void Backslash_Embedded()
+        {
+            const string path = "Hello\\World";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Hello\\World\"", actual);
+        }
+
+        [TestMethod]
+        public void Backslash_Leading()
+        {
+            const string path = "\\Hello";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"\\Hello\"", actual);
+        }
+
+        [TestMethod]
+        public void Backslash_LeadingAndTrailing()
+        {
+            const string path = "\\Hello\\";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"\\Hello\\\"", actual);
+        }
+
+        [TestMethod]
+        public void Backslash_Trailing()
+        {
+            const string path = "HelloWorld\\";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"HelloWorld\\\"", actual);
+        }
+
+        [TestMethod]
+        public void Backtick_Embedded()
+        {
+            const string path = "back`tick";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"back`tick\"", actual);
+        }
+
+        [TestMethod]
+        public void Backtick_Leading()
+        {
+            const string path = "`front";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"`front\"", actual);
+        }
+
+        [TestMethod]
+        public void Backtick_LeadingAndTrailing()
+        {
+            const string path = "`FrontAndBack`";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"`FrontAndBack`\"", actual);
+        }
+
+        [TestMethod]
+        public void Backtick_Trailing()
+        {
+            const string path = "back`";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"back`\"", actual);
+        }
+
+        [TestMethod]
+        public void Circumflex_Embedded()
+        {
+            const string path = "You^Me";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"You^Me\"", actual);
+        }
+
+        [TestMethod]
+        public void Circumflex_Leading()
+        {
+            const string path = "^Or";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"^Or\"", actual);
+        }
+
+        [TestMethod]
+        public void Circumflex_LeadingAndTrailing()
+        {
+            const string path = "^Or^";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"^Or^\"", actual);
+        }
+
+        [TestMethod]
+        public void Circumflex_Trailing()
+        {
+            const string path = "And^";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"And^\"", actual);
+        }
+
+        [TestMethod]
+        public void CurlyBrackets_Close_Embedded()
+        {
+            const string path = "Halo}Devine";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Halo}Devine\"", actual);
+        }
+
+        [TestMethod]
+        public void CurlyBrackets_Close_Leading()
+        {
+            const string path = "}Open";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"}Open\"", actual);
+        }
+
+        [TestMethod]
+        public void CurlyBrackets_Close_LeadingAndTrailing()
+        {
+            const string path = "}Closed}";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"}Closed}\"", actual);
+        }
+
+        [TestMethod]
+        public void CurlyBrackets_Close_Trailing()
+        {
+            const string path = "Finish}";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Finish}\"", actual);
+        }
+
+        [TestMethod]
+        public void CurlyBrackets_Open_Embedded()
+        {
+            const string path = "Halo{Devine";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Halo{Devine\"", actual);
+        }
+
+        [TestMethod]
+        public void CurlyBrackets_Open_Leading()
+        {
+            const string path = "{Open";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"{Open\"", actual);
+        }
+
+        [TestMethod]
+        public void CurlyBrackets_Open_LeadingAndTrailing()
+        {
+            const string path = "{Closed{";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"{Closed{\"", actual);
+        }
+
+        [TestMethod]
+        public void CurlyBrackets_Open_Trailing()
+        {
+            const string path = "Finish{";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Finish{\"", actual);
+        }
+
+        [TestMethod]
+        public void Dollar_Embedded()
+        {
+            const string path = "IGiveYouOne$ForYourThoughts";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"IGiveYouOne$ForYourThoughts\"", actual);
+        }
+
+        [TestMethod]
+        public void Dollar_Leading()
+        {
+            const string path = "$Blues";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"$Blues\"", actual);
+        }
+
+        [TestMethod]
+        public void Dollar_LeadingAndTrailing()
+        {
+            const string path = "$SUM$";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"$SUM$\"", actual);
+        }
+
+        [TestMethod]
+        public void Dollar_Trailing()
+        {
+            const string path = "NotCravingForMore$";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"NotCravingForMore$\"", actual);
+        }
+
+        [TestMethod]
+        public void DoubleQuote_Embedded()
+        {
+            const string path = "DoNot\"MeOnThis";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"DoNot\\\"MeOnThis\"", actual);
+        }
+
+        [TestMethod]
+        public void DoubleQuote_Leading()
+        {
+            const string path = "\"OrNotToQuote";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"\\\"OrNotToQuote\"", actual);
+        }
+
+        [TestMethod]
+        public void DoubleQuote_Trailing()
+        {
+            const string path = "Famous\"";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Famous\\\"\"", actual);
+        }
+
+        [TestMethod]
+        public void DoubleQuote_LeadingAndTrailing()
+        {
+            const string path = "\"OrNotTo\"";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"\\\"OrNotTo\\\"\"", actual);
+        }
+
+        [TestMethod]
+        public void Equals_Embedded()
+        {
+            const string path = "You=Me";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"You=Me\"", actual);
+        }
+
+        [TestMethod]
+        public void Equals_Leading()
+        {
+            const string path = "=Or";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"=Or\"", actual);
+        }
+
+        [TestMethod]
+        public void Equals_LeadingAndTrailing()
+        {
+            const string path = "=Or=";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"=Or=\"", actual);
+        }
+
+        [TestMethod]
+        public void Equals_Trailing()
+        {
+            const string path = "And=";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"And=\"", actual);
+        }
+
+        [TestMethod]
+        public void ExclamationMark_Embedded_Single()
+        {
+            const string path = "/var/garbage!/temp";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"/var/garbage!/temp\"", actual);
+        }
+
+        [TestMethod]
+        public void ExclamationMark_Embedded_Sequence()
+        {
+            const string path = "/var/garbage!!/temp";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"/var/garbage!!/temp\"", actual);
+        }
+
+        [TestMethod]
+        public void ExclamationMark_Leading()
+        {
+            const string path = "!Error";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"!Error\"", actual);
+        }
+
+        [TestMethod]
+        public void ExclamationMark_LeadingAndTrailing()
+        {
+            const string path = "!ignore!";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"!ignore!\"", actual);
+        }
+
+        [TestMethod]
+        public void ExclamationMark_Trailing()
+        {
+            const string path = "Done!";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Done!\"", actual);
+        }
+
+        [TestMethod]
+        public void GreaterThan_Embedded()
+        {
+            const string path = "You>Me";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"You>Me\"", actual);
+        }
+
+        [TestMethod]
+        public void GreaterThan_Leading()
+        {
+            const string path = ">Or";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\">Or\"", actual);
+        }
+
+        [TestMethod]
+        public void GreaterThan_LeadingAndTrailing()
+        {
+            const string path = ">Or>";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\">Or>\"", actual);
+        }
+
+        [TestMethod]
+        public void GreaterThan_Trailing()
+        {
+            const string path = "And>";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"And>\"", actual);
+        }
+
+        [TestMethod]
+        public void Hash_Embedded()
+        {
+            const string path = "Smoke#EveryDay";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Smoke#EveryDay\"", actual);
+        }
+
+        [TestMethod]
+        public void Hash_Leading()
+        {
+            const string path = "#4Ever";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"#4Ever\"", actual);
+        }
+
+        [TestMethod]
+        public void Hash_LeadingAndTrailing()
+        {
+            const string path = "#4Ever#";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"#4Ever#\"", actual);
+        }
+
+        [TestMethod]
+        public void Hash_Trailing()
+        {
+            const string path = "Legalize#";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Legalize#\"", actual);
+        }
+
+        [TestMethod]
+        public void LessThan_Embedded()
+        {
+            const string path = "You<Me";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"You<Me\"", actual);
+        }
+
+        [TestMethod]
+        public void LessThan_Leading()
+        {
+            const string path = "<Or";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"<Or\"", actual);
+        }
+
+        [TestMethod]
+        public void LessThan_LeadingAndTrailing()
+        {
+            const string path = "<Or<";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"<Or<\"", actual);
+        }
+
+        [TestMethod]
+        public void LessThan_Trailing()
+        {
+            const string path = "And<";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"And<\"", actual);
+        }
+
+        [TestMethod]
+        public void NewLine_Embedded()
+        {
+            const string path = "line\nfeed";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"line\nfeed\"", actual);
+        }
+
+        [TestMethod]
+        public void NewLine_Leading()
+        {
+            const string path = "\nFooter";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"\nFooter\"", actual);
+        }
+
+        [TestMethod]
+        public void NewLine_LeadingAndTrailing()
+        {
+            const string path = "\nBanner\n";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"\nBanner\n\"", actual);
+        }
+
+        [TestMethod]
+        public void NewLine_Trailing()
+        {
+            const string path = "Header\n";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Header\n\"", actual);
+        }
+
+        [TestMethod]
+        public void Parentheses_Close_Embedded()
+        {
+            const string path = "Halo)Devine";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Halo)Devine\"", actual);
+        }
+
+        [TestMethod]
+        public void Parentheses_Close_Leading()
+        {
+            const string path = ")Open";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\")Open\"", actual);
+        }
+
+        [TestMethod]
+        public void Parentheses_Close_LeadingAndTrailing()
+        {
+            const string path = ")Closed)";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\")Closed)\"", actual);
+        }
+
+        [TestMethod]
+        public void Parentheses_Close_Trailing()
+        {
+            const string path = "Finish)";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Finish)\"", actual);
+        }
+
+        [TestMethod]
+        public void Parentheses_Open_Embedded()
+        {
+            const string path = "Halo(Devine";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Halo(Devine\"", actual);
+        }
+
+        [TestMethod]
+        public void Parentheses_Open_Leading()
+        {
+            const string path = "(Open";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"(Open\"", actual);
+        }
+
+        [TestMethod]
+        public void Parentheses_Open_LeadingAndTrailing()
+        {
+            const string path = "(Closed(";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"(Closed(\"", actual);
+        }
+
+        [TestMethod]
+        public void Parentheses_Open_Trailing()
+        {
+            const string path = "Finish(";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Finish(\"", actual);
+        }
+
+        [TestMethod]
+        public void Percentage_Embedded()
+        {
+            const string path = "Ten%OfOneDollarIsTenCent";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Ten%OfOneDollarIsTenCent\"", actual);
+        }
+
+        [TestMethod]
+        public void Percentage_Leading()
+        {
+            const string path = "%MoreOrLess";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"%MoreOrLess\"", actual);
+        }
+
+        [TestMethod]
+        public void Percentage_LeadingAndTrailing()
+        {
+            const string path = "%USERNAME%";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"%USERNAME%\"", actual);
+        }
+
+        [TestMethod]
+        public void Percentage_Trailing()
+        {
+            const string path = "TakeA%";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"TakeA%\"", actual);
+        }
+
+        [TestMethod]
+        public void Pipe_Embedded()
+        {
+            const string path = "You|Me";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"You|Me\"", actual);
+        }
+
+        [TestMethod]
+        public void Pipe_Leading()
+        {
+            const string path = "|Or";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"|Or\"", actual);
+        }
+
+        [TestMethod]
+        public void Pipe_LeadingAndTrailing()
+        {
+            const string path = "|Or|";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"|Or|\"", actual);
+        }
+
+        [TestMethod]
+        public void Pipe_Trailing()
+        {
+            const string path = "And|";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"And|\"", actual);
+        }
+
+        [TestMethod]
+        public void QuestionMark_Embedded()
+        {
+            const string path = "WhatTimeIsIt?SheSaid";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"WhatTimeIsIt?SheSaid\"", actual);
+        }
+
+        [TestMethod]
+        public void QuestionMark_Leading()
+        {
+            const string path = "?Quizz";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"?Quizz\"", actual);
+        }
+
+        [TestMethod]
+        public void QuestionMark_LeadingAndTrailing()
+        {
+            const string path = "?Crazy?";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"?Crazy?\"", actual);
+        }
+
+        [TestMethod]
+        public void QuestionMark_Trailing()
+        {
+            const string path = "WhatTimeIsLove?";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"WhatTimeIsLove?\"", actual);
+        }
+
+        [TestMethod]
+        public void Semicolon_Embedded()
+        {
+            const string path = "Rain;Storm";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Rain;Storm\"", actual);
+        }
+
+        [TestMethod]
+        public void Semicolon_Leading()
+        {
+            const string path = ";List";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\";List\"", actual);
+        }
+
+        [TestMethod]
+        public void Semicolon_LeadingAndTrailing()
+        {
+            const string path = ";Trapped;";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\";Trapped;\"", actual);
+        }
+
+        [TestMethod]
+        public void Semicolon_Trailing()
+        {
+            const string path = "Time;";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Time;\"", actual);
+        }
+
+        [TestMethod]
+        public void SingleQuote_Embedded_Single()
+        {
+            const string path = "Rain'Storm";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Rain'Storm\"", actual);
+        }
+
+        [TestMethod]
+        public void SingleQuote_Embedded_Sequence()
+        {
+            const string path = "Rain''Storm";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Rain''Storm\"", actual);
+        }
+
+        [TestMethod]
+        public void SingleQuote_Leading()
+        {
+            const string path = "'List";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"'List\"", actual);
+        }
+
+        [TestMethod]
+        public void SingleQuote_LeadingAndTrailing()
+        {
+            const string path = "'Trapped'";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"'Trapped'\"", actual);
+        }
+
+        [TestMethod]
+        public void SingleQuote_Trailing()
+        {
+            const string path = "Time'";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Time'\"", actual);
+        }
+
+        [TestMethod]
+        public void SingleQuoteAndExclamationMark_Embedded()
+        {
+            const string path = "Rain'!Storm";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Rain'!Storm\"", actual);
+        }
+
+        [TestMethod]
+        public void SingleQuoteAndExclamationMark_Leading()
+        {
+            const string path = "'!Rain";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"'!Rain\"", actual);
+        }
+
+        [TestMethod]
+        public void SingleQuoteAndExclamationMark_LeadingAndTrailing()
+        {
+            const string path = "'!Rain'!";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"'!Rain'!\"", actual);
+        }
+
+        [TestMethod]
+        public void SingleQuoteAndExclamationMark_Trailing()
+        {
+            const string path = "Rain'!";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Rain'!\"", actual);
+        }
+
+        [TestMethod]
+        public void Space_Embedded()
+        {
+            const string path = "You Me";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"You Me\"", actual);
+        }
+
+        [TestMethod]
+        public void Space_Leading()
+        {
+            const string path = " Or";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\" Or\"", actual);
+        }
+
+        [TestMethod]
+        public void Space_LeadingAndTrailing()
+        {
+            const string path = " Or ";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\" Or \"", actual);
+        }
+
+        [TestMethod]
+        public void Space_Trailing()
+        {
+            const string path = "And ";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"And \"", actual);
+        }
+
+        [TestMethod]
+        public void SquareBrackets_Close_Embedded()
+        {
+            const string path = "Halo]Devine";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Halo]Devine\"", actual);
+        }
+
+        [TestMethod]
+        public void SquareBrackets_Close_Leading()
+        {
+            const string path = "]Open";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"]Open\"", actual);
+        }
+
+        [TestMethod]
+        public void SquareBrackets_Close_LeadingAndTrailing()
+        {
+            const string path = "]Closed]";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"]Closed]\"", actual);
+        }
+
+        [TestMethod]
+        public void SquareBrackets_Close_Trailing()
+        {
+            const string path = "Finish]";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Finish]\"", actual);
+        }
+
+        [TestMethod]
+        public void SquareBrackets_Open_Embedded()
+        {
+            const string path = "Halo[Devine";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Halo[Devine\"", actual);
+        }
+
+        [TestMethod]
+        public void SquareBrackets_Open_Leading()
+        {
+            const string path = "[Open";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"[Open\"", actual);
+        }
+
+        [TestMethod]
+        public void SquareBrackets_Open_LeadingAndTrailing()
+        {
+            const string path = "[Closed[";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"[Closed[\"", actual);
+        }
+
+        [TestMethod]
+        public void SquareBrackets_Open_Trailing()
+        {
+            const string path = "Finish[";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Finish[\"", actual);
+        }
+
+        [TestMethod]
+        public void Tab_Embedded()
+        {
+            const string path = "You\tMe";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"You\tMe\"", actual);
+        }
+
+        [TestMethod]
+        public void Tab_Leading()
+        {
+            const string path = "\tOr";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"\tOr\"", actual);
+        }
+
+        [TestMethod]
+        public void Tab_LeadingAndTrailing()
+        {
+            const string path = "\tOr\t";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"\tOr\t\"", actual);
+        }
+
+        [TestMethod]
+        public void Tab_Trailing()
+        {
+            const string path = "And\t";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"And\t\"", actual);
+        }
+
+        [TestMethod]
+        public void Tilde_Embedded()
+        {
+            const string path = "Seven~Nine";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Seven~Nine\"", actual);
+        }
+
+        [TestMethod]
+        public void Tilde_Leading()
+        {
+            const string path = "~Ten";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"~Ten\"", actual);
+        }
+
+        [TestMethod]
+        public void Tilde_LeadingAndTrailing()
+        {
+            const string path = "~One~";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"~One~\"", actual);
+        }
+
+        [TestMethod]
+        public void Tilde_Trailing()
+        {
+            const string path = "Two~";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"Two~\"", actual);
+        }
+    }
+}

+ 1188 - 0
src/Renci.SshNet.Tests/Classes/RemotePathShellQuoteTransformationTest.cs

@@ -0,0 +1,1188 @@
+using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class RemotePathShellQuoteTransformationTest
+    {
+        private IRemotePathTransformation _transformation;
+
+        [TestInitialize]
+        public void SetUp()
+        {
+            _transformation = new RemotePathShellQuoteTransformation();
+        }
+
+        /// <summary>
+        /// Test cases from triple-slash comments
+        /// </summary>
+        [TestMethod]
+        public void Mixed()
+        {
+            Assert.AreEqual("'/var/log/auth.log'", _transformation.Transform("/var/log/auth.log"));
+            Assert.AreEqual("'/var/mp3/Guns N'\"'\"' Roses'", _transformation.Transform("/var/mp3/Guns N' Roses"));
+            Assert.AreEqual("'/var/garbage'\\!'/temp'", _transformation.Transform("/var/garbage!/temp"));
+            Assert.AreEqual("'/var/would be '\"'\"'kewl'\"'\"\\!', not?'", _transformation.Transform("/var/would be 'kewl'!, not?"));
+            Assert.AreEqual("''", _transformation.Transform(string.Empty));
+            Assert.AreEqual("'Hello \"World\"'", _transformation.Transform("Hello \"World\""));
+        }
+
+        [TestMethod]
+        public void Null()
+        {
+            const string path = null;
+
+            try
+            {
+                _transformation.Transform(path);
+                Assert.Fail();
+            }
+            catch (ArgumentNullException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("path", ex.ParamName);
+            }
+        }
+
+        [TestMethod]
+        public void Ampersand_Embedded()
+        {
+            const string path = "You&Me";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'You&Me'", actual);
+        }
+
+        [TestMethod]
+        public void Ampersand_Leading()
+        {
+            const string path = "&Or";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'&Or'", actual);
+        }
+
+        [TestMethod]
+        public void Ampersand_LeadingAndTrailing()
+        {
+            const string path = "&Or&";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'&Or&'", actual);
+        }
+
+        [TestMethod]
+        public void Ampersand_Trailing()
+        {
+            const string path = "And&";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'And&'", actual);
+        }
+
+        [TestMethod]
+        public void Asterisk_Embedded()
+        {
+            const string path = "Love*Hate";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Love*Hate'", actual);
+        }
+
+        [TestMethod]
+        public void Asterisk_Leading()
+        {
+            const string path = "*Times";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'*Times'", actual);
+        }
+
+        [TestMethod]
+        public void Asterisk_LeadingAndTrailing()
+        {
+            const string path = "*WAR*";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'*WAR*'", actual);
+        }
+
+        [TestMethod]
+        public void Asterisk_Trailing()
+        {
+            const string path = "Censor*";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Censor*'", actual);
+        }
+
+        [TestMethod]
+        public void Backslash_Embedded()
+        {
+            const string path = "Hello\\World";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Hello\\World'", actual);
+        }
+
+        [TestMethod]
+        public void Backslash_Leading()
+        {
+            const string path = "\\Hello";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'\\Hello'", actual);
+        }
+
+        [TestMethod]
+        public void Backslash_LeadingAndTrailing()
+        {
+            const string path = "\\Hello\\";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'\\Hello\\'", actual);
+        }
+
+        [TestMethod]
+        public void Backslash_Trailing()
+        {
+            const string path = "HelloWorld\\";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'HelloWorld\\'", actual);
+        }
+
+        [TestMethod]
+        public void Backtick_Embedded()
+        {
+            const string path = "back`tick";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'back`tick'", actual);
+        }
+
+        [TestMethod]
+        public void Backtick_Leading()
+        {
+            const string path = "`front";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'`front'", actual);
+        }
+
+        [TestMethod]
+        public void Backtick_LeadingAndTrailing()
+        {
+            const string path = "`FrontAndBack`";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'`FrontAndBack`'", actual);
+        }
+
+        [TestMethod]
+        public void Backtick_Trailing()
+        {
+            const string path = "back`";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'back`'", actual);
+        }
+
+        [TestMethod]
+        public void Circumflex_Embedded()
+        {
+            const string path = "You^Me";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'You^Me'", actual);
+        }
+
+        [TestMethod]
+        public void Circumflex_Leading()
+        {
+            const string path = "^Or";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'^Or'", actual);
+        }
+
+        [TestMethod]
+        public void Circumflex_LeadingAndTrailing()
+        {
+            const string path = "^Or^";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'^Or^'", actual);
+        }
+
+        [TestMethod]
+        public void Circumflex_Trailing()
+        {
+            const string path = "And^";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'And^'", actual);
+        }
+
+        [TestMethod]
+        public void CurlyBrackets_Close_Embedded()
+        {
+            const string path = "Halo}Devine";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Halo}Devine'", actual);
+        }
+
+        [TestMethod]
+        public void CurlyBrackets_Close_Leading()
+        {
+            const string path = "}Open";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'}Open'", actual);
+        }
+
+        [TestMethod]
+        public void CurlyBrackets_Close_LeadingAndTrailing()
+        {
+            const string path = "}Closed}";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'}Closed}'", actual);
+        }
+
+        [TestMethod]
+        public void CurlyBrackets_Close_Trailing()
+        {
+            const string path = "Finish}";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Finish}'", actual);
+        }
+
+        [TestMethod]
+        public void CurlyBrackets_Open_Embedded()
+        {
+            const string path = "Halo{Devine";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Halo{Devine'", actual);
+        }
+
+        [TestMethod]
+        public void CurlyBrackets_Open_Leading()
+        {
+            const string path = "{Open";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'{Open'", actual);
+        }
+
+        [TestMethod]
+        public void CurlyBrackets_Open_LeadingAndTrailing()
+        {
+            const string path = "{Closed{";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'{Closed{'", actual);
+        }
+
+        [TestMethod]
+        public void CurlyBrackets_Open_Trailing()
+        {
+            const string path = "Finish{";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Finish{'", actual);
+        }
+
+        [TestMethod]
+        public void Dollar_Embedded()
+        {
+            const string path = "IGiveYouOne$ForYourThoughts";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'IGiveYouOne$ForYourThoughts'", actual);
+        }
+
+        [TestMethod]
+        public void Dollar_Leading()
+        {
+            const string path = "$Blues";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'$Blues'", actual);
+        }
+
+        [TestMethod]
+        public void Dollar_LeadingAndTrailing()
+        {
+            const string path = "$SUM$";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'$SUM$'", actual);
+        }
+
+        [TestMethod]
+        public void Dollar_Trailing()
+        {
+            const string path = "NotCravingForMore$";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'NotCravingForMore$'", actual);
+        }
+
+        [TestMethod]
+        public void DoubleQuote_Embedded()
+        {
+            const string path = "DoNot\"MeOnThis";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'DoNot\"MeOnThis'", actual);
+        }
+
+        [TestMethod]
+        public void DoubleQuote_Leading()
+        {
+            const string path = "\"OrNotToQuote";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'\"OrNotToQuote'", actual);
+        }
+
+        [TestMethod]
+        public void DoubleQuote_LeadingAndTrailing()
+        {
+            const string path = "\"OrNotTo\"";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'\"OrNotTo\"'", actual);
+        }
+
+        [TestMethod]
+        public void DoubleQuote_Trailing()
+        {
+            const string path = "Famous\"";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Famous\"'", actual);
+        }
+
+        [TestMethod]
+        public void Equals_Embedded()
+        {
+            const string path = "You=Me";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'You=Me'", actual);
+        }
+
+        [TestMethod]
+        public void Equals_Leading()
+        {
+            const string path = "=Or";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'=Or'", actual);
+        }
+
+        [TestMethod]
+        public void Equals_LeadingAndTrailing()
+        {
+            const string path = "=Or=";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'=Or='", actual);
+        }
+
+        [TestMethod]
+        public void Equals_Trailing()
+        {
+            const string path = "And=";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'And='", actual);
+        }
+
+        [TestMethod]
+        public void ExclamationMark_Embedded_Single()
+        {
+            const string path = "/var/garbage!/temp";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'/var/garbage'\\!'/temp'", actual);
+        }
+
+        [TestMethod]
+        public void ExclamationMark_Embedded_Sequence()
+        {
+            const string path = "/var/garbage!!/temp";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'/var/garbage'\\!\\!'/temp'", actual);
+        }
+
+        [TestMethod]
+        public void ExclamationMark_Leading()
+        {
+            const string path = "!Error";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\\!'Error'", actual);
+        }
+
+        [TestMethod]
+        public void ExclamationMark_LeadingAndTrailing()
+        {
+            const string path = "!ignore!";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\\!'ignore'\\!", actual);
+        }
+
+        [TestMethod]
+        public void ExclamationMark_Trailing()
+        {
+            const string path = "Done!";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Done'\\!", actual);
+        }
+
+        [TestMethod]
+        public void GreaterThan_Embedded()
+        {
+            const string path = "You>Me";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'You>Me'", actual);
+        }
+
+        [TestMethod]
+        public void GreaterThan_Leading()
+        {
+            const string path = ">Or";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'>Or'", actual);
+        }
+
+        [TestMethod]
+        public void GreaterThan_LeadingAndTrailing()
+        {
+            const string path = ">Or>";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'>Or>'", actual);
+        }
+
+        [TestMethod]
+        public void GreaterThan_Trailing()
+        {
+            const string path = "And>";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'And>'", actual);
+        }
+
+        [TestMethod]
+        public void Hash_Embedded()
+        {
+            const string path = "Smoke#EveryDay";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Smoke#EveryDay'", actual);
+        }
+
+        [TestMethod]
+        public void Hash_Leading()
+        {
+            const string path = "#4Ever";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'#4Ever'", actual);
+        }
+
+        [TestMethod]
+        public void Hash_LeadingAndTrailing()
+        {
+            const string path = "#4Ever#";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'#4Ever#'", actual);
+        }
+
+        [TestMethod]
+        public void Hash_Trailing()
+        {
+            const string path = "Legalize#";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Legalize#'", actual);
+        }
+
+        [TestMethod]
+        public void LessThan_Embedded()
+        {
+            const string path = "You<Me";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'You<Me'", actual);
+        }
+
+        [TestMethod]
+        public void LessThan_Leading()
+        {
+            const string path = "<Or";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'<Or'", actual);
+        }
+
+        [TestMethod]
+        public void LessThan_LeadingAndTrailing()
+        {
+            const string path = "<Or<";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'<Or<'", actual);
+        }
+
+        [TestMethod]
+        public void LessThan_Trailing()
+        {
+            const string path = "And<";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'And<'", actual);
+        }
+
+        [TestMethod]
+        public void NewLine_Embedded()
+        {
+            const string path = "line\nfeed";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'line\nfeed'", actual);
+        }
+
+        [TestMethod]
+        public void NewLine_Leading()
+        {
+            const string path = "\nFooter";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'\nFooter'", actual);
+        }
+
+        [TestMethod]
+        public void NewLine_LeadingAndTrailing()
+        {
+            const string path = "\nBanner\n";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'\nBanner\n'", actual);
+        }
+
+        [TestMethod]
+        public void NewLine_Trailing()
+        {
+            const string path = "Header\n";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Header\n'", actual);
+        }
+
+        [TestMethod]
+        public void Parentheses_Close_Embedded()
+        {
+            const string path = "Halo)Devine";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Halo)Devine'", actual);
+        }
+
+        [TestMethod]
+        public void Parentheses_Close_Leading()
+        {
+            const string path = ")Open";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("')Open'", actual);
+        }
+
+        [TestMethod]
+        public void Parentheses_Close_LeadingAndTrailing()
+        {
+            const string path = ")Closed)";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("')Closed)'", actual);
+        }
+
+        [TestMethod]
+        public void Parentheses_Close_Trailing()
+        {
+            const string path = "Finish)";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Finish)'", actual);
+        }
+
+        [TestMethod]
+        public void Parentheses_Open_Embedded()
+        {
+            const string path = "Halo(Devine";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Halo(Devine'", actual);
+        }
+
+        [TestMethod]
+        public void Parentheses_Open_Leading()
+        {
+            const string path = "(Open";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'(Open'", actual);
+        }
+
+        [TestMethod]
+        public void Parentheses_Open_LeadingAndTrailing()
+        {
+            const string path = "(Closed(";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'(Closed('", actual);
+        }
+
+        [TestMethod]
+        public void Parentheses_Open_Trailing()
+        {
+            const string path = "Finish(";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Finish('", actual);
+        }
+
+        [TestMethod]
+        public void Percentage_Embedded()
+        {
+            const string path = "Ten%OfOneDollarIsTenCent";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Ten%OfOneDollarIsTenCent'", actual);
+        }
+
+        [TestMethod]
+        public void Percentage_Leading()
+        {
+            const string path = "%MoreOrLess";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'%MoreOrLess'", actual);
+        }
+
+        [TestMethod]
+        public void Percentage_LeadingAndTrailing()
+        {
+            const string path = "%USERNAME%";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'%USERNAME%'", actual);
+        }
+
+        [TestMethod]
+        public void Percentage_Trailing()
+        {
+            const string path = "TakeA%";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'TakeA%'", actual);
+        }
+
+        [TestMethod]
+        public void Pipe_Embedded()
+        {
+            const string path = "You|Me";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'You|Me'", actual);
+        }
+
+        [TestMethod]
+        public void Pipe_Leading()
+        {
+            const string path = "|Or";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'|Or'", actual);
+        }
+
+        [TestMethod]
+        public void Pipe_LeadingAndTrailing()
+        {
+            const string path = "|Or|";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'|Or|'", actual);
+        }
+
+        [TestMethod]
+        public void Pipe_Trailing()
+        {
+            const string path = "And|";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'And|'", actual);
+        }
+
+        [TestMethod]
+        public void QuestionMark_Embedded()
+        {
+            const string path = "WhatTimeIsIt?SheSaid";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'WhatTimeIsIt?SheSaid'", actual);
+        }
+
+        [TestMethod]
+        public void QuestionMark_Leading()
+        {
+            const string path = "?Quizz";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'?Quizz'", actual);
+        }
+
+        [TestMethod]
+        public void QuestionMark_LeadingAndTrailing()
+        {
+            const string path = "?Crazy?";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'?Crazy?'", actual);
+        }
+
+        [TestMethod]
+        public void QuestionMark_Trailing()
+        {
+            const string path = "WhatTimeIsLove?";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'WhatTimeIsLove?'", actual);
+        }
+
+        [TestMethod]
+        public void Semicolon_Embedded()
+        {
+            const string path = "Rain;Storm";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Rain;Storm'", actual);
+        }
+
+        [TestMethod]
+        public void Semicolon_Leading()
+        {
+            const string path = ";List";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("';List'", actual);
+        }
+
+        [TestMethod]
+        public void Semicolon_LeadingAndTrailing()
+        {
+            const string path = ";Trapped;";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("';Trapped;'", actual);
+        }
+
+        [TestMethod]
+        public void Semicolon_Trailing()
+        {
+            const string path = "Time;";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Time;'", actual);
+        }
+
+        [TestMethod]
+        public void SingleQuote_Embedded_Single()
+        {
+            const string path = "Rain'Storm";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Rain'\"'\"'Storm'", actual);
+        }
+
+        [TestMethod]
+        public void SingleQuote_Embedded_Sequence()
+        {
+            const string path = "Rain''Storm";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Rain'\"''\"'Storm'", actual);
+        }
+
+        [TestMethod]
+        public void SingleQuote_Leading()
+        {
+            const string path = "'List";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"'\"'List'", actual);
+        }
+
+        [TestMethod]
+        public void SingleQuote_LeadingAndTrailing()
+        {
+            const string path = "'Trapped'";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"'\"'Trapped'\"'\"", actual);
+        }
+
+        [TestMethod]
+        public void SingleQuote_Trailing()
+        {
+            const string path = "Time'";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Time'\"'\"", actual);
+        }
+
+        [TestMethod]
+        public void SingleQuoteAndExclamationMark_Embedded()
+        {
+            const string path = "Rain'!Storm";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Rain'\"'\"\\!'Storm'", actual);
+        }
+
+        [TestMethod]
+        public void SingleQuoteAndExclamationMark_Leading()
+        {
+            const string path = "'!Rain";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"'\"\\!'Rain'", actual);
+        }
+
+        [TestMethod]
+        public void SingleQuoteAndExclamationMark_LeadingAndTrailing()
+        {
+            const string path = "'!Rain'!";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("\"'\"\\!'Rain'\"'\"\\!", actual);
+        }
+
+        [TestMethod]
+        public void SingleQuoteAndExclamationMark_Trailing()
+        {
+            const string path = "Rain'!";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Rain'\"'\"\\!", actual);
+        }
+
+        [TestMethod]
+        public void Space_Embedded()
+        {
+            const string path = "You Me";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'You Me'", actual);
+        }
+
+        [TestMethod]
+        public void Space_Leading()
+        {
+            const string path = " Or";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("' Or'", actual);
+        }
+
+        [TestMethod]
+        public void Space_LeadingAndTrailing()
+        {
+            const string path = " Or ";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("' Or '", actual);
+        }
+
+        [TestMethod]
+        public void Space_Trailing()
+        {
+            const string path = "And ";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'And '", actual);
+        }
+
+        [TestMethod]
+        public void SquareBrackets_Close_Embedded()
+        {
+            const string path = "Halo]Devine";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Halo]Devine'", actual);
+        }
+
+        [TestMethod]
+        public void SquareBrackets_Close_Leading()
+        {
+            const string path = "]Open";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("']Open'", actual);
+        }
+
+        [TestMethod]
+        public void SquareBrackets_Close_LeadingAndTrailing()
+        {
+            const string path = "]Closed]";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("']Closed]'", actual);
+        }
+
+        [TestMethod]
+        public void SquareBrackets_Close_Trailing()
+        {
+            const string path = "Finish]";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Finish]'", actual);
+        }
+
+        [TestMethod]
+        public void SquareBrackets_Open_Embedded()
+        {
+            const string path = "Halo[Devine";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Halo[Devine'", actual);
+        }
+
+        [TestMethod]
+        public void SquareBrackets_Open_Leading()
+        {
+            const string path = "[Open";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'[Open'", actual);
+        }
+
+        [TestMethod]
+        public void SquareBrackets_Open_LeadingAndTrailing()
+        {
+            const string path = "[Closed[";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'[Closed['", actual);
+        }
+
+        [TestMethod]
+        public void SquareBrackets_Open_Trailing()
+        {
+            const string path = "Finish[";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Finish['", actual);
+        }
+
+        [TestMethod]
+        public void Tab_Embedded()
+        {
+            const string path = "You\tMe";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'You\tMe'", actual);
+        }
+
+        [TestMethod]
+        public void Tab_Leading()
+        {
+            const string path = "\tOr";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'\tOr'", actual);
+        }
+
+        [TestMethod]
+        public void Tab_LeadingAndTrailing()
+        {
+            const string path = "\tOr\t";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'\tOr\t'", actual);
+        }
+
+        [TestMethod]
+        public void Tab_Trailing()
+        {
+            const string path = "And\t";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'And\t'", actual);
+        }
+
+        [TestMethod]
+        public void Tilde_Embedded()
+        {
+            const string path = "Seven~Nine";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Seven~Nine'", actual);
+        }
+
+        [TestMethod]
+        public void Tilde_Leading()
+        {
+            const string path = "~Ten";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'~Ten'", actual);
+        }
+
+        [TestMethod]
+        public void Tilde_LeadingAndTrailing()
+        {
+            const string path = "~One~";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'~One~'", actual);
+        }
+
+        [TestMethod]
+        public void Tilde_Trailing()
+        {
+            const string path = "Two~";
+
+            var actual = _transformation.Transform(path);
+
+            Assert.AreEqual("'Two~'", actual);
+        }
+    }
+}

+ 229 - 78
src/Renci.SshNet.Tests/Classes/ScpClientTest.cs

@@ -1,4 +1,5 @@
 using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 using Renci.SshNet.Tests.Common;
 using Renci.SshNet.Tests.Properties;
 using System;
@@ -15,6 +16,206 @@ namespace Renci.SshNet.Tests.Classes
     [TestClass]
     public partial class ScpClientTest : TestBase
     {
+        private Random _random;
+
+        [TestInitialize]
+        public void SetUp()
+        {
+            _random = new Random();
+        }
+
+        [TestMethod]
+        public void Ctor_ConnectionInfo_Null()
+        {
+            const ConnectionInfo connectionInfo = null;
+
+            try
+            {
+                new ScpClient(connectionInfo);
+                Assert.Fail();
+            }
+            catch (ArgumentNullException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("connectionInfo", ex.ParamName);
+            }
+        }
+
+        [TestMethod]
+        public void Ctor_ConnectionInfo_NotNull()
+        {
+            var connectionInfo = new ConnectionInfo("HOST", "USER", new PasswordAuthenticationMethod("USER", "PWD"));
+
+            var client = new ScpClient(connectionInfo);
+            Assert.AreEqual(16 * 1024U, client.BufferSize);
+            Assert.AreSame(connectionInfo, client.ConnectionInfo);
+            Assert.IsFalse(client.IsConnected);
+            Assert.AreEqual(new TimeSpan(0, 0, 0, 0, -1), client.KeepAliveInterval);
+            Assert.AreEqual(new TimeSpan(0, 0, 0, 0, -1), client.OperationTimeout);
+            Assert.AreSame(RemotePathTransformation.DoubleQuote, client.RemotePathTransformation);
+            Assert.IsNull(client.Session);
+        }
+
+        [TestMethod]
+        public void Ctor_HostAndPortAndUsernameAndPassword()
+        {
+            var host = _random.Next().ToString();
+            var port = _random.Next(1, 100);
+            var userName = _random.Next().ToString();
+            var password = _random.Next().ToString();
+
+            var client = new ScpClient(host, port, userName, password);
+            Assert.AreEqual(16 * 1024U, client.BufferSize);
+            Assert.IsNotNull(client.ConnectionInfo);
+            Assert.IsFalse(client.IsConnected);
+            Assert.AreEqual(new TimeSpan(0, 0, 0, 0, -1), client.KeepAliveInterval);
+            Assert.AreEqual(new TimeSpan(0, 0, 0, 0, -1), client.OperationTimeout);
+            Assert.AreSame(RemotePathTransformation.DoubleQuote, client.RemotePathTransformation);
+            Assert.IsNull(client.Session);
+
+            var passwordConnectionInfo = client.ConnectionInfo as PasswordConnectionInfo;
+            Assert.IsNotNull(passwordConnectionInfo);
+            Assert.AreEqual(host, passwordConnectionInfo.Host);
+            Assert.AreEqual(port, passwordConnectionInfo.Port);
+            Assert.AreSame(userName, passwordConnectionInfo.Username);
+            Assert.IsNotNull(passwordConnectionInfo.AuthenticationMethods);
+            Assert.AreEqual(1, passwordConnectionInfo.AuthenticationMethods.Count);
+
+            var passwordAuthentication = passwordConnectionInfo.AuthenticationMethods[0] as PasswordAuthenticationMethod;
+            Assert.IsNotNull(passwordAuthentication);
+            Assert.AreEqual(userName, passwordAuthentication.Username);
+            Assert.IsTrue(Encoding.UTF8.GetBytes(password).IsEqualTo(passwordAuthentication.Password));
+        }
+
+        [TestMethod]
+        public void Ctor_HostAndUsernameAndPassword()
+        {
+            var host = _random.Next().ToString();
+            var userName = _random.Next().ToString();
+            var password = _random.Next().ToString();
+
+            var client = new ScpClient(host, userName, password);
+            Assert.AreEqual(16 * 1024U, client.BufferSize);
+            Assert.IsNotNull(client.ConnectionInfo);
+            Assert.IsFalse(client.IsConnected);
+            Assert.AreEqual(new TimeSpan(0, 0, 0, 0, -1), client.KeepAliveInterval);
+            Assert.AreEqual(new TimeSpan(0, 0, 0, 0, -1), client.OperationTimeout);
+            Assert.AreSame(RemotePathTransformation.DoubleQuote, client.RemotePathTransformation);
+            Assert.IsNull(client.Session);
+
+            var passwordConnectionInfo = client.ConnectionInfo as PasswordConnectionInfo;
+            Assert.IsNotNull(passwordConnectionInfo);
+            Assert.AreEqual(host, passwordConnectionInfo.Host);
+            Assert.AreEqual(22, passwordConnectionInfo.Port);
+            Assert.AreSame(userName, passwordConnectionInfo.Username);
+            Assert.IsNotNull(passwordConnectionInfo.AuthenticationMethods);
+            Assert.AreEqual(1, passwordConnectionInfo.AuthenticationMethods.Count);
+
+            var passwordAuthentication = passwordConnectionInfo.AuthenticationMethods[0] as PasswordAuthenticationMethod;
+            Assert.IsNotNull(passwordAuthentication);
+            Assert.AreEqual(userName, passwordAuthentication.Username);
+            Assert.IsTrue(Encoding.UTF8.GetBytes(password).IsEqualTo(passwordAuthentication.Password));
+        }
+
+        [TestMethod]
+        public void Ctor_HostAndPortAndUsernameAndPrivateKeys()
+        {
+            var host = _random.Next().ToString();
+            var port = _random.Next(1, 100);
+            var userName = _random.Next().ToString();
+            var privateKeys = new[] {GetRsaKey(), GetDsaKey()};
+
+            var client = new ScpClient(host, port, userName, privateKeys);
+            Assert.AreEqual(16 * 1024U, client.BufferSize);
+            Assert.IsNotNull(client.ConnectionInfo);
+            Assert.IsFalse(client.IsConnected);
+            Assert.AreEqual(new TimeSpan(0, 0, 0, 0, -1), client.KeepAliveInterval);
+            Assert.AreEqual(new TimeSpan(0, 0, 0, 0, -1), client.OperationTimeout);
+            Assert.AreSame(RemotePathTransformation.DoubleQuote, client.RemotePathTransformation);
+            Assert.IsNull(client.Session);
+
+            var privateKeyConnectionInfo = client.ConnectionInfo as PrivateKeyConnectionInfo;
+            Assert.IsNotNull(privateKeyConnectionInfo);
+            Assert.AreEqual(host, privateKeyConnectionInfo.Host);
+            Assert.AreEqual(port, privateKeyConnectionInfo.Port);
+            Assert.AreSame(userName, privateKeyConnectionInfo.Username);
+            Assert.IsNotNull(privateKeyConnectionInfo.AuthenticationMethods);
+            Assert.AreEqual(1, privateKeyConnectionInfo.AuthenticationMethods.Count);
+
+            var privateKeyAuthentication = privateKeyConnectionInfo.AuthenticationMethods[0] as PrivateKeyAuthenticationMethod;
+            Assert.IsNotNull(privateKeyAuthentication);
+            Assert.AreEqual(userName, privateKeyAuthentication.Username);
+            Assert.IsNotNull(privateKeyAuthentication.KeyFiles);
+            Assert.AreEqual(privateKeys.Length, privateKeyAuthentication.KeyFiles.Count);
+            Assert.IsTrue(privateKeyAuthentication.KeyFiles.Contains(privateKeys[0]));
+            Assert.IsTrue(privateKeyAuthentication.KeyFiles.Contains(privateKeys[1]));
+        }
+
+        [TestMethod]
+        public void Ctor_HostAndUsernameAndPrivateKeys()
+        {
+            var host = _random.Next().ToString();
+            var userName = _random.Next().ToString();
+            var privateKeys = new[] { GetRsaKey(), GetDsaKey() };
+
+            var client = new ScpClient(host, userName, privateKeys);
+            Assert.AreEqual(16 * 1024U, client.BufferSize);
+            Assert.IsNotNull(client.ConnectionInfo);
+            Assert.IsFalse(client.IsConnected);
+            Assert.AreEqual(new TimeSpan(0, 0, 0, 0, -1), client.KeepAliveInterval);
+            Assert.AreEqual(new TimeSpan(0, 0, 0, 0, -1), client.OperationTimeout);
+            Assert.AreSame(RemotePathTransformation.DoubleQuote, client.RemotePathTransformation);
+            Assert.IsNull(client.Session);
+
+            var privateKeyConnectionInfo = client.ConnectionInfo as PrivateKeyConnectionInfo;
+            Assert.IsNotNull(privateKeyConnectionInfo);
+            Assert.AreEqual(host, privateKeyConnectionInfo.Host);
+            Assert.AreEqual(22, privateKeyConnectionInfo.Port);
+            Assert.AreSame(userName, privateKeyConnectionInfo.Username);
+            Assert.IsNotNull(privateKeyConnectionInfo.AuthenticationMethods);
+            Assert.AreEqual(1, privateKeyConnectionInfo.AuthenticationMethods.Count);
+
+            var privateKeyAuthentication = privateKeyConnectionInfo.AuthenticationMethods[0] as PrivateKeyAuthenticationMethod;
+            Assert.IsNotNull(privateKeyAuthentication);
+            Assert.AreEqual(userName, privateKeyAuthentication.Username);
+            Assert.IsNotNull(privateKeyAuthentication.KeyFiles);
+            Assert.AreEqual(privateKeys.Length, privateKeyAuthentication.KeyFiles.Count);
+            Assert.IsTrue(privateKeyAuthentication.KeyFiles.Contains(privateKeys[0]));
+            Assert.IsTrue(privateKeyAuthentication.KeyFiles.Contains(privateKeys[1]));
+        }
+
+        [TestMethod]
+        public void RemotePathTransformation_Value_NotNull()
+        {
+            var client = new ScpClient("HOST", 22, "USER", "PWD");
+
+            Assert.AreSame(RemotePathTransformation.DoubleQuote, client.RemotePathTransformation);
+            client.RemotePathTransformation = RemotePathTransformation.ShellQuote;
+            Assert.AreSame(RemotePathTransformation.ShellQuote, client.RemotePathTransformation);
+        }
+
+        [TestMethod]
+        public void RemotePathTransformation_Value_Null()
+        {
+            var client = new ScpClient("HOST", 22, "USER", "PWD")
+            {
+                RemotePathTransformation = RemotePathTransformation.ShellQuote
+            };
+
+            try
+            {
+                client.RemotePathTransformation = null;
+                Assert.Fail();
+            }
+            catch (ArgumentNullException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("value", ex.ParamName);
+            }
+
+            Assert.AreSame(RemotePathTransformation.ShellQuote, client.RemotePathTransformation);
+        }
+
         [TestMethod]
         [TestCategory("Scp")]
         [TestCategory("integration")]
@@ -172,10 +373,12 @@ namespace Renci.SshNet.Tests.Classes
             {
                 scp.Connect();
 
-                var uploadDirectory = Directory.CreateDirectory(string.Format("{0}\\{1}", Path.GetTempPath(), Path.GetRandomFileName()));
+                var uploadDirectory =
+                    Directory.CreateDirectory(string.Format("{0}\\{1}", Path.GetTempPath(), Path.GetRandomFileName()));
                 for (int i = 0; i < 3; i++)
                 {
-                    var subfolder = Directory.CreateDirectory(string.Format(@"{0}\folder_{1}", uploadDirectory.FullName, i));
+                    var subfolder =
+                        Directory.CreateDirectory(string.Format(@"{0}\folder_{1}", uploadDirectory.FullName, i));
                     for (int j = 0; j < 5; j++)
                     {
                         this.CreateTestFile(string.Format(@"{0}\file_{1}", subfolder.FullName, j), 1);
@@ -185,7 +388,8 @@ namespace Renci.SshNet.Tests.Classes
 
                 scp.Upload(uploadDirectory, "uploaded_dir");
 
-                var downloadDirectory = Directory.CreateDirectory(string.Format("{0}\\{1}", Path.GetTempPath(), Path.GetRandomFileName()));
+                var downloadDirectory =
+                    Directory.CreateDirectory(string.Format("{0}\\{1}", Path.GetTempPath(), Path.GetRandomFileName()));
 
                 scp.Download("uploaded_dir", downloadDirectory);
 
@@ -193,11 +397,12 @@ namespace Renci.SshNet.Tests.Classes
                 var downloadFiles = downloadDirectory.GetFiles("*.*", System.IO.SearchOption.AllDirectories);
 
                 var result = from f1 in uploadedFiles
-                             from f2 in downloadFiles
-                             where
-                                f1.FullName.Substring(uploadDirectory.FullName.Length) == f2.FullName.Substring(downloadDirectory.FullName.Length)
-                                && CalculateMD5(f1.FullName) == CalculateMD5(f2.FullName)
-                             select f1;
+                    from f2 in downloadFiles
+                    where
+                    f1.FullName.Substring(uploadDirectory.FullName.Length) ==
+                    f2.FullName.Substring(downloadDirectory.FullName.Length)
+                    && CalculateMD5(f1.FullName) == CalculateMD5(f2.FullName)
+                    select f1;
 
                 var counter = result.Count();
 
@@ -331,76 +536,6 @@ namespace Renci.SshNet.Tests.Classes
             Assert.Inconclusive("A method that does not return a value cannot be verified.");
         }
 
-        /// <summary>
-        ///A test for ScpClient Constructor
-        ///</summary>
-        [TestMethod]
-        [Ignore] // placeholder for actual test
-        public void ScpClientConstructorTest()
-        {
-            string host = string.Empty; // TODO: Initialize to an appropriate value
-            string username = string.Empty; // TODO: Initialize to an appropriate value
-            PrivateKeyFile[] keyFiles = null; // TODO: Initialize to an appropriate value
-            ScpClient target = new ScpClient(host, username, keyFiles);
-            Assert.Inconclusive("TODO: Implement code to verify target");
-        }
-
-        /// <summary>
-        ///A test for ScpClient Constructor
-        ///</summary>
-        [TestMethod]
-        [Ignore] // placeholder for actual test
-        public void ScpClientConstructorTest1()
-        {
-            string host = string.Empty; // TODO: Initialize to an appropriate value
-            int port = 0; // TODO: Initialize to an appropriate value
-            string username = string.Empty; // TODO: Initialize to an appropriate value
-            PrivateKeyFile[] keyFiles = null; // TODO: Initialize to an appropriate value
-            ScpClient target = new ScpClient(host, port, username, keyFiles);
-            Assert.Inconclusive("TODO: Implement code to verify target");
-        }
-
-        /// <summary>
-        ///A test for ScpClient Constructor
-        ///</summary>
-        [TestMethod]
-        [Ignore] // placeholder for actual test
-        public void ScpClientConstructorTest2()
-        {
-            string host = string.Empty; // TODO: Initialize to an appropriate value
-            string username = string.Empty; // TODO: Initialize to an appropriate value
-            string password = string.Empty; // TODO: Initialize to an appropriate value
-            ScpClient target = new ScpClient(host, username, password);
-            Assert.Inconclusive("TODO: Implement code to verify target");
-        }
-
-        /// <summary>
-        ///A test for ScpClient Constructor
-        ///</summary>
-        [TestMethod]
-        [Ignore] // placeholder for actual test
-        public void ScpClientConstructorTest3()
-        {
-            string host = string.Empty; // TODO: Initialize to an appropriate value
-            int port = 0; // TODO: Initialize to an appropriate value
-            string username = string.Empty; // TODO: Initialize to an appropriate value
-            string password = string.Empty; // TODO: Initialize to an appropriate value
-            ScpClient target = new ScpClient(host, port, username, password);
-            Assert.Inconclusive("TODO: Implement code to verify target");
-        }
-
-        /// <summary>
-        ///A test for ScpClient Constructor
-        ///</summary>
-        [TestMethod]
-        [Ignore] // placeholder for actual test
-        public void ScpClientConstructorTest4()
-        {
-            ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value
-            ScpClient target = new ScpClient(connectionInfo);
-            Assert.Inconclusive("TODO: Implement code to verify target");
-        }
-
         protected static string CalculateMD5(string fileName)
         {
             using (var file = new FileStream(fileName, FileMode.Open))
@@ -427,5 +562,21 @@ namespace Renci.SshNet.Tests.Classes
                 client.Disconnect();
             }
         }
+
+        private PrivateKeyFile GetRsaKey()
+        {
+            using (var stream = GetData("Key.RSA.txt"))
+            {
+                return new PrivateKeyFile(stream);
+            }
+        }
+
+        private PrivateKeyFile GetDsaKey()
+        {
+            using (var stream = GetData("Key.SSH2.DSA.txt"))
+            {
+                return new PrivateKeyFile(stream);
+            }
+        }
     }
 }

+ 45 - 0
src/Renci.SshNet.Tests/Classes/ScpClientTestBase.cs

@@ -0,0 +1,45 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Channels;
+using Renci.SshNet.Common;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    public abstract class ScpClientTestBase
+    {
+        internal Mock<IServiceFactory> _serviceFactoryMock;
+        internal Mock<IRemotePathTransformation> _remotePathTransformationMock;
+        internal Mock<ISession> _sessionMock;
+        internal Mock<IChannelSession> _channelSessionMock;
+        internal Mock<PipeStream> _pipeStreamMock;
+
+        protected abstract void SetupData();
+
+        protected void CreateMocks()
+        {
+            _serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
+            _remotePathTransformationMock = new Mock<IRemotePathTransformation>(MockBehavior.Strict);
+            _sessionMock = new Mock<ISession>(MockBehavior.Strict);
+            _channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
+            _pipeStreamMock = new Mock<PipeStream>(MockBehavior.Strict);
+        }
+
+        protected abstract void SetupMocks();
+
+        protected virtual void Arrange()
+        {
+            SetupData();
+            CreateMocks();
+            SetupMocks();
+        }
+
+        [TestInitialize]
+        public void Initialize()
+        {
+            Arrange();
+            Act();
+        }
+
+        protected abstract void Act();
+    }
+}

+ 111 - 0
src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs

@@ -0,0 +1,111 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Common;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse : ScpClientTestBase
+    {
+        private ConnectionInfo _connectionInfo;
+        private ScpClient _scpClient;
+        private DirectoryInfo _directoryInfo;
+        private string _path;
+        private string _transformedPath;
+        private IList<ScpUploadEventArgs> _uploadingRegister;
+        private SshException _actualException;
+
+        protected override void SetupData()
+        {
+            var random = new Random();
+
+            _connectionInfo = new ConnectionInfo("host", 22, "user", new PasswordAuthenticationMethod("user", "pwd"));
+            _directoryInfo = new DirectoryInfo("destination");
+            _path = "/home/sshnet/" + random.Next().ToString(CultureInfo.InvariantCulture);
+            _transformedPath = random.Next().ToString();
+            _uploadingRegister = new List<ScpUploadEventArgs>();
+        }
+
+        protected override void SetupMocks()
+        {
+            var sequence = new MockSequence();
+
+            _serviceFactoryMock.InSequence(sequence)
+                               .Setup(p => p.CreateRemotePathDoubleQuoteTransformation())
+                               .Returns(_remotePathTransformationMock.Object);
+            _serviceFactoryMock.InSequence(sequence)
+                               .Setup(p => p.CreateSession(_connectionInfo))
+                               .Returns(_sessionMock.Object);
+            _sessionMock.InSequence(sequence).Setup(p => p.Connect());
+            _serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object);
+            _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object);
+            _channelSessionMock.InSequence(sequence).Setup(p => p.Open());
+            _remotePathTransformationMock.InSequence(sequence)
+                                         .Setup(p => p.Transform(_path))
+                                         .Returns(_transformedPath);
+            _channelSessionMock.InSequence(sequence)
+                               .Setup(p => p.SendExecRequest(string.Format("scp -prf {0}", _transformedPath)))
+                               .Returns(false);
+            _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
+            _pipeStreamMock.As<IDisposable>().InSequence(sequence).Setup(p => p.Dispose());
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _scpClient = new ScpClient(_connectionInfo, false, _serviceFactoryMock.Object);
+            _scpClient.Uploading += (sender, args) => _uploadingRegister.Add(args);
+            _scpClient.Connect();
+        }
+
+        protected override void Act()
+        {
+            try
+            {
+                _scpClient.Download(_path, _directoryInfo);
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void UploadShouldHaveThrownSshException()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.IsNull(_actualException.InnerException);
+            Assert.AreEqual("Secure copy execution request was rejected by the server. Please consult the server logs.", _actualException.Message);
+        }
+
+        [TestMethod]
+        public void SendExecRequestOnChannelSessionShouldBeInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -prf {0}", _transformedPath)), Times.Once);
+        }
+
+        [TestMethod]
+        public void DisposeOnChannelShouldBeInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.Dispose(), Times.Once);
+        }
+
+        [TestMethod]
+        public void DisposeOnPipeStreamShouldBeInvokedOnce()
+        {
+            _pipeStreamMock.As<IDisposable>().Verify(p => p.Dispose(), Times.Once);
+        }
+
+        [TestMethod]
+        public void UploadingShouldNeverHaveFired()
+        {
+            Assert.AreEqual(0, _uploadingRegister.Count);
+        }
+    }
+}

+ 110 - 0
src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs

@@ -0,0 +1,110 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Common;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse : ScpClientTestBase
+    {
+        private ConnectionInfo _connectionInfo;
+        private ScpClient _scpClient;
+        private FileInfo _fileInfo;
+        private string _path;
+        private string _transformedPath;
+        private IList<ScpUploadEventArgs> _uploadingRegister;
+        private SshException _actualException;
+
+        protected override void SetupData()
+        {
+            var random = new Random();
+
+            _connectionInfo = new ConnectionInfo("host", 22, "user", new PasswordAuthenticationMethod("user", "pwd"));
+            _fileInfo = new FileInfo("destination");
+            _path = "/home/sshnet/" + random.Next().ToString(CultureInfo.InvariantCulture);
+            _transformedPath = random.Next().ToString();
+            _uploadingRegister = new List<ScpUploadEventArgs>();
+        }
+
+        protected override void SetupMocks()
+        {
+            var sequence = new MockSequence();
+
+            _serviceFactoryMock.InSequence(sequence)
+                               .Setup(p => p.CreateRemotePathDoubleQuoteTransformation())
+                               .Returns(_remotePathTransformationMock.Object);
+            _serviceFactoryMock.InSequence(sequence)
+                               .Setup(p => p.CreateSession(_connectionInfo))
+                               .Returns(_sessionMock.Object);
+            _sessionMock.InSequence(sequence).Setup(p => p.Connect());
+            _serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object);
+            _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object);
+            _channelSessionMock.InSequence(sequence).Setup(p => p.Open());
+            _remotePathTransformationMock.InSequence(sequence)
+                                         .Setup(p => p.Transform(_path))
+                                         .Returns(_transformedPath);
+            _channelSessionMock.InSequence(sequence)
+                .Setup(p => p.SendExecRequest(string.Format("scp -pf {0}", _transformedPath))).Returns(false);
+            _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
+            _pipeStreamMock.As<IDisposable>().InSequence(sequence).Setup(p => p.Dispose());
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _scpClient = new ScpClient(_connectionInfo, false, _serviceFactoryMock.Object);
+            _scpClient.Uploading += (sender, args) => _uploadingRegister.Add(args);
+            _scpClient.Connect();
+        }
+
+        protected override void Act()
+        {
+            try
+            {
+                _scpClient.Download(_path, _fileInfo);
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void UploadShouldHaveThrownSshException()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.IsNull(_actualException.InnerException);
+            Assert.AreEqual("Secure copy execution request was rejected by the server. Please consult the server logs.", _actualException.Message);
+        }
+
+        [TestMethod]
+        public void SendExecRequestOnChannelSessionShouldBeInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -pf {0}", _transformedPath)), Times.Once);
+        }
+
+        [TestMethod]
+        public void DisposeOnChannelShouldBeInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.Dispose(), Times.Once);
+        }
+
+        [TestMethod]
+        public void DisposeOnPipeStreamShouldBeInvokedOnce()
+        {
+            _pipeStreamMock.As<IDisposable>().Verify(p => p.Dispose(), Times.Once);
+        }
+
+        [TestMethod]
+        public void UploadingShouldNeverHaveFired()
+        {
+            Assert.AreEqual(0, _uploadingRegister.Count);
+        }
+    }
+}

+ 120 - 0
src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs

@@ -0,0 +1,120 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Common;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse : ScpClientTestBase
+    {
+        private ConnectionInfo _connectionInfo;
+        private ScpClient _scpClient;
+        private Stream _destination;
+        private string _path;
+        private string _transformedPath;
+        private IList<ScpUploadEventArgs> _uploadingRegister;
+        private SshException _actualException;
+
+        [TestCleanup]
+        public void Cleanup()
+        {
+            if (_destination != null)
+            {
+                _destination.Dispose();
+            }
+        }
+
+        protected override void SetupData()
+        {
+            var random = new Random();
+
+            _connectionInfo = new ConnectionInfo("host", 22, "user", new PasswordAuthenticationMethod("user", "pwd"));
+            _destination = new MemoryStream();
+            _path = "/home/sshnet/" + random.Next().ToString(CultureInfo.InvariantCulture);
+            _transformedPath = random.Next().ToString();
+            _uploadingRegister = new List<ScpUploadEventArgs>();
+        }
+
+        protected override void SetupMocks()
+        {
+            var sequence = new MockSequence();
+
+            _serviceFactoryMock.InSequence(sequence)
+                               .Setup(p => p.CreateRemotePathDoubleQuoteTransformation())
+                               .Returns(_remotePathTransformationMock.Object);
+            _serviceFactoryMock.InSequence(sequence)
+                               .Setup(p => p.CreateSession(_connectionInfo))
+                               .Returns(_sessionMock.Object);
+            _sessionMock.InSequence(sequence).Setup(p => p.Connect());
+            _serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object);
+            _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object);
+            _channelSessionMock.InSequence(sequence).Setup(p => p.Open());
+            _remotePathTransformationMock.InSequence(sequence)
+                                         .Setup(p => p.Transform(_path))
+                                         .Returns(_transformedPath);
+            _channelSessionMock.InSequence(sequence)
+                               .Setup(p => p.SendExecRequest(string.Format("scp -f {0}", _transformedPath)))
+                               .Returns(false);
+            _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
+            _pipeStreamMock.As<IDisposable>().InSequence(sequence).Setup(p => p.Dispose());
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _scpClient = new ScpClient(_connectionInfo, false, _serviceFactoryMock.Object);
+            _scpClient.Uploading += (sender, args) => _uploadingRegister.Add(args);
+            _scpClient.Connect();
+        }
+
+        protected override void Act()
+        {
+            try
+            {
+                _scpClient.Download(_path, _destination);
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void UploadShouldHaveThrownSshException()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.IsNull(_actualException.InnerException);
+            Assert.AreEqual("Secure copy execution request was rejected by the server. Please consult the server logs.", _actualException.Message);
+        }
+
+        [TestMethod]
+        public void SendExecRequestOnChannelSessionShouldBeInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -f {0}", _transformedPath)), Times.Once);
+        }
+
+        [TestMethod]
+        public void DisposeOnChannelShouldBeInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.Dispose(), Times.Once);
+        }
+
+        [TestMethod]
+        public void DisposeOnPipeStreamShouldBeInvokedOnce()
+        {
+            _pipeStreamMock.As<IDisposable>().Verify(p => p.Dispose(), Times.Once);
+        }
+
+        [TestMethod]
+        public void UploadingShouldNeverHaveFired()
+        {
+            Assert.AreEqual(0, _uploadingRegister.Count);
+        }
+    }
+}

+ 111 - 0
src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs

@@ -0,0 +1,111 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Common;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse : ScpClientTestBase
+    {
+        private ConnectionInfo _connectionInfo;
+        private ScpClient _scpClient;
+        private DirectoryInfo _directoryInfo;
+        private string _path;
+        private string _transformedPath;
+        private IList<ScpUploadEventArgs> _uploadingRegister;
+        private SshException _actualException;
+
+        protected override void SetupData()
+        {
+            var random = new Random();
+
+            _connectionInfo = new ConnectionInfo("host", 22, "user", new PasswordAuthenticationMethod("user", "pwd"));
+            _directoryInfo = new DirectoryInfo("source");
+            _path = "/home/sshnet/" + random.Next().ToString(CultureInfo.InvariantCulture);
+            _transformedPath = random.Next().ToString();
+            _uploadingRegister = new List<ScpUploadEventArgs>();
+        }
+
+        protected override void SetupMocks()
+        {
+            var sequence = new MockSequence();
+
+            _serviceFactoryMock.InSequence(sequence)
+                               .Setup(p => p.CreateRemotePathDoubleQuoteTransformation())
+                               .Returns(_remotePathTransformationMock.Object);
+            _serviceFactoryMock.InSequence(sequence)
+                               .Setup(p => p.CreateSession(_connectionInfo))
+                               .Returns(_sessionMock.Object);
+            _sessionMock.InSequence(sequence).Setup(p => p.Connect());
+            _serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object);
+            _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object);
+            _channelSessionMock.InSequence(sequence).Setup(p => p.Open());
+            _remotePathTransformationMock.InSequence(sequence)
+                                         .Setup(p => p.Transform(_path))
+                                         .Returns(_transformedPath);
+            _channelSessionMock.InSequence(sequence)
+                               .Setup(p => p.SendExecRequest(string.Format("scp -rt {0}", _transformedPath)))
+                               .Returns(false);
+            _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
+            _pipeStreamMock.As<IDisposable>().InSequence(sequence).Setup(p => p.Dispose());
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _scpClient = new ScpClient(_connectionInfo, false, _serviceFactoryMock.Object);
+            _scpClient.Uploading += (sender, args) => _uploadingRegister.Add(args);
+            _scpClient.Connect();
+        }
+
+        protected override void Act()
+        {
+            try
+            {
+                _scpClient.Upload(_directoryInfo, _path);
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void UploadShouldHaveThrownSshException()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.IsNull(_actualException.InnerException);
+            Assert.AreEqual("Secure copy execution request was rejected by the server. Please consult the server logs.", _actualException.Message);
+        }
+
+        [TestMethod]
+        public void SendExecREquestOnChannelSessionShouldBeInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -rt {0}", _transformedPath)), Times.Once);
+        }
+
+        [TestMethod]
+        public void DisposeOnChannelShouldBeInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.Dispose(), Times.Once);
+        }
+
+        [TestMethod]
+        public void DisposeOnPipeStreamShouldBeInvokedOnce()
+        {
+            _pipeStreamMock.As<IDisposable>().Verify(p => p.Dispose(), Times.Once);
+        }
+
+        [TestMethod]
+        public void UploadingShouldNeverHaveFired()
+        {
+            Assert.AreEqual(0, _uploadingRegister.Count);
+        }
+    }
+}

+ 29 - 29
src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs

@@ -1,36 +1,24 @@
 using System;
 using System.Collections.Generic;
-using System.Globalization;
 using System.IO;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
-using Renci.SshNet.Channels;
 using Renci.SshNet.Common;
 
 namespace Renci.SshNet.Tests.Classes
 {
     [TestClass]
-    public class ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse
+    public class ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse : ScpClientTestBase
     {
-        private Mock<IServiceFactory> _serviceFactoryMock;
-        private Mock<ISession> _sessionMock;
-        private Mock<IChannelSession> _channelSessionMock;
-        private Mock<PipeStream> _pipeStreamMock;
         private ConnectionInfo _connectionInfo;
         private ScpClient _scpClient;
         private FileInfo _fileInfo;
         private string _path;
+        private string _transformedPath;
         private string _fileName;
         private IList<ScpUploadEventArgs> _uploadingRegister;
         private SshException _actualException;
 
-        [TestInitialize]
-        public void Setup()
-        {
-            Arrange();
-            Act();
-        }
-
         [TestCleanup]
         public void Cleanup()
         {
@@ -41,40 +29,52 @@ namespace Renci.SshNet.Tests.Classes
             }
         }
 
-        protected void Arrange()
+        protected override void SetupData()
         {
             var random = new Random();
-            _fileName = CreateTemporaryFile(new byte[] {1});
+
+            _fileName = CreateTemporaryFile(new byte[] { 1 });
             _connectionInfo = new ConnectionInfo("host", 22, "user", new PasswordAuthenticationMethod("user", "pwd"));
             _fileInfo = new FileInfo(_fileName);
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
+            _path = "/home/sshnet/" + random.Next();
+            _transformedPath = random.Next().ToString();
             _uploadingRegister = new List<ScpUploadEventArgs>();
+        }
 
-            _serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
-            _sessionMock = new Mock<ISession>(MockBehavior.Strict);
-            _channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
-            _pipeStreamMock = new Mock<PipeStream>(MockBehavior.Strict);
-
+        protected override void SetupMocks()
+        {
             var sequence = new MockSequence();
+
+            _serviceFactoryMock.InSequence(sequence)
+                               .Setup(p => p.CreateRemotePathDoubleQuoteTransformation())
+                               .Returns(_remotePathTransformationMock.Object);
             _serviceFactoryMock.InSequence(sequence)
-                .Setup(p => p.CreateSession(_connectionInfo))
-                .Returns(_sessionMock.Object);
+                               .Setup(p => p.CreateSession(_connectionInfo))
+                               .Returns(_sessionMock.Object);
             _sessionMock.InSequence(sequence).Setup(p => p.Connect());
             _serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object);
             _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object);
             _channelSessionMock.InSequence(sequence).Setup(p => p.Open());
+            _remotePathTransformationMock.InSequence(sequence)
+                                         .Setup(p => p.Transform(_path))
+                                         .Returns(_transformedPath);
             _channelSessionMock.InSequence(sequence)
-                .Setup(
-                    p => p.SendExecRequest(string.Format("scp -t \"{0}\"", _path))).Returns(false);
+                               .Setup(p => p.SendExecRequest(string.Format("scp -t {0}", _transformedPath)))
+                               .Returns(false);
             _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
             _pipeStreamMock.As<IDisposable>().InSequence(sequence).Setup(p => p.Dispose());
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
 
             _scpClient = new ScpClient(_connectionInfo, false, _serviceFactoryMock.Object);
             _scpClient.Uploading += (sender, args) => _uploadingRegister.Add(args);
             _scpClient.Connect();
         }
 
-        protected virtual void Act()
+        protected override void Act()
         {
             try
             {
@@ -96,9 +96,9 @@ namespace Renci.SshNet.Tests.Classes
         }
 
         [TestMethod]
-        public void SendExecREquestOnChannelSessionShouldBeInvokedOnce()
+        public void SendExecRequestOnChannelSessionShouldBeInvokedOnce()
         {
-            _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -t \"{0}\"", _path)), Times.Once);
+            _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -t {0}", _transformedPath)), Times.Once);
         }
 
         [TestMethod]

+ 22 - 39
src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs

@@ -6,35 +6,24 @@ using System.Linq;
 using System.Text;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
-using Renci.SshNet.Channels;
 using Renci.SshNet.Common;
 
 namespace Renci.SshNet.Tests.Classes
 {
     [TestClass]
-    public class ScpClientTest_Upload_FileInfoAndPath_Success
+    public class ScpClientTest_Upload_FileInfoAndPath_Success : ScpClientTestBase
     {
-        private Mock<IServiceFactory> _serviceFactoryMock;
-        private Mock<ISession> _sessionMock;
-        private Mock<IChannelSession> _channelSessionMock;
-        private Mock<PipeStream> _pipeStreamMock;
         private ConnectionInfo _connectionInfo;
         private ScpClient _scpClient;
         private FileInfo _fileInfo;
         private string _path;
+        private string _transformedPath;
         private int _bufferSize;
         private byte[] _fileContent;
         private string _fileName;
         private int _fileSize;
         private IList<ScpUploadEventArgs> _uploadingRegister;
 
-        [TestInitialize]
-        public void Setup()
-        {
-            Arrange();
-            Act();
-        }
-
         [TestCleanup]
         public void Cleanup()
         {
@@ -45,7 +34,7 @@ namespace Renci.SshNet.Tests.Classes
             }
         }
 
-        private void SetupData()
+        protected override void SetupData()
         {
             var random = new Random();
 
@@ -55,41 +44,37 @@ namespace Renci.SshNet.Tests.Classes
             _fileName = CreateTemporaryFile(_fileContent);
             _connectionInfo = new ConnectionInfo("host", 22, "user", new PasswordAuthenticationMethod("user", "pwd"));
             _fileInfo = new FileInfo(_fileName);
-            _path = random.Next().ToString(CultureInfo.InvariantCulture);
+            _path = "/home/sshnet/" + random.Next().ToString(CultureInfo.InvariantCulture);
+            _transformedPath = random.Next().ToString();
             _uploadingRegister = new List<ScpUploadEventArgs>();
         }
 
-        private void CreateMocks()
-        {
-            _serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
-            _sessionMock = new Mock<ISession>(MockBehavior.Strict);
-            _channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
-            _pipeStreamMock = new Mock<PipeStream>(MockBehavior.Strict);
-        }
-
-        private void SetupMocks()
+        protected override void SetupMocks()
         {
             var sequence = new MockSequence();
+
             _serviceFactoryMock.InSequence(sequence)
-                .Setup(p => p.CreateSession(_connectionInfo))
-                .Returns(_sessionMock.Object);
+                               .Setup(p => p.CreateRemotePathDoubleQuoteTransformation())
+                               .Returns(_remotePathTransformationMock.Object);
+            _serviceFactoryMock.InSequence(sequence)
+                               .Setup(p => p.CreateSession(_connectionInfo))
+                               .Returns(_sessionMock.Object);
             _sessionMock.InSequence(sequence).Setup(p => p.Connect());
             _serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object);
             _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object);
             _channelSessionMock.InSequence(sequence).Setup(p => p.Open());
+            _remotePathTransformationMock.InSequence(sequence)
+                                         .Setup(p => p.Transform(_path))
+                                         .Returns(_transformedPath);
             _channelSessionMock.InSequence(sequence)
-                .Setup(
-                    p => p.SendExecRequest(string.Format("scp -t \"{0}\"", _path))).Returns(true);
+                               .Setup(p => p.SendExecRequest(string.Format("scp -t {0}", _transformedPath)))
+                               .Returns(true);
             _pipeStreamMock.InSequence(sequence).Setup(p => p.ReadByte()).Returns(0);
             _channelSessionMock.InSequence(sequence).Setup(p => p.SendData(It.IsAny<byte[]>()));
             _pipeStreamMock.InSequence(sequence).Setup(p => p.ReadByte()).Returns(0);
             _channelSessionMock.InSequence(sequence)
                 .Setup(p => p.SendData(It.Is<byte[]>(b => b.SequenceEqual(CreateData(
-                    string.Format("C0644 {0} {1}\n",
-                        _fileInfo.Length,
-                        Path.GetFileName(_fileName)
-                        )
-                    )))));
+                    string.Format("C0644 {0} {1}\n", _fileInfo.Length, string.Empty))))));
             _pipeStreamMock.InSequence(sequence).Setup(p => p.ReadByte()).Returns(0);
             _channelSessionMock.InSequence(sequence)
                 .Setup(
@@ -105,11 +90,9 @@ namespace Renci.SshNet.Tests.Classes
             _pipeStreamMock.As<IDisposable>().InSequence(sequence).Setup(p => p.Dispose());
         }
 
-        protected void Arrange()
+        protected override void Arrange()
         {
-            SetupData();
-            CreateMocks();
-            SetupMocks();
+            base.Arrange();
 
             _scpClient = new ScpClient(_connectionInfo, false, _serviceFactoryMock.Object)
                 {
@@ -119,7 +102,7 @@ namespace Renci.SshNet.Tests.Classes
             _scpClient.Connect();
         }
 
-        protected virtual void Act()
+        protected override void Act()
         {
             _scpClient.Upload(_fileInfo, _path);
         }
@@ -127,7 +110,7 @@ namespace Renci.SshNet.Tests.Classes
         [TestMethod]
         public void SendExecRequestOnChannelSessionShouldBeInvokedOnce()
         {
-            _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -t \"{0}\"", _path)), Times.Once);
+            _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -t {0}", _transformedPath)), Times.Once);
         }
 
         [TestMethod]

+ 120 - 0
src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs

@@ -0,0 +1,120 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Common;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse : ScpClientTestBase
+    {
+        private ConnectionInfo _connectionInfo;
+        private ScpClient _scpClient;
+        private Stream _source;
+        private string _path;
+        private string _transformedPath;
+        private IList<ScpUploadEventArgs> _uploadingRegister;
+        private SshException _actualException;
+
+        [TestCleanup]
+        public void Cleanup()
+        {
+            if (_source != null)
+            {
+                _source.Dispose();
+            }
+        }
+
+        protected override void SetupData()
+        {
+            var random = new Random();
+
+            _connectionInfo = new ConnectionInfo("host", 22, "user", new PasswordAuthenticationMethod("user", "pwd"));
+            _source = new MemoryStream();
+            _path = "/home/sshnet/" + random.Next().ToString(CultureInfo.InvariantCulture);
+            _transformedPath = random.Next().ToString();
+            _uploadingRegister = new List<ScpUploadEventArgs>();
+        }
+
+        protected override void SetupMocks()
+        {
+            var sequence = new MockSequence();
+
+            _serviceFactoryMock.InSequence(sequence)
+                               .Setup(p => p.CreateRemotePathDoubleQuoteTransformation())
+                               .Returns(_remotePathTransformationMock.Object);
+            _serviceFactoryMock.InSequence(sequence)
+                               .Setup(p => p.CreateSession(_connectionInfo))
+                               .Returns(_sessionMock.Object);
+            _sessionMock.InSequence(sequence).Setup(p => p.Connect());
+            _serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object);
+            _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object);
+            _channelSessionMock.InSequence(sequence).Setup(p => p.Open());
+            _remotePathTransformationMock.InSequence(sequence)
+                                         .Setup(p => p.Transform(_path))
+                                         .Returns(_transformedPath);
+            _channelSessionMock.InSequence(sequence)
+                               .Setup(p => p.SendExecRequest(string.Format("scp -t {0}", _transformedPath)))
+                               .Returns(false);
+            _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
+            _pipeStreamMock.As<IDisposable>().InSequence(sequence).Setup(p => p.Dispose());
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _scpClient = new ScpClient(_connectionInfo, false, _serviceFactoryMock.Object);
+            _scpClient.Uploading += (sender, args) => _uploadingRegister.Add(args);
+            _scpClient.Connect();
+        }
+
+        protected override void Act()
+        {
+            try
+            {
+                _scpClient.Upload(_source, _path);
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void UploadShouldHaveThrownSshException()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.IsNull(_actualException.InnerException);
+            Assert.AreEqual("Secure copy execution request was rejected by the server. Please consult the server logs.", _actualException.Message);
+        }
+
+        [TestMethod]
+        public void SendExecRequestOnChannelSessionShouldBeInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -t {0}", _transformedPath)), Times.Once);
+        }
+
+        [TestMethod]
+        public void DisposeOnChannelShouldBeInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.Dispose(), Times.Once);
+        }
+
+        [TestMethod]
+        public void DisposeOnPipeStreamShouldBeInvokedOnce()
+        {
+            _pipeStreamMock.As<IDisposable>().Verify(p => p.Dispose(), Times.Once);
+        }
+
+        [TestMethod]
+        public void UploadingShouldNeverHaveFired()
+        {
+            Assert.AreEqual(0, _uploadingRegister.Count);
+        }
+    }
+}

+ 1 - 0
src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs

@@ -1,4 +1,5 @@
 using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 using Renci.SshNet.Security.Cryptography.Ciphers;
 using Renci.SshNet.Security.Cryptography.Ciphers.Modes;
 using Renci.SshNet.Tests.Common;

+ 1 - 0
src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Arc4CipherTest.cs

@@ -1,5 +1,6 @@
 using System.Text;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 using Renci.SshNet.Security.Cryptography.Ciphers;
 using Renci.SshNet.Tests.Common;
 using Renci.SshNet.Tests.Properties;

+ 1 - 0
src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/DesCipherTest.cs

@@ -1,5 +1,6 @@
 using System.Text;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 using Renci.SshNet.Security.Cryptography.Ciphers;
 using Renci.SshNet.Security.Cryptography.Ciphers.Modes;
 using Renci.SshNet.Security.Cryptography.Ciphers.Paddings;

+ 1 - 0
src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Paddings/PKCS5PaddingTest.cs

@@ -1,4 +1,5 @@
 using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 using Renci.SshNet.Security.Cryptography.Ciphers.Paddings;
 
 namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers.Paddings

+ 1 - 0
src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Paddings/PKCS7PaddingTest.cs

@@ -1,4 +1,5 @@
 using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Common;
 using Renci.SshNet.Security.Cryptography.Ciphers.Paddings;
 
 namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers.Paddings

+ 95 - 0
src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_EndLStatThrowsSshException.cs

@@ -0,0 +1,95 @@
+using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Abstractions;
+using Renci.SshNet.Common;
+using Renci.SshNet.Sftp;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class ServiceFactoryTest_CreateSftpFileReader_EndLStatThrowsSshException
+    {
+        private ServiceFactory _serviceFactory;
+        private Mock<ISftpSession> _sftpSessionMock;
+        private Mock<ISftpFileReader> _sftpFileReaderMock;
+        private uint _bufferSize;
+        private string _fileName;
+        private SftpOpenAsyncResult _openAsyncResult;
+        private byte[] _handle;
+        private SFtpStatAsyncResult _statAsyncResult;
+        private uint _chunkSize;
+        private ISftpFileReader _actual;
+
+        private void SetupData()
+        {
+            var random = new Random();
+
+            _bufferSize = (uint)random.Next(1, int.MaxValue);
+            _openAsyncResult = new SftpOpenAsyncResult(null, null);
+            _handle = CryptoAbstraction.GenerateRandom(random.Next(1, 10));
+            _statAsyncResult = new SFtpStatAsyncResult(null, null);
+            _fileName = random.Next().ToString();
+            _chunkSize = (uint) random.Next(1, int.MaxValue);
+        }
+
+        private void CreateMocks()
+        {
+            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+            _sftpFileReaderMock = new Mock<ISftpFileReader>(MockBehavior.Strict);
+        }
+
+        private void SetupMocks()
+        {
+            var seq = new MockSequence();
+
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.BeginOpen(_fileName, Flags.Read, null, null))
+                            .Returns(_openAsyncResult);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.EndOpen(_openAsyncResult))
+                            .Returns(_handle);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.BeginLStat(_fileName, null, null))
+                            .Returns(_statAsyncResult);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                            .Returns(_chunkSize);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.EndLStat(_statAsyncResult))
+                            .Throws(new SshException());
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.CreateFileReader(_handle, _sftpSessionMock.Object, _chunkSize, 3, null))
+                            .Returns(_sftpFileReaderMock.Object);
+        }
+
+        private void Arrange()
+        {
+            SetupData();
+            CreateMocks();
+            SetupMocks();
+
+            _serviceFactory = new ServiceFactory();
+        }
+
+        [TestInitialize]
+        public void Initialize()
+        {
+            Arrange();
+            Act();
+        }
+
+        private void Act()
+        {
+            _actual = _serviceFactory.CreateSftpFileReader(_fileName, _sftpSessionMock.Object, _bufferSize);
+        }
+
+        [TestMethod]
+        public void CreateSftpFileReaderShouldReturnCreatedInstance()
+        {
+            Assert.IsNotNull(_actual);
+            Assert.AreSame(_sftpFileReaderMock.Object, _actual);
+        }
+
+    }
+}

+ 98 - 0
src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsAlmostSixTimesGreaterThanChunkSize.cs

@@ -0,0 +1,98 @@
+using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Abstractions;
+using Renci.SshNet.Sftp;
+using Renci.SshNet.Tests.Common;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class ServiceFactoryTest_CreateSftpFileReader_FileSizeIsAlmostSixTimesGreaterThanChunkSize
+    {
+        private ServiceFactory _serviceFactory;
+        private Mock<ISftpSession> _sftpSessionMock;
+        private Mock<ISftpFileReader> _sftpFileReaderMock;
+        private uint _bufferSize;
+        private string _fileName;
+        private SftpOpenAsyncResult _openAsyncResult;
+        private byte[] _handle;
+        private SFtpStatAsyncResult _statAsyncResult;
+        private uint _chunkSize;
+        private SftpFileAttributes _fileAttributes;
+        private long _fileSize;
+        private ISftpFileReader _actual;
+
+        private void SetupData()
+        {
+            var random = new Random();
+
+            _bufferSize = (uint) random.Next(1, int.MaxValue);
+            _openAsyncResult = new SftpOpenAsyncResult(null, null);
+            _handle = CryptoAbstraction.GenerateRandom(random.Next(1, 10));
+            _statAsyncResult = new SFtpStatAsyncResult(null, null);
+            _fileName = random.Next().ToString();
+            _chunkSize = (uint) random.Next(1000, 5000);
+            _fileSize = (_chunkSize * 6) - 10;
+            _fileAttributes = new SftpFileAttributesBuilder().WithSize(_fileSize).Build();
+        }
+
+        private void CreateMocks()
+        {
+            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+            _sftpFileReaderMock = new Mock<ISftpFileReader>(MockBehavior.Strict);
+        }
+
+        private void SetupMocks()
+        {
+            var seq = new MockSequence();
+
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.BeginOpen(_fileName, Flags.Read, null, null))
+                            .Returns(_openAsyncResult);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.EndOpen(_openAsyncResult))
+                            .Returns(_handle);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.BeginLStat(_fileName, null, null))
+                            .Returns(_statAsyncResult);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                            .Returns(_chunkSize);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.EndLStat(_statAsyncResult))
+                            .Returns(_fileAttributes);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.CreateFileReader(_handle, _sftpSessionMock.Object, _chunkSize, 7, _fileSize))
+                            .Returns(_sftpFileReaderMock.Object);
+        }
+
+        private void Arrange()
+        {
+            SetupData();
+            CreateMocks();
+            SetupMocks();
+
+            _serviceFactory = new ServiceFactory();
+        }
+
+        [TestInitialize]
+        public void Initialize()
+        {
+            Arrange();
+            Act();
+        }
+
+        private void Act()
+        {
+            _actual = _serviceFactory.CreateSftpFileReader(_fileName, _sftpSessionMock.Object, _bufferSize);
+        }
+
+        [TestMethod]
+        public void CreateSftpFileReaderShouldReturnCreatedInstance()
+        {
+            Assert.IsNotNull(_actual);
+            Assert.AreSame(_sftpFileReaderMock.Object, _actual);
+        }
+    }
+}

+ 98 - 0
src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsEqualToChunkSize.cs

@@ -0,0 +1,98 @@
+using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Abstractions;
+using Renci.SshNet.Sftp;
+using Renci.SshNet.Tests.Common;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class ServiceFactoryTest_CreateSftpFileReader_FileSizeIsEqualToChunkSize
+    {
+        private ServiceFactory _serviceFactory;
+        private Mock<ISftpSession> _sftpSessionMock;
+        private Mock<ISftpFileReader> _sftpFileReaderMock;
+        private uint _bufferSize;
+        private string _fileName;
+        private SftpOpenAsyncResult _openAsyncResult;
+        private byte[] _handle;
+        private SFtpStatAsyncResult _statAsyncResult;
+        private uint _chunkSize;
+        private SftpFileAttributes _fileAttributes;
+        private long _fileSize;
+        private ISftpFileReader _actual;
+
+        private void SetupData()
+        {
+            var random = new Random();
+
+            _bufferSize = (uint)random.Next(1, int.MaxValue);
+            _openAsyncResult = new SftpOpenAsyncResult(null, null);
+            _handle = CryptoAbstraction.GenerateRandom(random.Next(1, 10));
+            _statAsyncResult = new SFtpStatAsyncResult(null, null);
+            _fileName = random.Next().ToString();
+            _chunkSize = (uint)random.Next(1000, int.MaxValue);
+            _fileSize = _chunkSize;
+            _fileAttributes = new SftpFileAttributesBuilder().WithSize(_fileSize).Build();
+        }
+
+        private void CreateMocks()
+        {
+            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+            _sftpFileReaderMock = new Mock<ISftpFileReader>(MockBehavior.Strict);
+        }
+
+        private void SetupMocks()
+        {
+            var seq = new MockSequence();
+
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.BeginOpen(_fileName, Flags.Read, null, null))
+                            .Returns(_openAsyncResult);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.EndOpen(_openAsyncResult))
+                            .Returns(_handle);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.BeginLStat(_fileName, null, null))
+                            .Returns(_statAsyncResult);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                            .Returns(_chunkSize);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.EndLStat(_statAsyncResult))
+                            .Returns(_fileAttributes);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.CreateFileReader(_handle, _sftpSessionMock.Object, _chunkSize, 2, _fileSize))
+                            .Returns(_sftpFileReaderMock.Object);
+        }
+
+        private void Arrange()
+        {
+            SetupData();
+            CreateMocks();
+            SetupMocks();
+
+            _serviceFactory = new ServiceFactory();
+        }
+
+        [TestInitialize]
+        public void Initialize()
+        {
+            Arrange();
+            Act();
+        }
+
+        private void Act()
+        {
+            _actual = _serviceFactory.CreateSftpFileReader(_fileName, _sftpSessionMock.Object, _bufferSize);
+        }
+
+        [TestMethod]
+        public void CreateSftpFileReaderShouldReturnCreatedInstance()
+        {
+            Assert.IsNotNull(_actual);
+            Assert.AreSame(_sftpFileReaderMock.Object, _actual);
+        }
+    }
+}

+ 98 - 0
src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsExactlyFiveTimesGreaterThanChunkSize.cs

@@ -0,0 +1,98 @@
+using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Abstractions;
+using Renci.SshNet.Sftp;
+using Renci.SshNet.Tests.Common;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class ServiceFactoryTest_CreateSftpFileReader_FileSizeIsExactlyFiveTimesGreaterThanChunkSize
+    {
+        private ServiceFactory _serviceFactory;
+        private Mock<ISftpSession> _sftpSessionMock;
+        private Mock<ISftpFileReader> _sftpFileReaderMock;
+        private uint _bufferSize;
+        private string _fileName;
+        private SftpOpenAsyncResult _openAsyncResult;
+        private byte[] _handle;
+        private SFtpStatAsyncResult _statAsyncResult;
+        private uint _chunkSize;
+        private SftpFileAttributes _fileAttributes;
+        private long _fileSize;
+        private ISftpFileReader _actual;
+
+        private void SetupData()
+        {
+            var random = new Random();
+
+            _bufferSize = (uint) random.Next(1, int.MaxValue);
+            _openAsyncResult = new SftpOpenAsyncResult(null, null);
+            _handle = CryptoAbstraction.GenerateRandom(random.Next(1, 10));
+            _statAsyncResult = new SFtpStatAsyncResult(null, null);
+            _fileName = random.Next().ToString();
+            _chunkSize = (uint) random.Next(1000, 5000);
+            _fileSize = _chunkSize * 5;
+            _fileAttributes = new SftpFileAttributesBuilder().WithSize(_fileSize).Build();
+        }
+
+        private void CreateMocks()
+        {
+            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+            _sftpFileReaderMock = new Mock<ISftpFileReader>(MockBehavior.Strict);
+        }
+
+        private void SetupMocks()
+        {
+            var seq = new MockSequence();
+
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.BeginOpen(_fileName, Flags.Read, null, null))
+                            .Returns(_openAsyncResult);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.EndOpen(_openAsyncResult))
+                            .Returns(_handle);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.BeginLStat(_fileName, null, null))
+                            .Returns(_statAsyncResult);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                            .Returns(_chunkSize);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.EndLStat(_statAsyncResult))
+                            .Returns(_fileAttributes);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.CreateFileReader(_handle, _sftpSessionMock.Object, _chunkSize, 6, _fileSize))
+                            .Returns(_sftpFileReaderMock.Object);
+        }
+
+        private void Arrange()
+        {
+            SetupData();
+            CreateMocks();
+            SetupMocks();
+
+            _serviceFactory = new ServiceFactory();
+        }
+
+        [TestInitialize]
+        public void Initialize()
+        {
+            Arrange();
+            Act();
+        }
+
+        private void Act()
+        {
+            _actual = _serviceFactory.CreateSftpFileReader(_fileName, _sftpSessionMock.Object, _bufferSize);
+        }
+
+        [TestMethod]
+        public void CreateSftpFileReaderShouldReturnCreatedInstance()
+        {
+            Assert.IsNotNull(_actual);
+            Assert.AreSame(_sftpFileReaderMock.Object, _actual);
+        }
+    }
+}

+ 98 - 0
src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLessThanChunkSize.cs

@@ -0,0 +1,98 @@
+using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Abstractions;
+using Renci.SshNet.Sftp;
+using Renci.SshNet.Tests.Common;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLessThanChunkSize
+    {
+        private ServiceFactory _serviceFactory;
+        private Mock<ISftpSession> _sftpSessionMock;
+        private Mock<ISftpFileReader> _sftpFileReaderMock;
+        private uint _bufferSize;
+        private string _fileName;
+        private SftpOpenAsyncResult _openAsyncResult;
+        private byte[] _handle;
+        private SFtpStatAsyncResult _statAsyncResult;
+        private uint _chunkSize;
+        private SftpFileAttributes _fileAttributes;
+        private long _fileSize;
+        private ISftpFileReader _actual;
+
+        private void SetupData()
+        {
+            var random = new Random();
+
+            _bufferSize = (uint)random.Next(1, int.MaxValue);
+            _openAsyncResult = new SftpOpenAsyncResult(null, null);
+            _handle = CryptoAbstraction.GenerateRandom(random.Next(1, 10));
+            _statAsyncResult = new SFtpStatAsyncResult(null, null);
+            _fileName = random.Next().ToString();
+            _chunkSize = (uint)random.Next(1000, int.MaxValue);
+            _fileSize = _chunkSize - random.Next(1, 10);
+            _fileAttributes = new SftpFileAttributesBuilder().WithSize(_fileSize).Build();
+        }
+
+        private void CreateMocks()
+        {
+            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+            _sftpFileReaderMock = new Mock<ISftpFileReader>(MockBehavior.Strict);
+        }
+
+        private void SetupMocks()
+        {
+            var seq = new MockSequence();
+
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.BeginOpen(_fileName, Flags.Read, null, null))
+                            .Returns(_openAsyncResult);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.EndOpen(_openAsyncResult))
+                            .Returns(_handle);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.BeginLStat(_fileName, null, null))
+                            .Returns(_statAsyncResult);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                            .Returns(_chunkSize);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.EndLStat(_statAsyncResult))
+                            .Returns(_fileAttributes);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.CreateFileReader(_handle, _sftpSessionMock.Object, _chunkSize, 2, _fileSize))
+                            .Returns(_sftpFileReaderMock.Object);
+        }
+
+        private void Arrange()
+        {
+            SetupData();
+            CreateMocks();
+            SetupMocks();
+
+            _serviceFactory = new ServiceFactory();
+        }
+
+        [TestInitialize]
+        public void Initialize()
+        {
+            Arrange();
+            Act();
+        }
+
+        private void Act()
+        {
+            _actual = _serviceFactory.CreateSftpFileReader(_fileName, _sftpSessionMock.Object, _bufferSize);
+        }
+
+        [TestMethod]
+        public void CreateSftpFileReaderShouldReturnCreatedInstance()
+        {
+            Assert.IsNotNull(_actual);
+            Assert.AreSame(_sftpFileReaderMock.Object, _actual);
+        }
+    }
+}

+ 98 - 0
src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLittleMoreThanFiveTimesGreaterThanChunkSize.cs

@@ -0,0 +1,98 @@
+using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Abstractions;
+using Renci.SshNet.Sftp;
+using Renci.SshNet.Tests.Common;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLittleMoreThanFiveTimesGreaterThanChunkSize
+    {
+        private ServiceFactory _serviceFactory;
+        private Mock<ISftpSession> _sftpSessionMock;
+        private Mock<ISftpFileReader> _sftpFileReaderMock;
+        private uint _bufferSize;
+        private string _fileName;
+        private SftpOpenAsyncResult _openAsyncResult;
+        private byte[] _handle;
+        private SFtpStatAsyncResult _statAsyncResult;
+        private uint _chunkSize;
+        private SftpFileAttributes _fileAttributes;
+        private long _fileSize;
+        private ISftpFileReader _actual;
+
+        private void SetupData()
+        {
+            var random = new Random();
+
+            _bufferSize = (uint)random.Next(1, int.MaxValue);
+            _openAsyncResult = new SftpOpenAsyncResult(null, null);
+            _handle = CryptoAbstraction.GenerateRandom(random.Next(1, 10));
+            _statAsyncResult = new SFtpStatAsyncResult(null, null);
+            _fileName = random.Next().ToString();
+            _chunkSize = (uint)random.Next(1000, 5000);
+            _fileSize = (_chunkSize * 5) + 10;
+            _fileAttributes = new SftpFileAttributesBuilder().WithSize(_fileSize).Build();
+        }
+
+        private void CreateMocks()
+        {
+            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+            _sftpFileReaderMock = new Mock<ISftpFileReader>(MockBehavior.Strict);
+        }
+
+        private void SetupMocks()
+        {
+            var seq = new MockSequence();
+
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.BeginOpen(_fileName, Flags.Read, null, null))
+                            .Returns(_openAsyncResult);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.EndOpen(_openAsyncResult))
+                            .Returns(_handle);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.BeginLStat(_fileName, null, null))
+                            .Returns(_statAsyncResult);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                            .Returns(_chunkSize);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.EndLStat(_statAsyncResult))
+                            .Returns(_fileAttributes);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.CreateFileReader(_handle, _sftpSessionMock.Object, _chunkSize, 7, _fileSize))
+                            .Returns(_sftpFileReaderMock.Object);
+        }
+
+        private void Arrange()
+        {
+            SetupData();
+            CreateMocks();
+            SetupMocks();
+
+            _serviceFactory = new ServiceFactory();
+        }
+
+        [TestInitialize]
+        public void Initialize()
+        {
+            Arrange();
+            Act();
+        }
+
+        private void Act()
+        {
+            _actual = _serviceFactory.CreateSftpFileReader(_fileName, _sftpSessionMock.Object, _bufferSize);
+        }
+
+        [TestMethod]
+        public void CreateSftpFileReaderShouldReturnCreatedInstance()
+        {
+            Assert.IsNotNull(_actual);
+            Assert.AreSame(_sftpFileReaderMock.Object, _actual);
+        }
+    }
+}

+ 98 - 0
src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanTenTimesGreaterThanChunkSize.cs

@@ -0,0 +1,98 @@
+using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Abstractions;
+using Renci.SshNet.Sftp;
+using Renci.SshNet.Tests.Common;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanTenTimesGreaterThanChunkSize
+    {
+        private ServiceFactory _serviceFactory;
+        private Mock<ISftpSession> _sftpSessionMock;
+        private Mock<ISftpFileReader> _sftpFileReaderMock;
+        private uint _bufferSize;
+        private string _fileName;
+        private SftpOpenAsyncResult _openAsyncResult;
+        private byte[] _handle;
+        private SFtpStatAsyncResult _statAsyncResult;
+        private uint _chunkSize;
+        private SftpFileAttributes _fileAttributes;
+        private long _fileSize;
+        private ISftpFileReader _actual;
+
+        private void SetupData()
+        {
+            var random = new Random();
+
+            _bufferSize = (uint)random.Next(1, int.MaxValue);
+            _openAsyncResult = new SftpOpenAsyncResult(null, null);
+            _handle = CryptoAbstraction.GenerateRandom(random.Next(1, 10));
+            _statAsyncResult = new SFtpStatAsyncResult(null, null);
+            _fileName = random.Next().ToString();
+            _chunkSize = (uint) random.Next(1000, 5000);
+            _fileSize = _chunkSize * random.Next(11, 50);
+            _fileAttributes = new SftpFileAttributesBuilder().WithSize(_fileSize).Build();
+        }
+
+        private void CreateMocks()
+        {
+            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+            _sftpFileReaderMock = new Mock<ISftpFileReader>(MockBehavior.Strict);
+        }
+
+        private void SetupMocks()
+        {
+            var seq = new MockSequence();
+
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.BeginOpen(_fileName, Flags.Read, null, null))
+                            .Returns(_openAsyncResult);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.EndOpen(_openAsyncResult))
+                            .Returns(_handle);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.BeginLStat(_fileName, null, null))
+                            .Returns(_statAsyncResult);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                            .Returns(_chunkSize);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.EndLStat(_statAsyncResult))
+                            .Returns(_fileAttributes);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.CreateFileReader(_handle, _sftpSessionMock.Object, _chunkSize, 10, _fileSize))
+                            .Returns(_sftpFileReaderMock.Object);
+        }
+
+        private void Arrange()
+        {
+            SetupData();
+            CreateMocks();
+            SetupMocks();
+
+            _serviceFactory = new ServiceFactory();
+        }
+
+        [TestInitialize]
+        public void Initialize()
+        {
+            Arrange();
+            Act();
+        }
+
+        private void Act()
+        {
+            _actual = _serviceFactory.CreateSftpFileReader(_fileName, _sftpSessionMock.Object, _bufferSize);
+        }
+
+        [TestMethod]
+        public void CreateSftpFileReaderShouldReturnCreatedInstance()
+        {
+            Assert.IsNotNull(_actual);
+            Assert.AreSame(_sftpFileReaderMock.Object, _actual);
+        }
+    }
+}

+ 98 - 0
src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsZero.cs

@@ -0,0 +1,98 @@
+using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Abstractions;
+using Renci.SshNet.Sftp;
+using Renci.SshNet.Tests.Common;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class ServiceFactoryTest_CreateSftpFileReader_FileSizeIsZero
+    {
+        private ServiceFactory _serviceFactory;
+        private Mock<ISftpSession> _sftpSessionMock;
+        private Mock<ISftpFileReader> _sftpFileReaderMock;
+        private uint _bufferSize;
+        private string _fileName;
+        private SftpOpenAsyncResult _openAsyncResult;
+        private byte[] _handle;
+        private SFtpStatAsyncResult _statAsyncResult;
+        private uint _chunkSize;
+        private long _fileSize;
+        private SftpFileAttributes _fileAttributes;
+        private ISftpFileReader _actual;
+
+        private void SetupData()
+        {
+            var random = new Random();
+
+            _bufferSize = (uint) random.Next(1, int.MaxValue);
+            _openAsyncResult = new SftpOpenAsyncResult(null, null);
+            _handle = CryptoAbstraction.GenerateRandom(random.Next(1, 10));
+            _statAsyncResult = new SFtpStatAsyncResult(null, null);
+            _fileName = random.Next().ToString();
+            _chunkSize = (uint) random.Next(1, int.MaxValue);
+            _fileSize = 0L;
+            _fileAttributes = new SftpFileAttributesBuilder().WithSize(_fileSize).Build();
+        }
+
+        private void CreateMocks()
+        {
+            _sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
+            _sftpFileReaderMock = new Mock<ISftpFileReader>(MockBehavior.Strict);
+        }
+
+        private void SetupMocks()
+        {
+            var seq = new MockSequence();
+
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.BeginOpen(_fileName, Flags.Read, null, null))
+                            .Returns(_openAsyncResult);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.EndOpen(_openAsyncResult))
+                            .Returns(_handle);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.BeginLStat(_fileName, null, null))
+                            .Returns(_statAsyncResult);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.CalculateOptimalReadLength(_bufferSize))
+                            .Returns(_chunkSize);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.EndLStat(_statAsyncResult))
+                            .Returns(_fileAttributes);
+            _sftpSessionMock.InSequence(seq)
+                            .Setup(p => p.CreateFileReader(_handle, _sftpSessionMock.Object, _chunkSize, 1, _fileSize))
+                            .Returns(_sftpFileReaderMock.Object);
+        }
+
+        private void Arrange()
+        {
+            SetupData();
+            CreateMocks();
+            SetupMocks();
+
+            _serviceFactory = new ServiceFactory();
+        }
+
+        [TestInitialize]
+        public void Initialize()
+        {
+            Arrange();
+            Act();
+        }
+
+        private void Act()
+        {
+            _actual = _serviceFactory.CreateSftpFileReader(_fileName, _sftpSessionMock.Object, _bufferSize);
+        }
+
+        [TestMethod]
+        public void CreateSftpFileReaderShouldReturnCreatedInstance()
+        {
+            Assert.IsNotNull(_actual);
+            Assert.AreSame(_sftpFileReaderMock.Object, _actual);
+        }
+    }
+}

+ 134 - 0
src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream.cs

@@ -0,0 +1,134 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Channels;
+using Renci.SshNet.Common;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class ServiceFactoryTest_CreateShellStream
+    {
+        private Mock<ISession> _sessionMock;
+        private Mock<IConnectionInfo> _connectionInfoMock;
+        private Mock<IChannelSession> _channelSessionMock;
+        private MockSequence _mockSequence;
+        private ServiceFactory _serviceFactory;
+        private string _terminalName;
+        private uint _columns;
+        private uint _rows;
+        private uint _width;
+        private uint _height;
+        private IDictionary<TerminalModes, uint> _terminalModeValues;
+        private int _bufferSize;
+        private ShellStream _shellStream;
+
+        private void SetupData()
+        {
+            var random = new Random();
+
+            _terminalName = random.Next().ToString();
+            _columns = (uint) random.Next();
+            _rows = (uint) random.Next();
+            _width = (uint) random.Next();
+            _height = (uint) random.Next();
+            _terminalModeValues = new Dictionary<TerminalModes, uint>();
+            _bufferSize = random.Next();
+        }
+
+        private void CreateMocks()
+        {
+            _sessionMock = new Mock<ISession>(MockBehavior.Strict);
+            _connectionInfoMock = new Mock<IConnectionInfo>(MockBehavior.Strict);
+            _channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
+        }
+
+        private void SetupMocks()
+        {
+            _mockSequence = new MockSequence();
+
+            _sessionMock.InSequence(_mockSequence)
+                        .Setup(p => p.ConnectionInfo)
+                        .Returns(_connectionInfoMock.Object);
+            _connectionInfoMock.InSequence(_mockSequence)
+                               .Setup(p => p.Encoding)
+                               .Returns(new UTF8Encoding());
+            _sessionMock.InSequence(_mockSequence)
+                        .Setup(p => p.CreateChannelSession())
+                        .Returns(_channelSessionMock.Object);
+            _channelSessionMock.InSequence(_mockSequence)
+                               .Setup(p => p.Open());
+            _channelSessionMock.InSequence(_mockSequence)
+                               .Setup(p => p.SendPseudoTerminalRequest(_terminalName,
+                                                                       _columns,
+                                                                       _rows,
+                                                                       _width,
+                                                                       _height,
+                                                                       _terminalModeValues))
+                               .Returns(true);
+            _channelSessionMock.InSequence(_mockSequence)
+                               .Setup(p => p.SendShellRequest())
+                               .Returns(true);
+        }
+
+        private void Arrange()
+        {
+            SetupData();
+            CreateMocks();
+            SetupMocks();
+
+            _serviceFactory = new ServiceFactory();
+        }
+
+        [TestInitialize]
+        public void Initialize()
+        {
+            Arrange();
+            Act();
+        }
+
+        private void Act()
+        {
+            _shellStream = _serviceFactory.CreateShellStream(_sessionMock.Object,
+                                                             _terminalName,
+                                                             _columns,
+                                                             _rows,
+                                                             _width,
+                                                             _height,
+                                                             _terminalModeValues,
+                                                             _bufferSize);
+        }
+
+        [TestMethod]
+        public void CreateShellStreamShouldNotReturnNull()
+        {
+            Assert.IsNotNull(_shellStream);
+        }
+
+        [TestMethod]
+        public void BufferSizeOfShellStreamShouldBeValuePassedToCreateShellStream()
+        {
+            Assert.AreEqual(_bufferSize, _shellStream.BufferSize);
+        }
+
+        [TestMethod]
+        public void SendPseudoTerminalRequestShouldHaveBeenInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.SendPseudoTerminalRequest(_terminalName,
+                                                                        _columns,
+                                                                        _rows,
+                                                                        _width,
+                                                                        _height,
+                                                                        _terminalModeValues),
+                                       Times.Once);
+        }
+
+        [TestMethod]
+        public void SendShellRequestShouldHaveBeenInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.SendShellRequest(), Times.Once);
+        }
+    }
+}

+ 35 - 10
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_DisposeShouldUnblockReadAndReadAhead.cs

@@ -1,5 +1,8 @@
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
+#if !FEATURE_EVENTWAITHANDLE_DISPOSE
+using Renci.SshNet.Common;
+#endif // !FEATURE_EVENTWAITHANDLE_DISPOSE
 using Renci.SshNet.Abstractions;
 using Renci.SshNet.Sftp;
 using System;
@@ -22,7 +25,8 @@ namespace Renci.SshNet.Tests.Classes.Sftp
         private SftpCloseAsyncResult _closeAsyncResult;
         private SftpFileReader _reader;
         private ObjectDisposedException _actualException;
-        private ManualResetEvent _disposeCompleted;
+        private AsyncCallback _readAsyncCallback;
+        private EventWaitHandle _disposeCompleted;
 
         [TestCleanup]
         public void TearDown()
@@ -43,6 +47,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
             _operationTimeout = random.Next(10000, 20000);
             _closeAsyncResult = new SftpCloseAsyncResult(null, null);
             _disposeCompleted = new ManualResetEvent(false);
+            _readAsyncCallback = null;
         }
 
         protected override void SetupMocks()
@@ -52,24 +57,36 @@ namespace Renci.SshNet.Tests.Classes.Sftp
             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);
+                                {
+                                    _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);
+                           .Returns<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                                {
+                                    _readAsyncCallback = callback;
+                                    return 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));
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.BeginClose(_handle, null, null))
+                           .Returns(_closeAsyncResult);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.EndClose(_closeAsyncResult));
         }
 
         protected override void Arrange()
@@ -144,5 +161,13 @@ namespace Renci.SshNet.Tests.Classes.Sftp
             SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
             SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
         }
+
+        [TestMethod]
+        public void InvokeOfReadAheadCallbackShouldCompleteImmediately()
+        {
+            Assert.IsNotNull(_readAsyncCallback);
+
+            _readAsyncCallback(new SftpReadAsyncResult(null, null));
+        }
     }
 }

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

@@ -0,0 +1,138 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+#if !FEATURE_EVENTWAITHANDLE_DISPOSE
+using Renci.SshNet.Common;
+#endif // !FEATURE_EVENTWAITHANDLE_DISPOSE
+using Renci.SshNet.Sftp;
+using System;
+using System.Threading;
+using BufferedRead = Renci.SshNet.Sftp.SftpFileReader.BufferedRead;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileReaderTest_Dispose_SftpSessionIsNotOpen : SftpFileReaderTestBase
+    {
+        private const int ChunkLength = 32 * 1024;
+
+        private MockSequence _seq;
+        private byte[] _handle;
+        private int _fileSize;
+        private WaitHandle[] _waitHandleArray;
+        private int _operationTimeout;
+        private SftpFileReader _reader;
+        private AsyncCallback _readAsyncCallback;
+        private ManualResetEvent _beginReadInvoked;
+        private EventWaitHandle _disposeCompleted;
+
+        [TestCleanup]
+        public void TearDown()
+        {
+            if (_beginReadInvoked != null)
+            {
+                _beginReadInvoked.Dispose();
+            }
+
+            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);
+            _beginReadInvoked = new ManualResetEvent(false);
+            _disposeCompleted = new ManualResetEvent(false);
+            _readAsyncCallback = 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(() =>
+                                {
+                                    // harden test by making sure that we've invoked BeginRead before Dispose is invoked
+                                    _beginReadInvoked.Set();
+                                })
+                           .Returns<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                                {
+                                    _readAsyncCallback = callback;
+                                    return null;
+                                })
+                           .Callback(() =>
+                                {
+                                    // wait until Dispose has been invoked on reader to allow us to harden test, and
+                                    // verify whether Dispose will prevent us from entering the read-ahead loop again
+                                    _waitHandleArray[0].WaitOne();
+                                });
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.IsOpen)
+                           .Returns(false);
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _reader = new SftpFileReader(_handle, SftpSessionMock.Object, ChunkLength, 1, _fileSize);
+        }
+
+        protected override void Act()
+        {
+            Assert.IsTrue(_beginReadInvoked.WaitOne(5000));
+            _reader.Dispose();
+        }
+
+        [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 InvokeOfReadAheadCallbackShouldCompleteImmediately()
+        {
+            Assert.IsNotNull(_readAsyncCallback);
+
+            _readAsyncCallback(new SftpReadAsyncResult(null, null));
+        }
+
+        [TestMethod]
+        public void BeginCloseOnSftpSessionShouldNeverHaveBeenInvoked()
+        {
+            SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Never);
+        }
+    }
+}

+ 141 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_BeginCloseThrowsException.cs

@@ -0,0 +1,141 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+#if !FEATURE_EVENTWAITHANDLE_DISPOSE
+using Renci.SshNet.Common;
+#endif // !FEATURE_EVENTWAITHANDLE_DISPOSE
+using Renci.SshNet.Sftp;
+using System;
+using System.Threading;
+using BufferedRead = Renci.SshNet.Sftp.SftpFileReader.BufferedRead;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileReaderTest_Dispose_SftpSessionIsOpen_BeginCloseThrowsException : SftpFileReaderTestBase
+    {
+        private const int ChunkLength = 32 * 1024;
+
+        private MockSequence _seq;
+        private byte[] _handle;
+        private int _fileSize;
+        private WaitHandle[] _waitHandleArray;
+        private int _operationTimeout;
+        private SftpFileReader _reader;
+        private AsyncCallback _readAsyncCallback;
+        private ManualResetEvent _beginReadInvoked;
+        private EventWaitHandle _disposeCompleted;
+
+        [TestCleanup]
+        public void TearDown()
+        {
+            if (_beginReadInvoked != null)
+            {
+                _beginReadInvoked.Dispose();
+            }
+
+            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);
+            _beginReadInvoked = new ManualResetEvent(false);
+            _disposeCompleted = new ManualResetEvent(false);
+            _readAsyncCallback = 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(() =>
+                                {
+                                    // harden test by making sure that we've invoked BeginRead before Dispose is invoked
+                                    _beginReadInvoked.Set();
+                                })
+                           .Returns<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                                {
+                                    _readAsyncCallback = callback;
+                                    return null;
+                                })
+                            .Callback(() =>
+                                {
+                                    // wait until Dispose has been invoked on reader to allow us to harden test, and
+                                    // verify whether Dispose will prevent us from entering the read-ahead loop again
+                                    _waitHandleArray[0].WaitOne();
+                                });
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.BeginClose(_handle, null, null))
+                           .Throws(new SshException());
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _reader = new SftpFileReader(_handle, SftpSessionMock.Object, ChunkLength, 1, _fileSize);
+        }
+
+        protected override void Act()
+        {
+            Assert.IsTrue(_beginReadInvoked.WaitOne(5000));
+            _reader.Dispose();
+        }
+
+        [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 InvokeOfReadAheadCallbackShouldCompleteImmediately()
+        {
+            Assert.IsNotNull(_readAsyncCallback);
+
+            _readAsyncCallback(new SftpReadAsyncResult(null, null));
+        }
+
+        [TestMethod]
+        public void BeginCloseOnSftpSessionShouldHaveBeenInvokedOnce()
+        {
+            SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
+        }
+    }
+}

+ 146 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_EndCloseThrowsException.cs

@@ -0,0 +1,146 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+#if !FEATURE_EVENTWAITHANDLE_DISPOSE
+using Renci.SshNet.Common;
+#endif // !FEATURE_EVENTWAITHANDLE_DISPOSE
+using Renci.SshNet.Sftp;
+using System;
+using System.Threading;
+using BufferedRead = Renci.SshNet.Sftp.SftpFileReader.BufferedRead;
+
+namespace Renci.SshNet.Tests.Classes.Sftp
+{
+    [TestClass]
+    public class SftpFileReaderTest_Dispose_SftpSessionIsOpen_EndCloseThrowsException : 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 AsyncCallback _readAsyncCallback;
+        private ManualResetEvent _beginReadInvoked;
+        private EventWaitHandle _disposeCompleted;
+
+        [TestCleanup]
+        public void TearDown()
+        {
+            if (_beginReadInvoked != null)
+            {
+                _beginReadInvoked.Dispose();
+            }
+
+            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);
+            _beginReadInvoked = new ManualResetEvent(false);
+            _disposeCompleted = new ManualResetEvent(false);
+            _readAsyncCallback = 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(() =>
+                                {
+                                    // harden test by making sure that we've invoked BeginRead before Dispose is invoked
+                                    _beginReadInvoked.Set();
+                                })
+                           .Returns<byte[], ulong, uint, AsyncCallback, object>((handle, offset, length, callback, state) =>
+                                {
+                                    _readAsyncCallback = callback;
+                                    return null;
+                                })
+                           .Callback(() =>
+                                {
+                                    // wait until Dispose has been invoked on reader to allow us to harden test, and
+                                    // verify whether Dispose will prevent us from entering the read-ahead loop again
+                                    _waitHandleArray[0].WaitOne();
+                                });
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.IsOpen)
+                           .Returns(true);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.BeginClose(_handle, null, null))
+                           .Returns(_closeAsyncResult);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.EndClose(_closeAsyncResult))
+                           .Throws(new SshException());
+        }
+
+        protected override void Arrange()
+        {
+            base.Arrange();
+
+            _reader = new SftpFileReader(_handle, SftpSessionMock.Object, ChunkLength, 1, _fileSize);
+        }
+
+        protected override void Act()
+        {
+            Assert.IsTrue(_beginReadInvoked.WaitOne(5000));
+            _reader.Dispose();
+        }
+
+        [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 InvokeOfReadAheadCallbackShouldCompleteImmediately()
+        {
+            Assert.IsNotNull(_readAsyncCallback);
+
+            _readAsyncCallback(new SftpReadAsyncResult(null, null));
+        }
+
+        [TestMethod]
+        public void EndCloseOnSftpSessionShouldHaveBeenInvokedOnce()
+        {
+            SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
+        }
+    }
+}

+ 10 - 8
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_LastChunkBeforeEofIsComplete.cs

@@ -19,6 +19,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
         private int _fileSize;
         private WaitHandle[] _waitHandleArray;
         private int _operationTimeout;
+        private SftpReadAsyncResult _readAsyncResultBeyondEof;
         private SftpCloseAsyncResult _closeAsyncResult;
         private byte[] _chunk1;
         private byte[] _chunk2;
@@ -41,6 +42,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
             _waitHandleArray = new WaitHandle[2];
             _operationTimeout = random.Next(10000, 20000);
             _closeAsyncResult = new SftpCloseAsyncResult(null, null);
+            _readAsyncResultBeyondEof = new SftpReadAsyncResult(null, null);
         }
 
         protected override void SetupMocks()
@@ -78,19 +80,17 @@ namespace Renci.SshNet.Tests.Classes.Sftp
                                 var asyncResult = new SftpReadAsyncResult(callback, state);
                                 asyncResult.SetAsCompleted(_chunk2, false);
                             })
-                            .Returns((SftpReadAsyncResult)null);
+                            .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);
+                           .Setup(p => p.BeginRead(_handle, 2 * ChunkLength, ChunkLength, null, It.IsAny<BufferedRead>()))
+                           .Returns(_readAsyncResultBeyondEof);
+            SftpSessionMock.InSequence(_seq)
+                           .Setup(p => p.EndRead(_readAsyncResultBeyondEof))
+                           .Returns(_chunk3);
         }
 
         protected override void Arrange()
@@ -146,6 +146,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
         [TestMethod]
         public void DisposeShouldCloseHandleAndCompleteImmediately()
         {
+            SftpSessionMock.InSequence(_seq).Setup(p => p.IsOpen).Returns(true);
             SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult);
             SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult));
 
@@ -155,6 +156,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
 
             Assert.IsTrue(stopwatch.ElapsedMilliseconds < 200, "Dispose took too long to complete: " + stopwatch.ElapsedMilliseconds);
 
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Once);
             SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
             SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
         }

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

@@ -145,6 +145,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
         [TestMethod]
         public void DisposeShouldCloseHandleAndCompleteImmediately()
         {
+            SftpSessionMock.InSequence(_seq).Setup(p => p.IsOpen).Returns(true);
             SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult);
             SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult));
 
@@ -154,6 +155,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
 
             Assert.IsTrue(stopwatch.ElapsedMilliseconds < 200, "Dispose took too long to complete: " + stopwatch.ElapsedMilliseconds);
 
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Once);
             SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
             SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
         }

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

@@ -284,6 +284,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
         [TestMethod]
         public void DisposeShouldCloseHandleAndCompleteImmediately()
         {
+            SftpSessionMock.InSequence(_seq).Setup(p => p.IsOpen).Returns(true);
             SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult);
             SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult));
 
@@ -293,6 +294,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
 
             Assert.IsTrue(stopwatch.ElapsedMilliseconds < 200, "Dispose took too long to complete: " + stopwatch.ElapsedMilliseconds);
 
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Once);
             SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
             SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
         }

+ 3 - 1
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsReached.cs

@@ -111,7 +111,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
         {
             base.Arrange();
 
-            _reader = new SftpFileReader(_handle, SftpSessionMock.Object, ChunkLength, 3, _fileSize);
+            _reader = new SftpFileReader(_handle, SftpSessionMock.Object, ChunkLength, 5, _fileSize);
         }
 
         protected override void Act()
@@ -174,6 +174,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
         [TestMethod]
         public void DisposeShouldCloseHandleAndCompleteImmediately()
         {
+            SftpSessionMock.InSequence(_seq).Setup(p => p.IsOpen).Returns(true);
             SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult);
             SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult));
 
@@ -183,6 +184,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
 
             Assert.IsTrue(stopwatch.ElapsedMilliseconds < 200, "Dispose took too long to complete: " + stopwatch.ElapsedMilliseconds);
 
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Once);
             SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
             SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
         }

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

@@ -191,6 +191,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
         [TestMethod]
         public void DisposeShouldCloseHandleAndCompleteImmediately()
         {
+            SftpSessionMock.InSequence(_seq).Setup(p => p.IsOpen).Returns(true);
             SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult);
             SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult));
 
@@ -200,6 +201,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
 
             Assert.IsTrue(stopwatch.ElapsedMilliseconds < 200, "Dispose took too long to complete: " + stopwatch.ElapsedMilliseconds);
 
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Once);
             SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
             SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
         }

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

@@ -152,6 +152,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
         [TestMethod]
         public void DisposeShouldCloseHandleAndCompleteImmediately()
         {
+            SftpSessionMock.InSequence(_seq).Setup(p => p.IsOpen).Returns(true);
             SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult);
             SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult));
 
@@ -161,6 +162,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
 
             Assert.IsTrue(stopwatch.ElapsedMilliseconds < 200, "Dispose took too long to complete: " + stopwatch.ElapsedMilliseconds);
 
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Once);
             SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
             SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
         }

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

@@ -122,6 +122,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
         [TestMethod]
         public void DisposeShouldCloseHandleAndCompleteImmediately()
         {
+            SftpSessionMock.InSequence(_seq).Setup(p => p.IsOpen).Returns(true);
             SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult);
             SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult));
 
@@ -131,6 +132,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
 
             Assert.IsTrue(stopwatch.ElapsedMilliseconds < 200, "Dispose took too long to complete: " + stopwatch.ElapsedMilliseconds);
 
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Once);
             SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
             SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
         }

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

@@ -106,6 +106,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
         [TestMethod]
         public void DisposeShouldCloseHandleAndCompleteImmediately()
         {
+            SftpSessionMock.InSequence(_seq).Setup(p => p.IsOpen).Returns(true);
             SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult);
             SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult));
 
@@ -115,6 +116,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
 
             Assert.IsTrue(stopwatch.ElapsedMilliseconds < 200, "Dispose took too long to complete: " + stopwatch.ElapsedMilliseconds);
 
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Once);
             SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
             SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
         }

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

@@ -150,6 +150,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
         [TestMethod]
         public void DisposeShouldCloseHandleAndCompleteImmediately()
         {
+            SftpSessionMock.InSequence(_seq).Setup(p => p.IsOpen).Returns(true);
             SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult);
             SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult));
 
@@ -159,6 +160,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp
 
             Assert.IsTrue(stopwatch.ElapsedMilliseconds < 200, "Dispose took too long to complete: " + stopwatch.ElapsedMilliseconds);
 
+            SftpSessionMock.Verify(p => p.IsOpen, Times.Once);
             SftpSessionMock.Verify(p => p.BeginClose(_handle, null, null), Times.Once);
             SftpSessionMock.Verify(p => p.EndClose(_closeAsyncResult), Times.Once);
         }

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

@@ -3,6 +3,7 @@ using System.IO;
 using System.Threading;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
+using Renci.SshNet.Common;
 using Renci.SshNet.Sftp;
 
 namespace Renci.SshNet.Tests.Classes.Sftp

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

@@ -3,6 +3,7 @@ using System.IO;
 using System.Threading;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
+using Renci.SshNet.Common;
 using Renci.SshNet.Sftp;
 
 namespace Renci.SshNet.Tests.Classes.Sftp

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

@@ -3,6 +3,7 @@ using System.IO;
 using System.Threading;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
+using Renci.SshNet.Common;
 using Renci.SshNet.Sftp;
 
 namespace Renci.SshNet.Tests.Classes.Sftp

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

@@ -2,6 +2,7 @@
 using System.IO;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
+using Renci.SshNet.Common;
 using Renci.SshNet.Sftp;
 
 namespace Renci.SshNet.Tests.Classes.Sftp

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

@@ -3,6 +3,7 @@ using System.IO;
 using System.Threading;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
+using Renci.SshNet.Common;
 using Renci.SshNet.Sftp;
 
 namespace Renci.SshNet.Tests.Classes.Sftp

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

@@ -2,6 +2,7 @@
 using System.IO;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
+using Renci.SshNet.Common;
 using Renci.SshNet.Sftp;
 
 namespace Renci.SshNet.Tests.Classes.Sftp

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

@@ -3,6 +3,7 @@ using System.IO;
 using System.Threading;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
+using Renci.SshNet.Common;
 using Renci.SshNet.Sftp;
 
 namespace Renci.SshNet.Tests.Classes.Sftp

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

@@ -3,6 +3,7 @@ using System.IO;
 using System.Threading;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
+using Renci.SshNet.Common;
 using Renci.SshNet.Sftp;
 
 namespace Renci.SshNet.Tests.Classes.Sftp

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

@@ -1,5 +1,6 @@
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
+using Renci.SshNet.Common;
 using Renci.SshNet.Sftp;
 using Renci.SshNet.Tests.Common;
 using System;

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

@@ -1,5 +1,6 @@
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
+using Renci.SshNet.Common;
 using Renci.SshNet.Sftp;
 using Renci.SshNet.Tests.Common;
 using System;

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

@@ -1,5 +1,6 @@
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
+using Renci.SshNet.Common;
 using Renci.SshNet.Sftp;
 using Renci.SshNet.Tests.Common;
 using System;

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

@@ -1,5 +1,6 @@
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
+using Renci.SshNet.Common;
 using Renci.SshNet.Sftp;
 using Renci.SshNet.Sftp.Responses;
 using Renci.SshNet.Tests.Common;

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

@@ -1,5 +1,6 @@
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
+using Renci.SshNet.Common;
 using Renci.SshNet.Sftp;
 using Renci.SshNet.Sftp.Responses;
 using Renci.SshNet.Tests.Common;
@@ -19,7 +20,6 @@ namespace Renci.SshNet.Tests.Classes.Sftp
         private uint _readBufferSize;
         private uint _writeBufferSize;
         private byte[] _writeBytes;
-        private byte[] _requestWriteBytes;
 
         protected override void SetupData()
         {

+ 0 - 1
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetPositive.cs

@@ -19,7 +19,6 @@ namespace Renci.SshNet.Tests.Classes.Sftp
         private byte[] _handle;
         private SftpFileStream _target;
         private int _offset;
-        private EndOfStreamException _actualException;
         private long _actual;
 
         protected override void SetupData()

+ 1 - 0
src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_ReadBuffer.cs

@@ -2,6 +2,7 @@
 using System.IO;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Moq;
+using Renci.SshNet.Common;
 using Renci.SshNet.Sftp;
 
 namespace Renci.SshNet.Tests.Classes.Sftp

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.