public void IsRequired_SetToTrue_WithDataMemberIsRequiredTrue()
        {
            // Arrange
            var provider = new DataMemberRequiredBindingMetadataProvider();

            var attributes = new object[]
            {
                new DataMemberAttribute()
                {
                    IsRequired = true,
                }
            };

            var key = ModelMetadataIdentity.ForProperty(
                typeof(string),
                nameof(ClassWithDataMemberIsRequiredTrue.StringProperty),
                typeof(ClassWithDataMemberIsRequiredTrue));
            var context = new BindingMetadataProviderContext(key, attributes);

            // Act
            provider.GetBindingMetadata(context);

            // Assert
            Assert.True(context.BindingMetadata.IsRequired);
        }
        public void GetBindingDetails_BindingBehaviorLeftAlone_ForAttributeOnPropertyType(bool initialValue)
        {
            // Arrange
            var typeAttributes = new object[]
            {
                new BindingBehaviorAttribute(BindingBehavior.Required),
            };

            var context = new BindingMetadataProviderContext(
                ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
                new ModelAttributes(propertyAttributes: new object[0], typeAttributes: typeAttributes));

            // These values shouldn't be changed since this is a Type-Metadata
            context.BindingMetadata.IsBindingAllowed  = initialValue;
            context.BindingMetadata.IsBindingRequired = initialValue;

            var provider = new DefaultBindingMetadataProvider();

            // Act
            provider.GetBindingMetadata(context);

            // Assert
            Assert.Equal(initialValue, context.BindingMetadata.IsBindingAllowed);
            Assert.Equal(initialValue, context.BindingMetadata.IsBindingRequired);
        }
        public void IsRequired_LeftAlone_DataMemberIsRequiredFalse(bool?initialValue)
        {
            // Arrange
            var provider = new DataMemberRequiredBindingMetadataProvider();

            var attributes = new object[]
            {
                new DataMemberAttribute()
                {
                    IsRequired = false,
                }
            };

            var key = ModelMetadataIdentity.ForProperty(
                typeof(string),
                nameof(ClassWithDataMemberIsRequiredFalse.StringProperty),
                typeof(ClassWithDataMemberIsRequiredFalse));
            var context = new BindingMetadataProviderContext(key, attributes);

            context.BindingMetadata.IsRequired = initialValue;

            // Act
            provider.GetBindingMetadata(context);

            // Assert
            Assert.Equal(initialValue, context.BindingMetadata.IsRequired);
        }
        public void IsBindingRequired_LeftAlone_WithoutDataContractAttribute(bool initialValue)
        {
            // Arrange
            var provider = new DataMemberRequiredBindingMetadataProvider();

            var attributes = new object[]
            {
                new DataMemberAttribute()
                {
                    IsRequired = true,
                }
            };

            var key = ModelMetadataIdentity.ForProperty(
                typeof(string),
                nameof(ClassWithDataMemberIsRequiredTrueWithoutDataContract.StringProperty),
                typeof(ClassWithDataMemberIsRequiredTrueWithoutDataContract));
            var context = new BindingMetadataProviderContext(key, new ModelAttributes(attributes, new object[0]));

            context.BindingMetadata.IsBindingRequired = initialValue;

            // Act
            provider.GetBindingMetadata(context);

            // Assert
            Assert.Equal(initialValue, context.BindingMetadata.IsBindingRequired);
        }
        public void GetBindingDetails_OverrideBehaviorOnBaseClass_OverrideWithRequired_OnClass()
        {
            // Arrange
            var context = new BindingMetadataProviderContext(
                ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(BindRequiredOverridesInheritedBindNever)),
                new ModelAttributes(propertyAttributes: new object[0], typeAttributes: new object[0]));

            var provider = new DefaultBindingMetadataProvider();

            // Act
            provider.GetBindingMetadata(context);

            // Assert
            Assert.True(context.BindingMetadata.IsBindingAllowed);
            Assert.True(context.BindingMetadata.IsBindingRequired);
        }
        public void GetBindingDetails_FindsBindNever_OnContainerClass()
        {
            // Arrange
            var context = new BindingMetadataProviderContext(
                ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(BindNeverOnClass)),
                new ModelAttributes(propertyAttributes: new object[0], typeAttributes: new object[0]));

            var provider = new DefaultBindingMetadataProvider();

            // Act
            provider.GetBindingMetadata(context);

            // Assert
            Assert.False(context.BindingMetadata.IsBindingAllowed);
            Assert.False(context.BindingMetadata.IsBindingRequired);
        }
示例#7
0
        public void GetBindingDetails_NoEditableAttribute_IsReadOnlyLeftAlone(bool?initialValue)
        {
            // Arrange
            var provider = new DataAnnotationsMetadataProvider();

            var attributes = new Attribute[] { };
            var key        = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string));
            var context    = new BindingMetadataProviderContext(key, new ModelAttributes(attributes, new object[0]));

            context.BindingMetadata.IsReadOnly = initialValue;

            // Act
            provider.GetBindingMetadata(context);

            // Assert
            Assert.Equal(initialValue, context.BindingMetadata.IsReadOnly);
        }
示例#8
0
        public void GetBindingMetadata_RequiredAttribute_IsBindingRequiredLeftAlone(bool initialValue)
        {
            // Arrange
            var provider = new DataAnnotationsMetadataProvider();

            var attributes = new Attribute[] { new RequiredAttribute() };
            var key        = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string));
            var context    = new BindingMetadataProviderContext(key, new ModelAttributes(attributes, new object[0]));

            context.BindingMetadata.IsBindingRequired = initialValue;

            // Act
            provider.GetBindingMetadata(context);

            // Assert
            Assert.Equal(initialValue, context.BindingMetadata.IsBindingRequired);
        }
示例#9
0
        public void GetValidationMetadata_RequiredAttribute_SetsIsRequiredToTrue()
        {
            // Arrange
            var provider = new DataAnnotationsMetadataProvider();

            var required = new RequiredAttribute();

            var attributes = new Attribute[] { required };
            var key        = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string));
            var context    = new ValidationMetadataProviderContext(key, new ModelAttributes(attributes, new object[0]));

            // Act
            provider.GetValidationMetadata(context);

            // Assert
            Assert.True(context.ValidationMetadata.IsRequired);
        }
示例#10
0
        public void GetBindingDetails_RequiredAttribute_SetsIsRequiredToTrue()
        {
            // Arrange
            var provider = new DataAnnotationsMetadataProvider();

            var required = new RequiredAttribute();

            var attributes = new Attribute[] { required };
            var key        = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string));
            var context    = new BindingMetadataProviderContext(key, attributes);

            // Act
            provider.GetBindingMetadata(context);

            // Assert
            Assert.True(context.BindingMetadata.IsRequired);
        }
示例#11
0
        public void CreateMetadataForProperty()
        {
            // Arrange
            var provider        = new EmptyModelMetadataProvider();
            var detailsProvider = new EmptyCompositeMetadataDetailsProvider();

            var key   = ModelMetadataIdentity.ForProperty(typeof(string), "Message", typeof(Exception));
            var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0], new object[0]));

            // Act
            var metadata = new DefaultModelMetadata(provider, detailsProvider, cache);

            // Assert
            Assert.Equal(typeof(string), metadata.ModelType);
            Assert.Equal("Message", metadata.PropertyName);
            Assert.Equal(typeof(Exception), metadata.ContainerType);
        }
示例#12
0
        public void GetValidationDetails_MarkedWithModelValidator_ReturnsValidator()
        {
            // Arrange
            var provider = new DefaultValidationMetadataProvider();

            var attribute  = new TestModelValidationAttribute();
            var attributes = new Attribute[] { attribute };
            var key        = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string));
            var context    = new ValidationMetadataProviderContext(key, new ModelAttributes(attributes, new object[0]));

            // Act
            provider.GetValidationMetadata(context);

            // Assert
            var validatorMetadata = Assert.Single(context.ValidationMetadata.ValidatorMetadata);

            Assert.Same(attribute, validatorMetadata);
        }
示例#13
0
        public void PropertiesProperty_CallsProvider()
        {
            // Arrange
            var provider        = new Mock <IModelMetadataProvider>(MockBehavior.Strict);
            var detailsProvider = new EmptyCompositeMetadataDetailsProvider();

            var expectedProperties = new DefaultModelMetadata[]
            {
                new DefaultModelMetadata(
                    provider.Object,
                    detailsProvider,
                    new DefaultMetadataDetails(
                        ModelMetadataIdentity.ForProperty(typeof(int), "Prop1", typeof(string)),
                        attributes: new ModelAttributes(new object[0], new object[0]))),
                new DefaultModelMetadata(
                    provider.Object,
                    detailsProvider,
                    new DefaultMetadataDetails(
                        ModelMetadataIdentity.ForProperty(typeof(int), "Prop2", typeof(string)),
                        attributes: new ModelAttributes(new object[0], new object[0]))),
            };

            provider
            .Setup(p => p.GetMetadataForProperties(typeof(string)))
            .Returns(expectedProperties);

            var key   = ModelMetadataIdentity.ForType(typeof(string));
            var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0]));

            var metadata = new DefaultModelMetadata(provider.Object, detailsProvider, cache);

            // Act
            var properties = metadata.Properties;

            // Assert
            Assert.Equal(expectedProperties.Length, properties.Count);

            for (var i = 0; i < expectedProperties.Length; i++)
            {
                Assert.Same(expectedProperties[i], properties[i]);
            }
        }
示例#14
0
        public void GetValidationDetails_ValidatableObject_AlreadyInContext_Ignores()
        {
            // Arrange
            var provider = new DataAnnotationsMetadataProvider();

            var attribute  = new TestValidationAttribute();
            var attributes = new Attribute[] { attribute };
            var key        = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string));
            var context    = new ValidationMetadataProviderContext(key, new ModelAttributes(attributes, new object[0]));

            context.ValidationMetadata.ValidatorMetadata.Add(attribute);

            // Act
            provider.GetValidationMetadata(context);

            // Assert
            var validatorMetadata = Assert.Single(context.ValidationMetadata.ValidatorMetadata);

            Assert.Same(attribute, validatorMetadata);
        }
示例#15
0
        public void PropertiesProperty_OrdersPropertyNamesUsingOrder_ThenAsProvided(
            IEnumerable <KeyValuePair <string, int> > originalNamesAndOrders,
            IEnumerable <string> expectedNames)
        {
            // Arrange
            var provider        = new Mock <IModelMetadataProvider>(MockBehavior.Strict);
            var detailsProvider = new EmptyCompositeMetadataDetailsProvider();

            var expectedProperties = new List <DefaultModelMetadata>();

            foreach (var kvp in originalNamesAndOrders)
            {
                var propertyCache = new DefaultMetadataDetails(
                    ModelMetadataIdentity.ForProperty(typeof(int), kvp.Key, typeof(string)),
                    attributes: new ModelAttributes(new object[0], new object[0]));

                propertyCache.DisplayMetadata       = new DisplayMetadata();
                propertyCache.DisplayMetadata.Order = kvp.Value;

                expectedProperties.Add(new DefaultModelMetadata(
                                           provider.Object,
                                           detailsProvider,
                                           propertyCache));
            }

            provider
            .Setup(p => p.GetMetadataForProperties(typeof(string)))
            .Returns(expectedProperties);

            var key   = ModelMetadataIdentity.ForType(typeof(string));
            var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0]));

            var metadata = new DefaultModelMetadata(provider.Object, detailsProvider, cache);

            // Act
            var properties = metadata.Properties;

            // Assert
            Assert.Equal(expectedNames.Count(), properties.Count);
            Assert.Equal(expectedNames.ToArray(), properties.Select(p => p.PropertyName).ToArray());
        }
        public void GetBindingDetails_FindsBindRequired_OnProperty()
        {
            // Arrange
            var propertyAttributes = new object[]
            {
                new BindRequiredAttribute(),
            };

            var context = new BindingMetadataProviderContext(
                ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
                new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));

            var provider = new DefaultBindingMetadataProvider();

            // Act
            provider.GetBindingMetadata(context);

            // Assert
            Assert.True(context.BindingMetadata.IsBindingAllowed);
            Assert.True(context.BindingMetadata.IsBindingRequired);
        }
        public void GetBindingDetails_OverrideBehaviorOnClass_OverrideWithOptional()
        {
            // Arrange
            var propertyAttributes = new object[]
            {
                new BindingBehaviorAttribute(BindingBehavior.Optional)
            };

            var context = new BindingMetadataProviderContext(
                ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(BindNeverOnClass)),
                new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));

            var provider = new DefaultBindingMetadataProvider();

            // Act
            provider.GetBindingMetadata(context);

            // Assert
            Assert.True(context.BindingMetadata.IsBindingAllowed);
            Assert.False(context.BindingMetadata.IsBindingRequired);
        }
示例#18
0
        public void GetBindingDetails_UsesFirstAttribute()
        {
            // Arrange
            var propertyAttributes = new object[]
            {
                new BindingBehaviorAttribute(BindingBehavior.Required),
                new BindNeverAttribute(),
            };

            var context = new BindingMetadataProviderContext(
                ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
                new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));

            var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());

            // Act
            provider.GetBindingMetadata(context);

            // Assert
            Assert.True(context.BindingMetadata.IsBindingAllowed);
            Assert.True(context.BindingMetadata.IsBindingRequired);
        }
示例#19
0
        /// <summary>
        /// Creates the <see cref="DefaultMetadataDetails"/> entries for the properties of a model
        /// <see cref="Type"/>.
        /// </summary>
        /// <param name="key">
        /// The <see cref="ModelMetadataIdentity"/> identifying the model <see cref="Type"/>.
        /// </param>
        /// <returns>A details object for each property of the model <see cref="Type"/>.</returns>
        /// <remarks>
        /// The results of this method will be cached and used to satisfy calls to
        /// <see cref="GetMetadataForProperties(Type)"/>. Override this method to provide a different
        /// set of property data.
        /// </remarks>
        protected virtual DefaultMetadataDetails[] CreatePropertyDetails(ModelMetadataIdentity key)
        {
            var propertyHelpers = PropertyHelper.GetVisibleProperties(key.ModelType);

            var propertyEntries = new List <DefaultMetadataDetails>(propertyHelpers.Length);

            for (var i = 0; i < propertyHelpers.Length; i++)
            {
                var propertyHelper = propertyHelpers[i];
                var propertyKey    = ModelMetadataIdentity.ForProperty(
                    propertyHelper.Property.PropertyType,
                    propertyHelper.Name,
                    key.ModelType);

                var attributes = ModelAttributes.GetAttributesForProperty(
                    key.ModelType,
                    propertyHelper.Property);

                var propertyEntry = new DefaultMetadataDetails(propertyKey, attributes);
                if (propertyHelper.Property.CanRead && propertyHelper.Property.GetMethod?.IsPublic == true)
                {
                    var getter = PropertyHelper.MakeNullSafeFastPropertyGetter(propertyHelper.Property);
                    propertyEntry.PropertyGetter = getter;
                }

                if (propertyHelper.Property.CanWrite &&
                    propertyHelper.Property.SetMethod?.IsPublic == true &&
                    !key.ModelType.GetTypeInfo().IsValueType)
                {
                    propertyEntry.PropertySetter = propertyHelper.ValueSetter;
                }

                propertyEntries.Add(propertyEntry);
            }

            return(propertyEntries.ToArray());
        }
        public void PropertiesProperty_WithDefaultOrder_OrdersPropertyNamesAsProvided(
            IEnumerable <string> originalNames,
            IEnumerable <string> expectedNames)
        {
            // Arrange
            var provider        = new Mock <IModelMetadataProvider>(MockBehavior.Strict);
            var detailsProvider = new EmptyCompositeMetadataDetailsProvider();

            var expectedProperties = new List <DefaultModelMetadata>();

            foreach (var originalName in originalNames)
            {
                expectedProperties.Add(new DefaultModelMetadata(
                                           provider.Object,
                                           detailsProvider,
                                           new DefaultMetadataDetailsCache(
                                               ModelMetadataIdentity.ForProperty(typeof(int), originalName, typeof(string)),
                                               attributes: null)));
            }

            provider
            .Setup(p => p.GetMetadataForProperties(typeof(string)))
            .Returns(expectedProperties);

            var key   = ModelMetadataIdentity.ForType(typeof(string));
            var cache = new DefaultMetadataDetailsCache(key, new object[0]);

            var metadata = new DefaultModelMetadata(provider.Object, detailsProvider, cache);

            // Act
            var properties = metadata.Properties;

            // Assert
            Assert.Equal(expectedNames.Count(), properties.Count);
            Assert.Equal(expectedNames.ToArray(), properties.Select(p => p.PropertyName).ToArray());
        }
示例#21
0
        /// <summary>
        /// Creates the <see cref="DefaultMetadataDetailsCache"/> entries for the properties of a model
        /// <see cref="Type"/>.
        /// </summary>
        /// <param name="key">
        /// The <see cref="ModelMetadataIdentity"/> identifying the model <see cref="Type"/>.
        /// </param>
        /// <returns>A cache object for each property of the model <see cref="Type"/>.</returns>
        /// <remarks>
        /// The results of this method will be cached and used to satisfy calls to
        /// <see cref="GetMetadataForProperties(Type)"/>. Override this method to provide a different
        /// set of property data.
        /// </remarks>
        protected virtual DefaultMetadataDetailsCache[] CreatePropertyCacheEntries([NotNull] ModelMetadataIdentity key)
        {
            var propertyHelpers = PropertyHelper.GetProperties(key.ModelType);

            var propertyEntries = new List <DefaultMetadataDetailsCache>(propertyHelpers.Length);

            for (var i = 0; i < propertyHelpers.Length; i++)
            {
                var propertyHelper = propertyHelpers[i];
                if (propertyHelper.Property.DeclaringType != key.ModelType)
                {
                    // If this property was declared on a base type then look for the definition closest to the
                    // the model type to see if we should include it.
                    var ignoreProperty = false;

                    // Walk up the hierarchy until we find the type that actally declares this
                    // PropertyInfo.
                    var currentType = key.ModelType.GetTypeInfo();
                    while (currentType != propertyHelper.Property.DeclaringType.GetTypeInfo())
                    {
                        // We've found a 'more proximal' public definition
                        var declaredProperty = currentType.GetDeclaredProperty(propertyHelper.Name);
                        if (declaredProperty != null)
                        {
                            ignoreProperty = true;
                            break;
                        }

                        currentType = currentType.BaseType.GetTypeInfo();
                    }

                    if (ignoreProperty)
                    {
                        // There's a better definition, ignore this.
                        continue;
                    }
                }

                var propertyKey = ModelMetadataIdentity.ForProperty(
                    propertyHelper.Property.PropertyType,
                    propertyHelper.Name,
                    key.ModelType);

                var attributes = new List <object>(ModelAttributes.GetAttributesForProperty(
                                                       key.ModelType,
                                                       propertyHelper.Property));

                var propertyEntry = new DefaultMetadataDetailsCache(propertyKey, attributes);
                if (propertyHelper.Property.CanRead && propertyHelper.Property.GetMethod?.IsPrivate == true)
                {
                    propertyEntry.PropertyAccessor = PropertyHelper.MakeFastPropertyGetter(propertyHelper.Property);
                }

                if (propertyHelper.Property.CanWrite && propertyHelper.Property.SetMethod?.IsPrivate == true)
                {
                    propertyEntry.PropertySetter = PropertyHelper.MakeFastPropertySetter(propertyHelper.Property);
                }

                propertyEntries.Add(propertyEntry);
            }

            return(propertyEntries.ToArray());
        }