Renamed Quote transformation and corresponding class to ShellQuote.

Added DoubleQuote transformation.
Modified default remote path transformation for ScpClient to DoubleQuote.
This commit is contained in:
Gert Driesen
2017-09-04 18:45:23 +02:00
parent 7dde512a9c
commit e434f97be5
21 changed files with 689 additions and 317 deletions
@@ -581,14 +581,14 @@
<Compile Include="..\Renci.SshNet\ProxyTypes.cs">
<Link>ProxyTypes.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet\RemotePathEscapeTransformation.cs">
<Link>RemotePathEscapeTransformation.cs</Link>
<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\RemotePathQuoteTransformation.cs">
<Link>RemotePathQuoteTransformation.cs</Link>
<Compile Include="..\Renci.SshNet\RemotePathShellQuoteTransformation.cs">
<Link>RemotePathShellQuoteTransformation.cs</Link>
</Compile>
<Compile Include="..\Renci.SshNet\RemotePathTransformation.cs">
<Link>RemotePathTransformation.cs</Link>
@@ -768,6 +768,9 @@
<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>
@@ -1584,7 +1587,7 @@
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
<UserProperties ProjectLinkReference="c45379b9-17b1-4e89-bc2e-6d41726413e8" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
<UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="c45379b9-17b1-4e89-bc2e-6d41726413e8" />
</VisualStudio>
</ProjectExtensions>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+228 -78
View File
@@ -15,6 +15,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 +372,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 +387,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 +396,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 +535,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 +561,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);
}
}
}
}
@@ -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();
}
}
@@ -4,66 +4,66 @@ 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_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse
public class ScpClientTest_Download_PathAndDirectoryInfo_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 DirectoryInfo _directoryInfo;
private string _path;
private string _quotedPath;
private string _transformedPath;
private IList<ScpUploadEventArgs> _uploadingRegister;
private SshException _actualException;
[TestInitialize]
public void Setup()
{
Arrange();
Act();
}
protected void Arrange()
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);
_quotedPath = _path.ShellQuote();
_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.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 -prf {0}", _quotedPath))).Returns(false);
.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 virtual void Act()
protected override void Act()
{
try
{
@@ -87,7 +87,7 @@ namespace Renci.SshNet.Tests.Classes
[TestMethod]
public void SendExecRequestOnChannelSessionShouldBeInvokedOnce()
{
_channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -prf {0}", _quotedPath)), Times.Once);
_channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -prf {0}", _transformedPath)), Times.Once);
}
[TestMethod]
@@ -4,66 +4,65 @@ 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_Download_PathAndFileInfo_SendExecRequestReturnsFalse
public class ScpClientTest_Download_PathAndFileInfo_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 _quotedPath;
private string _transformedPath;
private IList<ScpUploadEventArgs> _uploadingRegister;
private SshException _actualException;
[TestInitialize]
public void Setup()
{
Arrange();
Act();
}
protected void Arrange()
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);
_quotedPath = _path.ShellQuote();
_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.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 -pf {0}", _quotedPath))).Returns(false);
.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 virtual void Act()
protected override void Act()
{
try
{
@@ -87,7 +86,7 @@ namespace Renci.SshNet.Tests.Classes
[TestMethod]
public void SendExecRequestOnChannelSessionShouldBeInvokedOnce()
{
_channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -pf {0}", _quotedPath)), Times.Once);
_channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -pf {0}", _transformedPath)), Times.Once);
}
[TestMethod]
@@ -4,33 +4,21 @@ 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_Download_PathAndStream_SendExecRequestReturnsFalse
public class ScpClientTest_Download_PathAndStream_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 Stream _destination;
private string _path;
private string _quotedPath;
private string _transformedPath;
private IList<ScpUploadEventArgs> _uploadingRegister;
private SshException _actualException;
[TestInitialize]
public void Setup()
{
Arrange();
Act();
}
[TestCleanup]
public void Cleanup()
{
@@ -40,39 +28,51 @@ namespace Renci.SshNet.Tests.Classes
}
}
protected void Arrange()
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);
_quotedPath = _path.ShellQuote();
_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.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 -f {0}", _quotedPath))).Returns(false);
.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 virtual void Act()
protected override void Act()
{
try
{
@@ -96,7 +96,7 @@ namespace Renci.SshNet.Tests.Classes
[TestMethod]
public void SendExecRequestOnChannelSessionShouldBeInvokedOnce()
{
_channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -f {0}", _quotedPath)), Times.Once);
_channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -f {0}", _transformedPath)), Times.Once);
}
[TestMethod]
@@ -4,66 +4,66 @@ 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_DirectoryInfoAndPath_SendExecRequestReturnsFalse
public class ScpClientTest_Upload_DirectoryInfoAndPath_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 DirectoryInfo _directoryInfo;
private string _path;
private string _quotedPath;
private string _transformedPath;
private IList<ScpUploadEventArgs> _uploadingRegister;
private SshException _actualException;
[TestInitialize]
public void Setup()
{
Arrange();
Act();
}
protected void Arrange()
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);
_quotedPath = _path.ShellQuote();
_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.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 -rt {0}", _quotedPath))).Returns(false);
.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 virtual void Act()
protected override void Act()
{
try
{
@@ -87,7 +87,7 @@ namespace Renci.SshNet.Tests.Classes
[TestMethod]
public void SendExecREquestOnChannelSessionShouldBeInvokedOnce()
{
_channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -rt {0}", _quotedPath)), Times.Once);
_channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -rt {0}", _transformedPath)), Times.Once);
}
[TestMethod]
@@ -4,34 +4,22 @@ 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 _quotedPath;
private string _transformedPath;
private string _fileName;
private IList<ScpUploadEventArgs> _uploadingRegister;
private SshException _actualException;
[TestInitialize]
public void Setup()
{
Arrange();
Act();
}
[TestCleanup]
public void Cleanup()
{
@@ -42,40 +30,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 = "/home/sshnet/" + random.Next().ToString(CultureInfo.InvariantCulture);
_quotedPath = _path.ShellQuote();
_transformedPath = _path.ShellQuote();
_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.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}", _quotedPath))).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
{
@@ -99,7 +99,7 @@ namespace Renci.SshNet.Tests.Classes
[TestMethod]
public void SendExecRequestOnChannelSessionShouldBeInvokedOnce()
{
_channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -t {0}", _quotedPath)), Times.Once);
_channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -t {0}", _transformedPath)), Times.Once);
}
[TestMethod]
@@ -6,36 +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 _quotedPath;
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()
{
@@ -46,7 +34,7 @@ namespace Renci.SshNet.Tests.Classes
}
}
private void SetupData()
protected override void SetupData()
{
var random = new Random();
@@ -57,30 +45,30 @@ namespace Renci.SshNet.Tests.Classes
_connectionInfo = new ConnectionInfo("host", 22, "user", new PasswordAuthenticationMethod("user", "pwd"));
_fileInfo = new FileInfo(_fileName);
_path = "/home/sshnet/" + random.Next().ToString(CultureInfo.InvariantCulture);
_quotedPath = _path.ShellQuote();
_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}", _quotedPath))).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);
@@ -102,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)
{
@@ -116,7 +102,7 @@ namespace Renci.SshNet.Tests.Classes
_scpClient.Connect();
}
protected virtual void Act()
protected override void Act()
{
_scpClient.Upload(_fileInfo, _path);
}
@@ -124,7 +110,7 @@ namespace Renci.SshNet.Tests.Classes
[TestMethod]
public void SendExecRequestOnChannelSessionShouldBeInvokedOnce()
{
_channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -t {0}", _quotedPath)), Times.Once);
_channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -t {0}", _transformedPath)), Times.Once);
}
[TestMethod]
@@ -4,33 +4,21 @@ 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_StreamAndPath_SendExecRequestReturnsFalse
public class ScpClientTest_Upload_StreamAndPath_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 Stream _source;
private string _path;
private string _quotedPath;
private string _transformedPath;
private IList<ScpUploadEventArgs> _uploadingRegister;
private SshException _actualException;
[TestInitialize]
public void Setup()
{
Arrange();
Act();
}
[TestCleanup]
public void Cleanup()
{
@@ -40,39 +28,51 @@ namespace Renci.SshNet.Tests.Classes
}
}
protected void Arrange()
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);
_quotedPath = _path.ShellQuote();
_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.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}", _quotedPath))).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,7 +96,7 @@ namespace Renci.SshNet.Tests.Classes
[TestMethod]
public void SendExecRequestOnChannelSessionShouldBeInvokedOnce()
{
_channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -t {0}", _quotedPath)), Times.Once);
_channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -t {0}", _transformedPath)), Times.Once);
}
[TestMethod]
@@ -211,6 +211,7 @@
<Compile Include="Classes\NetConfClientTest_Dispose_Disposed.cs" />
<Compile Include="Classes\NetConfClientTest_Finalize_Connected.cs" />
<Compile Include="Classes\PipeStreamTest_Dispose.cs" />
<Compile Include="Classes\ScpClientTestBase.cs" />
<Compile Include="Classes\ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs" />
<Compile Include="Classes\ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs" />
<Compile Include="Classes\ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs" />
+5 -4
View File
@@ -64,13 +64,14 @@ namespace Renci.SshNet
ISftpResponseFactory CreateSftpResponseFactory();
/// <summary>
/// Creates an <see cref="IRemotePathTransformation"/> that quotes a path in a way to be suitable
/// to be used with a shell.
/// Creates an <see cref="IRemotePathTransformation"/> that encloses a path in double quotes, and escapes
/// any embedded double quote with a backslash.
/// </summary>
/// <returns>
/// An <see cref="IRemotePathTransformation"/> that quotes a path in a way to be suitable to be used
/// An <see cref="IRemotePathTransformation"/> that encloses a path in double quotes, and escapes any
/// embedded double quote with a backslash.
/// with a shell.
/// </returns>
IRemotePathTransformation CreateRemotePathQuoteTransformation();
IRemotePathTransformation CreateRemotePathDoubleQuoteTransformation();
}
}
@@ -28,6 +28,17 @@ namespace Renci.SshNet
get { return _requestMessage.MethodName; }
}
/// <summary>
/// Gets the password as a sequence of bytes.
/// </summary>
/// <value>
/// The password as a sequence of bytes.
/// </value>
internal byte[] Password
{
get { return _password; }
}
/// <summary>
/// Occurs when user's password has expired and needs to be changed.
/// </summary>
@@ -0,0 +1,76 @@
using System;
using System.Text;
namespace Renci.SshNet
{
/// <summary>
/// Encloses a path in double quotes, and escapes any embedded double quote with a backslash.
/// </summary>
internal class RemotePathDoubleQuoteTransformation : IRemotePathTransformation
{
/// <summary>
/// Encloses a path in double quotes, and escapes any embedded double quote with a backslash.
/// </summary>
/// <param name="path">The path to transform.</param>
/// <returns>
/// The transformed path.
/// </returns>
/// <exception cref="ArgumentNullException"><paramref name="path"/> is <c>null</c>.</exception>
/// <example>
/// <list type="table">
/// <listheader>
/// <term>Original</term>
/// <term>Transformed</term>
/// </listheader>
/// <item>
/// <term>/var/log/auth.log</term>
/// <term>&quot;/var/log/auth.log&quot;</term>
/// </item>
/// <item>
/// <term>/var/mp3/Guns N' Roses</term>
/// <term>&quot;/var/mp3/Guns N' Roses&quot;</term>
/// </item>
/// <item>
/// <term>/var/garbage!/temp</term>
/// <term>&quot;/var/garbage!/temp&quot;</term>
/// </item>
/// <item>
/// <term>/var/would be 'kewl'!/not?</term>
/// <term>&quot;/var/would be 'kewl'!, not?&quot;</term>
/// </item>
/// <item>
/// <term>!ignore!</term>
/// <term>&quot;!ignore!&quot;</term>
/// </item>
/// <item>
/// <term></term>
/// <term>&quot;&quot;</term>
/// </item>
/// <item>
/// <term>Hello &quot;World&quot;</term>
/// <term>&quot;Hello \&quot;World&quot;</term>
/// </item>
/// </list>
/// </example>
public string Transform(string path)
{
if (path == null)
{
throw new ArgumentNullException("path");
}
var transformed = new StringBuilder(path.Length);
transformed.Append('"');
foreach (var c in path)
{
if (c == '"')
transformed.Append('\\');
transformed.Append(c);
}
transformed.Append('"');
return transformed.ToString();
}
}
}
@@ -12,6 +12,10 @@
/// <returns>
/// The specified path as is.
/// </returns>
/// <remarks>
/// This transformation is recommended for servers that do not require any quoting to preserve the
/// literal value of metacharacters, or when paths are guaranteed to never contain any such characters.
/// </remarks>
public string Transform(string path)
{
return path;
@@ -4,12 +4,12 @@ using System.Text;
namespace Renci.SshNet
{
/// <summary>
/// Quotes a path in a way to be suitable to be used with a shell.
/// Quotes a path in a way to be suitable to be used with a shell-based server.
/// </summary>
internal class RemotePathQuoteTransformation : IRemotePathTransformation
internal class RemotePathShellQuoteTransformation : IRemotePathTransformation
{
/// <summary>
/// Quotes a path in a way to be suitable to be used with a shell.
/// Quotes a path in a way to be suitable to be used with a shell-based server.
/// </summary>
/// <param name="path">The path to transform.</param>
/// <returns>
@@ -23,9 +23,13 @@ namespace Renci.SshNet
/// pair of quotation marks.
/// </para>
/// <para>
/// If a shell command contains an exclamation mark (!), the C-Shell interprets it as a
/// meta-character for history substitution. This even works inside single-quotes or
/// quotation marks, unless escaped with a backslash (\).
/// An exclamation mark in <paramref name="path"/> is escaped with a backslash. This is
/// necessary because C Shell interprets it as a meta-character for history substitution
/// even when enclosed in single quotes or quotation marks.
/// </para>
/// <para>
/// All other characters are enclosed in single quotes. Sequences of such characters are grouped
/// in a single pair of single quotes.
/// </para>
/// <para>
/// References:
@@ -42,10 +46,42 @@ namespace Renci.SshNet
/// </list>
/// </para>
/// </remarks>
/// <returns>
/// The transformed path.
/// </returns>
/// <exception cref="ArgumentNullException"><paramref name="path"/> is <c>null</c>.</exception>
/// <example>
/// <list type="table">
/// <listheader>
/// <term>Original</term>
/// <term>Transformed</term>
/// </listheader>
/// <item>
/// <term>/var/log/auth.log</term>
/// <term>'/var/log/auth.log'</term>
/// </item>
/// <item>
/// <term>/var/mp3/Guns N' Roses</term>
/// <term>'/var/mp3/Guns N'"'"' Roses'</term>
/// </item>
/// <item>
/// <term>/var/garbage!/temp</term>
/// <term>'/var/garbage'\!'/temp'</term>
/// </item>
/// <item>
/// <term>/var/would be 'kewl'!, not?</term>
/// <term>'/var/would be '"'"'kewl'"'"\!', not?'</term>
/// </item>
/// <item>
/// <term>!ignore!</term>
/// <term>\!'ignore'\!</term>
/// </item>
/// <item>
/// <term></term>
/// <term>''</term>
/// </item>
/// <item>
/// <term>Hello &quot;World&quot;</term>
/// <term>'Hello "World"'</term>
/// </item>
/// </list>
/// </example>
public string Transform(string path)
{
if (path == null)
+72 -20
View File
@@ -5,32 +5,36 @@
/// </summary>
public static class RemotePathTransformation
{
private static readonly IRemotePathTransformation QuoteTransformation = new RemotePathQuoteTransformation();
private static readonly IRemotePathTransformation ShellQuoteTransformation = new RemotePathShellQuoteTransformation();
private static readonly IRemotePathTransformation NoneTransformation = new RemotePathNoneTransformation();
private static readonly IRemotePathTransformation DoubleQuoteTransformation = new RemotePathDoubleQuoteTransformation();
/// <summary>
/// Quotes a path in a way to be suitable to be used with a shell.
/// Quotes a path in a way to be suitable to be used with a shell-based server.
/// </summary>
/// <returns>
/// A quoted path.
/// </returns>
/// <remarks>
/// <para>
/// If the path contains a single-quote, that character is embedded in quotation marks.
/// If a path contains a single-quote, that character is embedded in quotation marks (eg. "'").
/// Sequences of single-quotes are grouped in a single pair of quotation marks.
/// </para>
/// <para>
/// An exclamation mark (!) is escaped with a backslash, because the C shell would otherwise
/// interprete it as a meta-character for history substitution. It does this even if it's
/// enclosed in single-quotes or quotation marks, unless escaped with a backslash (\).
/// An exclamation mark in a path is escaped with a backslash. This is necessary because C Shell
/// interprets it as a meta-character for history substitution even when enclosed in single quotes
/// or quotation marks.
/// </para>
/// <para>
/// All other character are enclosed in single-quotes, and grouped in a single pair of
/// single quotes where contiguous.
/// All other characters are enclosed in single quotes. Sequences of such characters are grouped
/// in a single pair of single quotes.
/// </para>
/// </remarks>
/// <example>
/// <list type="table">
/// <listheader>
/// <term>Original</term>
/// <term>Quoted</term>
/// <term>Transformed</term>
/// </listheader>
/// <item>
/// <term>/var/log/auth.log</term>
@@ -42,15 +46,11 @@
/// </item>
/// <item>
/// <term>/var/garbage!/temp</term>
/// <term>'/var/garbage\!/temp'</term>
/// </item>
/// <item>
/// <term>/var/garbage!/temp</term>
/// <term>'/var/garbage'\!'/temp'</term>
/// </item>
/// <item>
/// <term>/var/would be 'kewl'!/not?</term>
/// <term>'/var/would be '"'"'kewl'"'"\!'/not?'</term>
/// <term>/var/would be 'kewl'!, not?</term>
/// <term>'/var/would be '"'"'kewl'"'"\!', not?'</term>
/// </item>
/// <item>
/// <term>!ignore!</term>
@@ -60,24 +60,76 @@
/// <term></term>
/// <term>''</term>
/// </item>
/// <item>
/// <term>Hello &quot;World&quot;</term>
/// <term>'Hello "World"'</term>
/// </item>
/// </list>
/// </example>
public static IRemotePathTransformation Quote
public static IRemotePathTransformation ShellQuote
{
get { return QuoteTransformation; }
get { return ShellQuoteTransformation; }
}
/// <summary>
/// Performs no transformation.
/// </summary>
/// <remarks>
/// This transformation should be used for servers that do not support escape sequences in paths
/// or paths enclosed in quotes, or would preserve the escape characters or quotes in the path that
/// is handed off to the IO layer. This is recommended for servers that are not shell-based.
/// Recommended for servers that do not require any character to be escaped or enclosed in quotes,
/// or when paths are guaranteed to never contain any special characters (such as #, &quot;, ', $, ...).
/// </remarks>
public static IRemotePathTransformation None
{
get { return NoneTransformation; }
}
/// <summary>
/// Encloses a path in double quotes, and escapes any embedded double quote with a backslash.
/// </summary>
/// <value>
/// A transformation that encloses a path in double quotes, and escapes any embedded double quote with
/// a backslash.
/// </value>
/// <example>
/// <list type="table">
/// <listheader>
/// <term>Original</term>
/// <term>Transformed</term>
/// </listheader>
/// <item>
/// <term>/var/log/auth.log</term>
/// <term>&quot;/var/log/auth.log&quot;</term>
/// </item>
/// <item>
/// <term>/var/mp3/Guns N' Roses</term>
/// <term>&quot;/var/mp3/Guns N' Roses&quot;</term>
/// </item>
/// <item>
/// <term>/var/garbage!/temp</term>
/// <term>&quot;/var/garbage!/temp&quot;</term>
/// </item>
/// <item>
/// <term>/var/would be 'kewl'!/not?</term>
/// <term>&quot;/var/would be 'kewl'!, not?&quot;</term>
/// </item>
/// <item>
/// <term>!ignore!</term>
/// <term>&quot;!ignore!&quot;</term>
/// </item>
/// <item>
/// <term></term>
/// <term>&quot;&quot;</term>
/// </item>
/// <item>
/// <term>Hello &quot;World&quot;</term>
/// <term>&quot;Hello \&quot;World&quot;</term>
/// </item>
/// </list>
/// </example>
public static IRemotePathTransformation DoubleQuote
{
get { return DoubleQuoteTransformation; }
}
}
}
+2 -1
View File
@@ -163,8 +163,9 @@
<Compile Include="Messages\Transport\KeyExchangeEcdhInitMessage.cs" />
<Compile Include="Messages\Transport\KeyExchangeEcdhReplyMessage.cs" />
<Compile Include="Netconf\INetConfSession.cs" />
<Compile Include="RemotePathDoubleQuoteTransformation.cs" />
<Compile Include="RemotePathNoneTransformation.cs" />
<Compile Include="RemotePathQuoteTransformation.cs" />
<Compile Include="RemotePathShellQuoteTransformation.cs" />
<Compile Include="RemotePathTransformation.cs" />
<Compile Include="Security\Cryptography\HMACMD5.cs" />
<Compile Include="Security\Cryptography\HMACSHA1.cs" />
+9 -3
View File
@@ -56,12 +56,18 @@ namespace Renci.SshNet
/// Gets or sets the transformation to apply to remote paths.
/// </summary>
/// <value>
/// The transformation to apply to remote paths. The default is <see cref="SshNet.RemotePathTransformation.Quote"/>.
/// The transformation to apply to remote paths. The default is <see cref="SshNet.RemotePathTransformation.DoubleQuote"/>.
/// </value>
/// <exception cref="RemotePathTransformation"><paramref name="value"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentNullException"><paramref name="value"/> is <c>null</c>.</exception>
/// <remarks>
/// <para>
/// This transformation is applied to the remote file or directory path that is passed to the
/// <c>scp</c> command.
/// </para>
/// <para>
/// See <see cref="SshNet.RemotePathTransformation"/> for the transformations that are supplied
/// out-of-the-box with SSH.NET.
/// </para>
/// </remarks>
public IRemotePathTransformation RemotePathTransformation
{
@@ -186,7 +192,7 @@ namespace Renci.SshNet
{
OperationTimeout = SshNet.Session.InfiniteTimeSpan;
BufferSize = 1024 * 16;
_remotePathTransformation = SshNet.RemotePathTransformation.Quote;
_remotePathTransformation = serviceFactory.CreateRemotePathDoubleQuoteTransformation();
}
#endregion
+6 -5
View File
@@ -138,16 +138,17 @@ namespace Renci.SshNet
}
/// <summary>
/// Creates an <see cref="IRemotePathTransformation"/> that quotes a path in a way to be suitable
/// to be used with a shell.
/// Creates an <see cref="IRemotePathTransformation"/> that encloses a path in double quotes, and escapes
/// any embedded double quote with a backslash.
/// </summary>
/// <returns>
/// An <see cref="IRemotePathTransformation"/> that quotes a path in a way to be suitable to be used
/// An <see cref="IRemotePathTransformation"/> that encloses a path in double quotes, and escapes any
/// embedded double quote with a backslash.
/// with a shell.
/// </returns>
public IRemotePathTransformation CreateRemotePathQuoteTransformation()
public IRemotePathTransformation CreateRemotePathDoubleQuoteTransformation()
{
return new RemotePathQuoteTransformation();
return RemotePathTransformation.DoubleQuote;
}
}
}