// Copyright (C) Stichting Deltares 2016. All rights reserved. // // This file is part of Ringtoets. // // Ringtoets is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program. If not, see . // // All names, logos, and references to "Deltares" are registered trademarks of // Stichting Deltares and remain full property of Stichting Deltares at all times. // All rights reserved. using System; using System.ComponentModel; using System.Linq; using System.Reflection; using Core.Common.Gui.PropertyBag; using Core.Common.TestUtil; using NUnit.Framework; namespace Core.Common.Gui.Test.PropertyBag { [TestFixture] public class PropertySpecTest { [Test] public void ParameteredConstructor_FromPropertyWithoutAttributesWithPublicGetSet_ExpectedValues() { // Setup var propertyName = "IntegerProperty"; var propertyInfo = typeof(ClassWithProperties).GetProperty(propertyName); // Call var propertySpec = new PropertySpec(propertyInfo); // Assert Assert.AreEqual(propertyName, propertySpec.Name); Assert.AreEqual(propertyInfo.PropertyType.AssemblyQualifiedName, propertySpec.TypeName); CollectionAssert.IsEmpty(propertySpec.Attributes); } [Test] public void ParameteredConstructor_FromPropertyWithoutAttributesWithOnlyPublicGet_ExpectedValues() { // Setup var propertyName = "DoublePropertyWithOnlyPublicGet"; var propertyInfo = typeof(ClassWithProperties).GetProperty(propertyName); // Call var propertySpec = new PropertySpec(propertyInfo); // Assert Assert.AreEqual(propertyName, propertySpec.Name); Assert.AreEqual(propertyInfo.PropertyType.AssemblyQualifiedName, propertySpec.TypeName); Assert.AreEqual(1, propertySpec.Attributes.Length); var readOnlyAttribute = (ReadOnlyAttribute) propertySpec.Attributes[0]; Assert.IsTrue(readOnlyAttribute.IsReadOnly); } [Test] public void ParameteredConstructor_FromPropertyWithAttributesWithPublicGetSet_ExpectedValues() { // Setup var propertyName = "StringPropertyWithAttributes"; var propertyInfo = typeof(ClassWithProperties).GetProperty(propertyName); // Call var propertySpec = new PropertySpec(propertyInfo); // Assert Assert.AreEqual(propertyName, propertySpec.Name); Assert.AreEqual(propertyInfo.PropertyType.AssemblyQualifiedName, propertySpec.TypeName); Assert.AreEqual(2, propertySpec.Attributes.Length); var browsableAttribute = propertySpec.Attributes.OfType().Single(); Assert.IsTrue(browsableAttribute.Browsable); var readOnlyAttribute = propertySpec.Attributes.OfType().Single(); Assert.IsFalse(readOnlyAttribute.IsReadOnly); } [Test] public void ParameteredConstructor_FromPropertyOverridingAttributesFromBaseClass_InheritedAttributesAreInherited() { // Setup var propertyName = "StringPropertyWithAttributes"; var propertyInfo = typeof(InheritorSettingPropertyToNotBrowsable).GetProperty(propertyName); // Call var propertySpec = new PropertySpec(propertyInfo); // Assert Assert.AreEqual(propertyName, propertySpec.Name); Assert.AreEqual(propertyInfo.PropertyType.AssemblyQualifiedName, propertySpec.TypeName); Assert.AreEqual(2, propertySpec.Attributes.Length); var browsableAttribute = propertySpec.Attributes.OfType().Single(); Assert.IsFalse(browsableAttribute.Browsable, "Should have the override value."); var readOnlyAttribute = propertySpec.Attributes.OfType().Single(); Assert.IsFalse(readOnlyAttribute.IsReadOnly, "Should have the base value."); } [Test] public void ParameteredConstructor_FromPropertyWithAttributesFromBaseClass_InheritedAttributesAreInherited() { // Setup var propertyName = "BoolPropertyWithAttributes"; var propertyInfo = typeof(InheritorSettingPropertyToNotBrowsable).GetProperty(propertyName); // Call var propertySpec = new PropertySpec(propertyInfo); // Assert Assert.AreEqual(propertyName, propertySpec.Name); Assert.AreEqual(propertyInfo.PropertyType.AssemblyQualifiedName, propertySpec.TypeName); Assert.AreEqual(1, propertySpec.Attributes.Length); var browsableAttribute = propertySpec.Attributes.OfType().Single(); Assert.IsTrue(browsableAttribute.Browsable, "No override in 'InheritorSettingPropertyToNotBrowsable' for property 'BoolPropertyWithAttributes', so use base class."); } [Test] public void ParameteredConstructor_ForIndexProperty_ThrowArgumentException() { // Setup var propertyInfo = new ClassWithProperties().GetType().GetProperty("Item"); // Call TestDelegate call = () => new PropertySpec(propertyInfo); // Assert const string expectedMessage = "Index properties are not allowed."; TestHelper.AssertThrowsArgumentExceptionAndTestMessage(call, expectedMessage); } [Test] public void SetValue_ProperInstanceTypeAndValueType_PropertyIsUpdated() { // Setup var target = new ClassWithProperties(); var propertySpec = new PropertySpec(target.GetType().GetProperty("IntegerProperty")); // Call propertySpec.SetValue(target, 2); // Assert Assert.AreEqual(2, target.IntegerProperty); } [Test] public void SetValue_IncorrectInstanceType_ThrowTargetException() { // Setup var target = new ClassWithProperties(); var propertySpec = new PropertySpec(target.GetType().GetProperty("IntegerProperty")); // Call TestDelegate call = () => propertySpec.SetValue(new object(), 2); // Assert Assert.Throws(call); } [Test] public void SetValue_InstanceIsNull_ThrowTargetException() { // Setup var target = new ClassWithProperties(); var propertySpec = new PropertySpec(target.GetType().GetProperty("IntegerProperty")); // Call TestDelegate call = () => propertySpec.SetValue(null, 2); // Assert Assert.Throws(call); } [Test] public void SetValue_SettingValueResultsInException_ThrowTargetInvocationException() { // Setup var target = new ClassWithProperties(); var propertySpec = new PropertySpec(target.GetType().GetProperty("ThrowsException")); // Call TestDelegate call = () => propertySpec.SetValue(target, ""); // Assert var innerException = Assert.Throws(call).InnerException; Assert.IsInstanceOf(innerException); } [Test] public void SetValue_PropertyWithoutPublicSet_ThrowInvalidOperationException() { // Setup var target = new ClassWithProperties(); var propertySpec = new PropertySpec(target.GetType().GetProperty("DoublePropertyWithOnlyGetter")); // Call TestDelegate call = () => propertySpec.SetValue(target, 2); // Assert var exception = Assert.Throws(call); Assert.AreEqual("Property lacks public setter!", exception.Message); } [Test] public void SetValue_SettingValueOfIncorrectType_ThrowArgumentException() { // Setup var target = new ClassWithProperties(); var propertySpec = new PropertySpec(target.GetType().GetProperty("IntegerProperty")); // Call TestDelegate call = () => propertySpec.SetValue(target, new object()); // Assert var exception = Assert.Throws(call); Assert.IsNull(exception.InnerException); } [Test] public void GetValue_ProperInstanceType_ReturnPropertyValue() { // Setup var target = new ClassWithProperties { IntegerProperty = 5 }; var propertySpec = new PropertySpec(target.GetType().GetProperty("IntegerProperty")); // Call var value = propertySpec.GetValue(target); // Assert Assert.AreEqual(target.IntegerProperty, value); } [Test] public void GetValue_PropertyHasNoPublicGetter_ThrowInvalidOperationException() { // Setup var target = new ClassWithProperties(); var propertySpec = new PropertySpec(target.GetType().GetProperty("DoublePropertyWithOnlyPublicSet")); // Call TestDelegate call = () => propertySpec.GetValue(target); // Assert var message = Assert.Throws(call).Message; Assert.AreEqual("Property lacks public getter!", message); } [Test] public void GetValue_IncorrectInstanceType_ThrowArgumentException() { // Setup var target = new ClassWithProperties(); var propertySpec = new PropertySpec(target.GetType().GetProperty("IntegerProperty")); // Call TestDelegate call = () => propertySpec.GetValue(new object()); // Assert var exception = Assert.Throws(call); Assert.IsInstanceOf(exception.InnerException); } [Test] public void GetValue_InstanceIsNull_ThrowArgumentException() { // Setup var target = new ClassWithProperties(); var propertySpec = new PropertySpec(target.GetType().GetProperty("IntegerProperty")); // Call TestDelegate call = () => propertySpec.GetValue(null); // Assert var exception = Assert.Throws(call); Assert.IsInstanceOf(exception.InnerException); } [Test] public void IsNonCustomExpandableObjectProperty_PropertyWithoutTypeConverter_ReturnFalse() { // Setup var target = new ClassWithProperties(); var propertySpec = new PropertySpec(target.GetType().GetProperty("IntegerProperty")); // Call var hasExpandableObjectTypeConverter = propertySpec.IsNonCustomExpandableObjectProperty(); // Assert Assert.False(hasExpandableObjectTypeConverter); } [Test] public void IsNonCustomExpandableObjectProperty_PropertyWithExpandableObjectTypeConverter_ReturnTrue() { // Setup var target = new ClassWithProperties(); var propertySpec = new PropertySpec(target.GetType().GetProperty("StringPropertyWithExpandableObjectConverter")); // Call var hasExpandableObjectTypeConverter = propertySpec.IsNonCustomExpandableObjectProperty(); // Assert Assert.True(hasExpandableObjectTypeConverter); } [Test] public void IsNonCustomExpandableObjectProperty_PropertyWithCustomExpandableObjectTypeConverter_ReturnFalse() { // Setup var target = new ClassWithProperties(); var propertySpec = new PropertySpec(target.GetType().GetProperty("StringPropertyWithCustomExpandableObjectConverter")); // Call var hasExpandableObjectTypeConverter = propertySpec.IsNonCustomExpandableObjectProperty(); // Assert Assert.False(hasExpandableObjectTypeConverter, "As we cannot copy the same behavior of a ExpandableObjectConverter with customizations, we should not recognize it as such."); } [Test] public void IsNonCustomExpandableObjectProperty_PropertyWithSomeTypeConverter_ReturnFalse() { // Setup var target = new ClassWithProperties(); var propertySpec = new PropertySpec(target.GetType().GetProperty("StringPropertyWithSomeTypeConverter")); // Call var hasExpandableObjectTypeConverter = propertySpec.IsNonCustomExpandableObjectProperty(); // Assert Assert.False(hasExpandableObjectTypeConverter); } [Test] public void IsNonCustomExpandableObjectProperty_ExpandableObjectConverterInherited_ReturnTrue() { // Setup var target = new InheritorSettingPropertyToNotBrowsable(); var propertySpec = new PropertySpec(target.GetType().GetProperty("StringPropertyWithExpandableObjectConverter")); // Call var hasExpandableObjectTypeConverter = propertySpec.IsNonCustomExpandableObjectProperty(); // Assert Assert.True(hasExpandableObjectTypeConverter); } private class ClassWithProperties { public float this[int index] { get { return default(float); } set {} } public int IntegerProperty { get; set; } public double DoublePropertyWithOnlyPublicGet { get; private set; } public double DoublePropertyWithOnlyPublicSet { private get; set; } public double DoublePropertyWithOnlyGetter { get { return 0.0; } } [Browsable(true)] [ReadOnly(false)] public virtual string StringPropertyWithAttributes { get; set; } [Browsable(true)] public bool BoolPropertyWithAttributes { get; set; } [TypeConverter(typeof(ExpandableObjectConverter))] public virtual string StringPropertyWithExpandableObjectConverter { get; set; } [TypeConverter(typeof(CustomExpandableObjectConverter))] public string StringPropertyWithCustomExpandableObjectConverter { get; set; } [TypeConverter(typeof(SomeTypeConverter))] public string StringPropertyWithSomeTypeConverter { get; set; } public string ThrowsException { set { throw new ArgumentException(); } } } private class InheritorSettingPropertyToNotBrowsable : ClassWithProperties { [Browsable(false)] public override string StringPropertyWithAttributes { get; set; } public override string StringPropertyWithExpandableObjectConverter { get; set; } } private class SomeTypeConverter : TypeConverter {} private class CustomExpandableObjectConverter : ExpandableObjectConverter {} } }