// 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.Drawing.Design; using System.Linq; using Core.Common.Gui.Attributes; using Core.Common.Gui.PropertyBag; using Core.Common.TestUtil; using Core.Common.Utils.Reflection; using NUnit.Framework; using CategoryAttribute = System.ComponentModel.CategoryAttribute; namespace Core.Common.Gui.Test.PropertyBag { [TestFixture] public class DynamicPropertyBagTest { [Test] public void Constructor_PropertyObjectNull_ThrowArgumentNullException() { // Call TestDelegate call = () => new DynamicPropertyBag(null); // Assert string paramName = Assert.Throws(call).ParamName; Assert.AreEqual("propertyObject", paramName); } [Test] public void ParameteredConstructor_ExpectedValues() { // Setup var propertyObject = new object(); // Call var dynamicPropertyBag = new DynamicPropertyBag(propertyObject); // Assert CollectionAssert.IsEmpty(dynamicPropertyBag.Properties, "Object has no properties, therefore bag should have none too."); Assert.AreSame(propertyObject, dynamicPropertyBag.WrappedObject); } [Test] public void Constructor_ClassWith4Properties_CorrectNumberOfPropertiesCreated() { // Setup var propertyObject = new TestProperties(); // Call var dynamicPropertyBag = new DynamicPropertyBag(propertyObject); // Assert Assert.AreEqual(4, dynamicPropertyBag.Properties.Count, "Expected property count wrong"); } [Test] public void Constructor_ClassWithAttributes_PropertySpecsHaveAttributesSet() { // Setup var propertyObject = new TestProperties(); // Call var dynamicPropertyBag = new DynamicPropertyBag(propertyObject); // Assert PropertySpec namePropertySpec = dynamicPropertyBag.Properties.First(ps => ps.Name == "Name"); CollectionAssert.Contains(namePropertySpec.Attributes, new CategoryAttribute("General"), "Should have initialized Attributes of the property spec with declared Category(\"General\")."); PropertySpec descriptionPropertySpec = dynamicPropertyBag.Properties.First(ps => ps.Name == "Description"); CollectionAssert.Contains(descriptionPropertySpec.Attributes, ReadOnlyAttribute.Yes, "Should have initialized Attributes of the property spec with declared ReadOnlyAttribute."); } [Test] public void ToString_ReturnToStringFromWrappedObject() { // Setup var target = new TestProperties(); var dynamicPropertyBag = new DynamicPropertyBag(target); // Call string text = dynamicPropertyBag.ToString(); // Assert Assert.AreEqual(target.ToString(), text); } [Test] public void GetAttributes_Always_ReturnEmpty() { // Setup var target = new TestProperties(); var dynamicPropertyBag = new DynamicPropertyBag(target); // Call AttributeCollection attributes = dynamicPropertyBag.GetAttributes(); // Assert CollectionAssert.IsEmpty(attributes); } [Test] public void GetClassName_Always_ReturnDynamicPropertyBagClassName() { // Setup var target = new TestProperties(); var dynamicPropertyBag = new DynamicPropertyBag(target); // Call string className = dynamicPropertyBag.GetClassName(); // Assert Assert.AreEqual(dynamicPropertyBag.GetType().FullName, className); } [Test] public void GetComponentName_Always_ReturnNull() { // Setup var target = new TestProperties(); var dynamicPropertyBag = new DynamicPropertyBag(target); // Call string componentName = dynamicPropertyBag.GetComponentName(); // Assert Assert.IsNull(componentName); } [Test] public void GetConverter_Always_ReturnDefaultTypeConverter() { // Setup var target = new TestProperties(); var dynamicPropertyBag = new DynamicPropertyBag(target); // Call TypeConverter typeConverter = dynamicPropertyBag.GetConverter(); // Assert Assert.AreEqual(TypeDescriptor.GetConverter(dynamicPropertyBag, true), typeConverter); } [Test] public void GetDefaultEvent_Always_ReturnNull() { // Setup var target = new TestProperties(); var dynamicPropertyBag = new DynamicPropertyBag(target); // Call EventDescriptor eventDescriptor = dynamicPropertyBag.GetDefaultEvent(); // Assert Assert.IsNull(eventDescriptor); } [Test] public void GetEvents_Always_ReturnEmpty() { // Setup var target = new TestProperties(); var dynamicPropertyBag = new DynamicPropertyBag(target); // Call EventDescriptorCollection events = dynamicPropertyBag.GetEvents(); // Assert CollectionAssert.IsEmpty(events); } [Test] public void GetEventsParametered_Always_ReturnEmpty() { // Setup var target = new TestProperties(); var dynamicPropertyBag = new DynamicPropertyBag(target); // Call EventDescriptorCollection events = dynamicPropertyBag.GetEvents(new Attribute[0]); // Assert CollectionAssert.IsEmpty(events); } [Test] public void GetEditor_Always_ReturnNull() { // Setup var target = new TestProperties(); var dynamicPropertyBag = new DynamicPropertyBag(target); // Call object editor = dynamicPropertyBag.GetEditor(typeof(UITypeEditor)); // Assert Assert.IsNull(editor); } [Test] public void GetDefaultProperty_ObjectHasNotProperties_ReturnNull() { // Setup var dynamicPropertyBag = new DynamicPropertyBag(new object()); // Call PropertyDescriptor defaultProperty = dynamicPropertyBag.GetDefaultProperty(); // Assert Assert.IsNull(defaultProperty); } [Test] public void GetDefaultProperty_ObjectWithProperties_ReturnFirstFromProperties() { // Setup var target = new TestProperties(); var dynamicPropertyBag = new DynamicPropertyBag(target); // Call PropertyDescriptor defaultProperty = dynamicPropertyBag.GetDefaultProperty(); // Assert Assert.NotNull(defaultProperty); Assert.AreEqual(dynamicPropertyBag.Properties.First().Name, defaultProperty.Name); } [Test] public void GivenObjectPropertiesWithDynamicVisibleProperties_WhenPropertyShown_ThenPropertyShouldBePresentInBag() { // Given var propertyObject = new TestProperties { Visible = true }; var dynamicPropertyBag = new DynamicPropertyBag(propertyObject); PropertyDescriptorCollection propertyDescriptorCollection = dynamicPropertyBag.GetProperties(new Attribute[] { new BrowsableAttribute(true) }); // When string dynamicallyVisiblePropertyName = TypeUtils.GetMemberName(tp => tp.Name); PropertyDescriptor namePropertyDescriptor = propertyDescriptorCollection.Find(dynamicallyVisiblePropertyName, false); // Then Assert.IsTrue(namePropertyDescriptor.IsBrowsable, $"{dynamicallyVisiblePropertyName} should be visible"); } [Test] public void GivenObjectPropertiesWithDynamicVisibleProperties_WhenPropertyHidden_ThenPropertyNotPresentInBag() { // Setup var propertyObject = new TestProperties { Visible = false }; var dynamicPropertyBag = new DynamicPropertyBag(propertyObject); PropertyDescriptorCollection propertyDescriptorCollection = dynamicPropertyBag.GetProperties(new Attribute[] { new BrowsableAttribute(true) }); // Call string dynamicallyVisiblePropertyName = TypeUtils.GetMemberName(tp => tp.Name); PropertyDescriptor namePropertyDescriptor = propertyDescriptorCollection.Find(dynamicallyVisiblePropertyName, false); // Assert Assert.IsNull(namePropertyDescriptor, $"{dynamicallyVisiblePropertyName} should not be visible anymore"); } [Test] public void GetProperties_SomePropertiesWithOrderAttribute_ReturnElementsInDesiredOrdering() { // Setup var dynamicPropertyBag = new DynamicPropertyBag(new TestOrderedProperties()); // Call PropertyDescriptorCollection propertyDescriptorCollection = dynamicPropertyBag.GetProperties(); // Assert var index = 0; Assert.AreEqual("PropSix", propertyDescriptorCollection[index++].DisplayName); Assert.AreEqual("PropFour", propertyDescriptorCollection[index++].DisplayName); Assert.AreEqual("PropTwo", propertyDescriptorCollection[index++].DisplayName); Assert.AreEqual("PropOne", propertyDescriptorCollection[index++].DisplayName); Assert.AreEqual("Description", propertyDescriptorCollection[index++].DisplayName); Assert.AreEqual("PropFive", propertyDescriptorCollection[index++].DisplayName); Assert.AreEqual("Name", propertyDescriptorCollection[index++].DisplayName); PropertyDescriptor propThreeDescriptor = propertyDescriptorCollection.Find("PropThree", false); Assert.GreaterOrEqual(propertyDescriptorCollection.IndexOf(propThreeDescriptor), index, "PropThree is not decorated with PropertyOrderAttribute or DynamicPropertyOrderAttribute, therefore should come after those that are."); PropertyDescriptor propSevenDescriptor = propertyDescriptorCollection.Find("PropSeven", false); Assert.GreaterOrEqual(propertyDescriptorCollection.IndexOf(propSevenDescriptor), index, "PropSeven is not decorated with PropertyOrderAttribute or DynamicPropertyOrderAttribute, therefore should come after those that are."); } [Test] public void GetProperties_PropertyIsDecoratedWithExpandableObjectConverter_WrapPropertyValueInDynamicPropertyBag() { // Setup var subProperties = new TestProperties { Name = "test" }; var testProperties = new TestWithNestedPropertiesClassProperties { SubProperties = subProperties }; var dynamicPropertyBag = new DynamicPropertyBag(testProperties); // Call PropertyDescriptorCollection propertiesCollection = dynamicPropertyBag.GetProperties(); // Assert var bag = propertiesCollection[0].GetValue(dynamicPropertyBag.WrappedObject) as DynamicPropertyBag; Assert.NotNull(bag); Assert.AreSame(subProperties, bag.WrappedObject); } [Test] public void GivenPropertyDescriptorFromDynamicPropertyBag_WhenSettingProperty_ThenWrappedObjectUpdated() { // Given var testProperties = new TestProperties { Name = "name" }; var dynamicPropertyBag = new DynamicPropertyBag(testProperties); var newName = "newName"; // When dynamicPropertyBag.GetProperties()["Name"].SetValue(testProperties, newName); // Then Assert.AreEqual(newName, testProperties.Name); } [Test] public void GetProperties_ClassWithPropertiesWithoutPublicSetter_PropertiesDecoratedWithReadOnlyAttribute() { // Setup var dynamicPropertyBag = new DynamicPropertyBag(new TestWithoutSetterPropertyClassProperties()); // Call PropertyDescriptorCollection propertyDescriptorCollection = dynamicPropertyBag.GetProperties(); // Assert Assert.IsTrue(propertyDescriptorCollection[0].Attributes.Matches(ReadOnlyAttribute.Yes)); Assert.IsTrue(propertyDescriptorCollection[1].Attributes.Matches(ReadOnlyAttribute.Yes)); } [Test] public void GetProperties_RepeatedCallForSameState_RetainSameElementOrderAndContents() { // Setup var propertyObject = new TestOrderedProperties(); var dynamicPropertyBag = new DynamicPropertyBag(propertyObject); PropertyDescriptorCollection originalProperties = dynamicPropertyBag.GetProperties(); // Call for (var i = 0; i < 100; i++) { PropertyDescriptorCollection currentProperties = dynamicPropertyBag.GetProperties(); // Assert CollectionAssert.AreEqual(originalProperties, currentProperties); } } [Test] public void GetProperties_RepeatedConstructionsForSameState_RetainSameElementOrderAndContents() { // Setup var propertyObject = new TestOrderedProperties(); PropertyDescriptorCollection originalProperties = new DynamicPropertyBag(propertyObject).GetProperties(); // Call for (var i = 0; i < 100; i++) { PropertyDescriptorCollection currentProperties = new DynamicPropertyBag(propertyObject).GetProperties(); // Assert CollectionAssert.AreEqual(originalProperties, currentProperties); } } [Test] public void GetProperties_BrowsableTrueFilter_ReturnOnlyPropertiesThatAreBrowsable() { // Setup var propertyObject = new TestProperties { Visible = false }; var dynamicPropertyBag = new DynamicPropertyBag(propertyObject); // Call PropertyDescriptorCollection properties = PropertiesTestHelper.GetAllVisiblePropertyDescriptors(propertyObject); // Assert Assert.Less(properties.Count, dynamicPropertyBag.Properties.Count); Assert.IsNull(properties.Find("Name", false), "Name is dynamically not browsable, therefore should not be returned."); Assert.IsNotNull(properties.Find("Description", false)); Assert.IsNotNull(properties.Find("IsNameReadOnly", false)); Assert.IsNull(properties.Find("Visible", false), "Visible is statically not browsable, therefore should not be returned."); } [Test] public void GetProperties_BrowsableNoFilter_ReturnOnlyPropertiesThatAreBrowsable() { // Setup var propertyObject = new TestProperties { Visible = false }; var dynamicPropertyBag = new DynamicPropertyBag(propertyObject); // Call PropertyDescriptorCollection properties = dynamicPropertyBag.GetProperties(new Attribute[] { BrowsableAttribute.No }); // Assert Assert.Less(properties.Count, dynamicPropertyBag.Properties.Count); Assert.IsNotNull(properties.Find("Name", false), "Name is dynamically not browsable, therefore should be returned."); Assert.IsNull(properties.Find("Description", false)); Assert.IsNull(properties.Find("IsNameReadOnly", false)); Assert.IsNotNull(properties.Find("Visible", false), "Visible is statically not browsable, therefore should be returned."); } [Test] public void GetPropertyOwner_Always_ReturnWrappedObject() { // Setup var propertyObject = new TestProperties(); var dynamicPropertyBag = new DynamicPropertyBag(propertyObject); // Call object owner = dynamicPropertyBag.GetPropertyOwner(null); // Assert Assert.AreSame(propertyObject, owner); } #region Test Classes private class TestOrderedProperties { [PropertyOrder(6)] public string Name { get; set; } [PropertyOrder(4)] public string Description { get; set; } [PropertyOrder(3)] public string PropOne { get; set; } [PropertyOrder(2)] public string PropTwo { get; set; } public int PropThree { get; set; } [DynamicPropertyOrder] public int PropFour { get; set; } [DynamicPropertyOrder] public int PropFive { get; set; } [PropertyOrder(0)] [DynamicPropertyOrder] public int PropSix { get; set; } public int PropSeven { get; set; } [DynamicPropertyOrderEvaluationMethod] public int PropertyOrder(string propertyName) { if (propertyName == "PropFour") { return 1; } if (propertyName == "PropFive") { return 5; } return 7; } } private class TestWithNestedPropertiesClassProperties { [TypeConverter(typeof(ExpandableObjectConverter))] public TestProperties SubProperties { get; set; } } private class TestProperties { public TestProperties() { Name = "my name"; Description = "short description"; Visible = true; IsNameReadOnly = true; } /// /// Dynamic property. ReadOnly when IsNameReadOnly true. /// [DynamicReadOnly] [DynamicVisible] [Category("General")] public string Name { get; set; } [Browsable(true)] public bool IsNameReadOnly { get; set; } [Browsable(false)] public bool Visible { get; set; } [ReadOnly(true)] //one static property public string Description { get; set; } /// /// Method checks if propertyName property is read-only (setter can be used). /// /// /// [DynamicReadOnlyValidationMethod] public bool DynamicReadOnlyValidationMethod(string propertyName) { Assert.IsTrue(propertyName == "Name"); return IsNameReadOnly; } [DynamicVisibleValidationMethod] public bool DynamicVisibleValidationMethod(string propertyName) { return Visible; } public override string ToString() { return Name; } } private class TestWithoutSetterPropertyClassProperties { public string PrivateSetter { get; private set; } public string NoSetter { get { return ""; } } } #endregion } }