فهرست منبع

Port shared tests folder (#1467)

These tests were presumably once shared with the old integration tests repo
but have since been sat doing nothing. This brings them into the unit tests
project.

Co-authored-by: Wojciech Nagórski <wojtpl2@gmail.com>
Rob Hague 1 سال پیش
والد
کامیت
1af01692fe
19فایلهای تغییر یافته به همراه502 افزوده شده و 1613 حذف شده
  1. 2 2
      src/Renci.SshNet/Abstractions/SocketAbstraction.cs
  2. 0 9
      src/Renci.SshNet/Abstractions/ThreadAbstraction.cs
  3. 2 2
      src/Renci.SshNet/SshMessageFactory.cs
  4. 0 49
      test/Renci.SshNet.Shared.Tests/Abstractions/CryptoAbstraction_GenerateRandom.cs
  5. 0 84
      test/Renci.SshNet.Shared.Tests/Abstractions/DnsAbstraction_GetHostAddresses.cs
  6. 0 162
      test/Renci.SshNet.Shared.Tests/Abstractions/FileSystemAbstraction_EnumerateFiles.cs
  7. 0 20
      test/Renci.SshNet.Shared.Tests/Abstractions/SocketAbstraction_CanWrite.cs
  8. 0 61
      test/Renci.SshNet.Shared.Tests/Abstractions/ThreadAbstraction_ExecuteThread.cs
  9. 0 23
      test/Renci.SshNet.Shared.Tests/Renci.SshNet.Shared.Tests.projitems
  10. 0 13
      test/Renci.SshNet.Shared.Tests/Renci.SshNet.Shared.Tests.shproj
  11. 0 982
      test/Renci.SshNet.Shared.Tests/SshMessageFactoryTest.cs
  12. 63 0
      test/Renci.SshNet.Tests/Classes/AbstractionsTest.cs
  13. 3 3
      test/Renci.SshNet.Tests/Classes/ForwardedPortStatusTest_Started.cs
  14. 3 3
      test/Renci.SshNet.Tests/Classes/ForwardedPortStatusTest_Starting.cs
  15. 3 3
      test/Renci.SshNet.Tests/Classes/ForwardedPortStatusTest_Stopped.cs
  16. 3 1
      test/Renci.SshNet.Tests/Classes/ForwardedPortStatusTest_Stopping.cs
  17. 423 0
      test/Renci.SshNet.Tests/Classes/SshMessageFactoryTest.cs
  18. 0 179
      test/Renci.SshNet.Tests/Common/HttpProxyStub.cs
  19. 0 17
      test/Renci.SshNet.Tests/Common/HttpRequest.cs

+ 2 - 2
src/Renci.SshNet/Abstractions/SocketAbstraction.cs

@@ -292,7 +292,7 @@ namespace Renci.SshNet.Abstractions
                 {
                     if (IsErrorResumable(ex.SocketErrorCode))
                     {
-                        ThreadAbstraction.Sleep(30);
+                        Thread.Sleep(30);
                         continue;
                     }
 
@@ -346,7 +346,7 @@ namespace Renci.SshNet.Abstractions
                     if (IsErrorResumable(ex.SocketErrorCode))
                     {
                         // socket buffer is probably full, wait and try again
-                        ThreadAbstraction.Sleep(30);
+                        Thread.Sleep(30);
                     }
                     else
                     {

+ 0 - 9
src/Renci.SshNet/Abstractions/ThreadAbstraction.cs

@@ -6,15 +6,6 @@ namespace Renci.SshNet.Abstractions
 {
     internal static class ThreadAbstraction
     {
-        /// <summary>
-        /// Suspends the current thread for the specified number of milliseconds.
-        /// </summary>
-        /// <param name="millisecondsTimeout">The number of milliseconds for which the thread is suspended.</param>
-        public static void Sleep(int millisecondsTimeout)
-        {
-            Thread.Sleep(millisecondsTimeout);
-        }
-
         /// <summary>
         /// Creates and starts a long-running <see cref="Task"/> for the specified <see cref="Action"/>.
         /// </summary>

+ 2 - 2
src/Renci.SshNet/SshMessageFactory.cs

@@ -16,7 +16,7 @@ namespace Renci.SshNet
         private readonly bool[] _activatedMessagesById;
         private readonly object _lock = new object();
 
-        private static readonly MessageMetadata[] AllMessages = new MessageMetadata[]
+        internal static readonly MessageMetadata[] AllMessages = new MessageMetadata[]
             {
                 new MessageMetadata<KeyExchangeInitMessage>(0, "SSH_MSG_KEXINIT", 20),
                 new MessageMetadata<NewKeysMessage>(1, "SSH_MSG_NEWKEYS", 21),
@@ -263,7 +263,7 @@ namespace Renci.SshNet
                                                  currentEnabledForMessageName));
         }
 
-        private abstract class MessageMetadata
+        internal abstract class MessageMetadata
         {
             protected MessageMetadata(byte id, string name, byte number)
             {

+ 0 - 49
test/Renci.SshNet.Shared.Tests/Abstractions/CryptoAbstraction_GenerateRandom.cs

@@ -1,49 +0,0 @@
-using System;
-using System.Linq;
-using Renci.SshNet.Abstractions;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace Renci.SshNet.Tests.Abstractions
-{
-    [TestClass]
-    public class CryptoAbstraction_GenerateRandom
-    {
-        [TestMethod]
-        public void ShouldThrowArgumentNullExceptionWhenDataIsNull()
-        {
-            const byte[] data = null;
-
-            try
-            {
-                CryptoAbstraction.GenerateRandom(data); 
-                Assert.Fail();
-            }
-            catch (ArgumentNullException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual("data", ex.ParamName);
-            }
-        }
-
-        [TestMethod]
-        public void ShouldPerformNoOpWhenDataIsZeroLength()
-        {
-            var data = new byte[0];
-
-            CryptoAbstraction.GenerateRandom(data);
-        }
-
-        [TestMethod]
-        public void ShouldGenerateRandomSequenceOfValues()
-        {
-            var dataLength = new Random().Next(1, 100);
-            var dataA = new byte[dataLength];
-            var dataB = new byte[dataLength];
-
-            CryptoAbstraction.GenerateRandom(dataA);
-            CryptoAbstraction.GenerateRandom(dataB);
-
-            Assert.IsFalse(dataA.SequenceEqual(dataB));
-        }
-    }
-}

+ 0 - 84
test/Renci.SshNet.Shared.Tests/Abstractions/DnsAbstraction_GetHostAddresses.cs

@@ -1,84 +0,0 @@
-using System;
-using System.Net;
-using System.Net.Sockets;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Renci.SshNet.Abstractions;
-
-namespace Renci.SshNet.Tests.Abstractions
-{
-    [TestClass]
-    public class DnsAbstraction_GetHostAddresses
-    {
-        [TestMethod]
-        public void ShouldThrowArgumentNullExceptionWhenHostNameOrAddressIsNull()
-        {
-            const string hostNameOrAddress = null;
-
-            try
-            {
-                DnsAbstraction.GetHostAddresses(hostNameOrAddress);
-                Assert.Fail();
-            }
-            catch (ArgumentNullException)
-            {
-            }
-        }
-
-        [TestMethod]
-        public void ShouldThrowSocketExceptionWhenHostIsNotFound()
-        {
-            const string hostNameOrAddress = "surelydoesnotexist.OrAmIWrong";
-
-            try
-            {
-                var addresses = DnsAbstraction.GetHostAddresses(hostNameOrAddress);
-                Assert.Fail(addresses.ToString());
-            }
-            catch (SocketException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual(SocketError.HostNotFound, ex.SocketErrorCode);
-            }
-        }
-
-        [TestMethod]
-        public void ShouldReturnHostAddressesOfLocalHostWhenHostNameOrAddressIsEmpty()
-        {
-            const string hostNameOrAddress = "";
-
-            var addresses = DnsAbstraction.GetHostAddresses(hostNameOrAddress);
-            Assert.IsNotNull(addresses);
-
-            var hostEntry = Dns.GetHostEntry(Dns.GetHostName());
-            Assert.IsNotNull(hostEntry);
-
-            Assert.AreEqual(hostEntry.AddressList.Length, addresses.Length);
-            for (var i = 0; i < hostEntry.AddressList.Length; i++)
-                Assert.AreEqual(hostEntry.AddressList[i], addresses[i]);
-        }
-
-        [TestMethod]
-        public void ShouldReturnSingleIpv4AddressWhenHostNameOrAddressIsValidIpv4Address()
-        {
-            const string hostNameOrAddress = "1.2.3.4";
-
-            var addresses = DnsAbstraction.GetHostAddresses(hostNameOrAddress);
-            Assert.IsNotNull(addresses);
-            Assert.AreEqual(1, addresses.Length);
-            Assert.AreEqual(AddressFamily.InterNetwork, addresses[0].AddressFamily);
-            Assert.AreEqual(IPAddress.Parse(hostNameOrAddress), addresses[0]);
-        }
-
-        [TestMethod]
-        public void ShouldReturnSingleIpv6AddressWhenHostNameOrAddressIsValidIpv6Address()
-        {
-            const string hostNameOrAddress = "2001:0:9d38:90d7:384f:2133:ab3d:d152";
-
-            var addresses = DnsAbstraction.GetHostAddresses(hostNameOrAddress);
-            Assert.IsNotNull(addresses);
-            Assert.AreEqual(1, addresses.Length);
-            Assert.AreEqual(AddressFamily.InterNetworkV6, addresses[0].AddressFamily);
-            Assert.AreEqual(IPAddress.Parse(hostNameOrAddress), addresses[0]);
-        }
-    }
-}

+ 0 - 162
test/Renci.SshNet.Shared.Tests/Abstractions/FileSystemAbstraction_EnumerateFiles.cs

@@ -1,162 +0,0 @@
-using System;
-using System.IO;
-using System.Linq;
-using Renci.SshNet.Abstractions;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace Renci.SshNet.Tests.Abstractions
-{
-    [TestClass]
-    public class FileSystemAbstraction_EnumerateFiles
-    {
-        private string _temporaryDirectory;
-
-        [TestInitialize]
-        public void SetUp()
-        {
-            _temporaryDirectory = Path.GetTempFileName();
-            File.Delete(_temporaryDirectory);
-            Directory.CreateDirectory(_temporaryDirectory);
-        }
-
-        [TestCleanup]
-        public void TearDown()
-        {
-            if (_temporaryDirectory != null && Directory.Exists(_temporaryDirectory))
-            {
-                Directory.Delete(_temporaryDirectory, true);
-            }
-        }
-
-        [TestMethod]
-        public void ShouldThrowArgumentNullExceptionWhenDirectoryInfoIsNull()
-        {
-            const DirectoryInfo directoryInfo = null;
-            const string searchPattern = "*.xml";
-
-            try
-            {
-                FileSystemAbstraction.EnumerateFiles(directoryInfo, searchPattern);
-                Assert.Fail();
-            }
-            catch (ArgumentNullException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual("directoryInfo", ex.ParamName);
-            }
-        }
-
-        [TestMethod]
-        public void ShouldThrowArgumentNullExceptionWhenSearchPatternIsNull()
-        {
-            var directoryInfo = new DirectoryInfo(_temporaryDirectory);
-            const string searchPattern = null;
-
-            try
-            {
-                FileSystemAbstraction.EnumerateFiles(directoryInfo, searchPattern);
-                Assert.Fail();
-            }
-            catch (ArgumentNullException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual("searchPattern", ex.ParamName);
-            }
-        }
-
-        [TestMethod]
-        public void ShouldThrowDirectoryNotFoundExceptionWhenDirectoryDoesNotExist()
-        {
-            var directoryInfo = new DirectoryInfo(_temporaryDirectory);
-            const string searchPattern = "*.xml";
-
-            Directory.Delete(_temporaryDirectory, true);
-
-            try
-            {
-                FileSystemAbstraction.EnumerateFiles(directoryInfo, searchPattern);
-                Assert.Fail();
-            }
-            catch (DirectoryNotFoundException)
-            {
-            }
-        }
-
-        [TestMethod]
-        public void ShouldReturnEmptyEnumerableWhenNoFilesExistInDirectory()
-        {
-            var directoryInfo = new DirectoryInfo(_temporaryDirectory);
-            const string searchPattern = "*.xml";
-
-            var actual = FileSystemAbstraction.EnumerateFiles(directoryInfo, searchPattern);
-
-            Assert.IsFalse(actual.GetEnumerator().MoveNext());
-        }
-
-        [TestMethod]
-        public void ShouldReturnEmptyEnumerableWhenNoFilesMatchSearchPatternExistInDirectory()
-        {
-            CreateFile(Path.Combine(_temporaryDirectory, "test.txt"));
-
-            var directoryInfo = new DirectoryInfo(_temporaryDirectory);
-            const string searchPattern = "*.xml";
-
-            var actual = FileSystemAbstraction.EnumerateFiles(directoryInfo, searchPattern);
-
-            Assert.IsFalse(actual.GetEnumerator().MoveNext());
-        }
-
-        [TestMethod]
-        public void ShouldReturnEmptyEnumerableWhenSearchPatternIsEmpty()
-        {
-            CreateFile(Path.Combine(_temporaryDirectory, "test.txt"));
-
-            var directoryInfo = new DirectoryInfo(_temporaryDirectory);
-            const string searchPattern = "";
-
-            var actual = FileSystemAbstraction.EnumerateFiles(directoryInfo, searchPattern);
-
-            Assert.IsFalse(actual.GetEnumerator().MoveNext());
-        }
-
-        [TestMethod]
-        public void ShouldReturnAllFilesInDirectoryWhenSearchPatternIsAsterisk()
-        {
-            CreateFile(Path.Combine(_temporaryDirectory, "test.txt"));
-            CreateFile(Path.Combine(_temporaryDirectory, "test.xml"));
-
-            var directoryInfo = new DirectoryInfo(_temporaryDirectory);
-            const string searchPattern = "*";
-
-            var actual = FileSystemAbstraction.EnumerateFiles(directoryInfo, searchPattern).ToList();
-
-            Assert.AreEqual(2, actual.Count);
-            Assert.IsTrue(actual.Exists(p => p.Name == "test.txt"));
-            Assert.IsTrue(actual.Exists(p => p.Name == "test.xml"));
-        }
-
-        [TestMethod]
-        public void ShouldReturnOnlyReturnFilesFromTopLevelDirectory()
-        {
-            CreateFile(Path.Combine(_temporaryDirectory, "test.txt"));
-            CreateFile(Path.Combine(_temporaryDirectory, "test.xml"));
-            Directory.CreateDirectory(Path.Combine(_temporaryDirectory, "sub"));
-            CreateFile(Path.Combine(_temporaryDirectory, "sub", "test.csv"));
-
-            var directoryInfo = new DirectoryInfo(_temporaryDirectory);
-            const string searchPattern = "*";
-
-            var actual = FileSystemAbstraction.EnumerateFiles(directoryInfo, searchPattern).ToList();
-
-            Assert.AreEqual(2, actual.Count);
-            Assert.IsTrue(actual.Exists(p => p.Name == "test.txt"));
-            Assert.IsTrue(actual.Exists(p => p.Name == "test.xml"));
-        }
-
-        private static void CreateFile(string fileName)
-        {
-            var fs = File.Create(fileName);
-            fs.Dispose();
-        }
-    }
-}

+ 0 - 20
test/Renci.SshNet.Shared.Tests/Abstractions/SocketAbstraction_CanWrite.cs

@@ -1,20 +0,0 @@
-using System.Net.Sockets;
-using Renci.SshNet.Abstractions;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace Renci.SshNet.Tests.Abstractions
-{
-    [TestClass]
-    public class SocketAbstraction_CanWrite
-    {
-        [TestMethod]
-        public void ShouldReturnFalseWhenSocketIsNull()
-        {
-            const Socket socket = null;
-
-            var actual = SocketAbstraction.CanWrite(socket);
-
-            Assert.IsFalse(actual);
-        }
-    }
-}

+ 0 - 61
test/Renci.SshNet.Shared.Tests/Abstractions/ThreadAbstraction_ExecuteThread.cs

@@ -1,61 +0,0 @@
-using System;
-using System.Threading;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Renci.SshNet.Abstractions;
-
-namespace Renci.SshNet.Tests.Abstractions
-{
-    [TestClass]
-    public class ThreadAbstraction_ExecuteThread
-    {
-        [TestMethod]
-        public void ShouldThrowArgumentNullExceptionWhenActionIsNull()
-        {
-            const Action action = null;
-
-            try
-            {
-                ThreadAbstraction.ExecuteThread(action);
-                Assert.Fail();
-            }
-            catch (ArgumentNullException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual("action", ex.ParamName);
-            }
-        }
-
-        [TestMethod]
-        public void ShouldExecuteActionOnSeparateThread()
-        {
-            DateTime? executionTime = null;
-            int executionCount = 0;
-            EventWaitHandle waitHandle = new ManualResetEvent(false);
-
-            Action action = () =>
-            {
-                ThreadAbstraction.Sleep(500);
-                executionCount++;
-                executionTime = DateTime.Now;
-                waitHandle.Set();
-            };
-
-            DateTime start = DateTime.Now;
-
-            ThreadAbstraction.ExecuteThread(action);
-
-            Assert.AreEqual(0, executionCount);
-            Assert.IsNull(executionTime);
-
-            Assert.IsTrue(waitHandle.WaitOne(2000));
-
-            Assert.AreEqual(1, executionCount);
-            Assert.IsNotNull(executionTime);
-
-            var elapsedTime = executionTime.Value - start;
-            Assert.IsTrue(elapsedTime > TimeSpan.Zero);
-            Assert.IsTrue(elapsedTime > TimeSpan.FromMilliseconds(500));
-            Assert.IsTrue(elapsedTime < TimeSpan.FromMilliseconds(1000));
-        }
-    }
-}

+ 0 - 23
test/Renci.SshNet.Shared.Tests/Renci.SshNet.Shared.Tests.projitems

@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
-    <HasSharedItems>true</HasSharedItems>
-    <SharedGUID>fae3948f-a438-458e-8e0e-7f6e39a5dd8a</SharedGUID>
-  </PropertyGroup>
-  <PropertyGroup Label="Configuration">
-    <Import_RootNamespace>Renci.SshNet.Tests</Import_RootNamespace>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="$(MSBuildThisFileDirectory)Abstractions\CryptoAbstraction_GenerateRandom.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)Abstractions\DnsAbstraction_GetHostAddresses.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)Abstractions\FileSystemAbstraction_EnumerateFiles.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)Abstractions\SocketAbstraction_CanWrite.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)Abstractions\ThreadAbstraction_ExecuteThread.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)ForwardedPortStatusTest_Started.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)ForwardedPortStatusTest_Starting.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)ForwardedPortStatusTest_Stopped.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)ForwardedPortStatusTest_Stopping.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)SshMessageFactoryTest.cs" />
-  </ItemGroup>
-</Project>

+ 0 - 13
test/Renci.SshNet.Shared.Tests/Renci.SshNet.Shared.Tests.shproj

@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>fae3948f-a438-458e-8e0e-7f6e39a5dd8a</ProjectGuid>
-    <MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
-  </PropertyGroup>
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
-  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
-  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
-  <PropertyGroup />
-  <Import Project="Renci.SshNet.Shared.Tests.projitems" Label="Shared" />
-  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
-</Project>

+ 0 - 982
test/Renci.SshNet.Shared.Tests/SshMessageFactoryTest.cs

@@ -1,982 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Globalization;
-using System.Linq;
-using Renci.SshNet.Common;
-using Renci.SshNet.Messages;
-using Renci.SshNet.Messages.Authentication;
-using Renci.SshNet.Messages.Connection;
-using Renci.SshNet.Messages.Transport;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace Renci.SshNet.Tests
-{
-    [TestClass]
-    public class SshMessageFactoryTest
-    {
-        private SshMessageFactory _sshMessageFactory;
-        private SshMessageFactoryOriginal _sshMessageFactoryOriginal;
-
-        [TestInitialize]
-        public void SetUp()
-        {
-            _sshMessageFactory = new SshMessageFactory();
-            _sshMessageFactoryOriginal = new SshMessageFactoryOriginal();
-        }
-
-        [TestMethod]
-        public void CreateShouldThrowSshExceptionWhenMessageIsNotEnabled()
-        {
-            const byte messageNumber = 60;
-
-            try
-            {
-                _sshMessageFactory.Create(messageNumber);
-                Assert.Fail();
-            }
-            catch (SshException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message);
-            }
-        }
-
-        [TestMethod]
-        public void CreateShouldThrowSshExceptionWhenMessageDoesNotExist_OutsideOfMessageNumberRange()
-        {
-            const byte messageNumber = 255;
-
-            try
-            {
-                _sshMessageFactory.Create(messageNumber);
-                Assert.Fail();
-            }
-            catch (SshException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not supported.", messageNumber), ex.Message);
-            }
-        }
-
-        [TestMethod]
-        public void CreateShouldThrowSshExceptionWhenMessageDoesNotExist_WithinMessageNumberRange()
-        {
-            const byte messageNumber = 5;
-
-            try
-            {
-                _sshMessageFactory.Create(messageNumber);
-                Assert.Fail();
-            }
-            catch (SshException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not supported.", messageNumber), ex.Message);
-            }
-        }
-
-        [TestMethod]
-        public void CreateShouldThrowSshExceptionWhenMessageIsNotActivated()
-        {
-            const byte messageNumber = 60;
-            const string messageName = "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ";
-
-            _sshMessageFactory.EnableAndActivateMessage(messageName);
-            _sshMessageFactory.DisableAndDeactivateMessage(messageName);
-
-            try
-            {
-                _sshMessageFactory.Create(messageNumber);
-                Assert.Fail();
-            }
-            catch (SshException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message);
-            }
-        }
-
-        [TestMethod]
-        public void CreateShouldReturnMessageInstanceCorrespondingToMessageNumberWhenMessageIsEnabledAndActivated()
-        {
-            const byte messageNumber = 60;
-            const string messageName = "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ";
-
-            _sshMessageFactory.EnableAndActivateMessage(messageName);
-
-            var actual = _sshMessageFactory.Create(messageNumber);
-
-            Assert.IsNotNull(actual);
-            Assert.AreEqual(typeof (PasswordChangeRequiredMessage), actual.GetType());
-
-            _sshMessageFactory.DisableAndDeactivateMessage(messageName);
-            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST");
-
-            actual = _sshMessageFactory.Create(messageNumber);
-
-            Assert.IsNotNull(actual);
-            Assert.AreEqual(typeof(InformationRequestMessage), actual.GetType());
-        }
-
-        [TestMethod]
-        public void DisableAndDeactivateMessageShouldThrowSshExceptionWhenAnotherMessageWithSameMessageNumberIsEnabled()
-        {
-            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
-
-            try
-            {
-                _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST");
-                Assert.Fail();
-            }
-            catch (SshException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual("Cannot enable message 'SSH_MSG_USERAUTH_INFO_REQUEST'. Message type 60 is already enabled for 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'.", ex.Message);
-            }
-
-            // verify that the original message remains enabled
-            var actual = _sshMessageFactory.Create(60);
-            Assert.IsNotNull(actual);
-            Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType());
-        }
-
-        [TestMethod]
-        public void DisableAndDeactivateMessageShouldNotThrowExceptionWhenMessageIsAlreadyDisabled()
-        {
-            const byte messageNumber = 60;
-
-            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
-            _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
-            _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
-
-            // verify that message remains disabled
-            try
-            {
-                _sshMessageFactory.Create(messageNumber);
-                Assert.Fail();
-            }
-            catch (SshException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message);
-            }
-        }
-
-        [TestMethod]
-        public void DisableAndDeactivateMessageShouldNotThrowExceptionWhenMessageWasNeverEnabled()
-        {
-            const byte messageNumber = 60;
-
-            _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
-
-            // verify that message is disabled
-            try
-            {
-                _sshMessageFactory.Create(messageNumber);
-                Assert.Fail();
-            }
-            catch (SshException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message);
-            }
-        }
-
-        [TestMethod]
-        public void DisableAndDeactivateMessageShouldThrowSshExceptionWhenMessageIsNotSupported()
-        {
-            const string messageName = "WHATEVER";
-
-            try
-            {
-                _sshMessageFactory.DisableAndDeactivateMessage("WHATEVER");
-                Assert.Fail();
-            }
-            catch (SshException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual(string.Format("Message '{0}' is not supported.", messageName), ex.Message);
-            }
-        }
-
-        [TestMethod]
-        public void DisableAndDeactivateMessageShouldThrowArgumentNullExceptionWhenMessageNameIsNull()
-        {
-            const string messageName = null;
-
-            try
-            {
-                _sshMessageFactory.DisableAndDeactivateMessage(messageName);
-                Assert.Fail();
-            }
-            catch (ArgumentNullException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual("messageName", ex.ParamName);
-            }
-        }
-
-        [TestMethod]
-        public void EnableAndActivateMessageShouldThrowSshExceptionWhenAnotherMessageWithSameMessageNumberIsAlreadyEnabled()
-        {
-            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
-
-            try
-            {
-                _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST");
-                Assert.Fail();
-            }
-            catch (SshException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual("Cannot enable message 'SSH_MSG_USERAUTH_INFO_REQUEST'. Message type 60 is already enabled for 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'.", ex.Message);
-            }
-
-            // verify that the original message remains enabled
-            var actual = _sshMessageFactory.Create(60);
-            Assert.IsNotNull(actual);
-            Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType());
-        }
-
-        [TestMethod]
-        public void EnableAndActivateMessageShouldNotThrowExceptionWhenMessageIsAlreadyEnabled()
-        {
-            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
-            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
-
-            var actual = _sshMessageFactory.Create(60);
-            Assert.IsNotNull(actual);
-            Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType());
-        }
-
-        [TestMethod]
-        public void EnableAndActivateMessageShouldThrowSshExceptionWhenMessageIsNotSupported()
-        {
-            const string messageName = "WHATEVER";
-
-            try
-            {
-                _sshMessageFactory.EnableAndActivateMessage("WHATEVER");
-                Assert.Fail();
-            }
-            catch (SshException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual(string.Format("Message '{0}' is not supported.", messageName), ex.Message);
-            }
-        }
-
-        [TestMethod]
-        public void EnableAndActivateMessageShouldThrowArgumentNullExceptionWhenMessageNameIsNull()
-        {
-            const string messageName = null;
-
-            try
-            {
-                _sshMessageFactory.EnableAndActivateMessage(messageName);
-                Assert.Fail();
-            }
-            catch (ArgumentNullException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual("messageName", ex.ParamName);
-            }
-        }
-
-        [TestMethod]
-        public void DisableNonKeyExchangeMessagesShouldDisableNonKeyExchangeMessages()
-        {
-            const byte messageNumber = 60;
-
-            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
-            _sshMessageFactory.DisableNonKeyExchangeMessages();
-
-            // verify that message is disabled
-            try
-            {
-                _sshMessageFactory.Create(messageNumber);
-                Assert.Fail();
-            }
-            catch (SshException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message);
-            }
-        }
-
-        [TestMethod]
-        public void DisableNonKeyExchangeMessagesShouldNotDisableKeyExchangeMessages()
-        {
-            const byte messageNumber = 21;
-
-            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_NEWKEYS");
-            _sshMessageFactory.DisableNonKeyExchangeMessages();
-
-            // verify that message remains enabled
-            var actual = _sshMessageFactory.Create(messageNumber);
-            Assert.IsNotNull(actual);
-            Assert.AreEqual(typeof (NewKeysMessage), actual.GetType());
-        }
-
-        [TestMethod]
-        public void EnableActivatedMessagesShouldEnableMessagesThatWereEnabledPriorToInvokingDisableNonKeyExchangeMessages()
-        {
-            const byte messageNumber = 60;
-
-            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
-            _sshMessageFactory.DisableNonKeyExchangeMessages();
-            _sshMessageFactory.EnableActivatedMessages();
-
-            var actual = _sshMessageFactory.Create(messageNumber);
-            Assert.IsNotNull(actual);
-            Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType());
-        }
-
-        [TestMethod]
-        public void EnableActivatedMessagesShouldNotEnableMessagesThatWereDisabledPriorToInvokingDisableNonKeyExchangeMessages()
-        {
-            const byte messageNumber = 60;
-
-            _sshMessageFactory.DisableNonKeyExchangeMessages();
-            _sshMessageFactory.EnableActivatedMessages();
-
-            try
-            {
-                _sshMessageFactory.Create(messageNumber);
-                Assert.Fail();
-            }
-            catch (SshException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message);
-            }
-        }
-
-        [TestMethod]
-        public void EnableActivatedMessagesShouldNotEnableMessagesThatWereDisabledAfterInvokingDisableNonKeyExchangeMessages()
-        {
-            const byte messageNumber = 60;
-
-            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
-            _sshMessageFactory.DisableNonKeyExchangeMessages();
-            _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
-            _sshMessageFactory.EnableActivatedMessages();
-
-            try
-            {
-                _sshMessageFactory.Create(messageNumber);
-                Assert.Fail();
-            }
-            catch (SshException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message);
-            }
-        }
-
-        [TestMethod]
-        public void EnableActivatedMessagesShouldThrowSshExceptionWhenAnothersMessageWithSameMessageNumberWasEnabledAfterInvokingDisableNonKeyExchangeMessages()
-        {
-            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
-            _sshMessageFactory.DisableNonKeyExchangeMessages();
-            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST");
-
-            try
-            {
-                _sshMessageFactory.EnableActivatedMessages();
-                Assert.Fail();
-            }
-            catch (SshException ex)
-            {
-                Assert.IsNull(ex.InnerException);
-                Assert.AreEqual("Cannot enable message 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'. Message type 60 is already enabled for 'SSH_MSG_USERAUTH_INFO_REQUEST'.", ex.Message);
-            }
-        }
-
-        [TestMethod]
-        public void EnableActivatedMessagesShouldLeaveMessagesEnabledThatWereEnabledAfterInvokingDisableNonKeyExchangeMessages()
-        {
-            const byte messageNumber = 60;
-
-            _sshMessageFactory.DisableNonKeyExchangeMessages();
-            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
-            _sshMessageFactory.EnableActivatedMessages();
-
-            var actual = _sshMessageFactory.Create(messageNumber);
-            Assert.IsNotNull(actual);
-            Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType());
-        }
-
-        [TestMethod]
-        public void HighestMessageNumberShouldCorrespondWithHighestSupportedMessageNumber()
-        {
-            var highestSupportMessageNumber = SshMessageFactory.AllMessages.Max(m => m.Number);
-
-            Assert.AreEqual(highestSupportMessageNumber, SshMessageFactory.HighestMessageNumber);
-        }
-
-        [TestMethod]
-        public void TotalMessageCountShouldBeTotalNumberOfSupportedMessages()
-        {
-            var totalNumberOfSupportedMessages = SshMessageFactory.AllMessages.Length;
-
-            Assert.AreEqual(totalNumberOfSupportedMessages, SshMessageFactory.TotalMessageCount);
-        }
-
-        [TestMethod]
-        [TestCategory("Performance")]
-        public void Performance_Ctor()
-        {
-            const int runCount = 100000;
-
-            // warm-up
-            for (var i = 0; i < 3; i++)
-            {
-                var sshMessageFactory = new SshMessageFactory();
-                var sshMessageFactoryOriginal = new SshMessageFactoryOriginal();
-            }
-
-            GC.Collect();
-            GC.WaitForPendingFinalizers();
-            GC.Collect();
-
-            var stopwatch = new Stopwatch();
-            stopwatch.Start();
-
-            for (var i = 0; i < runCount; i++)
-            {
-                var sshMessageFactory = new SshMessageFactory();
-            }
-
-            GC.Collect();
-            GC.WaitForPendingFinalizers();
-            GC.Collect();
-
-            stopwatch.Stop();
-
-            Console.WriteLine(stopwatch.ElapsedMilliseconds);
-
-            stopwatch.Reset();
-            stopwatch.Start();
-
-            for (var i = 0; i < runCount; i++)
-            {
-                var sshMessageFactory = new SshMessageFactoryOriginal();
-            }
-
-            GC.Collect();
-            GC.WaitForPendingFinalizers();
-            GC.Collect();
-
-            stopwatch.Stop();
-
-            Console.WriteLine(stopwatch.ElapsedMilliseconds);
-        }
-
-        [TestMethod]
-        [TestCategory("LongRunning")]
-        [TestCategory("Performance")]
-        public void Performance_Create()
-        {
-            const int runCount = 10000000;
-            const string messageName = "SSH_MSG_CHANNEL_CLOSE";
-
-            _sshMessageFactory.EnableAndActivateMessage(messageName);
-            _sshMessageFactoryOriginal.EnableAndActivateMessage(messageName);
-
-            // warm-up
-            for (var i = 0; i < 3; i++)
-            {
-                _sshMessageFactory.Create(97);
-                _sshMessageFactoryOriginal.Create(97);
-            }
-
-            GC.Collect();
-            GC.WaitForPendingFinalizers();
-            GC.Collect();
-
-            var stopwatch = new Stopwatch();
-            stopwatch.Start();
-
-            for (var i = 0; i < runCount; i++)
-            {
-                var msg = _sshMessageFactory.Create(97);
-                if (msg == null)
-                    Console.WriteLine();
-            }
-
-            GC.Collect();
-            GC.WaitForPendingFinalizers();
-            GC.Collect();
-
-            stopwatch.Stop();
-
-            Console.WriteLine(stopwatch.ElapsedMilliseconds);
-
-            stopwatch.Reset();
-            stopwatch.Start();
-
-            for (var i = 0; i < runCount; i++)
-            {
-                var msg = _sshMessageFactoryOriginal.Create(97);
-                if (msg == null)
-                    Console.WriteLine();
-            }
-
-            GC.Collect();
-            GC.WaitForPendingFinalizers();
-            GC.Collect();
-
-            stopwatch.Stop();
-
-            Console.WriteLine(stopwatch.ElapsedMilliseconds);
-        }
-
-        [TestMethod]
-        [TestCategory("LongRunning")]
-        [TestCategory("Performance")]
-        public void Performance_EnableAndActivateMessage()
-        {
-            const int runCount = 1000000;
-            const string messageName = "SSH_MSG_CHANNEL_CLOSE";
-
-            // warm-up
-            for (var i = 0; i < 3; i++)
-            {
-                _sshMessageFactory.EnableAndActivateMessage(messageName);
-                _sshMessageFactoryOriginal.EnableAndActivateMessage(messageName);
-            }
-
-            GC.Collect();
-            GC.WaitForPendingFinalizers();
-            GC.Collect();
-
-            var stopwatch = new Stopwatch();
-            stopwatch.Start();
-
-            for (var i = 0; i < runCount; i++)
-                _sshMessageFactory.EnableAndActivateMessage(messageName);
-
-            GC.Collect();
-            GC.WaitForPendingFinalizers();
-            GC.Collect();
-
-            stopwatch.Stop();
-
-            Console.WriteLine(stopwatch.ElapsedMilliseconds);
-
-            stopwatch.Reset();
-            stopwatch.Start();
-
-            for (var i = 0; i < runCount; i++)
-                _sshMessageFactoryOriginal.EnableAndActivateMessage(messageName);
-
-            GC.Collect();
-            GC.WaitForPendingFinalizers();
-            GC.Collect();
-
-            stopwatch.Stop();
-
-            Console.WriteLine(stopwatch.ElapsedMilliseconds);
-        }
-
-        [TestMethod]
-        [TestCategory("LongRunning")]
-        [TestCategory("Performance")]
-        public void Performance_DisableAndDeactivateMessage()
-        {
-            const int runCount = 1000000;
-            const string messageName = "SSH_MSG_CHANNEL_CLOSE";
-
-            // warm-up
-            for (var i = 0; i < 3; i++)
-            {
-                _sshMessageFactory.DisableAndDeactivateMessage(messageName);
-                _sshMessageFactoryOriginal.DisableAndDeactivateMessage(messageName);
-            }
-
-            GC.Collect();
-            GC.WaitForPendingFinalizers();
-            GC.Collect();
-
-            var stopwatch = new Stopwatch();
-            stopwatch.Start();
-
-            for (var i = 0; i < runCount; i++)
-                _sshMessageFactory.DisableAndDeactivateMessage(messageName);
-
-            GC.Collect();
-            GC.WaitForPendingFinalizers();
-            GC.Collect();
-
-            stopwatch.Stop();
-
-            Console.WriteLine(stopwatch.ElapsedMilliseconds);
-
-            stopwatch.Reset();
-            stopwatch.Start();
-
-            for (var i = 0; i < runCount; i++)
-                _sshMessageFactoryOriginal.DisableAndDeactivateMessage(messageName);
-
-            GC.Collect();
-            GC.WaitForPendingFinalizers();
-            GC.Collect();
-
-            stopwatch.Stop();
-
-            Console.WriteLine(stopwatch.ElapsedMilliseconds);
-        }
-
-        [TestMethod]
-        [TestCategory("LongRunning")]
-        [TestCategory("Performance")]
-        public void Performance_DisableNonKeyExchangeMessages()
-        {
-            const int runCount = 1000000;
-
-            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_BANNER");
-            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_DEBUG");
-            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_UNIMPLEMENTED");
-            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_SERVICE_ACCEPT");
-
-            _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_USERAUTH_BANNER");
-            _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_DEBUG");
-            _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_UNIMPLEMENTED");
-            _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_SERVICE_ACCEPT");
-
-            // warm-up
-            for (var i = 0; i < 3; i++)
-            {
-                _sshMessageFactory.DisableNonKeyExchangeMessages();
-                _sshMessageFactory.EnableActivatedMessages();
-
-                _sshMessageFactoryOriginal.DisableNonKeyExchangeMessages();
-                _sshMessageFactoryOriginal.EnableActivatedMessages();
-            }
-
-            //Console.WriteLine("Starting test");
-
-            GC.Collect();
-            GC.WaitForPendingFinalizers();
-            GC.Collect();
-
-            var stopwatch = new Stopwatch();
-            stopwatch.Start();
-
-            for (var i = 0; i < runCount; i++)
-            {
-                _sshMessageFactory.DisableNonKeyExchangeMessages();
-                _sshMessageFactory.EnableActivatedMessages();
-            }
-
-            GC.Collect();
-            GC.WaitForPendingFinalizers();
-            GC.Collect();
-
-            stopwatch.Stop();
-
-            Console.WriteLine(stopwatch.ElapsedMilliseconds);
-
-            stopwatch.Reset();
-            stopwatch.Start();
-
-            for (var i = 0; i < runCount; i++)
-            {
-                _sshMessageFactoryOriginal.DisableNonKeyExchangeMessages();
-                _sshMessageFactoryOriginal.EnableActivatedMessages();
-            }
-
-            GC.Collect();
-            GC.WaitForPendingFinalizers();
-            GC.Collect();
-
-            stopwatch.Stop();
-
-            Console.WriteLine(stopwatch.ElapsedMilliseconds);
-        }
-
-        internal class SshMessageFactoryOriginal
-        {
-            private readonly IEnumerable<MessageMetadata> _messagesMetadata;
-
-            public SshMessageFactoryOriginal()
-            {
-                _messagesMetadata = new[]
-                {
-                    new MessageMetadata {Name = "SSH_MSG_NEWKEYS", Number = 21, Type = typeof(NewKeysMessage)},
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_REQUEST_FAILURE",
-                        Number = 82,
-                        Type = typeof(RequestFailureMessage)
-                    },
-                    new MessageMetadata {Name = "SSH_MSG_KEXINIT", Number = 20, Type = typeof(KeyExchangeInitMessage)},
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_CHANNEL_OPEN_FAILURE",
-                        Number = 92,
-                        Type = typeof(ChannelOpenFailureMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_CHANNEL_FAILURE",
-                        Number = 100,
-                        Type = typeof(ChannelFailureMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_CHANNEL_EXTENDED_DATA",
-                        Number = 95,
-                        Type = typeof(ChannelExtendedDataMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_CHANNEL_DATA",
-                        Number = 94,
-                        Type = typeof(ChannelDataMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_USERAUTH_REQUEST",
-                        Number = 50,
-                        Type = typeof(RequestMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_CHANNEL_REQUEST",
-                        Number = 98,
-                        Type = typeof(ChannelRequestMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_USERAUTH_BANNER",
-                        Number = 53,
-                        Type = typeof(BannerMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_USERAUTH_INFO_RESPONSE",
-                        Number = 61,
-                        Type = typeof(InformationResponseMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_USERAUTH_FAILURE",
-                        Number = 51,
-                        Type = typeof(FailureMessage)
-                    },
-                    new MessageMetadata {Name = "SSH_MSG_DEBUG", Number = 4, Type = typeof(DebugMessage),},
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_KEXDH_INIT",
-                        Number = 30,
-                        Type = typeof(KeyExchangeDhInitMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_GLOBAL_REQUEST",
-                        Number = 80,
-                        Type = typeof(GlobalRequestMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_CHANNEL_OPEN",
-                        Number = 90,
-                        Type = typeof(ChannelOpenMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_CHANNEL_OPEN_CONFIRMATION",
-                        Number = 91,
-                        Type = typeof(ChannelOpenConfirmationMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_USERAUTH_INFO_REQUEST",
-                        Number = 60,
-                        Type = typeof(InformationRequestMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_UNIMPLEMENTED",
-                        Number = 3,
-                        Type = typeof(UnimplementedMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_REQUEST_SUCCESS",
-                        Number = 81,
-                        Type = typeof(RequestSuccessMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_CHANNEL_SUCCESS",
-                        Number = 99,
-                        Type = typeof(ChannelSuccessMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ",
-                        Number = 60,
-                        Type = typeof(PasswordChangeRequiredMessage)
-                    },
-                    new MessageMetadata {Name = "SSH_MSG_DISCONNECT", Number = 1, Type = typeof(DisconnectMessage)},
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_SERVICE_REQUEST",
-                        Number = 5,
-                        Type = typeof(ServiceRequestMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_KEX_DH_GEX_REQUEST",
-                        Number = 34,
-                        Type = typeof(KeyExchangeDhGroupExchangeRequest)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_KEX_DH_GEX_GROUP",
-                        Number = 31,
-                        Type = typeof(KeyExchangeDhGroupExchangeGroup)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_USERAUTH_SUCCESS",
-                        Number = 52,
-                        Type = typeof(SuccessMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_USERAUTH_PK_OK",
-                        Number = 60,
-                        Type = typeof(PublicKeyMessage)
-                    },
-                    new MessageMetadata {Name = "SSH_MSG_IGNORE", Number = 2, Type = typeof(IgnoreMessage)},
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_CHANNEL_WINDOW_ADJUST",
-                        Number = 93,
-                        Type = typeof(ChannelWindowAdjustMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_CHANNEL_EOF",
-                        Number = 96,
-                        Type = typeof(ChannelEofMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_CHANNEL_CLOSE",
-                        Number = 97,
-                        Type = typeof(ChannelCloseMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_SERVICE_ACCEPT",
-                        Number = 6,
-                        Type = typeof(ServiceAcceptMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_KEXDH_REPLY",
-                        Number = 31,
-                        Type = typeof(KeyExchangeDhReplyMessage)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_KEX_DH_GEX_INIT",
-                        Number = 32,
-                        Type = typeof(KeyExchangeDhGroupExchangeInit)
-                    },
-                    new MessageMetadata
-                    {
-                        Name = "SSH_MSG_KEX_DH_GEX_REPLY",
-                        Number = 33,
-                        Type = typeof(KeyExchangeDhGroupExchangeReply)
-                    }
-                };
-            }
-
-            /// <summary>
-            /// Disables and deactivate all messages.
-            /// </summary>
-            public void Reset()
-            {
-                foreach (var messageMetadata in _messagesMetadata)
-                {
-                    messageMetadata.Activated = messageMetadata.Enabled = false;
-                }
-            }
-
-            public void EnableActivatedMessages()
-            {
-                foreach (var messageMetadata in _messagesMetadata)
-                {
-                    if (messageMetadata.Activated)
-                        messageMetadata.Enabled = true;
-                }
-            }
-
-            public Message Create(byte messageNumber)
-            {
-                var messageMetadata =
-                    (from m in _messagesMetadata where m.Number == messageNumber && m.Enabled && m.Activated select m)
-                        .FirstOrDefault();
-                if (messageMetadata == null)
-                    throw new SshException(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid.",
-                        messageNumber));
-
-                return messageMetadata.Type.CreateInstance<Message>();
-            }
-
-            public void DisableNonKeyExchangeMessages()
-            {
-                foreach (var messageMetadata in _messagesMetadata)
-                {
-                    if (messageMetadata.Activated && messageMetadata.Number > 2 &&
-                        (messageMetadata.Number < 20 || messageMetadata.Number > 30))
-                    {
-                        //Console.WriteLine("Disabling " + messageMetadata.Name + "...");
-
-                        messageMetadata.Enabled = false;
-                    }
-                }
-            }
-
-            public void EnableAndActivateMessage(string messageName)
-            {
-                lock (_messagesMetadata)
-                {
-                    var messagesMetadata = _messagesMetadata.Where(m => m.Name == messageName);
-                    foreach (var messageMetadata in messagesMetadata)
-                        messageMetadata.Enabled = messageMetadata.Activated = true;
-                }
-            }
-
-            public void DisableAndDeactivateMessage(string messageName)
-            {
-                lock (_messagesMetadata)
-                {
-                    var messagesMetadata = _messagesMetadata.Where(m => m.Name == messageName);
-                    foreach (var messageMetadata in messagesMetadata)
-                        messageMetadata.Enabled = messageMetadata.Activated = false;
-                }
-            }
-
-            private class MessageMetadata
-            {
-                public string Name { get; set; }
-
-                public byte Number { get; set; }
-
-                public bool Enabled { get; set; }
-
-                public bool Activated { get; set; }
-
-                public Type Type { get; set; }
-            }
-        }
-    }
-}

+ 63 - 0
test/Renci.SshNet.Tests/Classes/AbstractionsTest.cs

@@ -0,0 +1,63 @@
+using Renci.SshNet.Abstractions;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Threading;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class AbstractionsTest
+    {
+        [TestMethod]
+        public void SocketAbstraction_CanWrite_ShouldReturnFalseWhenSocketIsNull()
+        {
+            Assert.IsFalse(SocketAbstraction.CanWrite(null));
+        }
+
+        [TestMethod]
+        public void CryptoAbstraction_GenerateRandom_ShouldPerformNoOpWhenDataIsZeroLength()
+        {
+            Assert.AreEqual(0, CryptoAbstraction.GenerateRandom(0).Length);
+        }
+
+        [TestMethod]
+        public void CryptoAbstraction_GenerateRandom_ShouldGenerateRandomSequenceOfValues()
+        {
+            var dataLength = new Random().Next(1, 100);
+
+            var dataA = CryptoAbstraction.GenerateRandom(dataLength);
+            var dataB = CryptoAbstraction.GenerateRandom(dataLength);
+
+            Assert.AreEqual(dataLength, dataA.Length);
+            Assert.AreEqual(dataLength, dataB.Length);
+
+            CollectionAssert.AreNotEqual(dataA, dataB);
+        }
+
+        [TestMethod]
+        public void ThreadAbstraction_ExecuteThread_ShouldThrowArgumentNullExceptionWhenActionIsNull()
+        {
+            var ex = Assert.ThrowsException<ArgumentNullException>(() => ThreadAbstraction.ExecuteThread(null));
+
+            Assert.IsNull(ex.InnerException);
+            Assert.AreEqual("action", ex.ParamName);
+        }
+
+        [TestMethod]
+        public void ThreadAbstraction_ExecuteThread_ShouldExecuteActionOnSeparateThread()
+        {
+            int threadId = 0;
+            using var waitHandle = new ManualResetEventSlim();
+
+            ThreadAbstraction.ExecuteThread(() =>
+            {
+                threadId = Environment.CurrentManagedThreadId;
+                waitHandle.Set();
+            });
+
+            Assert.IsTrue(waitHandle.Wait(1000));
+            Assert.AreNotEqual(0, threadId);
+            Assert.AreNotEqual(Environment.CurrentManagedThreadId, threadId);
+        }
+    }
+}

+ 3 - 3
test/Renci.SshNet.Shared.Tests/ForwardedPortStatusTest_Started.cs → test/Renci.SshNet.Tests/Classes/ForwardedPortStatusTest_Started.cs

@@ -1,7 +1,7 @@
-using System;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
 
-namespace Renci.SshNet.Tests
+#pragma warning disable SA1131 // Use readable conditions
+namespace Renci.SshNet.Tests.Classes
 {
     [TestClass]
     public class ForwardedPortStatusTest_Started

+ 3 - 3
test/Renci.SshNet.Shared.Tests/ForwardedPortStatusTest_Starting.cs → test/Renci.SshNet.Tests/Classes/ForwardedPortStatusTest_Starting.cs

@@ -1,7 +1,7 @@
-using System;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
 
-namespace Renci.SshNet.Tests
+#pragma warning disable SA1131 // Use readable conditions
+namespace Renci.SshNet.Tests.Classes
 {
     [TestClass]
     public class ForwardedPortStatusTest_Starting

+ 3 - 3
test/Renci.SshNet.Shared.Tests/ForwardedPortStatusTest_Stopped.cs → test/Renci.SshNet.Tests/Classes/ForwardedPortStatusTest_Stopped.cs

@@ -1,7 +1,7 @@
-using System;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
 
-namespace Renci.SshNet.Tests
+#pragma warning disable SA1131 // Use readable conditions
+namespace Renci.SshNet.Tests.Classes
 {
     [TestClass]
     public class ForwardedPortStatusTest_Stopped

+ 3 - 1
test/Renci.SshNet.Shared.Tests/ForwardedPortStatusTest_Stopping.cs → test/Renci.SshNet.Tests/Classes/ForwardedPortStatusTest_Stopping.cs

@@ -1,7 +1,9 @@
 using System;
+
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 
-namespace Renci.SshNet.Tests
+#pragma warning disable SA1131 // Use readable conditions
+namespace Renci.SshNet.Tests.Classes
 {
     [TestClass]
     public class ForwardedPortStatusTest_Stopping

+ 423 - 0
test/Renci.SshNet.Tests/Classes/SshMessageFactoryTest.cs

@@ -0,0 +1,423 @@
+using System;
+using System.Globalization;
+using System.Linq;
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using Renci.SshNet.Common;
+using Renci.SshNet.Messages.Authentication;
+using Renci.SshNet.Messages.Transport;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class SshMessageFactoryTest
+    {
+        private SshMessageFactory _sshMessageFactory;
+
+        [TestInitialize]
+        public void SetUp()
+        {
+            _sshMessageFactory = new SshMessageFactory();
+        }
+
+        [TestMethod]
+        public void CreateShouldThrowSshExceptionWhenMessageIsNotEnabled()
+        {
+            const byte messageNumber = 60;
+
+            try
+            {
+                _sshMessageFactory.Create(messageNumber);
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message);
+            }
+        }
+
+        [TestMethod]
+        public void CreateShouldThrowSshExceptionWhenMessageDoesNotExist_OutsideOfMessageNumberRange()
+        {
+            const byte messageNumber = 255;
+
+            try
+            {
+                _sshMessageFactory.Create(messageNumber);
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not supported.", messageNumber), ex.Message);
+            }
+        }
+
+        [TestMethod]
+        public void CreateShouldThrowSshExceptionWhenMessageDoesNotExist_WithinMessageNumberRange()
+        {
+            const byte messageNumber = 5;
+
+            try
+            {
+                _sshMessageFactory.Create(messageNumber);
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not supported.", messageNumber), ex.Message);
+            }
+        }
+
+        [TestMethod]
+        public void CreateShouldThrowSshExceptionWhenMessageIsNotActivated()
+        {
+            const byte messageNumber = 60;
+            const string messageName = "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ";
+
+            _sshMessageFactory.EnableAndActivateMessage(messageName);
+            _sshMessageFactory.DisableAndDeactivateMessage(messageName);
+
+            try
+            {
+                _sshMessageFactory.Create(messageNumber);
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message);
+            }
+        }
+
+        [TestMethod]
+        public void CreateShouldReturnMessageInstanceCorrespondingToMessageNumberWhenMessageIsEnabledAndActivated()
+        {
+            const byte messageNumber = 60;
+            const string messageName = "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ";
+
+            _sshMessageFactory.EnableAndActivateMessage(messageName);
+
+            var actual = _sshMessageFactory.Create(messageNumber);
+
+            Assert.IsNotNull(actual);
+            Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType());
+
+            _sshMessageFactory.DisableAndDeactivateMessage(messageName);
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST");
+
+            actual = _sshMessageFactory.Create(messageNumber);
+
+            Assert.IsNotNull(actual);
+            Assert.AreEqual(typeof(InformationRequestMessage), actual.GetType());
+        }
+
+        [TestMethod]
+        public void DisableAndDeactivateMessageShouldThrowSshExceptionWhenAnotherMessageWithSameMessageNumberIsEnabled()
+        {
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
+
+            try
+            {
+                _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST");
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Cannot enable message 'SSH_MSG_USERAUTH_INFO_REQUEST'. Message type 60 is already enabled for 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'.", ex.Message);
+            }
+
+            // verify that the original message remains enabled
+            var actual = _sshMessageFactory.Create(60);
+            Assert.IsNotNull(actual);
+            Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType());
+        }
+
+        [TestMethod]
+        public void DisableAndDeactivateMessageShouldNotThrowExceptionWhenMessageIsAlreadyDisabled()
+        {
+            const byte messageNumber = 60;
+
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
+            _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
+            _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
+
+            // verify that message remains disabled
+            try
+            {
+                _sshMessageFactory.Create(messageNumber);
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message);
+            }
+        }
+
+        [TestMethod]
+        public void DisableAndDeactivateMessageShouldNotThrowExceptionWhenMessageWasNeverEnabled()
+        {
+            const byte messageNumber = 60;
+
+            _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
+
+            // verify that message is disabled
+            try
+            {
+                _sshMessageFactory.Create(messageNumber);
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message);
+            }
+        }
+
+        [TestMethod]
+        public void DisableAndDeactivateMessageShouldThrowSshExceptionWhenMessageIsNotSupported()
+        {
+            const string messageName = "WHATEVER";
+
+            try
+            {
+                _sshMessageFactory.DisableAndDeactivateMessage("WHATEVER");
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual(string.Format("Message '{0}' is not supported.", messageName), ex.Message);
+            }
+        }
+
+        [TestMethod]
+        public void DisableAndDeactivateMessageShouldThrowArgumentNullExceptionWhenMessageNameIsNull()
+        {
+            const string messageName = null;
+
+            try
+            {
+                _sshMessageFactory.DisableAndDeactivateMessage(messageName);
+                Assert.Fail();
+            }
+            catch (ArgumentNullException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("messageName", ex.ParamName);
+            }
+        }
+
+        [TestMethod]
+        public void EnableAndActivateMessageShouldThrowSshExceptionWhenAnotherMessageWithSameMessageNumberIsAlreadyEnabled()
+        {
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
+
+            try
+            {
+                _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST");
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Cannot enable message 'SSH_MSG_USERAUTH_INFO_REQUEST'. Message type 60 is already enabled for 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'.", ex.Message);
+            }
+
+            // verify that the original message remains enabled
+            var actual = _sshMessageFactory.Create(60);
+            Assert.IsNotNull(actual);
+            Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType());
+        }
+
+        [TestMethod]
+        public void EnableAndActivateMessageShouldNotThrowExceptionWhenMessageIsAlreadyEnabled()
+        {
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
+
+            var actual = _sshMessageFactory.Create(60);
+            Assert.IsNotNull(actual);
+            Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType());
+        }
+
+        [TestMethod]
+        public void EnableAndActivateMessageShouldThrowSshExceptionWhenMessageIsNotSupported()
+        {
+            const string messageName = "WHATEVER";
+
+            try
+            {
+                _sshMessageFactory.EnableAndActivateMessage("WHATEVER");
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual(string.Format("Message '{0}' is not supported.", messageName), ex.Message);
+            }
+        }
+
+        [TestMethod]
+        public void EnableAndActivateMessageShouldThrowArgumentNullExceptionWhenMessageNameIsNull()
+        {
+            const string messageName = null;
+
+            try
+            {
+                _sshMessageFactory.EnableAndActivateMessage(messageName);
+                Assert.Fail();
+            }
+            catch (ArgumentNullException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("messageName", ex.ParamName);
+            }
+        }
+
+        [TestMethod]
+        public void DisableNonKeyExchangeMessagesShouldDisableNonKeyExchangeMessages()
+        {
+            const byte messageNumber = 60;
+
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
+            _sshMessageFactory.DisableNonKeyExchangeMessages(strict: false);
+
+            // verify that message is disabled
+            try
+            {
+                _sshMessageFactory.Create(messageNumber);
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message);
+            }
+        }
+
+        [TestMethod]
+        public void DisableNonKeyExchangeMessagesShouldNotDisableKeyExchangeMessages()
+        {
+            const byte messageNumber = 21;
+
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_NEWKEYS");
+            _sshMessageFactory.DisableNonKeyExchangeMessages(strict: false);
+
+            // verify that message remains enabled
+            var actual = _sshMessageFactory.Create(messageNumber);
+            Assert.IsNotNull(actual);
+            Assert.AreEqual(typeof(NewKeysMessage), actual.GetType());
+        }
+
+        [TestMethod]
+        public void EnableActivatedMessagesShouldEnableMessagesThatWereEnabledPriorToInvokingDisableNonKeyExchangeMessages()
+        {
+            const byte messageNumber = 60;
+
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
+            _sshMessageFactory.DisableNonKeyExchangeMessages(strict: false);
+            _sshMessageFactory.EnableActivatedMessages();
+
+            var actual = _sshMessageFactory.Create(messageNumber);
+            Assert.IsNotNull(actual);
+            Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType());
+        }
+
+        [TestMethod]
+        public void EnableActivatedMessagesShouldNotEnableMessagesThatWereDisabledPriorToInvokingDisableNonKeyExchangeMessages()
+        {
+            const byte messageNumber = 60;
+
+            _sshMessageFactory.DisableNonKeyExchangeMessages(strict: false);
+            _sshMessageFactory.EnableActivatedMessages();
+
+            try
+            {
+                _sshMessageFactory.Create(messageNumber);
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message);
+            }
+        }
+
+        [TestMethod]
+        public void EnableActivatedMessagesShouldNotEnableMessagesThatWereDisabledAfterInvokingDisableNonKeyExchangeMessages()
+        {
+            const byte messageNumber = 60;
+
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
+            _sshMessageFactory.DisableNonKeyExchangeMessages(strict: false);
+            _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
+            _sshMessageFactory.EnableActivatedMessages();
+
+            try
+            {
+                _sshMessageFactory.Create(messageNumber);
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message);
+            }
+        }
+
+        [TestMethod]
+        public void EnableActivatedMessagesShouldThrowSshExceptionWhenAnothersMessageWithSameMessageNumberWasEnabledAfterInvokingDisableNonKeyExchangeMessages()
+        {
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
+            _sshMessageFactory.DisableNonKeyExchangeMessages(strict: false);
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST");
+
+            try
+            {
+                _sshMessageFactory.EnableActivatedMessages();
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                Assert.IsNull(ex.InnerException);
+                Assert.AreEqual("Cannot enable message 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'. Message type 60 is already enabled for 'SSH_MSG_USERAUTH_INFO_REQUEST'.", ex.Message);
+            }
+        }
+
+        [TestMethod]
+        public void EnableActivatedMessagesShouldLeaveMessagesEnabledThatWereEnabledAfterInvokingDisableNonKeyExchangeMessages()
+        {
+            const byte messageNumber = 60;
+
+            _sshMessageFactory.DisableNonKeyExchangeMessages(strict: false);
+            _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
+            _sshMessageFactory.EnableActivatedMessages();
+
+            var actual = _sshMessageFactory.Create(messageNumber);
+            Assert.IsNotNull(actual);
+            Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType());
+        }
+
+        [TestMethod]
+        public void HighestMessageNumberShouldCorrespondWithHighestSupportedMessageNumber()
+        {
+            var highestSupportMessageNumber = SshMessageFactory.AllMessages.Max(m => m.Number);
+
+            Assert.AreEqual(highestSupportMessageNumber, SshMessageFactory.HighestMessageNumber);
+        }
+
+        [TestMethod]
+        public void TotalMessageCountShouldBeTotalNumberOfSupportedMessages()
+        {
+            var totalNumberOfSupportedMessages = SshMessageFactory.AllMessages.Length;
+
+            Assert.AreEqual(totalNumberOfSupportedMessages, SshMessageFactory.TotalMessageCount);
+        }
+    }
+}

+ 0 - 179
test/Renci.SshNet.Tests/Common/HttpProxyStub.cs

@@ -1,179 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Net;
-using System.Net.Sockets;
-using System.Text;
-
-namespace Renci.SshNet.Tests.Common
-{
-    public class HttpProxyStub : IDisposable
-    {
-        private readonly IPEndPoint _endPoint;
-        private AsyncSocketListener _listener;
-        private HttpRequestParser _httpRequestParser;
-        private readonly IList<byte[]> _responses;
-
-        public HttpProxyStub(IPEndPoint endPoint)
-        {
-            _endPoint = endPoint;
-            _responses = new List<byte[]>();
-        }
-
-        public HttpRequest HttpRequest
-        {
-            get
-            {
-                if (_httpRequestParser == null)
-                {
-                    throw new InvalidOperationException("The proxy is not started.");
-                }
-
-                return _httpRequestParser.HttpRequest;
-            }
-        }
-
-        public IList<byte[]> Responses
-        {
-            get { return _responses; }
-        }
-
-        public void Start()
-        {
-            _httpRequestParser = new HttpRequestParser();
-
-            _listener = new AsyncSocketListener(_endPoint);
-            _listener.BytesReceived += OnBytesReceived;
-            _listener.Start();
-        }
-
-        public void Stop()
-        {
-            _listener?.Stop();
-        }
-
-        public void Dispose()
-        {
-            Stop();
-            GC.SuppressFinalize(this);
-        }
-
-        private void OnBytesReceived(byte[] bytesReceived, Socket socket)
-        {
-            _httpRequestParser.ProcessData(bytesReceived);
-
-            if (_httpRequestParser.CurrentState == HttpRequestParser.State.Content)
-            {
-                foreach (var response in Responses)
-                {
-                    _ = socket.Send(response);
-                }
-
-                socket.Shutdown(SocketShutdown.Send);
-            }
-        }
-
-        private class HttpRequestParser
-        {
-            private readonly List<byte> _buffer;
-            private readonly HttpRequest _httpRequest;
-
-            public enum State
-            {
-                RequestLine,
-                Headers,
-                Content
-            }
-
-            public HttpRequestParser()
-            {
-                CurrentState = State.RequestLine;
-                _buffer = new List<byte>();
-                _httpRequest = new HttpRequest();
-            }
-
-            public HttpRequest HttpRequest
-            {
-                get { return _httpRequest; }
-            }
-
-            public State CurrentState { get; private set; }
-
-            public void ProcessData(byte[] data)
-            {
-                var position = 0;
-
-                while (position != data.Length)
-                {
-                    if (CurrentState == State.RequestLine)
-                    {
-                        var requestLine = ReadLine(data, ref position);
-                        if (requestLine != null)
-                        {
-                            _httpRequest.RequestLine = requestLine;
-                            CurrentState = State.Headers;
-                        }
-                    }
-
-                    if (CurrentState == State.Headers)
-                    {
-                        var line = ReadLine(data, ref position);
-                        if (line != null)
-                        {
-                            if (line.Length == 0)
-                            {
-                                CurrentState = State.Content;
-                            }
-                            else
-                            {
-                                _httpRequest.Headers.Add(line);
-                            }
-                        }
-                    }
-
-                    if (CurrentState == State.Content)
-                    {
-                        if (position < data.Length)
-                        {
-                            var currentContent = _httpRequest.MessageBody;
-                            var newBufferSize = currentContent.Length + (data.Length - position);
-                            var copyBuffer = new byte[newBufferSize];
-                            Array.Copy(currentContent, copyBuffer, currentContent.Length);
-                            Array.Copy(data, position, copyBuffer, currentContent.Length, data.Length - position);
-                            _httpRequest.MessageBody = copyBuffer;
-                            break;
-                        }
-                    }
-                }
-            }
-
-            private string ReadLine(byte[] data, ref int position)
-            {
-                for (; position < data.Length; position++)
-                {
-                    var b = data[position];
-                    if (b == '\n')
-                    {
-                        var buffer = _buffer.ToArray();
-                        var bytesInLine = buffer.Length;
-
-                        // when the previous byte was a CR, then do not include it in line
-                        if (buffer.Length > 0 && buffer[buffer.Length - 1] == '\r')
-                        {
-                            bytesInLine -= 1;
-                        }
-
-                        // clear the buffer
-                        _buffer.Clear();
-
-                        // move position up one position as we've processed the current byte
-                        position++;
-                        return Encoding.ASCII.GetString(buffer, 0, bytesInLine);
-                    }
-                    _buffer.Add(b);
-                }
-
-                return null;
-            }
-        }
-    }
-}

+ 0 - 17
test/Renci.SshNet.Tests/Common/HttpRequest.cs

@@ -1,17 +0,0 @@
-using System.Collections.Generic;
-
-namespace Renci.SshNet.Tests.Common
-{
-    public class HttpRequest
-    {
-        public HttpRequest()
-        {
-            Headers = new List<string>();
-            MessageBody = new byte[0];
-        }
-
-        public string RequestLine { get; set; }
-        public IList<string> Headers { get; set; }
-        public byte[] MessageBody { get; set; }
-    }
-}