Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

349 lines
14 KiB
C#

// 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 class AssociatedMetadataProviderTest
{
// FilterAttributes
[Fact]
public void ReadOnlyAttributeIsFilteredOffWhenContainerTypeIsViewPage()
{
// Arrange
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
// Act
provider.GetMetadataForProperty(() => null, typeof(ViewPage<PropertyModel>), "Model");
// Assert
CreateMetadataParams parms = provider.CreateMetadataLog.Single();
Assert.False(parms.Attributes.Any(a => a is ReadOnlyAttribute));
}
[Fact]
public void ReadOnlyAttributeIsFilteredOffWhenContainerTypeIsViewUserControl()
{
// Arrange
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
// Act
provider.GetMetadataForProperty(() => null, typeof(ViewUserControl<PropertyModel>), "Model");
// Assert
CreateMetadataParams parms = provider.CreateMetadataLog.Single();
Assert.False(parms.Attributes.Any(a => a is ReadOnlyAttribute));
}
[Fact]
public void ReadOnlyAttributeIsPreservedForReadOnlyModelProperties()
{
// Arrange
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
// Act
provider.GetMetadataForProperty(() => null, typeof(ModelWithReadOnlyProperty), "ReadOnlyProperty");
// Assert
CreateMetadataParams parms = provider.CreateMetadataLog.Single();
Assert.True(parms.Attributes.Any(a => a is ReadOnlyAttribute));
}
// GetMetadataForProperties
[Fact]
public void GetMetadataForPropertiesNullContainerTypeThrows()
{
// Arrange
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
// Act & Assert
Assert.ThrowsArgumentNull(
() => provider.GetMetadataForProperties(new Object(), null),
"containerType");
}
[Fact]
public void GetMetadataForPropertiesCreatesMetadataForAllPropertiesOnModelWithPropertyValues()
{
// Arrange
PropertyModel model = new PropertyModel { LocalAttributes = 42, MetadataAttributes = "hello", MixedAttributes = 21.12 };
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
// Act
provider.GetMetadataForProperties(model, typeof(PropertyModel)).ToList(); // Call ToList() to force the lazy evaluation to evaluate
// Assert
CreateMetadataParams local =
provider.CreateMetadataLog.Single(m => m.ContainerType == typeof(PropertyModel) &&
m.PropertyName == "LocalAttributes");
Assert.Equal(typeof(int), local.ModelType);
Assert.Equal(42, local.Model);
Assert.True(local.Attributes.Any(a => a is RequiredAttribute));
CreateMetadataParams metadata =
provider.CreateMetadataLog.Single(m => m.ContainerType == typeof(PropertyModel) &&
m.PropertyName == "MetadataAttributes");
Assert.Equal(typeof(string), metadata.ModelType);
Assert.Equal("hello", metadata.Model);
Assert.True(metadata.Attributes.Any(a => a is RangeAttribute));
CreateMetadataParams mixed =
provider.CreateMetadataLog.Single(m => m.ContainerType == typeof(PropertyModel) &&
m.PropertyName == "MixedAttributes");
Assert.Equal(typeof(double), mixed.ModelType);
Assert.Equal(21.12, mixed.Model);
Assert.True(mixed.Attributes.Any(a => a is RequiredAttribute));
Assert.True(mixed.Attributes.Any(a => a is RangeAttribute));
}
[Fact]
public void GetMetadataForPropertyWithNullContainerReturnsMetadataWithNullValuesForProperties()
{
// Arrange
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
// Act
provider.GetMetadataForProperties(null, typeof(PropertyModel)).ToList(); // Call ToList() to force the lazy evaluation to evaluate
// Assert
Assert.True(provider.CreateMetadataLog.Any());
foreach (var parms in provider.CreateMetadataLog)
{
Assert.Null(parms.Model);
}
}
// GetMetadataForProperty
[Fact]
public void GetMetadataForPropertyNullContainerTypeThrows()
{
// Arrange
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
// Act & Assert
Assert.ThrowsArgumentNull(
() => provider.GetMetadataForProperty(null /* model */, null /* containerType */, "propertyName"),
"containerType");
}
[Fact]
public void GetMetadataForPropertyNullOrEmptyPropertyNameThrows()
{
// Arrange
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
// Act & Assert
Assert.ThrowsArgumentNullOrEmpty(
() => provider.GetMetadataForProperty(null /* model */, typeof(object), null /* propertyName */),
"propertyName");
Assert.ThrowsArgumentNullOrEmpty(
() => provider.GetMetadataForProperty(null, typeof(object), String.Empty),
"propertyName");
}
[Fact]
public void GetMetadataForPropertyInvalidPropertyNameThrows()
{
// Arrange
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
// Act & Assert
Assert.Throws<ArgumentException>(
() => provider.GetMetadataForProperty(null, typeof(object), "BadPropertyName"),
"The property System.Object.BadPropertyName could not be found.");
}
[Fact]
public void GetMetadataForPropertyWithLocalAttributes()
{
// Arrange
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
ModelMetadata metadata = new ModelMetadata(provider, typeof(PropertyModel), null, typeof(int), "LocalAttributes");
provider.CreateMetadataReturnValue = metadata;
// Act
ModelMetadata result = provider.GetMetadataForProperty(null, typeof(PropertyModel), "LocalAttributes");
// Assert
Assert.Same(metadata, result);
Assert.True(provider.CreateMetadataLog.Single().Attributes.Any(a => a is RequiredAttribute));
}
[Fact]
public void GetMetadataForPropertyWithMetadataAttributes()
{
// Arrange
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
ModelMetadata metadata = new ModelMetadata(provider, typeof(PropertyModel), null, typeof(string), "MetadataAttributes");
provider.CreateMetadataReturnValue = metadata;
// Act
ModelMetadata result = provider.GetMetadataForProperty(null, typeof(PropertyModel), "MetadataAttributes");
// Assert
Assert.Same(metadata, result);
CreateMetadataParams parms = provider.CreateMetadataLog.Single(p => p.PropertyName == "MetadataAttributes");
Assert.True(parms.Attributes.Any(a => a is RangeAttribute));
}
[Fact]
public void GetMetadataForPropertyWithMixedAttributes()
{
// Arrange
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
ModelMetadata metadata = new ModelMetadata(provider, typeof(PropertyModel), null, typeof(double), "MixedAttributes");
provider.CreateMetadataReturnValue = metadata;
// Act
ModelMetadata result = provider.GetMetadataForProperty(null, typeof(PropertyModel), "MixedAttributes");
// Assert
Assert.Same(metadata, result);
CreateMetadataParams parms = provider.CreateMetadataLog.Single(p => p.PropertyName == "MixedAttributes");
Assert.True(parms.Attributes.Any(a => a is RequiredAttribute));
Assert.True(parms.Attributes.Any(a => a is RangeAttribute));
}
// GetMetadataForType
[Fact]
public void GetMetadataForTypeNullModelTypeThrows()
{
// Arrange
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
// Act & Assert
Assert.ThrowsArgumentNull(
() => provider.GetMetadataForType(() => new Object(), null),
"modelType");
}
[Fact]
public void GetMetadataForTypeIncludesAttributesOnType()
{
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
ModelMetadata metadata = new ModelMetadata(provider, null, null, typeof(TypeModel), null);
provider.CreateMetadataReturnValue = metadata;
// Act
ModelMetadata result = provider.GetMetadataForType(null, typeof(TypeModel));
// Assert
Assert.Same(metadata, result);
CreateMetadataParams parms = provider.CreateMetadataLog.Single(p => p.ModelType == typeof(TypeModel));
Assert.True(parms.Attributes.Any(a => a is ReadOnlyAttribute));
}
[AdditionalMetadata("ClassName", "ClassValue")]
class ClassWithAdditionalMetadata
{
[AdditionalMetadata("PropertyName", "PropertyValue")]
public int MyProperty { get; set; }
}
[Fact]
public void MetadataAwareAttributeCanModifyTypeMetadata()
{
// Arrange
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
provider.CreateMetadataReturnValue = new ModelMetadata(provider, null, null, typeof(ClassWithAdditionalMetadata), null);
// Act
ModelMetadata metadata = provider.GetMetadataForType(null, typeof(ClassWithAdditionalMetadata));
// Assert
var kvp = metadata.AdditionalValues.Single();
Assert.Equal("ClassName", kvp.Key);
Assert.Equal("ClassValue", kvp.Value);
}
[Fact]
public void MetadataAwareAttributeCanModifyPropertyMetadata()
{
// Arrange
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
provider.CreateMetadataReturnValue = new ModelMetadata(provider, typeof(ClassWithAdditionalMetadata), null, typeof(int), "MyProperty");
// Act
ModelMetadata metadata = provider.GetMetadataForProperty(null, typeof(ClassWithAdditionalMetadata), "MyProperty");
// Assert
var kvp = metadata.AdditionalValues.Single();
Assert.Equal("PropertyName", kvp.Key);
Assert.Equal("PropertyValue", kvp.Value);
}
// Helpers
[MetadataType(typeof(Metadata))]
private class PropertyModel
{
[Required]
public int LocalAttributes { get; set; }
public string MetadataAttributes { get; set; }
[Required]
public double MixedAttributes { get; set; }
private class Metadata
{
[Range(10, 100)]
public object MetadataAttributes { get; set; }
[Range(10, 100)]
public object MixedAttributes { get; set; }
}
}
private class ModelWithReadOnlyProperty
{
public int ReadOnlyProperty { get; private set; }
}
[ReadOnly(true)]
private class TypeModel
{
}
class TestableAssociatedMetadataProvider : AssociatedMetadataProvider
{
public List<CreateMetadataParams> CreateMetadataLog = new List<CreateMetadataParams>();
public ModelMetadata CreateMetadataReturnValue = null;
protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType,
Func<object> modelAccessor, Type modelType,
string propertyName)
{
CreateMetadataLog.Add(new CreateMetadataParams
{
Attributes = attributes,
ContainerType = containerType,
Model = modelAccessor == null ? null : modelAccessor(),
ModelType = modelType,
PropertyName = propertyName
});
return CreateMetadataReturnValue;
}
}
class CreateMetadataParams
{
public IEnumerable<Attribute> Attributes { get; set; }
public Type ContainerType { get; set; }
public object Model { get; set; }
public Type ModelType { get; set; }
public string PropertyName { get; set; }
}
}
}