// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Linq.Expressions; using Moq; using Xunit; using Assert = Microsoft.TestCommon.AssertEx; namespace System.Web.Mvc.Test { public class ModelMetadataTest { // Guard clauses [Fact] public void NullProviderThrows() { // Act & Assert Assert.ThrowsArgumentNull( () => new ModelMetadata(null /* provider */, null /* containerType */, null /* model */, typeof(object), null /* propertyName */), "provider"); } [Fact] public void NullTypeThrows() { // Arrange Mock provider = new Mock(); // Act & Assert Assert.ThrowsArgumentNull( () => new ModelMetadata(provider.Object, null /* containerType */, null /* model */, null /* modelType */, null /* propertyName */), "modelType"); } // Constructor [Fact] public void DefaultValues() { // Arrange Mock provider = new Mock(); // Act ModelMetadata metadata = new ModelMetadata(provider.Object, typeof(Exception), () => "model", typeof(string), "propertyName"); // Assert Assert.Equal(typeof(Exception), metadata.ContainerType); Assert.True(metadata.ConvertEmptyStringToNull); Assert.Null(metadata.DataTypeName); Assert.Null(metadata.Description); Assert.Null(metadata.DisplayFormatString); Assert.Null(metadata.DisplayName); Assert.Null(metadata.EditFormatString); Assert.False(metadata.HideSurroundingHtml); Assert.Equal("model", metadata.Model); Assert.Equal(typeof(string), metadata.ModelType); Assert.Null(metadata.NullDisplayText); Assert.Equal(10000, metadata.Order); Assert.Equal("propertyName", metadata.PropertyName); Assert.False(metadata.IsReadOnly); Assert.True(metadata.RequestValidationEnabled); Assert.Null(metadata.ShortDisplayName); Assert.True(metadata.ShowForDisplay); Assert.True(metadata.ShowForEdit); Assert.Null(metadata.TemplateHint); Assert.Null(metadata.Watermark); } // IsComplexType struct IsComplexTypeModel { } [Fact] public void IsComplexTypeTests() { // Arrange Mock provider = new Mock(); // Act & Assert Assert.True(new ModelMetadata(provider.Object, null, null, typeof(Object), null).IsComplexType); Assert.False(new ModelMetadata(provider.Object, null, null, typeof(string), null).IsComplexType); Assert.True(new ModelMetadata(provider.Object, null, null, typeof(IDisposable), null).IsComplexType); Assert.False(new ModelMetadata(provider.Object, null, null, typeof(Nullable), null).IsComplexType); Assert.False(new ModelMetadata(provider.Object, null, null, typeof(int), null).IsComplexType); Assert.True(new ModelMetadata(provider.Object, null, null, typeof(IsComplexTypeModel), null).IsComplexType); Assert.True(new ModelMetadata(provider.Object, null, null, typeof(Nullable), null).IsComplexType); } // IsNullableValueType [Fact] public void IsNullableValueTypeTests() { // Arrange Mock provider = new Mock(); // Act & Assert Assert.False(new ModelMetadata(provider.Object, null, null, typeof(string), null).IsNullableValueType); Assert.False(new ModelMetadata(provider.Object, null, null, typeof(IDisposable), null).IsNullableValueType); Assert.True(new ModelMetadata(provider.Object, null, null, typeof(Nullable), null).IsNullableValueType); Assert.False(new ModelMetadata(provider.Object, null, null, typeof(int), null).IsNullableValueType); } // IsRequired [Fact] public void IsRequiredTests() { // Arrange Mock provider = new Mock(); // Act & Assert Assert.False(new ModelMetadata(provider.Object, null, null, typeof(string), null).IsRequired); // Reference type not required Assert.False(new ModelMetadata(provider.Object, null, null, typeof(IDisposable), null).IsRequired); // Interface not required Assert.False(new ModelMetadata(provider.Object, null, null, typeof(Nullable), null).IsRequired); // Nullable value type not required Assert.True(new ModelMetadata(provider.Object, null, null, typeof(int), null).IsRequired); // Value type required Assert.True(new ModelMetadata(provider.Object, null, null, typeof(DayOfWeek), null).IsRequired); // Enum (implicit value type) is required } // Properties [Fact] public void PropertiesCallsProvider() { // Arrange Type modelType = typeof(string); List propertyMetadata = new List(); Mock provider = new Mock(); ModelMetadata metadata = new ModelMetadata(provider.Object, null, null, modelType, null); provider.Setup(p => p.GetMetadataForProperties(null, modelType)) .Returns(propertyMetadata) .Verifiable(); // Act IEnumerable result = metadata.Properties; // Assert Assert.Equal(propertyMetadata, result.ToList()); provider.Verify(); } [Fact] public void PropertiesUsesRealModelTypeRatherThanPassedModelType() { // Arrange string model = "String Value"; Expression> accessor = _ => model; ModelMetadata metadata = ModelMetadata.FromLambdaExpression(accessor, new ViewDataDictionary()); // Act IEnumerable result = metadata.Properties; // Assert Assert.Equal("Length", result.Single().PropertyName); } [Fact] public void PropertiesAreSortedByOrder() { // Arrange Type modelType = typeof(string); Mock provider = new Mock(); List propertyMetadata = new List { new ModelMetadata(provider.Object, null, () => 1, typeof(int), null) { Order = 20 }, new ModelMetadata(provider.Object, null, () => 2, typeof(int), null) { Order = 30 }, new ModelMetadata(provider.Object, null, () => 3, typeof(int), null) { Order = 10 }, }; ModelMetadata metadata = new ModelMetadata(provider.Object, null, null, modelType, null); provider.Setup(p => p.GetMetadataForProperties(null, modelType)) .Returns(propertyMetadata) .Verifiable(); // Act List result = metadata.Properties.ToList(); // Assert Assert.Equal(3, result.Count); Assert.Equal(3, result[0].Model); Assert.Equal(1, result[1].Model); Assert.Equal(2, result[2].Model); } [Fact] public void PropertiesListGetsResetWhenModelGetsReset() { // Dev10 Bug #923263 // Arrange var provider = new DataAnnotationsModelMetadataProvider(); var metadata = new ModelMetadata(provider, null, () => new Class1(), typeof(Class1), null); // Act ModelMetadata[] originalProps = metadata.Properties.ToArray(); metadata.Model = new Class2(); ModelMetadata[] newProps = metadata.Properties.ToArray(); // Assert ModelMetadata originalProp = Assert.Single(originalProps); Assert.Equal(typeof(string), originalProp.ModelType); Assert.Equal("Prop1", originalProp.PropertyName); ModelMetadata newProp = Assert.Single(newProps); Assert.Equal(typeof(int), newProp.ModelType); Assert.Equal("Prop2", newProp.PropertyName); } class Class1 { public string Prop1 { get; set; } } class Class2 { public int Prop2 { get; set; } } // SimpleDisplayText [Fact] public void SimpleDisplayTextReturnsNullDisplayTextForNullModel() { // Arrange string nullText = "(null)"; Mock provider = new Mock(); ModelMetadata metadata = new ModelMetadata(provider.Object, null, null, typeof(object), null) { NullDisplayText = nullText }; // Act string result = metadata.SimpleDisplayText; // Assert Assert.Equal(nullText, result); } private class SimpleDisplayTextModelWithToString { public override string ToString() { return "Custom ToString Value"; } } [Fact] public void SimpleDisplayTextReturnsToStringValueWhenOverridden() { // Arrange SimpleDisplayTextModelWithToString model = new SimpleDisplayTextModelWithToString(); EmptyModelMetadataProvider provider = new EmptyModelMetadataProvider(); ModelMetadata metadata = new ModelMetadata(provider, null, () => model, typeof(SimpleDisplayTextModelWithToString), null); // Act string result = metadata.SimpleDisplayText; // Assert Assert.Equal(model.ToString(), result); } private class SimpleDisplayTextModelWithoutToString { public string FirstProperty { get; set; } public int SecondProperty { get; set; } } [Fact] public void SimpleDisplayTextReturnsFirstPropertyValueForNonNullModel() { // Arrange SimpleDisplayTextModelWithoutToString model = new SimpleDisplayTextModelWithoutToString { FirstProperty = "First Property Value" }; EmptyModelMetadataProvider provider = new EmptyModelMetadataProvider(); ModelMetadata metadata = new ModelMetadata(provider, null, () => model, typeof(SimpleDisplayTextModelWithoutToString), null); // Act string result = metadata.SimpleDisplayText; // Assert Assert.Equal(model.FirstProperty, result); } [Fact] public void SimpleDisplayTextReturnsFirstPropertyNullDisplayTextForNonNullModelWithNullDisplayColumnPropertyValue() { // Arrange SimpleDisplayTextModelWithoutToString model = new SimpleDisplayTextModelWithoutToString(); EmptyModelMetadataProvider propertyProvider = new EmptyModelMetadataProvider(); ModelMetadata propertyMetadata = propertyProvider.GetMetadataForProperty(() => model.FirstProperty, typeof(SimpleDisplayTextModelWithoutToString), "FirstProperty"); propertyMetadata.NullDisplayText = "Null Display Text"; Mock provider = new Mock(); provider.Setup(p => p.GetMetadataForProperties(model, typeof(SimpleDisplayTextModelWithoutToString))) .Returns(new[] { propertyMetadata }); ModelMetadata metadata = new ModelMetadata(provider.Object, null, () => model, typeof(SimpleDisplayTextModelWithoutToString), null); // Act string result = metadata.SimpleDisplayText; // Assert Assert.Equal(propertyMetadata.NullDisplayText, result); } private class SimpleDisplayTextModelWithNoProperties { } [Fact] public void SimpleDisplayTextReturnsEmptyStringForNonNullModelWithNoVisibleProperties() { // Arrange SimpleDisplayTextModelWithNoProperties model = new SimpleDisplayTextModelWithNoProperties(); EmptyModelMetadataProvider provider = new EmptyModelMetadataProvider(); ModelMetadata metadata = new ModelMetadata(provider, null, () => model, typeof(SimpleDisplayTextModelWithNoProperties), null); // Act string result = metadata.SimpleDisplayText; // Assert Assert.Equal(String.Empty, result); } private class ObjectWithToStringOverride { private string _toStringValue; public ObjectWithToStringOverride(string toStringValue) { _toStringValue = toStringValue; } public override string ToString() { return _toStringValue; } } [Fact] public void SimpleDisplayTextReturnsToStringOfModelForNonNullModel() { // Arrange string toStringText = "text from ToString()"; ObjectWithToStringOverride model = new ObjectWithToStringOverride(toStringText); Mock provider = new Mock(); ModelMetadata metadata = new ModelMetadata(provider.Object, null, () => model, typeof(ObjectWithToStringOverride), null); // Act string result = metadata.SimpleDisplayText; // Assert Assert.Equal(toStringText, result); } [Fact] public void SimpleDisplayTextReturnsEmptyStringForNonNullModelWithToStringNull() { // Arrange string toStringText = null; ObjectWithToStringOverride model = new ObjectWithToStringOverride(toStringText); Mock provider = new Mock(); ModelMetadata metadata = new ModelMetadata(provider.Object, null, () => model, typeof(ObjectWithToStringOverride), null); // Act string result = metadata.SimpleDisplayText; // Assert Assert.Equal(String.Empty, result); } // FromStringExpression() [Fact] public void FromStringExpressionGuardClauses() { // Null expression throws Assert.ThrowsArgumentNull( () => ModelMetadata.FromStringExpression(null, new ViewDataDictionary()), "expression"); // Null view data dictionary throws Assert.ThrowsArgumentNull( () => ModelMetadata.FromStringExpression("expression", null), "viewData"); } [Fact] public void FromStringExpressionEmptyExpressionReturnsExistingModelMetadata() { // Arrange Mock provider = new Mock(); ModelMetadata metadata = new ModelMetadata(provider.Object, null, null, typeof(object), null); ViewDataDictionary viewData = new ViewDataDictionary(); viewData.ModelMetadata = metadata; // Act ModelMetadata result = ModelMetadata.FromStringExpression(String.Empty, viewData, provider.Object); // Assert Assert.Same(metadata, result); } [Fact] public void FromStringExpressionItemNotFoundInViewData() { // Arrange Mock provider = new Mock(); ViewDataDictionary viewData = new ViewDataDictionary(); provider.Setup(p => p.GetMetadataForType(It.IsAny>(), It.IsAny())) .Callback, Type>((accessor, type) => { Assert.Null(accessor); Assert.Equal(typeof(string), type); // Don't know the type, must fall back on string }) .Returns(() => null) .Verifiable(); // Act ModelMetadata.FromStringExpression("UnknownObject", viewData, provider.Object); // Assert provider.Verify(); } [Fact] public void FromStringExpressionNullItemFoundAtRootOfViewData() { // Arrange Mock provider = new Mock(); ViewDataDictionary viewData = new ViewDataDictionary(); viewData["Object"] = null; provider.Setup(p => p.GetMetadataForType(It.IsAny>(), It.IsAny())) .Callback, Type>((accessor, type) => { Assert.Null(accessor()); Assert.Equal(typeof(string), type); // Don't know the type, must fall back on string }) .Returns(() => null) .Verifiable(); // Act ModelMetadata.FromStringExpression("Object", viewData, provider.Object); // Assert provider.Verify(); } [Fact] public void FromStringExpressionNonNullItemFoundAtRootOfViewData() { // Arrange Mock provider = new Mock(); object model = new object(); ViewDataDictionary viewData = new ViewDataDictionary(); viewData["Object"] = model; provider.Setup(p => p.GetMetadataForType(It.IsAny>(), It.IsAny())) .Callback, Type>((accessor, type) => { Assert.Same(model, accessor()); Assert.Equal(typeof(object), type); }) .Returns(() => null) .Verifiable(); // Act ModelMetadata.FromStringExpression("Object", viewData, provider.Object); // Assert provider.Verify(); } [Fact] public void FromStringExpressionNullItemFoundOnPropertyOfItemInViewData() { // Arrange Mock provider = new Mock(); DummyModelContainer model = new DummyModelContainer(); ViewDataDictionary viewData = new ViewDataDictionary(); viewData["Object"] = model; provider.Setup(p => p.GetMetadataForProperty(It.IsAny>(), It.IsAny(), It.IsAny())) .Callback, Type, string>((accessor, type, propertyName) => { Assert.Null(accessor()); Assert.Equal(typeof(DummyModelContainer), type); Assert.Equal("Model", propertyName); }) .Returns(() => null) .Verifiable(); // Act ModelMetadata.FromStringExpression("Object.Model", viewData, provider.Object); // Assert provider.Verify(); } [Fact] public void FromStringExpressionNonNullItemFoundOnPropertyOfItemInViewData() { // Arrange Mock provider = new Mock(); DummyModelContainer model = new DummyModelContainer { Model = new DummyContactModel() }; ViewDataDictionary viewData = new ViewDataDictionary(); viewData["Object"] = model; provider.Setup(p => p.GetMetadataForProperty(It.IsAny>(), It.IsAny(), It.IsAny())) .Callback, Type, string>((accessor, type, propertyName) => { Assert.Same(model.Model, accessor()); Assert.Equal(typeof(DummyModelContainer), type); Assert.Equal("Model", propertyName); }) .Returns(() => null) .Verifiable(); // Act ModelMetadata.FromStringExpression("Object.Model", viewData, provider.Object); // Assert provider.Verify(); } [Fact] public void FromStringExpressionWithNullModelButValidModelMetadataShouldReturnProperPropertyMetadata() { // Arrange ViewDataDictionary viewData = new ViewDataDictionary(); viewData.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(DummyContactModel)); // Act ModelMetadata result = ModelMetadata.FromStringExpression("NullableIntValue", viewData); // Assert Assert.Null(result.Model); Assert.Equal(typeof(Nullable), result.ModelType); Assert.Equal("NullableIntValue", result.PropertyName); Assert.Equal(typeof(DummyContactModel), result.ContainerType); } [Fact] public void FromStringExpressionValueInModelProperty() { // Arrange DummyContactModel model = new DummyContactModel { FirstName = "John" }; ViewDataDictionary viewData = new ViewDataDictionary(model); // Act ModelMetadata metadata = ModelMetadata.FromStringExpression("FirstName", viewData); // Assert Assert.Equal("John", metadata.Model); } [Fact] public void FromStringExpressionValueInViewDataOverridesValueFromModelProperty() { // Arrange DummyContactModel model = new DummyContactModel { FirstName = "John" }; ViewDataDictionary viewData = new ViewDataDictionary(model); viewData["FirstName"] = "Jim"; // Act ModelMetadata metadata = ModelMetadata.FromStringExpression("FirstName", viewData); // Assert Assert.Equal("Jim", metadata.Model); } // FromLambdaExpression() [Fact] public void FromLambdaExpressionGuardClauseTests() { // Null expression throws Assert.ThrowsArgumentNull( () => ModelMetadata.FromLambdaExpression(null, new ViewDataDictionary()), "expression"); // Null view data throws Assert.ThrowsArgumentNull( () => ModelMetadata.FromLambdaExpression(m => m, null), "viewData"); // Unsupported expression type throws Assert.Throws( () => ModelMetadata.FromLambdaExpression(m => new Object(), new ViewDataDictionary()), "Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions."); } [Fact] public void FromLambdaExpressionModelIdentityExpressionReturnsExistingModelMetadata() { // Arrange Mock provider = new Mock(); ModelMetadata metadata = new ModelMetadata(provider.Object, null, null, typeof(object), null); ViewDataDictionary viewData = new ViewDataDictionary(); viewData.ModelMetadata = metadata; // Act ModelMetadata result = ModelMetadata.FromLambdaExpression(m => m, viewData, provider.Object); // Assert Assert.Same(metadata, result); } [Fact] public void FromLambdaExpressionPropertyExpressionFromParameter() { // Arrange Mock provider = new Mock(); DummyContactModel model = new DummyContactModel { FirstName = "Test" }; ViewDataDictionary viewData = new ViewDataDictionary(model); provider.Setup(p => p.GetMetadataForProperty(It.IsAny>(), It.IsAny(), It.IsAny())) .Callback, Type, string>((accessor, type, propertyName) => { Assert.Equal("Test", accessor()); Assert.Equal(typeof(DummyContactModel), type); Assert.Equal("FirstName", propertyName); }) .Returns(() => null) .Verifiable(); // Act ModelMetadata.FromLambdaExpression(m => m.FirstName, viewData, provider.Object); // Assert provider.Verify(); } [Fact] public void FromLambdaExpressionPropertyExpressionFromClosureValue() { // Arrange Mock provider = new Mock(); DummyContactModel model = new DummyContactModel { FirstName = "Test" }; ViewDataDictionary viewData = new ViewDataDictionary(); provider.Setup(p => p.GetMetadataForProperty(It.IsAny>(), It.IsAny(), It.IsAny())) .Callback, Type, string>((accessor, type, propertyName) => { Assert.Equal("Test", accessor()); Assert.Equal(typeof(DummyContactModel), type); Assert.Equal("FirstName", propertyName); }) .Returns(() => null) .Verifiable(); // Act ModelMetadata.FromLambdaExpression(m => model.FirstName, viewData, provider.Object); // Assert provider.Verify(); } [Fact] public void FromLambdaExpressionFieldExpressionFromParameter() { // Arrange Mock provider = new Mock(); DummyContactModel model = new DummyContactModel { IntField = 42 }; ViewDataDictionary viewData = new ViewDataDictionary(model); provider.Setup(p => p.GetMetadataForType(It.IsAny>(), It.IsAny())) .Callback, Type>((accessor, type) => { Assert.Equal(42, accessor()); Assert.Equal(typeof(int), type); }) .Returns(() => null) .Verifiable(); // Act ModelMetadata.FromLambdaExpression(m => m.IntField, viewData, provider.Object); // Assert provider.Verify(); } [Fact] public void FromLambdaExpressionFieldExpressionFromFieldOfClosureValue() { // Arrange Mock provider = new Mock(); DummyContactModel model = new DummyContactModel { IntField = 42 }; ViewDataDictionary viewData = new ViewDataDictionary(); provider.Setup(p => p.GetMetadataForType(It.IsAny>(), It.IsAny())) .Callback, Type>((accessor, type) => { Assert.Equal(42, accessor()); Assert.Equal(typeof(int), type); }) .Returns(() => null) .Verifiable(); // Act ModelMetadata.FromLambdaExpression(m => model.IntField, viewData, provider.Object); // Assert provider.Verify(); } [Fact] public void FromLambdaExpressionFieldExpressionFromClosureValue() { // Arrange Mock provider = new Mock(); DummyContactModel model = new DummyContactModel(); ViewDataDictionary viewData = new ViewDataDictionary(); provider.Setup(p => p.GetMetadataForType(It.IsAny>(), It.IsAny())) .Callback, Type>((accessor, type) => { Assert.Same(model, accessor()); Assert.Equal(typeof(DummyContactModel), type); }) .Returns(() => null) .Verifiable(); // Act ModelMetadata.FromLambdaExpression(m => model, viewData, provider.Object); // Assert provider.Verify(); } [Fact] public void FromLambdaExpressionSingleParameterClassIndexer() { // Arrange Mock provider = new Mock(); DummyContactModel model = new DummyContactModel(); ViewDataDictionary viewData = new ViewDataDictionary(model); provider.Setup(p => p.GetMetadataForType(It.IsAny>(), It.IsAny())) .Callback, Type>((accessor, type) => { Assert.Equal("Indexed into 42", accessor()); Assert.Equal(typeof(string), type); }) .Returns(() => null) .Verifiable(); // Act ModelMetadata.FromLambdaExpression(m => m[42], viewData, provider.Object); // Assert provider.Verify(); } [Fact] public void FromLambdaExpressionSingleDimensionArrayIndex() { // Arrange Mock provider = new Mock(); DummyContactModel model = new DummyContactModel { Array = new[] { 4, 8, 15, 16, 23, 42 } }; ViewDataDictionary viewData = new ViewDataDictionary(model); provider.Setup(p => p.GetMetadataForType(It.IsAny>(), It.IsAny())) .Callback, Type>((accessor, type) => { Assert.Equal(16, accessor()); Assert.Equal(typeof(int), type); }) .Returns(() => null) .Verifiable(); // Act ModelMetadata.FromLambdaExpression(m => m.Array[3], viewData, provider.Object); // Assert provider.Verify(); } [Fact] public void FromLambdaExpressionNullReferenceExceptionsInPropertyExpressionPreserveAllExpressionInformation() { // Arrange Mock provider = new Mock(); ViewDataDictionary viewData = new ViewDataDictionary(); provider.Setup(p => p.GetMetadataForProperty(It.IsAny>(), It.IsAny(), It.IsAny())) .Callback, Type, string>((accessor, type, propertyName) => { Assert.Null(accessor()); Assert.Equal(typeof(DummyContactModel), type); Assert.Equal("FirstName", propertyName); }) .Returns(() => null) .Verifiable(); // Act ModelMetadata.FromLambdaExpression(m => m.FirstName, viewData, provider.Object); // Assert provider.Verify(); } [Fact] public void FromLambdaExpressionSetsContainerTypeToDerivedMostType() { // Dev10 Bug #868619 // Arrange Mock provider = new Mock(); ViewDataDictionary viewData = new ViewDataDictionary(); provider.Setup(p => p.GetMetadataForProperty(It.IsAny>(), It.IsAny(), It.IsAny())) .Callback, Type, string>((accessor, type, propertyName) => { Assert.Null(accessor()); Assert.Equal(typeof(DerivedModel), type); Assert.Equal("MyProperty", propertyName); }) .Returns(() => null) .Verifiable(); // Act ModelMetadata.FromLambdaExpression(m => m.MyProperty, viewData, provider.Object); // Assert provider.Verify(); } private class BaseModel { public virtual string MyProperty { get; set; } } private class DerivedModel : BaseModel { [Required] public override string MyProperty { get { return base.MyProperty; } set { base.MyProperty = value; } } } // GetDisplayName() [Fact] public void ReturnsDisplayNameWhenSet() { // Arrange Mock provider = new Mock(); ModelMetadata metadata = new ModelMetadata(provider.Object, null, null, typeof(object), "PropertyName") { DisplayName = "Display Name" }; // Act string result = metadata.GetDisplayName(); // Assert Assert.Equal("Display Name", result); } [Fact] public void ReturnsPropertyNameWhenSetAndDisplayNameIsNull() { // Arrange Mock provider = new Mock(); ModelMetadata metadata = new ModelMetadata(provider.Object, null, null, typeof(object), "PropertyName"); // Act string result = metadata.GetDisplayName(); // Assert Assert.Equal("PropertyName", result); } [Fact] public void ReturnsTypeNameWhenPropertyNameAndDisplayNameAreNull() { // Arrange Mock provider = new Mock(); ModelMetadata metadata = new ModelMetadata(provider.Object, null, null, typeof(object), null); // Act string result = metadata.GetDisplayName(); // Assert Assert.Equal("Object", result); } // Helpers private class DummyContactModel { public int IntField = 0; public string FirstName { get; set; } public string LastName { get; set; } public Nullable NullableIntValue { get; set; } public int[] Array { get; set; } public string this[int index] { get { return "Indexed into " + index; } } } private class DummyModelContainer { public DummyContactModel Model { get; set; } } } }