Index: Core/Common/src/Core.Common.Gui/PropertyBag/PropertySpec.cs
===================================================================
diff -u -r7de564e0db6835c6821f0ce2303a983a2758e7d0 -r8de8647e95dd220a1a4d78980e88af32ee9d2d3f
--- Core/Common/src/Core.Common.Gui/PropertyBag/PropertySpec.cs (.../PropertySpec.cs) (revision 7de564e0db6835c6821f0ce2303a983a2758e7d0)
+++ Core/Common/src/Core.Common.Gui/PropertyBag/PropertySpec.cs (.../PropertySpec.cs) (revision 8de8647e95dd220a1a4d78980e88af32ee9d2d3f)
@@ -68,9 +68,8 @@
/// - does not match the target type.
/// - Property is an instance property but is null.
/// - is of incorrect type.
- /// - An error occurred while setting
- /// the property value. The property
- /// indicates the reason for the error.
+ /// - An error occurred while setting the property value. The
+ /// property indicates the reason for the error.
///
/// Calling this method while property
/// has no setter.
@@ -98,10 +97,87 @@
}
catch (TargetInvocationException e)
{
- var message = string.Format("Something when wrong while setting property with value '{0}'; Check InnerException for more information.",
+ var message = string.Format("Something went wrong while setting property with value '{0}'; Check InnerException for more information.",
newValue);
throw new ArgumentException(message, "newValue", e);
}
}
+
+ ///
+ /// Gets the property value represented by this instance of some object instance.
+ ///
+ /// The instance that holds the property to be retrieved.
+ /// When
+ ///
+ /// - Represented property is an index-property.
+ /// - Property getter is not available.
+ /// - does not match the target type.
+ /// - Property is an instance property but is null.
+ /// - An error occurred while setting the property value. The
+ /// property indicates the reason for the error.
+ ///
+ /// Calling this method while property
+ /// has no getter.
+ public object GetValue(object instance)
+ {
+ var getMethodInfo = propertyInfo.GetGetMethod();
+ if (getMethodInfo == null)
+ {
+ throw new InvalidOperationException("Property lacks public getter!");
+ }
+
+ try
+ {
+ return getMethodInfo.Invoke(instance, new object[0]);
+ }
+ catch (TargetException e)
+ {
+ object type = instance == null ? null : instance.GetType();
+ var message = string.Format("Are you calling GetValue on the correct instance? Expected '{0}', but was '{1}'",
+ propertyInfo.DeclaringType, type);
+ throw new ArgumentException(message, "instance", e);
+ }
+ catch (TargetInvocationException e)
+ {
+ throw new ArgumentException("Something went wrong while getting property; Check InnerException for more information.", "instance", e);
+ }
+ }
+
+ ///
+ /// Determines whether the captured property is decorated with [is non custom expandable object property].
+ /// that is configured to use .
+ ///
+ /// Returns true if a is declared using
+ /// , false if no match has been found or when
+ /// the type converter inherits from .
+ /// Custom implementations of is
+ /// likely to have behavior that Core.Common.Gui namespace cannot account for. As
+ /// such those properties will be considered not having the expandable object type converter.
+ public bool IsNonCustomExpandableObjectProperty()
+ {
+ var typeConverterClassName = propertyInfo.GetCustomAttributes(typeof(TypeConverterAttribute), false)
+ .OfType()
+ .Select(tca => tca.ConverterTypeName)
+ .Where(n => !string.IsNullOrEmpty(n));
+ foreach (string typeName in typeConverterClassName)
+ {
+ try
+ {
+ var type = Type.GetType(typeName);
+ if (type != null)
+ {
+ if (typeof(ExpandableObjectConverter) == type)
+ {
+ return true;
+ }
+ }
+ }
+ catch (Exception)
+ {
+ // gulp
+ }
+ }
+ return false;
+ }
}
}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Gui/PropertyBag/PropertySpecDescriptor.cs
===================================================================
diff -u -rd91a531792e48f042fa6c28ef8c0e16b8fa06fba -r8de8647e95dd220a1a4d78980e88af32ee9d2d3f
--- Core/Common/src/Core.Common.Gui/PropertyBag/PropertySpecDescriptor.cs (.../PropertySpecDescriptor.cs) (revision d91a531792e48f042fa6c28ef8c0e16b8fa06fba)
+++ Core/Common/src/Core.Common.Gui/PropertyBag/PropertySpecDescriptor.cs (.../PropertySpecDescriptor.cs) (revision 8de8647e95dd220a1a4d78980e88af32ee9d2d3f)
@@ -7,11 +7,26 @@
namespace Core.Common.Gui.PropertyBag
{
+ ///
+ /// A that works for properties captured in a
+ /// and handles Dynamic attributes.
+ ///
+ /// The following dynamic attributes are supported:
+ ///
+ ///
+ ///
+ ///
public class PropertySpecDescriptor : PropertyDescriptor
{
private readonly PropertySpec item;
private readonly object instance;
+ ///
+ /// Initializes a new instance of the class
+ /// for a given .
+ ///
+ /// The property spec.
+ /// The instance which has the property captured in .
public PropertySpecDescriptor(PropertySpec propertySpec, object instance)
: base(propertySpec.Name, propertySpec.Attributes)
{
@@ -43,8 +58,11 @@
{
get
{
- ReEvaluateAttributes();
- return base.IsBrowsable;
+ if (Attributes.Matches(new DynamicVisibleAttribute()))
+ {
+ return DynamicVisibleAttribute.IsVisible(instance, item.Name);
+ }
+ return !Attributes.Matches(BrowsableAttribute.No);
}
}
@@ -61,108 +79,28 @@
return false;
}
- public override object GetValue(object component)
- {
- return ReEvaluateAttributes().Value;
- }
-
public override void ResetValue(object component)
{
}
- public override void SetValue(object component, object value)
+ public override object GetValue(object component)
{
- item.SetValue(component, value);
- }
-
- public override bool ShouldSerializeValue(object component)
- {
- return false;
- }
-
- private PropertySpecEventArgs ReEvaluateAttributes()
- {
- UpdateDynamicAttributes();
-
- // Have the property bag raise an event to get the current value of the property:
- var e = new PropertySpecEventArgs(item, null);
- OnGetValue(e, e.Property);
- AttributeArray = e.Property.Attributes; // TODO: Override AttributeArray to reroute to 'item.Attributes'
- return e;
- }
-
- private void UpdateDynamicAttributes()
- {
- var attributeList = new List();
- attributeList.AddRange(item.Attributes.ToList());
-
- //check all of the attributes: if we find a dynamic one, evaluate it and possibly add/overwrite a static attribute
- foreach (Attribute customAttribute in item.Attributes)
+ var propertyValue = item.GetValue(component);
+ if (item.IsNonCustomExpandableObjectProperty())
{
- if (customAttribute is DynamicReadOnlyAttribute)
- {
- attributeList.RemoveAll(x => x is ReadOnlyAttribute);
-
- if (DynamicReadOnlyAttribute.IsReadOnly(instance, item.Name))
- {
- //condition is true: the dynamic attribute should be applied (as static attribute)
- attributeList.Add(new ReadOnlyAttribute(true)); //add static read only attribute
- }
- }
-
- if (customAttribute is DynamicVisibleAttribute)
- {
- attributeList.RemoveAll(x => x is BrowsableAttribute);
-
- if (!DynamicVisibleAttribute.IsVisible(instance, item.Name))
- {
- attributeList.Add(new BrowsableAttribute(false));
- }
- }
+ return new DynamicPropertyBag(propertyValue);
}
-
- item.Attributes = attributeList.ToArray();
+ return propertyValue;
}
- ///
- /// Raises the GetValue event.
- ///
- /// A PropertySpecEventArgs that contains the event data.
- ///
- private void OnGetValue(PropertySpecEventArgs e, PropertySpec propertySpec)
+ public override void SetValue(object component, object value)
{
- var propertyInfo = instance.GetType().GetProperty(propertySpec.Name);
- var value = propertyInfo.GetValue(instance, null);
-
- var isNestedPropertiesObject = IsNestedExpandablePropertiesObject(propertyInfo);
-
- // if nested properties object, wrap in DynamicPropertyBag to provide support for things like DynamicReadOnly
- e.Value = isNestedPropertiesObject ? new DynamicPropertyBag(value) : value;
+ item.SetValue(component, value);
}
- private bool IsNestedExpandablePropertiesObject(System.Reflection.PropertyInfo propertyInfo)
+ public override bool ShouldSerializeValue(object component)
{
- try
- {
- var typeConverterAttributes = propertyInfo.GetCustomAttributes(typeof(TypeConverterAttribute), false);
- foreach (TypeConverterAttribute typeConverterAttribute in typeConverterAttributes)
- {
- var typeString = typeConverterAttribute.ConverterTypeName;
- var type = Type.GetType(typeString);
- if (type != null)
- {
- if (typeof(ExpandableObjectConverter) == type)
- {
- return true;
- }
- }
- }
- }
- catch (Exception)
- {
- //gulp
- }
return false;
}
}
Index: Core/Common/test/Core.Common.Gui.Test/PropertyBag/DynamicPropertyBagTest.cs
===================================================================
diff -u -rd91a531792e48f042fa6c28ef8c0e16b8fa06fba -r8de8647e95dd220a1a4d78980e88af32ee9d2d3f
--- Core/Common/test/Core.Common.Gui.Test/PropertyBag/DynamicPropertyBagTest.cs (.../DynamicPropertyBagTest.cs) (revision d91a531792e48f042fa6c28ef8c0e16b8fa06fba)
+++ Core/Common/test/Core.Common.Gui.Test/PropertyBag/DynamicPropertyBagTest.cs (.../DynamicPropertyBagTest.cs) (revision 8de8647e95dd220a1a4d78980e88af32ee9d2d3f)
@@ -57,7 +57,7 @@
var descriptionPropertySpec = dynamicPropertyBag.Properties.OfType().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 GivenClassWithDynamicReadOnlyAttribute_WhenNotReadOnly_ThenTypeDescriptorDoesNotHaveReadOnlyAttribute()
@@ -88,23 +88,6 @@
}
[Test]
- public void DynamicPropertyBagResolvesDynamicAttributes()
- {
- var dynamicPropertyBag = new DynamicPropertyBag(new TestProperties());
-
- var propertyDescriptorCollection = ((ICustomTypeDescriptor) dynamicPropertyBag).GetProperties();
-
- var namePropertyDescriptor = propertyDescriptorCollection.Find("Name", false);
-
- namePropertyDescriptor.GetValue(dynamicPropertyBag);
-
- // asserts
- Assert.IsTrue(namePropertyDescriptor.Attributes.Matches(new DynamicReadOnlyAttribute()), "Dynamic ReadOnly attribute was not added");
-
- Assert.IsTrue(namePropertyDescriptor.Attributes.Matches(new ReadOnlyAttribute(true)), "Dynamic ReadOnly attribute was not resolved to static attribute: wrong.");
- }
-
- [Test]
public void DynamicPropertyBagResolvesDynamicVisibleAttributes()
{
var propertyObject = new TestProperties
@@ -133,17 +116,6 @@
}
[Test]
- [ExpectedException(typeof(MissingMethodException), ExpectedMessage = "DynamicReadOnlyValidationMethod niet gevonden (of geen 'public' toegankelijkheid). Klasse: Core.Common.Gui.Test.PropertyBag.DynamicPropertyBagTest+TestWithoutValidationMethodClassProperties.")]
- public void ThrowsExceptionOnTypoInDynamicAttributeFunction()
- {
- var dynamicPropertyBag = new DynamicPropertyBag(new TestWithoutValidationMethodClassProperties());
- var propertyDescriptorCollection = ((ICustomTypeDescriptor) dynamicPropertyBag).GetProperties();
- var namePropertyDescriptor = propertyDescriptorCollection.Find("Name", false);
-
- namePropertyDescriptor.GetValue(dynamicPropertyBag);
- }
-
- [Test]
public void DynamicPropertyBagMaintainsDesiredOrdering()
{
var dynamicPropertyBag = new DynamicPropertyBag(new TestOrderedProperties());
@@ -170,7 +142,7 @@
var dynamicPropertyBag = new DynamicPropertyBag(testProperties);
var propertiesCollection = ((ICustomTypeDescriptor) dynamicPropertyBag).GetProperties();
- var wrappedValue = propertiesCollection[0].GetValue(dynamicPropertyBag);
+ var wrappedValue = propertiesCollection[0].GetValue(dynamicPropertyBag.WrappedObject);
// check the object properties are wrapped in a dynamic property bag
Assert.IsInstanceOf(wrappedValue, "Object properties wrapped in dynamic property bag");
@@ -196,17 +168,6 @@
}
[Test]
- [ExpectedException(typeof(MissingMethodException), ExpectedMessage = "DynamicReadOnlyValidationMethod heeft een incorrect aantal argumenten. Zou er één moeten zijn. Klasse: Core.Common.Gui.Test.PropertyBag.DynamicPropertyBagTest+TestInvalidValidationMethodClassProperties.")]
- public void ThrowsExceptionOnInvalidValidationMethod()
- {
- var dynamicPropertyBag = new DynamicPropertyBag(new TestInvalidValidationMethodClassProperties());
- var propertyDescriptorCollection = ((ICustomTypeDescriptor) dynamicPropertyBag).GetProperties();
- var namePropertyDescriptor = propertyDescriptorCollection.Find("Name", false);
-
- namePropertyDescriptor.GetValue(dynamicPropertyBag);
- }
-
- [Test]
public void PropertyWithNoSetterAreReadOnly()
{
var dynamicPropertyBag = new DynamicPropertyBag(new TestWithoutSetterPropertyClassProperties());
@@ -217,62 +178,8 @@
Assert.IsTrue(propertyDescriptorCollection[1].Attributes.Matches(new ReadOnlyAttribute(true)));
}
- [Test]
- [ExpectedException(typeof(MissingMethodException), ExpectedMessage = "Slechts één DynamicReadOnlyValidationMethod toegestaan per klasse: Core.Common.Gui.Test.PropertyBag.DynamicPropertyBagTest+TestWithTwoValidationMethodsClassProperties.")]
- public void OnlySingleValidationMethodIsAllowed()
- {
- var dynamicPropertyBag = new DynamicPropertyBag(new TestWithTwoValidationMethodsClassProperties());
-
- var propertyDescriptorCollection = ((ICustomTypeDescriptor) dynamicPropertyBag).GetProperties();
- var namePropertyDescriptor = propertyDescriptorCollection.Find("Name", false);
-
- namePropertyDescriptor.GetValue(dynamicPropertyBag);
- }
-
#region Test Classes
- private class TestWithNestedPropertiesClassProperties
- {
- [TypeConverter(typeof(ExpandableObjectConverter))]
- public TestProperties SubProperties { get; set; }
- }
-
- private class TestInvalidValidationMethodClassProperties
- {
- [DynamicReadOnly]
- public string Name { get; set; }
-
- [DynamicReadOnlyValidationMethod]
- public bool InvalidMethod() //method is invalid because it does not accept a string
- {
- return false;
- }
- }
-
- private class TestWithoutValidationMethodClassProperties
- {
- [DynamicReadOnly]
- public string Name { get; set; }
- }
-
- private class TestWithTwoValidationMethodsClassProperties
- {
- [DynamicReadOnly]
- public string Name { get; set; }
-
- [DynamicReadOnlyValidationMethod]
- public bool Method1(string property)
- {
- return false;
- }
-
- [DynamicReadOnlyValidationMethod]
- public bool Method2(string property)
- {
- return false;
- }
- }
-
private class TestOrderedProperties
{
[PropertyOrder(3)]
@@ -288,6 +195,12 @@
public string PropTwo { get; set; }
}
+ private class TestWithNestedPropertiesClassProperties
+ {
+ [TypeConverter(typeof(ExpandableObjectConverter))]
+ public TestProperties SubProperties { get; set; }
+ }
+
private class TestProperties
{
public TestProperties()
@@ -333,7 +246,7 @@
}
}
- public class TestWithoutSetterPropertyClassProperties
+ private class TestWithoutSetterPropertyClassProperties
{
public string PrivateSetter { get; private set; }
Index: Core/Common/test/Core.Common.Gui.Test/PropertyBag/PropertySpecDescriptorTest.cs
===================================================================
diff -u -rd91a531792e48f042fa6c28ef8c0e16b8fa06fba -r8de8647e95dd220a1a4d78980e88af32ee9d2d3f
--- Core/Common/test/Core.Common.Gui.Test/PropertyBag/PropertySpecDescriptorTest.cs (.../PropertySpecDescriptorTest.cs) (revision d91a531792e48f042fa6c28ef8c0e16b8fa06fba)
+++ Core/Common/test/Core.Common.Gui.Test/PropertyBag/PropertySpecDescriptorTest.cs (.../PropertySpecDescriptorTest.cs) (revision 8de8647e95dd220a1a4d78980e88af32ee9d2d3f)
@@ -1,4 +1,5 @@
-using System.ComponentModel;
+using System;
+using System.ComponentModel;
using Core.Common.Gui.Attributes;
using Core.Common.Gui.PropertyBag;
@@ -11,13 +12,31 @@
public class PropertySpecDescriptorTest
{
[Test]
+ public void ParameteredConstructor_IsPropertyReadOnlyProperty_ExpectedValues()
+ {
+ // Setup
+ var instance = new ClassWithProperties();
+ var propertyInfo = instance.GetType().GetProperty("IsPropertyReadOnly");
+ var spec = new PropertySpec(propertyInfo);
+
+ // Call
+ var propertyDescriptor = new PropertySpecDescriptor(spec, instance);
+
+ // Assert
+ Assert.AreEqual(spec.GetType(), propertyDescriptor.ComponentType);
+ Assert.IsFalse(propertyDescriptor.IsReadOnly);
+ Assert.IsTrue(propertyDescriptor.IsBrowsable);
+ Assert.AreEqual(propertyInfo.PropertyType, propertyDescriptor.PropertyType);
+ }
+
+ [Test]
[TestCase(false)]
[TestCase(true)]
public void IsReadOnly_PropertyHasDynamicReadOnlyProperty_ReturnExpectedValue(bool isPropertyReadOnly)
{
// Setup
- var instance = new TestClass{ IsPropertyReadOnly = isPropertyReadOnly };
- var propertySpec = new PropertySpec(instance.GetType().GetProperty("IntegerProperty"));
+ var instance = new ClassWithProperties{ IsPropertyReadOnly = isPropertyReadOnly };
+ var propertySpec = new PropertySpec(instance.GetType().GetProperty("IntegerPropertyWithDynamicReadOnly"));
var descriptor = new PropertySpecDescriptor(propertySpec, instance);
// Call
@@ -27,22 +46,258 @@
Assert.AreEqual(isPropertyReadOnly, isReadOnly);
}
- private class TestClass
+ [Test]
+ public void IsReadOnly_PropertyHasReadOnlyTrueAttribute_ReturnTrue()
{
+ // Setup
+ var instance = new ClassWithProperties();
+ var spec = new PropertySpec(instance.GetType().GetProperty("PropertyWithReadOnlyAttribute"));
+ var descriptor = new PropertySpecDescriptor(spec, instance);
+
+ // Call
+ var isReadOnly = descriptor.IsReadOnly;
+
+ // Assert
+ Assert.IsTrue(isReadOnly);
+ }
+
+ [Test]
+ public void IsReadOnly_PropertyHasReadOnlyFalseAttribute_ReturnFalse()
+ {
+ // Setup
+ var instance = new ClassWithProperties();
+ var spec = new PropertySpec(instance.GetType().GetProperty("PropertyWithReadOnlyFalseAttribute"));
+ var descriptor = new PropertySpecDescriptor(spec, instance);
+
+ // Call
+ var isReadOnly = descriptor.IsReadOnly;
+
+ // Assert
+ Assert.IsFalse(isReadOnly);
+ }
+
+ [Test]
+ public void IsReadOnly_PropertyHasNoAttributeAndOnlyGetter_ReturnTrue()
+ {
+ // Setup
+ var instance = new ClassWithProperties();
+ var spec = new PropertySpec(instance.GetType().GetProperty("PropertyWithOnlyGetter"));
+ var descriptor = new PropertySpecDescriptor(spec, instance);
+
+ // Call
+ var isReadOnly = descriptor.IsReadOnly;
+
+ // Assert
+ Assert.IsTrue(isReadOnly);
+ }
+
+ [Test]
+ [TestCase(false)]
+ [TestCase(true)]
+ public void IsBrowsable_PropertyHasDynamicBrowsableProperty_ReturnExpectedValue(bool isPropertyVisible)
+ {
+ // Setup
+ var instance = new ClassWithProperties { IsPropertyBrowsable = isPropertyVisible };
+ var propertySpec = new PropertySpec(instance.GetType().GetProperty("IntegerPropertyWithDynamicVisibility"));
+ var descriptor = new PropertySpecDescriptor(propertySpec, instance);
+
+ // Call
+ var isBrowsable = descriptor.IsBrowsable;
+
+ // Assert
+ Assert.AreEqual(isPropertyVisible, isBrowsable);
+ }
+
+ [Test]
+ public void IsIsBrowsable_PropertyHasBrowsableTrueAttribute_ReturnTrue()
+ {
+ // Setup
+ var instance = new ClassWithProperties();
+ var spec = new PropertySpec(instance.GetType().GetProperty("PropertyWithBrowsableAttribute"));
+ var descriptor = new PropertySpecDescriptor(spec, instance);
+
+ // Call
+ var isBrowsable = descriptor.IsBrowsable;
+
+ // Assert
+ Assert.IsTrue(isBrowsable);
+ }
+
+ [Test]
+ public void IsBrowsable_PropertyHasBrowsableFalseAttribute_ReturnFalse()
+ {
+ // Setup
+ var instance = new ClassWithProperties();
+ var spec = new PropertySpec(instance.GetType().GetProperty("PropertyWithBrowsableFalseAttribute"));
+ var descriptor = new PropertySpecDescriptor(spec, instance);
+
+ // Call
+ var isBrowsable = descriptor.IsBrowsable;
+
+ // Assert
+ Assert.IsFalse(isBrowsable);
+ }
+
+ [Test]
+ public void CanResetValue_ReturnFalse()
+ {
+ // Setup
+ var instance = new ClassWithProperties();
+ var spec = new PropertySpec(instance.GetType().GetProperty("PropertyWithOnlyGetter"));
+ var propertyDescriptor = new PropertySpecDescriptor(spec, instance);
+
+ // Call
+ var canReset = propertyDescriptor.CanResetValue(instance);
+
+ // Assert
+ Assert.IsFalse(canReset);
+ }
+
+ [Test]
+ public void ShouldSerializeValue_ReturnFalse()
+ {
+ // Setup
+ var instance = new ClassWithProperties();
+ var spec = new PropertySpec(instance.GetType().GetProperty("PropertyWithOnlyGetter"));
+ var propertyDescriptor = new PropertySpecDescriptor(spec, instance);
+
+ // Call
+ var shouldSerializeValue = propertyDescriptor.ShouldSerializeValue(instance);
+
+ // Assert
+ Assert.IsFalse(shouldSerializeValue);
+ }
+
+ [Test]
+ public void GetValue_SimpleValueProperty_ReturnPropertyValue()
+ {
+ // Setup
+ var instance = new ClassWithProperties();
+ var spec = new PropertySpec(instance.GetType().GetProperty("PropertyWithOnlyGetter"));
+ var propertyDescriptor = new PropertySpecDescriptor(spec, instance);
+
+ // Call
+ var value = propertyDescriptor.GetValue(instance);
+
+ // Assert
+ Assert.AreEqual(instance.PropertyWithOnlyGetter, value);
+ }
+
+ [Test]
+ public void GetValue_ObjectValueProperty_ReturnPropertyValue()
+ {
+ // Setup
+ var instance = new ClassWithProperties();
+ var spec = new PropertySpec(instance.GetType().GetProperty("ComplexSubProperty"));
+ var propertyDescriptor = new PropertySpecDescriptor(spec, instance);
+
+ // Call
+ var value = propertyDescriptor.GetValue(instance);
+
+ // Assert
+ Assert.AreSame(instance.ComplexSubProperty, value);
+ }
+
+ [Test]
+ public void GetValue_ObjectValuePropertyWithExpandableObjectConverterAttribute_ReturnPropertyValueWrappedInDynamicPropertyBag()
+ {
+ // Setup
+ var instance = new ClassWithProperties();
+ var spec = new PropertySpec(instance.GetType().GetProperty("ComplexSubPropertyWithExandableObjectConverter"));
+ var propertyDescriptor = new PropertySpecDescriptor(spec, instance);
+
+ // Call
+ var value = propertyDescriptor.GetValue(instance);
+
+ // Assert
+ var dynamicPropertyBag = (DynamicPropertyBag)value;
+ Assert.IsNotNull(dynamicPropertyBag);
+ Assert.AreSame(instance.ComplexSubPropertyWithExandableObjectConverter, dynamicPropertyBag.WrappedObject);
+ }
+
+ private class ClassWithProperties
+ {
+ public ClassWithProperties()
+ {
+ IsPropertyReadOnly = false;
+ IsPropertyBrowsable = true;
+ ComplexSubPropertyWithExandableObjectConverter = new AnotherClassWithProperties
+ {
+ Comment = "I have nice type converter, right?"
+ };
+ ComplexSubProperty = new AnotherClassWithProperties
+ {
+ Comment = "Don't want your type converter!"
+ };
+ }
+
+ #region IsReadOnly state influencing testing members
+
+ public string PropertyWithOnlyGetter
+ {
+ get
+ {
+ return "I only have a getter.";
+ }
+ }
+
public bool IsPropertyReadOnly { get; set; }
+ [ReadOnly(true)]
+ public double PropertyWithReadOnlyAttribute { get; set; }
+
+ [ReadOnly(false)]
+ public double PropertyWithReadOnlyFalseAttribute { get; set; }
+
[DynamicReadOnly]
- public int IntegerProperty { get; set; }
+ public int IntegerPropertyWithDynamicReadOnly { get; set; }
[DynamicReadOnlyValidationMethod]
public bool IsReadOnly(string propertyName)
{
- if (propertyName == "IntegerProperty")
+ if (propertyName == "IntegerPropertyWithDynamicReadOnly")
{
return IsPropertyReadOnly;
}
- return ReadOnlyAttribute.Default.IsReadOnly;
+ throw new NotImplementedException();
}
+
+ #endregion
+
+ #region IsBrowsable state influencing testing members
+
+ public bool IsPropertyBrowsable { get; set; }
+
+ [Browsable(true)]
+ public double PropertyWithBrowsableAttribute { get; set; }
+
+ [Browsable(false)]
+ public double PropertyWithBrowsableFalseAttribute { get; set; }
+
+ [DynamicVisible]
+ public int IntegerPropertyWithDynamicVisibility { get; set; }
+
+ [DynamicVisibleValidationMethod]
+ public bool IsVisible(string propertyName)
+ {
+ if (propertyName == "IntegerPropertyWithDynamicVisibility")
+ {
+ return IsPropertyBrowsable;
+ }
+ throw new NotImplementedException();
+ }
+
+ #endregion
+
+ [TypeConverter(typeof(ExpandableObjectConverter))]
+ public AnotherClassWithProperties ComplexSubPropertyWithExandableObjectConverter { get; set; }
+
+ public AnotherClassWithProperties ComplexSubProperty { get; set; }
}
+
+ private class AnotherClassWithProperties
+ {
+ public string Comment { get; set; }
+ }
}
}
\ No newline at end of file
Index: Core/Common/test/Core.Common.Gui.Test/PropertyBag/PropertySpecTest.cs
===================================================================
diff -u -r7de564e0db6835c6821f0ce2303a983a2758e7d0 -r8de8647e95dd220a1a4d78980e88af32ee9d2d3f
--- Core/Common/test/Core.Common.Gui.Test/PropertyBag/PropertySpecTest.cs (.../PropertySpecTest.cs) (revision 7de564e0db6835c6821f0ce2303a983a2758e7d0)
+++ Core/Common/test/Core.Common.Gui.Test/PropertyBag/PropertySpecTest.cs (.../PropertySpecTest.cs) (revision 8de8647e95dd220a1a4d78980e88af32ee9d2d3f)
@@ -197,6 +197,133 @@
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);
+ }
+
private class ClassWithProperties
{
public int IntegerProperty { get; set; }
@@ -215,6 +342,8 @@
public double DoublePropertyWithOnlyPublicGet { get; private set; }
+ public double DoublePropertyWithOnlyPublicSet { private get; set; }
+
public double DoublePropertyWithOnlyGetter
{
get
@@ -229,12 +358,31 @@
[Browsable(true)]
public bool BoolPropertyWithAttributes { get; set; }
+
+ [TypeConverter(typeof(ExpandableObjectConverter))]
+ public string StringPropertyWithExpandableObjectConverter { get; set; }
+
+ [TypeConverter(typeof(CustomExpandableObjectConverter))]
+ public string StringPropertyWithCustomExpandableObjectConverter { get; set; }
+
+ [TypeConverter(typeof(SomeTypeConverter))]
+ public string StringPropertyWithSomeTypeConverter { get; set; }
}
private class InheritorSettingPropertyToNotBrowsable : ClassWithProperties
{
[Browsable(false)]
public override string StringPropertyWithAttributes { get; set; }
}
+
+ private class SomeTypeConverter : TypeConverter
+ {
+
+ }
+
+ private class CustomExpandableObjectConverter : ExpandableObjectConverter
+ {
+
+ }
}
}
\ No newline at end of file