aspnetcore/test/Microsoft.AspNet.Mvc.ModelB.../Metadata/AssociatedMetadataProviderT...

261 lines
9.9 KiB
C#

// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
#if ASPNET50
using System.ComponentModel;
#endif
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Microsoft.AspNet.Testing;
using Xunit;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
public class AssociatedMetadataProviderTest
{
// GetMetadataForProperties
[Fact]
public void GetMetadataForPropertiesCreatesMetadataForAllPropertiesOnModelWithPropertyValues()
{
// Arrange
var model = new PropertyModel { LocalAttributes = 42, MetadataAttributes = "hello", MixedAttributes = 21.12 };
var provider = new TestableAssociatedMetadataProvider();
// Act
// Call ToList() to force the lazy evaluation to evaluate
provider.GetMetadataForProperties(typeof(PropertyModel)).ToList();
// Assert
var local = Assert.Single(
provider.CreateMetadataPrototypeLog,
m => m.ContainerType == typeof(PropertyModel) && m.PropertyName == "LocalAttributes");
Assert.Equal(typeof(int), local.ModelType);
Assert.True(local.Attributes.Any(a => a is RequiredAttribute));
var metadata = Assert.Single(
provider.CreateMetadataPrototypeLog,
m => m.ContainerType == typeof(PropertyModel) && m.PropertyName == "MetadataAttributes");
Assert.Equal(typeof(string), metadata.ModelType);
Assert.True(metadata.Attributes.Any(a => a is RangeAttribute));
var mixed = Assert.Single(
provider.CreateMetadataPrototypeLog,
m => m.ContainerType == typeof(PropertyModel) && m.PropertyName == "MixedAttributes");
Assert.Equal(typeof(double), mixed.ModelType);
Assert.True(mixed.Attributes.Any(a => a is RequiredAttribute));
Assert.True(mixed.Attributes.Any(a => a is RangeAttribute));
}
[Fact]
public void GetMetadataForProperties_ExcludesIndexers()
{
// Arrange
var model = new ModelWithIndexer();
var provider = new TestableAssociatedMetadataProvider();
var modelType = model.GetType();
// Act
provider.GetMetadataForProperties(modelType).ToList();
// Assert
Assert.Equal(2, provider.CreateMetadataFromPrototypeLog.Count);
var valueMetadata = Assert.Single(
provider.CreateMetadataPrototypeLog,
m => m.ContainerType == modelType && m.PropertyName == "Value");
Assert.Equal(typeof(string), valueMetadata.ModelType);
Assert.Single(valueMetadata.Attributes.OfType<MinLengthAttribute>());
var testPropertyMetadata = Assert.Single(
provider.CreateMetadataPrototypeLog,
m => m.ContainerType == modelType && m.PropertyName == "TestProperty");
Assert.Equal(typeof(string), testPropertyMetadata.ModelType);
}
[Fact]
public void GetMetadataForParameterNullOrEmptyPropertyNameThrows()
{
// Arrange
var provider = new TestableAssociatedMetadataProvider();
// Act & Assert
ExceptionAssert.ThrowsArgumentNullOrEmpty(
() => provider.GetMetadataForParameter(methodInfo: null, parameterName: null),
"parameterName");
ExceptionAssert.ThrowsArgumentNullOrEmpty(
() => provider.GetMetadataForParameter(methodInfo: null, parameterName: null),
"parameterName");
}
// GetMetadata and access metadata for a property
[Fact]
public void GetMetadataForProperty_WithLocalAttributes()
{
// Arrange
var provider = new TestableAssociatedMetadataProvider();
var metadata = new ModelMetadata(provider, null, typeof(PropertyModel), null);
var propertyMetadata = new ModelMetadata(provider, typeof(PropertyModel), typeof(int), "LocalAttributes");
provider.CreateMetadataFromPrototypeReturnValue = propertyMetadata;
// Act
var result = provider.GetMetadataForProperty(typeof(PropertyModel), "LocalAttributes");
// Assert
Assert.Same(propertyMetadata, result);
var localAttributes = Assert.Single(
provider.CreateMetadataPrototypeLog,
parameters => parameters.PropertyName == "LocalAttributes");
Assert.Single(localAttributes.Attributes, a => a is RequiredAttribute);
}
[Fact]
public void GetMetadataForProperty_WithMetadataAttributes()
{
// Arrange
var provider = new TestableAssociatedMetadataProvider();
var metadata = new ModelMetadata(provider, null, typeof(PropertyModel), null);
var propertyMetadata = new ModelMetadata(provider, typeof(PropertyModel), typeof(string), "MetadataAttributes");
provider.CreateMetadataFromPrototypeReturnValue = propertyMetadata;
// Act
var result = metadata.Properties["MetadataAttributes"];
// Assert
Assert.Same(propertyMetadata, result);
var parmaters = Assert.Single(
provider.CreateMetadataPrototypeLog,
p => p.PropertyName == "MetadataAttributes");
Assert.Single(parmaters.Attributes, a => a is RangeAttribute);
}
[Fact]
public void GetMetadataForProperty_WithMixedAttributes()
{
// Arrange
var provider = new TestableAssociatedMetadataProvider();
var metadata = new ModelMetadata(provider, null, typeof(PropertyModel), null);
var propertyMetadata = new ModelMetadata(provider, typeof(PropertyModel), typeof(double), "MixedAttributes");
provider.CreateMetadataFromPrototypeReturnValue = propertyMetadata;
// Act
var result = metadata.Properties["MixedAttributes"];
// Assert
Assert.Same(propertyMetadata, result);
var parms = Assert.Single(provider.CreateMetadataPrototypeLog, p => p.PropertyName == "MixedAttributes");
Assert.Single(parms.Attributes, a => a is RequiredAttribute);
Assert.Single(parms.Attributes, a => a is RangeAttribute);
}
// GetMetadataForType
#if ASPNET50 // No ReadOnlyAttribute in K
[Fact]
public void GetMetadataForTypeIncludesAttributesOnType()
{
var provider = new TestableAssociatedMetadataProvider();
var metadata = new ModelMetadata(provider, null, typeof(TypeModel), null);
provider.CreateMetadataFromPrototypeReturnValue = metadata;
// Act
var result = provider.GetMetadataForType(typeof(TypeModel));
// Assert
Assert.Same(metadata, result);
var parms = Assert.Single(provider.CreateMetadataPrototypeLog, p => p.ModelType == typeof(TypeModel));
Assert.Single(parms.Attributes, a => a is ReadOnlyAttribute);
}
#endif
// Helpers
private class PropertyModel
{
[Required]
public int LocalAttributes { get; set; }
[Range(10, 100)]
public string MetadataAttributes { get; set; }
[Required]
[Range(10, 100)]
public double MixedAttributes { get; set; }
}
private class BaseType
{
public string TestProperty { get; set; }
}
private class ModelWithIndexer : BaseType
{
public string this[string x]
{
get { return string.Empty; }
set { }
}
[MinLength(4)]
public string Value { get; set; }
}
#if ASPNET50 // No [ReadOnly] in K
[ReadOnly(true)]
private class TypeModel
{
}
#endif
private class TestableAssociatedMetadataProvider : AssociatedMetadataProvider<ModelMetadata>
{
public List<CreateMetadataPrototypeParams> CreateMetadataPrototypeLog = new List<CreateMetadataPrototypeParams>();
public List<CreateMetadataFromPrototypeParams> CreateMetadataFromPrototypeLog = new List<CreateMetadataFromPrototypeParams>();
public ModelMetadata CreateMetadataPrototypeReturnValue = null;
public ModelMetadata CreateMetadataFromPrototypeReturnValue = null;
protected override ModelMetadata CreateMetadataPrototype(IEnumerable<object> attributes, Type containerType, Type modelType, string propertyName)
{
CreateMetadataPrototypeLog.Add(new CreateMetadataPrototypeParams
{
Attributes = attributes,
ContainerType = containerType,
ModelType = modelType,
PropertyName = propertyName
});
return CreateMetadataPrototypeReturnValue;
}
protected override ModelMetadata CreateMetadataFromPrototype(ModelMetadata prototype)
{
CreateMetadataFromPrototypeLog.Add(new CreateMetadataFromPrototypeParams
{
Prototype = prototype,
});
return CreateMetadataFromPrototypeReturnValue;
}
}
private class CreateMetadataPrototypeParams
{
public IEnumerable<object> Attributes { get; set; }
public Type ContainerType { get; set; }
public Type ModelType { get; set; }
public string PropertyName { get; set; }
}
private class CreateMetadataFromPrototypeParams
{
public ModelMetadata Prototype { get; set; }
}
}
}