// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq; using Xunit; using Assert = Microsoft.TestCommon.AssertEx; namespace System.Web.Mvc.Test { public abstract class DataAnnotationsModelMetadataProviderTestBase { protected abstract AssociatedMetadataProvider MakeProvider(); [Fact] public void GetMetadataForPropertiesSetTypesAndPropertyNames() { // Arrange var provider = MakeProvider(); // Act IEnumerable result = provider.GetMetadataForProperties("foo", typeof(string)); // Assert Assert.True(result.Any(m => m.ModelType == typeof(int) && m.PropertyName == "Length" && (int)m.Model == 3)); } [Fact] public void GetMetadataForPropertySetsTypeAndPropertyName() { // Arrange var provider = MakeProvider(); // Act ModelMetadata result = provider.GetMetadataForProperty(null, typeof(string), "Length"); // Assert Assert.Equal(typeof(int), result.ModelType); Assert.Equal("Length", result.PropertyName); } [Fact] public void GetMetadataForTypeSetsTypeWithNullPropertyName() { // Arrange var provider = MakeProvider(); // Act ModelMetadata result = provider.GetMetadataForType(null, typeof(string)); // Assert Assert.Equal(typeof(string), result.ModelType); Assert.Null(result.PropertyName); } // [HiddenInput] tests class HiddenModel { public int NoAttribute { get; set; } [HiddenInput] public int DefaultHidden { get; set; } [HiddenInput(DisplayValue = false)] public int HiddenWithDisplayValueFalse { get; set; } [HiddenInput] [UIHint("CustomUIHint")] public int HiddenAndUIHint { get; set; } } [Fact] public void HiddenAttributeSetsTemplateHintAndHideSurroundingHtml() { // Arrange var provider = MakeProvider(); // Act & Assert ModelMetadata noAttributeMetadata = provider.GetMetadataForProperty(null, typeof(HiddenModel), "NoAttribute"); Assert.Null(noAttributeMetadata.TemplateHint); Assert.False(noAttributeMetadata.HideSurroundingHtml); ModelMetadata defaultHiddenMetadata = provider.GetMetadataForProperty(null, typeof(HiddenModel), "DefaultHidden"); Assert.Equal("HiddenInput", defaultHiddenMetadata.TemplateHint); Assert.False(defaultHiddenMetadata.HideSurroundingHtml); ModelMetadata hiddenWithDisplayValueFalseMetadata = provider.GetMetadataForProperty(null, typeof(HiddenModel), "HiddenWithDisplayValueFalse"); Assert.Equal("HiddenInput", hiddenWithDisplayValueFalseMetadata.TemplateHint); Assert.True(hiddenWithDisplayValueFalseMetadata.HideSurroundingHtml); // [UIHint] overrides the template hint from [Hidden] Assert.Equal("CustomUIHint", provider.GetMetadataForProperty(null, typeof(HiddenModel), "HiddenAndUIHint").TemplateHint); } // [UIHint] tests class UIHintModel { public int NoAttribute { get; set; } [UIHint("MyCustomTemplate")] public int DefaultUIHint { get; set; } [UIHint("MyMvcTemplate", "MVC")] public int MvcUIHint { get; set; } [UIHint("MyWebFormsTemplate", "WebForms")] public int NoMvcUIHint { get; set; } [UIHint("MyDefaultTemplate")] [UIHint("MyWebFormsTemplate", "WebForms")] [UIHint("MyMvcTemplate", "MVC")] public int MultipleUIHint { get; set; } } [Fact] public void UIHintAttributeSetsTemplateHint() { // Arrange var provider = MakeProvider(); // Act & Assert Assert.Null(provider.GetMetadataForProperty(null, typeof(UIHintModel), "NoAttribute").TemplateHint); Assert.Equal("MyCustomTemplate", provider.GetMetadataForProperty(null, typeof(UIHintModel), "DefaultUIHint").TemplateHint); Assert.Equal("MyMvcTemplate", provider.GetMetadataForProperty(null, typeof(UIHintModel), "MvcUIHint").TemplateHint); Assert.Null(provider.GetMetadataForProperty(null, typeof(UIHintModel), "NoMvcUIHint").TemplateHint); Assert.Equal("MyMvcTemplate", provider.GetMetadataForProperty(null, typeof(UIHintModel), "MultipleUIHint").TemplateHint); } // [DataType] tests class DataTypeModel { public int NoAttribute { get; set; } [DataType(DataType.EmailAddress)] public int EmailAddressProperty { get; set; } [DataType("CustomDataType")] public int CustomDataTypeProperty { get; set; } } [Fact] public void DataTypeAttributeSetsDataTypeName() { // Arrange var provider = MakeProvider(); // Act & Assert Assert.Null(provider.GetMetadataForProperty(null, typeof(DataTypeModel), "NoAttribute").DataTypeName); Assert.Equal("EmailAddress", provider.GetMetadataForProperty(null, typeof(DataTypeModel), "EmailAddressProperty").DataTypeName); Assert.Equal("CustomDataType", provider.GetMetadataForProperty(null, typeof(DataTypeModel), "CustomDataTypeProperty").DataTypeName); } // [ReadOnly] & [Editable] tests class ReadOnlyModel { public int NoAttributes { get; set; } [ReadOnly(true)] public int ReadOnlyAttribute { get; set; } [Editable(false)] public int EditableAttribute { get; set; } [ReadOnly(true)] [Editable(true)] public int BothAttributes { get; set; } // Editable trumps ReadOnly } [Fact] public void ReadOnlyTests() { // Arrange var provider = MakeProvider(); // Act & Assert Assert.False(provider.GetMetadataForProperty(null, typeof(ReadOnlyModel), "NoAttributes").IsReadOnly); Assert.True(provider.GetMetadataForProperty(null, typeof(ReadOnlyModel), "ReadOnlyAttribute").IsReadOnly); Assert.True(provider.GetMetadataForProperty(null, typeof(ReadOnlyModel), "EditableAttribute").IsReadOnly); Assert.False(provider.GetMetadataForProperty(null, typeof(ReadOnlyModel), "BothAttributes").IsReadOnly); } // [DisplayFormat] tests class DisplayFormatModel { public int NoAttribute { get; set; } [DisplayFormat(NullDisplayText = "(null value)")] public int NullDisplayText { get; set; } [DisplayFormat(DataFormatString = "Data {0} format")] public int DisplayFormatString { get; set; } [DisplayFormat(DataFormatString = "Data {0} format", ApplyFormatInEditMode = true)] public int DisplayAndEditFormatString { get; set; } [DisplayFormat(ConvertEmptyStringToNull = true)] public int ConvertEmptyStringToNullTrue { get; set; } [DisplayFormat(ConvertEmptyStringToNull = false)] public int ConvertEmptyStringToNullFalse { get; set; } [DataType(DataType.Currency)] public int DataTypeWithoutDisplayFormatOverride { get; set; } [DataType(DataType.Currency)] [DisplayFormat(DataFormatString = "format override")] public int DataTypeWithDisplayFormatOverride { get; set; } [DisplayFormat(HtmlEncode = true)] public int HtmlEncodeTrue { get; set; } [DisplayFormat(HtmlEncode = false)] public int HtmlEncodeFalse { get; set; } [DataType(DataType.Currency)] [DisplayFormat(HtmlEncode = false)] public int HtmlEncodeFalseWithDataType { get; set; } // DataType trumps DisplayFormat.HtmlEncode } [Fact] public void DisplayFormatAttributetSetsNullDisplayText() { // Arrange var provider = MakeProvider(); // Act & Assert Assert.Null(provider.GetMetadataForProperty(null, typeof(DisplayFormatModel), "NoAttribute").NullDisplayText); Assert.Equal("(null value)", provider.GetMetadataForProperty(null, typeof(DisplayFormatModel), "NullDisplayText").NullDisplayText); } [Fact] public void DisplayFormatAttributeSetsDisplayFormatString() { // Arrange var provider = MakeProvider(); // Act & Assert Assert.Null(provider.GetMetadataForProperty(null, typeof(DisplayFormatModel), "NoAttribute").DisplayFormatString); Assert.Equal("Data {0} format", provider.GetMetadataForProperty(null, typeof(DisplayFormatModel), "DisplayFormatString").DisplayFormatString); Assert.Equal("Data {0} format", provider.GetMetadataForProperty(null, typeof(DisplayFormatModel), "DisplayAndEditFormatString").DisplayFormatString); } [Fact] public void DisplayFormatAttributeSetEditFormatString() { // Arrange var provider = MakeProvider(); // Act & Assert Assert.Null(provider.GetMetadataForProperty(null, typeof(DisplayFormatModel), "NoAttribute").EditFormatString); Assert.Null(provider.GetMetadataForProperty(null, typeof(DisplayFormatModel), "DisplayFormatString").EditFormatString); Assert.Equal("Data {0} format", provider.GetMetadataForProperty(null, typeof(DisplayFormatModel), "DisplayAndEditFormatString").EditFormatString); } [Fact] public void DisplayFormatAttributeSetsConvertEmptyStringToNull() { // Arrange var provider = MakeProvider(); // Act & Assert Assert.True(provider.GetMetadataForProperty(null, typeof(DisplayFormatModel), "NoAttribute").ConvertEmptyStringToNull); Assert.True(provider.GetMetadataForProperty(null, typeof(DisplayFormatModel), "ConvertEmptyStringToNullTrue").ConvertEmptyStringToNull); Assert.False(provider.GetMetadataForProperty(null, typeof(DisplayFormatModel), "ConvertEmptyStringToNullFalse").ConvertEmptyStringToNull); } [Fact] public void DataTypeWithoutDisplayFormatOverrideUsesDataTypesDisplayFormat() { // Arrange var provider = MakeProvider(); // Act string result = provider.GetMetadataForProperty(null, typeof(DisplayFormatModel), "DataTypeWithoutDisplayFormatOverride").DisplayFormatString; // Assert Assert.Equal("{0:C}", result); // Currency's default format string } [Fact] public void DataTypeWithDisplayFormatOverrideUsesDisplayFormatOverride() { // Arrange var provider = MakeProvider(); // Act string result = provider.GetMetadataForProperty(null, typeof(DisplayFormatModel), "DataTypeWithDisplayFormatOverride").DisplayFormatString; // Assert Assert.Equal("format override", result); } [Fact] public void DataTypeInfluencedByDisplayFormatAttributeHtmlEncode() { // Arrange var provider = MakeProvider(); // Act & Assert Assert.Null(provider.GetMetadataForProperty(null, typeof(DisplayFormatModel), "NoAttribute").DataTypeName); Assert.Null(provider.GetMetadataForProperty(null, typeof(DisplayFormatModel), "HtmlEncodeTrue").DataTypeName); Assert.Equal("Html", provider.GetMetadataForProperty(null, typeof(DisplayFormatModel), "HtmlEncodeFalse").DataTypeName); Assert.Equal("Currency", provider.GetMetadataForProperty(null, typeof(DisplayFormatModel), "HtmlEncodeFalseWithDataType").DataTypeName); } // [ScaffoldColumn] tests class ScaffoldColumnModel { public int NoAttribute { get; set; } [ScaffoldColumn(true)] public int ScaffoldColumnTrue { get; set; } [ScaffoldColumn(false)] public int ScaffoldColumnFalse { get; set; } } [Fact] public void ScaffoldColumnAttributeSetsShowForDisplay() { // Arrange var provider = MakeProvider(); // Act & Assert Assert.True(provider.GetMetadataForProperty(null, typeof(ScaffoldColumnModel), "NoAttribute").ShowForDisplay); Assert.True(provider.GetMetadataForProperty(null, typeof(ScaffoldColumnModel), "ScaffoldColumnTrue").ShowForDisplay); Assert.False(provider.GetMetadataForProperty(null, typeof(ScaffoldColumnModel), "ScaffoldColumnFalse").ShowForDisplay); } [Fact] public void ScaffoldColumnAttributeSetsShowForEdit() { // Arrange var provider = MakeProvider(); // Act & Assert Assert.True(provider.GetMetadataForProperty(null, typeof(ScaffoldColumnModel), "NoAttribute").ShowForEdit); Assert.True(provider.GetMetadataForProperty(null, typeof(ScaffoldColumnModel), "ScaffoldColumnTrue").ShowForEdit); Assert.False(provider.GetMetadataForProperty(null, typeof(ScaffoldColumnModel), "ScaffoldColumnFalse").ShowForEdit); } // [DisplayColumn] tests [DisplayColumn("NoPropertyWithThisName")] class UnknownDisplayColumnModel { } [Fact] public void SimpleDisplayNameWithUnknownDisplayColumnThrows() { // Arrange var provider = MakeProvider(); // Act & Assert Assert.Throws( () => provider.GetMetadataForType(() => new UnknownDisplayColumnModel(), typeof(UnknownDisplayColumnModel)).SimpleDisplayText, typeof(UnknownDisplayColumnModel).FullName + " has a DisplayColumn attribute for NoPropertyWithThisName, but property NoPropertyWithThisName does not exist."); } [DisplayColumn("WriteOnlyProperty")] class WriteOnlyDisplayColumnModel { public int WriteOnlyProperty { set { } } } [DisplayColumn("PrivateReadPublicWriteProperty")] class PrivateReadPublicWriteDisplayColumnModel { public int PrivateReadPublicWriteProperty { private get; set; } } [Fact] public void SimpleDisplayTextForTypeWithWriteOnlyDisplayColumnThrows() { // Arrange var provider = MakeProvider(); // Act & Assert Assert.Throws( () => provider.GetMetadataForType(() => new WriteOnlyDisplayColumnModel(), typeof(WriteOnlyDisplayColumnModel)).SimpleDisplayText, typeof(WriteOnlyDisplayColumnModel).FullName + " has a DisplayColumn attribute for WriteOnlyProperty, but property WriteOnlyProperty does not have a public getter."); Assert.Throws( () => provider.GetMetadataForType(() => new PrivateReadPublicWriteDisplayColumnModel(), typeof(PrivateReadPublicWriteDisplayColumnModel)).SimpleDisplayText, typeof(PrivateReadPublicWriteDisplayColumnModel).FullName + " has a DisplayColumn attribute for PrivateReadPublicWriteProperty, but property PrivateReadPublicWriteProperty does not have a public getter."); } [DisplayColumn("DisplayColumnProperty")] class SimpleDisplayTextAttributeModel { public int FirstProperty { get { return 42; } } [ScaffoldColumn(false)] public string DisplayColumnProperty { get; set; } } class SimpleDisplayTextAttributeModelContainer { [DisplayFormat(NullDisplayText = "This is the null display text")] public SimpleDisplayTextAttributeModel Inner { get; set; } } [Fact] public void SimpleDisplayTextForNonNullClassWithNonNullDisplayColumnValue() { // Arrange string expected = "Custom property display value"; var provider = MakeProvider(); var model = new SimpleDisplayTextAttributeModel { DisplayColumnProperty = expected }; var metadata = provider.GetMetadataForType(() => model, typeof(SimpleDisplayTextAttributeModel)); // Act string result = metadata.SimpleDisplayText; // Assert Assert.Equal(expected, result); } [Fact] public void SimpleDisplayTextForNullClassRevertsToDefaultBehavior() { // Arrange var provider = MakeProvider(); var metadata = provider.GetMetadataForProperty(null, typeof(SimpleDisplayTextAttributeModelContainer), "Inner"); // Act string result = metadata.SimpleDisplayText; // Assert Assert.Equal("This is the null display text", result); } [Fact] public void SimpleDisplayTextForNonNullClassWithNullDisplayColumnValueRevertsToDefaultBehavior() { // Arrange var provider = MakeProvider(); var model = new SimpleDisplayTextAttributeModel(); var metadata = provider.GetMetadataForType(() => model, typeof(SimpleDisplayTextAttributeModel)); // Act string result = metadata.SimpleDisplayText; // Assert Assert.Equal("42", result); // Falls back to the default logic of first property value } // [Required] tests class IsRequiredModel { public int NonNullableWithout { get; set; } public string NullableWithout { get; set; } [Required] public string NullableWith { get; set; } } [Fact] public void IsRequiredTests() { // Arrange var provider = MakeProvider(); // Act & Assert Assert.True(provider.GetMetadataForProperty(null, typeof(IsRequiredModel), "NonNullableWithout").IsRequired); Assert.False(provider.GetMetadataForProperty(null, typeof(IsRequiredModel), "NullableWithout").IsRequired); Assert.True(provider.GetMetadataForProperty(null, typeof(IsRequiredModel), "NullableWith").IsRequired); } // [Display] & [DisplayName] tests class DisplayModel { public int NoAttribute { get; set; } // Description [Display] public int DescriptionNotSet { get; set; } [Display(Description = "Description text")] public int DescriptionSet { get; set; } // DisplayName [DisplayName("Value from DisplayName")] public int DisplayNameAttributeNoDisplayAttribute { get; set; } [Display] public int DisplayAttributeNameNotSet { get; set; } [Display(Name = "Non empty name")] public int DisplayAttributeNonEmptyName { get; set; } [Display] [DisplayName("Value from DisplayName")] public int BothAttributesNameNotSet { get; set; } [Display(Name = "Value from Display")] [DisplayName("Value from DisplayName")] public int BothAttributes { get; set; } // Display trumps DisplayName // Order [Display] public int OrderNotSet { get; set; } [Display(Order = 2112)] public int OrderSet { get; set; } // ShortDisplayName [Display] public int ShortNameNotSet { get; set; } [Display(ShortName = "Short name")] public int ShortNameSet { get; set; } // Watermark [Display] public int PromptNotSet { get; set; } [Display(Prompt = "Enter stuff here")] public int PromptSet { get; set; } } [Fact] public void DescriptionTests() { // Arrange var provider = MakeProvider(); // Act & Assert Assert.Null(provider.GetMetadataForProperty(null, typeof(DisplayModel), "NoAttribute").Description); Assert.Null(provider.GetMetadataForProperty(null, typeof(DisplayModel), "DescriptionNotSet").Description); Assert.Equal("Description text", provider.GetMetadataForProperty(null, typeof(DisplayModel), "DescriptionSet").Description); } [Fact] public void DisplayNameTests() { // Arrange var provider = MakeProvider(); // Act & Assert Assert.Null(provider.GetMetadataForProperty(null, typeof(DisplayModel), "NoAttribute").DisplayName); Assert.Equal("Value from DisplayName", provider.GetMetadataForProperty(null, typeof(DisplayModel), "DisplayNameAttributeNoDisplayAttribute").DisplayName); Assert.Null(provider.GetMetadataForProperty(null, typeof(DisplayModel), "DisplayAttributeNameNotSet").DisplayName); Assert.Equal("Non empty name", provider.GetMetadataForProperty(null, typeof(DisplayModel), "DisplayAttributeNonEmptyName").DisplayName); Assert.Equal("Value from DisplayName", provider.GetMetadataForProperty(null, typeof(DisplayModel), "BothAttributesNameNotSet").DisplayName); Assert.Equal("Value from Display", provider.GetMetadataForProperty(null, typeof(DisplayModel), "BothAttributes").DisplayName); } [Fact] public void OrderTests() { // Arrange var provider = MakeProvider(); // Act & Assert Assert.Equal(10000, provider.GetMetadataForProperty(null, typeof(DisplayModel), "NoAttribute").Order); Assert.Equal(10000, provider.GetMetadataForProperty(null, typeof(DisplayModel), "OrderNotSet").Order); Assert.Equal(2112, provider.GetMetadataForProperty(null, typeof(DisplayModel), "OrderSet").Order); } [Fact] public void ShortDisplayNameTests() { // Arrange var provider = MakeProvider(); // Act & Assert Assert.Null(provider.GetMetadataForProperty(null, typeof(DisplayModel), "NoAttribute").ShortDisplayName); Assert.Null(provider.GetMetadataForProperty(null, typeof(DisplayModel), "ShortNameNotSet").ShortDisplayName); Assert.Equal("Short name", provider.GetMetadataForProperty(null, typeof(DisplayModel), "ShortNameSet").ShortDisplayName); } [Fact] public void WatermarkTests() { // Arrange var provider = MakeProvider(); // Act & Assert Assert.Null(provider.GetMetadataForProperty(null, typeof(DisplayModel), "NoAttribute").Watermark); Assert.Null(provider.GetMetadataForProperty(null, typeof(DisplayModel), "PromptNotSet").Watermark); Assert.Equal("Enter stuff here", provider.GetMetadataForProperty(null, typeof(DisplayModel), "PromptSet").Watermark); } } }