diff --git a/mRemoteNGTests/Connection/DefaultConnectionInfoTests.cs b/mRemoteNGTests/Connection/DefaultConnectionInfoTests.cs index 0d9cf4a3..4c35bb7d 100644 --- a/mRemoteNGTests/Connection/DefaultConnectionInfoTests.cs +++ b/mRemoteNGTests/Connection/DefaultConnectionInfoTests.cs @@ -1,35 +1,41 @@ -using mRemoteNG.Connection; +using System.Collections.Generic; +using System.Reflection; +using mRemoteNG.Connection; using mRemoteNG.Connection.Protocol; +using mRemoteNGTests.TestHelpers; using NUnit.Framework; namespace mRemoteNGTests.Connection { - public class DefaultConnectionInfoTests + public class DefaultConnectionInfoTests { - private string _testDomain = "somedomain"; - [SetUp] public void Setup() { DefaultConnectionInfo.Instance.Domain = ""; } - [Test] - public void LoadingDefaultInfoUpdatesAllProperties() + [TestCaseSource(nameof(GetConnectionInfoProperties))] + public void LoadingDefaultInfoUpdatesAllProperties(PropertyInfo property) { - var connectionInfoSource = new ConnectionInfo { Domain = _testDomain }; + var connectionInfoSource = ConnectionInfoHelpers.GetRandomizedConnectionInfo(); DefaultConnectionInfo.Instance.LoadFrom(connectionInfoSource); - Assert.That(DefaultConnectionInfo.Instance.Domain, Is.EqualTo(_testDomain)); + var valueInDestination = property.GetValue(DefaultConnectionInfo.Instance); + var valueInSource = property.GetValue(connectionInfoSource); + Assert.That(valueInDestination, Is.EqualTo(valueInSource)); } - [Test] - public void SavingDefaultConnectionInfoExportsAllProperties() + [TestCaseSource(nameof(GetConnectionInfoProperties))] + public void SavingDefaultConnectionInfoExportsAllProperties(PropertyInfo property) { var saveTarget = new ConnectionInfo(); - DefaultConnectionInfo.Instance.Domain = _testDomain; + var randomizedValue = property.GetValue(ConnectionInfoHelpers.GetRandomizedConnectionInfo()); + property.SetValue(DefaultConnectionInfo.Instance, randomizedValue); DefaultConnectionInfo.Instance.SaveTo(saveTarget); - Assert.That(saveTarget.Domain, Is.EqualTo(_testDomain)); + var valueInDestination = property.GetValue(saveTarget); + var valueInSource = property.GetValue(DefaultConnectionInfo.Instance); + Assert.That(valueInDestination, Is.EqualTo(valueInSource)); } [Test] @@ -69,5 +75,10 @@ namespace mRemoteNGTests.Connection public string Protocol { get; set; } public string RDPMinutesToIdleTimeout { get; set; } } + + private static IEnumerable GetConnectionInfoProperties() + { + return new ConnectionInfo().GetSerializableProperties(); + } } } \ No newline at end of file diff --git a/mRemoteNGTests/TestHelpers/ConnectionInfoHelpers.cs b/mRemoteNGTests/TestHelpers/ConnectionInfoHelpers.cs new file mode 100644 index 00000000..9743ea0a --- /dev/null +++ b/mRemoteNGTests/TestHelpers/ConnectionInfoHelpers.cs @@ -0,0 +1,132 @@ +using System; +using mRemoteNG.Connection; +using mRemoteNG.Connection.Protocol; +using mRemoteNG.Connection.Protocol.Http; +using mRemoteNG.Connection.Protocol.ICA; +using mRemoteNG.Connection.Protocol.RDP; +using mRemoteNG.Connection.Protocol.VNC; + +namespace mRemoteNGTests.TestHelpers +{ + internal class ConnectionInfoHelpers + { + private static readonly Random _random = new Random(); + + /// + /// Returns a object with randomized + /// values in all fields. + /// + internal static ConnectionInfo GetRandomizedConnectionInfo(bool randomizeInheritance = false) + { + var connectionInfo = new ConnectionInfo + { + // string types + Name = RandomString(), + Hostname = RandomString(), + Description = RandomString(), + Domain = RandomString(), + ExtApp = RandomString(), + Icon = RandomString(), + LoadBalanceInfo = RandomString(), + MacAddress = RandomString(), + Panel = RandomString(), + Password = RandomString(), + PostExtApp = RandomString(), + PreExtApp = RandomString(), + PuttySession = RandomString(), + RDGatewayHostname = RandomString(), + RDGatewayUsername = RandomString(), + RDGatewayDomain = RandomString(), + RDGatewayPassword = RandomString(), + UserField = RandomString(), + Username = RandomString(), + VNCProxyIP = RandomString(), + VNCProxyPassword = RandomString(), + VNCProxyUsername = RandomString(), + + // bool types + AutomaticResize = RandomBool(), + CacheBitmaps = RandomBool(), + DisplayThemes = RandomBool(), + DisplayWallpaper = RandomBool(), + EnableDesktopComposition = RandomBool(), + EnableFontSmoothing = RandomBool(), + IsContainer = RandomBool(), + IsDefault = RandomBool(), + IsQuickConnect = RandomBool(), + PleaseConnect = RandomBool(), + RDPAlertIdleTimeout = RandomBool(), + RedirectDiskDrives = RandomBool(), + RedirectKeys = RandomBool(), + RedirectPorts = RandomBool(), + RedirectPrinters = RandomBool(), + RedirectSmartCards = RandomBool(), + UseConsoleSession = RandomBool(), + UseCredSsp = RandomBool(), + VNCViewOnly = RandomBool(), + + // ints + Port = RandomInt(), + RDPMinutesToIdleTimeout = RandomInt(), + VNCProxyPort = RandomInt(), + + // enums + Colors = RandomEnum(), + ICAEncryptionStrength = RandomEnum (), + Protocol = RandomEnum(), + RDGatewayUsageMethod = RandomEnum(), + RDGatewayUseConnectionCredentials = RandomEnum(), + RDPAuthenticationLevel = RandomEnum(), + RedirectSound = RandomEnum(), + RenderingEngine = RandomEnum(), + Resolution = RandomEnum(), + SoundQuality = RandomEnum(), + VNCAuthMode = RandomEnum(), + VNCColors = RandomEnum(), + VNCCompression = RandomEnum(), + VNCEncoding = RandomEnum(), + VNCProxyType = RandomEnum(), + VNCSmartSizeMode = RandomEnum(), + }; + + if (randomizeInheritance) + connectionInfo.Inheritance = GetRandomizedInheritance(connectionInfo); + + return connectionInfo; + } + + internal static ConnectionInfoInheritance GetRandomizedInheritance(ConnectionInfo parent) + { + var inheritance = new ConnectionInfoInheritance(parent, true); + foreach (var property in inheritance.GetProperties()) + { + property.SetValue(inheritance, RandomBool()); + } + return inheritance; + } + + internal static string RandomString() + { + return Guid.NewGuid().ToString("N"); + } + + internal static bool RandomBool() + { + return _random.Next() % 2 == 0; + } + + internal static int RandomInt() + { + return _random.Next(); + } + + internal static T RandomEnum() where T : struct, IConvertible + { + if (!typeof(T).IsEnum) + throw new ArgumentException("T must be an enum"); + + var values = Enum.GetValues(typeof(T)); + return (T)values.GetValue(_random.Next(values.Length)); + } + } +} diff --git a/mRemoteNGTests/mRemoteNGTests.csproj b/mRemoteNGTests/mRemoteNGTests.csproj index 48f7a3e1..3dcbcd08 100644 --- a/mRemoteNGTests/mRemoteNGTests.csproj +++ b/mRemoteNGTests/mRemoteNGTests.csproj @@ -170,6 +170,7 @@ + diff --git a/mRemoteV1/Connection/ConnectionInfo.cs b/mRemoteV1/Connection/ConnectionInfo.cs index 4626778f..dd6fda9f 100644 --- a/mRemoteV1/Connection/ConnectionInfo.cs +++ b/mRemoteV1/Connection/ConnectionInfo.cs @@ -15,7 +15,6 @@ using mRemoteNG.Connection.Protocol.Telnet; using mRemoteNG.Connection.Protocol.VNC; using mRemoteNG.Container; using mRemoteNG.Tree; -using mRemoteNG.Tree.Root; namespace mRemoteNG.Connection @@ -127,6 +126,14 @@ namespace mRemoteNG.Connection return filteredProperties; } + public virtual IEnumerable GetSerializableProperties() + { + var excludedProperties = new[] { "Parent", "Name", "Hostname", "Port", "Inheritance", "OpenConnections", + "IsContainer", "IsDefault", "PositionID", "ConstantID", "TreeNode", "IsQuickConnect", "PleaseConnect" }; + + return GetProperties(excludedProperties); + } + public virtual void SetParent(ContainerInfo newParent) { RemoveParent(); diff --git a/mRemoteV1/Connection/DefaultConnectionInfo.cs b/mRemoteV1/Connection/DefaultConnectionInfo.cs index 8bf0f990..2e44137e 100644 --- a/mRemoteV1/Connection/DefaultConnectionInfo.cs +++ b/mRemoteV1/Connection/DefaultConnectionInfo.cs @@ -1,15 +1,13 @@ using System; -using System.ComponentModel; +using System.Configuration; using mRemoteNG.App; namespace mRemoteNG.Connection { - public class DefaultConnectionInfo : ConnectionInfo + public class DefaultConnectionInfo : ConnectionInfo { public static DefaultConnectionInfo Instance { get; } = new DefaultConnectionInfo(); - private readonly string[] _excludedProperties = { "Parent", "Name", "Hostname", "Port", "Inheritance", - "OpenConnections", "IsContainer", "IsDefault", "PositionID", "ConstantID", "TreeNode", "IsQuickConnect", "PleaseConnect" }; private DefaultConnectionInfo() { @@ -18,18 +16,23 @@ namespace mRemoteNG.Connection public void LoadFrom(TSource sourceInstance, Func propertyNameMutator = null) { - if (propertyNameMutator == null) propertyNameMutator = a => a; - var connectionProperties = GetProperties(_excludedProperties); + if (propertyNameMutator == null) + propertyNameMutator = a => a; + + var connectionProperties = GetSerializableProperties(); foreach (var property in connectionProperties) { try { - var propertyFromSource = typeof(TSource).GetProperty(propertyNameMutator(property.Name)); - if (propertyFromSource == null) continue; - var valueFromSource = propertyFromSource.GetValue(sourceInstance, null); - var typeConverter = TypeDescriptor.GetConverter(property.PropertyType); - if (typeConverter.CanConvertFrom(valueFromSource.GetType())) - property.SetValue(Instance, typeConverter.ConvertFrom(valueFromSource), null); + var expectedPropertyName = propertyNameMutator(property.Name); + var propertyFromSource = typeof(TSource).GetProperty(expectedPropertyName); + if (propertyFromSource == null) + throw new SettingsPropertyNotFoundException($"No property with name '{expectedPropertyName}' found."); + + var valueFromSource = propertyFromSource.GetValue(sourceInstance, null); + var value = Convert.ChangeType(valueFromSource, property.PropertyType); + + property.SetValue(Instance, value, null); } catch (Exception ex) { @@ -40,19 +43,25 @@ namespace mRemoteNG.Connection public void SaveTo(TDestination destinationInstance, Func propertyNameMutator = null) { - if (propertyNameMutator == null) propertyNameMutator = (a) => a; - var inheritanceProperties = GetProperties(_excludedProperties); - foreach (var property in inheritanceProperties) + if (propertyNameMutator == null) + propertyNameMutator = (a) => a; + + var connectionProperties = GetSerializableProperties(); + + foreach (var property in connectionProperties) { try { - var propertyFromDestination = typeof(TDestination).GetProperty(propertyNameMutator(property.Name)); - var localValue = property.GetValue(Instance, null); - var typeConverter = TypeDescriptor.GetConverter(property.PropertyType); - if (propertyFromDestination != null && !typeConverter.CanConvertTo(propertyFromDestination.PropertyType)) continue; - if (propertyFromDestination == null) continue; - var convertedValue = typeConverter.ConvertTo(localValue, propertyFromDestination.PropertyType); - propertyFromDestination.SetValue(destinationInstance, convertedValue, null); + var expectedPropertyName = propertyNameMutator(property.Name); + var propertyFromDestination = typeof(TDestination).GetProperty(expectedPropertyName); + + if (propertyFromDestination == null) + throw new SettingsPropertyNotFoundException($"No property with name '{expectedPropertyName}' found."); + + // ensure value is of correct type + var value = Convert.ChangeType(property.GetValue(Instance, null), propertyFromDestination.PropertyType); + + propertyFromDestination.SetValue(destinationInstance, value, null); } catch (Exception ex) {