/test/System.Web.Http.Test/Validation/Providers/DataAnnotationsModelValidatorProviderTest.cs
C# | 517 lines | 363 code | 92 blank | 62 comment | 0 complexity | ef326cfe863f4a77523469841ba3f3c9 MD5 | raw file
- using System.Collections.Generic;
- using System.ComponentModel.DataAnnotations;
- using System.Linq;
- using System.Web.Http.Metadata;
- using System.Web.Http.Metadata.Providers;
- using System.Web.Http.Validation.Validators;
- using Moq;
- using Xunit;
- using Assert = Microsoft.TestCommon.AssertEx;
- namespace System.Web.Http.Validation.Providers
- {
- public class DataAnnotationsModelValidatorProviderTest
- {
- private static CachedDataAnnotationsModelMetadataProvider _metadataProvider = new CachedDataAnnotationsModelMetadataProvider();
- private static IEnumerable<ModelValidatorProvider> _noValidatorProviders = Enumerable.Empty<ModelValidatorProvider>();
- // Validation attribute adapter registration
- private class MyValidationAttribute : ValidationAttribute
- {
- public override bool IsValid(object value)
- {
- throw new NotImplementedException();
- }
- }
- private class MyValidationAttributeAdapter : DataAnnotationsModelValidator
- {
- public MyValidationAttributeAdapter(ModelMetadata metadata, IEnumerable<ModelValidatorProvider> validatorProviders, ValidationAttribute attribute)
- : base(metadata, validatorProviders, attribute)
- {
- }
- }
- private class MyValidationAttributeAdapterBadCtor : ModelValidator
- {
- public MyValidationAttributeAdapterBadCtor(ModelMetadata metadata, IEnumerable<ModelValidatorProvider> validatorProviders)
- : base(metadata, validatorProviders)
- {
- }
- public override IEnumerable<ModelValidationResult> Validate(object container)
- {
- throw new NotImplementedException();
- }
- }
- private class MyDefaultValidationAttributeAdapter : DataAnnotationsModelValidator
- {
- public MyDefaultValidationAttributeAdapter(ModelMetadata metadata, IEnumerable<ModelValidatorProvider> validatorProviders, ValidationAttribute attribute)
- : base(metadata, validatorProviders, attribute)
- {
- }
- }
- [MyValidation]
- private class MyValidatedClass
- {
- }
- [Fact]
- public void RegisterAdapter()
- {
- // Arrange
- var provider = new DataAnnotationsModelValidatorProvider();
- provider.AttributeFactories = new Dictionary<Type, DataAnnotationsModelValidationFactory>();
- // Act
- provider.RegisterAdapter(typeof(MyValidationAttribute), typeof(MyValidationAttributeAdapter));
- // Assert
- var type = provider.AttributeFactories.Keys.Single();
- Assert.Equal(typeof(MyValidationAttribute), type);
- var factory = provider.AttributeFactories.Values.Single();
- var metadata = _metadataProvider.GetMetadataForType(() => null, typeof(object));
- var attribute = new MyValidationAttribute();
- var validator = factory(metadata, _noValidatorProviders, attribute);
- Assert.IsType<MyValidationAttributeAdapter>(validator);
- }
- [Fact]
- public void RegisterAdapterGuardClauses()
- {
- var provider = new DataAnnotationsModelValidatorProvider();
- // Attribute type cannot be null
- Assert.ThrowsArgumentNull(
- () => provider.RegisterAdapter(null, typeof(MyValidationAttributeAdapter)),
- "attributeType");
- // Adapter type cannot be null
- Assert.ThrowsArgumentNull(
- () => provider.RegisterAdapter(typeof(MyValidationAttribute), null),
- "adapterType");
- // Validation attribute must derive from ValidationAttribute
- Assert.ThrowsArgument(
- () => provider.RegisterAdapter(typeof(object), typeof(MyValidationAttributeAdapter)),
- "attributeType",
- "The type Object must derive from ValidationAttribute");
- // Adapter must derive from ModelValidator
- Assert.ThrowsArgument(
- () => provider.RegisterAdapter(typeof(MyValidationAttribute), typeof(object)),
- "adapterType",
- "The type Object must derive from ModelValidator");
- // Adapter must have the expected constructor
- Assert.ThrowsArgument(
- () => provider.RegisterAdapter(typeof(MyValidationAttribute), typeof(MyValidationAttributeAdapterBadCtor)),
- "adapterType",
- "The type MyValidationAttributeAdapterBadCtor must have a public constructor which accepts three parameters of types ModelMetadata, IEnumerable<ModelValidatorProvider>, and MyValidationAttribute");
- }
- [Fact]
- public void RegisterAdapterFactory()
- {
- // Arrange
- var provider = new DataAnnotationsModelValidatorProvider();
- provider.AttributeFactories = new Dictionary<Type, DataAnnotationsModelValidationFactory>();
- DataAnnotationsModelValidationFactory factory = delegate { return null; };
- // Act
- provider.RegisterAdapterFactory(typeof(MyValidationAttribute), factory);
- // Assert
- var type = provider.AttributeFactories.Keys.Single();
- Assert.Equal(typeof(MyValidationAttribute), type);
- Assert.Same(factory, provider.AttributeFactories.Values.Single());
- }
- [Fact]
- public void RegisterAdapterFactoryGuardClauses()
- {
- var provider = new DataAnnotationsModelValidatorProvider();
- DataAnnotationsModelValidationFactory factory = (metadata, validatorProviders, attribute) => null;
- // Attribute type cannot be null
- Assert.ThrowsArgumentNull(
- () => provider.RegisterAdapterFactory(null, factory),
- "attributeType");
- // Factory cannot be null
- Assert.ThrowsArgumentNull(
- () => provider.RegisterAdapterFactory(typeof(MyValidationAttribute), null),
- "factory");
- // Validation attribute must derive from ValidationAttribute
- Assert.ThrowsArgument(
- () => provider.RegisterAdapterFactory(typeof(object), factory),
- "attributeType",
- "The type Object must derive from ValidationAttribute");
- }
- [Fact]
- public void RegisterDefaultAdapter()
- {
- // Arrange
- var provider = new DataAnnotationsModelValidatorProvider();
- var metadata = _metadataProvider.GetMetadataForType(() => null, typeof(MyValidatedClass));
- provider.RegisterDefaultAdapter(typeof(MyDefaultValidationAttributeAdapter));
- // Act
- var result = provider.GetValidators(metadata, _noValidatorProviders).Single();
- // Assert
- Assert.IsType<MyDefaultValidationAttributeAdapter>(result);
- }
- [Fact]
- public void RegisterDefaultAdapterGuardClauses()
- {
- var provider = new DataAnnotationsModelValidatorProvider();
- // Adapter type cannot be null
- Assert.ThrowsArgumentNull(
- () => provider.RegisterDefaultAdapter(null),
- "adapterType");
- // Adapter must derive from ModelValidator
- Assert.ThrowsArgument(
- () => provider.RegisterDefaultAdapter(typeof(object)),
- "adapterType",
- "The type Object must derive from ModelValidator");
- // Adapter must have the expected constructor
- Assert.ThrowsArgument(
- () => provider.RegisterDefaultAdapter(typeof(MyValidationAttributeAdapterBadCtor)),
- "adapterType",
- "The type MyValidationAttributeAdapterBadCtor must have a public constructor which accepts three parameters of types ModelMetadata, IEnumerable<ModelValidatorProvider>, and ValidationAttribute");
- }
- [Fact]
- public void RegisterDefaultAdapterFactory()
- {
- // Arrange
- var provider = new DataAnnotationsModelValidatorProvider();
- var metadata = _metadataProvider.GetMetadataForType(() => null, typeof(MyValidatedClass));
- ModelValidator validator = new Mock<ModelValidator>(metadata, _noValidatorProviders).Object;
- DataAnnotationsModelValidationFactory factory = delegate { return validator; };
- provider.RegisterDefaultAdapterFactory(factory);
- // Act
- var result = provider.GetValidators(metadata, _noValidatorProviders).Single();
- // Assert
- Assert.Same(validator, result);
- }
- [Fact]
- public void RegisterDefaultAdapterFactoryGuardClauses()
- {
- var provider = new DataAnnotationsModelValidatorProvider();
- // Factory cannot be null
- Assert.ThrowsArgumentNull(
- () => provider.RegisterDefaultAdapterFactory(null),
- "factory");
- }
- // IValidatableObject adapter registration
- private class MyValidatableAdapter : ModelValidator
- {
- public MyValidatableAdapter(ModelMetadata metadata, IEnumerable<ModelValidatorProvider> validatorProviders)
- : base(metadata, validatorProviders)
- {
- }
- public override IEnumerable<ModelValidationResult> Validate(object container)
- {
- throw new NotImplementedException();
- }
- }
- private class MyValidatableAdapterBadCtor : ModelValidator
- {
- public MyValidatableAdapterBadCtor(ModelMetadata metadata, IEnumerable<ModelValidatorProvider> validatorProviders, int unused)
- : base(metadata, validatorProviders)
- {
- }
- public override IEnumerable<ModelValidationResult> Validate(object container)
- {
- throw new NotImplementedException();
- }
- }
- private class MyValidatableClass : IValidatableObject
- {
- public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
- {
- throw new NotImplementedException();
- }
- }
- [Fact]
- public void RegisterValidatableObjectAdapter()
- {
- // Arrange
- var provider = new DataAnnotationsModelValidatorProvider();
- provider.ValidatableFactories = new Dictionary<Type, DataAnnotationsValidatableObjectAdapterFactory>();
- IValidatableObject validatable = new Mock<IValidatableObject>().Object;
- // Act
- provider.RegisterValidatableObjectAdapter(validatable.GetType(), typeof(MyValidatableAdapter));
- // Assert
- var type = provider.ValidatableFactories.Keys.Single();
- Assert.Equal(validatable.GetType(), type);
- var factory = provider.ValidatableFactories.Values.Single();
- var metadata = _metadataProvider.GetMetadataForType(() => null, typeof(object));
- var validator = factory(metadata, _noValidatorProviders);
- Assert.IsType<MyValidatableAdapter>(validator);
- }
- [Fact]
- public void RegisterValidatableObjectAdapterGuardClauses()
- {
- var provider = new DataAnnotationsModelValidatorProvider();
- // Attribute type cannot be null
- Assert.ThrowsArgumentNull(
- () => provider.RegisterValidatableObjectAdapter(null, typeof(MyValidatableAdapter)),
- "modelType");
- // Adapter type cannot be null
- Assert.ThrowsArgumentNull(
- () => provider.RegisterValidatableObjectAdapter(typeof(MyValidatableClass), null),
- "adapterType");
- // Validation attribute must derive from ValidationAttribute
- Assert.ThrowsArgument(
- () => provider.RegisterValidatableObjectAdapter(typeof(object), typeof(MyValidatableAdapter)),
- "modelType",
- "The type Object must derive from IValidatableObject.");
- // Adapter must derive from ModelValidator
- Assert.ThrowsArgument(
- () => provider.RegisterValidatableObjectAdapter(typeof(MyValidatableClass), typeof(object)),
- "adapterType",
- "The type Object must derive from ModelValidator");
- // Adapter must have the expected constructor
- Assert.ThrowsArgument(
- () => provider.RegisterValidatableObjectAdapter(typeof(MyValidatableClass), typeof(MyValidatableAdapterBadCtor)),
- "adapterType",
- "The type MyValidatableAdapterBadCtor must have a public constructor which accepts two parameters of types ModelMetadata and IEnumerable<ModelValidatorProvider>");
- }
- [Fact]
- public void RegisterValidatableObjectAdapterFactory()
- {
- // Arrange
- var provider = new DataAnnotationsModelValidatorProvider();
- provider.ValidatableFactories = new Dictionary<Type, DataAnnotationsValidatableObjectAdapterFactory>();
- DataAnnotationsValidatableObjectAdapterFactory factory = delegate { return null; };
- // Act
- provider.RegisterValidatableObjectAdapterFactory(typeof(MyValidatableClass), factory);
- // Assert
- var type = provider.ValidatableFactories.Keys.Single();
- Assert.Equal(typeof(MyValidatableClass), type);
- Assert.Same(factory, provider.ValidatableFactories.Values.Single());
- }
- [Fact]
- public void RegisterValidatableObjectAdapterFactoryGuardClauses()
- {
- var provider = new DataAnnotationsModelValidatorProvider();
- DataAnnotationsValidatableObjectAdapterFactory factory = (metadata, context) => null;
- // Attribute type cannot be null
- Assert.ThrowsArgumentNull(
- () => provider.RegisterValidatableObjectAdapterFactory(null, factory),
- "modelType");
- // Factory cannot be null
- Assert.ThrowsArgumentNull(
- () => provider.RegisterValidatableObjectAdapterFactory(typeof(MyValidatableClass), null),
- "factory");
- // Validation attribute must derive from ValidationAttribute
- Assert.ThrowsArgument(
- () => provider.RegisterValidatableObjectAdapterFactory(typeof(object), factory),
- "modelType",
- "The type Object must derive from IValidatableObject");
- }
- [Fact]
- public void RegisterDefaultValidatableObjectAdapter()
- {
- // Arrange
- var provider = new DataAnnotationsModelValidatorProvider();
- var metadata = _metadataProvider.GetMetadataForType(() => null, typeof(MyValidatableClass));
- provider.RegisterDefaultValidatableObjectAdapter(typeof(MyValidatableAdapter));
- // Act
- var result = provider.GetValidators(metadata, _noValidatorProviders).Single();
- // Assert
- Assert.IsType<MyValidatableAdapter>(result);
- }
- [Fact]
- public void RegisterDefaultValidatableObjectAdapterGuardClauses()
- {
- var provider = new DataAnnotationsModelValidatorProvider();
- // Adapter type cannot be null
- Assert.ThrowsArgumentNull(
- () => provider.RegisterDefaultValidatableObjectAdapter(null),
- "adapterType");
- // Adapter must derive from ModelValidator
- Assert.ThrowsArgument(
- () => provider.RegisterDefaultValidatableObjectAdapter(typeof(object)),
- "adapterType",
- "The type Object must derive from ModelValidator");
- // Adapter must have the expected constructor
- Assert.ThrowsArgument(
- () => provider.RegisterDefaultValidatableObjectAdapter(typeof(MyValidatableAdapterBadCtor)),
- "adapterType",
- "The type MyValidatableAdapterBadCtor must have a public constructor which accepts two parameters of types ModelMetadata and IEnumerable<ModelValidatorProvider>");
- }
- [Fact]
- public void RegisterDefaultValidatableObjectAdapterFactory()
- {
- // Arrange
- var provider = new DataAnnotationsModelValidatorProvider();
- var metadata = _metadataProvider.GetMetadataForType(() => null, typeof(MyValidatableClass));
- ModelValidator validator = new Mock<ModelValidator>(metadata, _noValidatorProviders).Object;
- DataAnnotationsValidatableObjectAdapterFactory factory = delegate { return validator; };
- provider.RegisterDefaultValidatableObjectAdapterFactory(factory);
- // Act
- var result = provider.GetValidators(metadata, _noValidatorProviders).Single();
- // Assert
- Assert.Same(validator, result);
- }
- [Fact]
- public void RegisterDefaultValidatableObjectAdapterFactoryGuardClauses()
- {
- var provider = new DataAnnotationsModelValidatorProvider();
- // Factory cannot be null
- Assert.ThrowsArgumentNull(
- () => provider.RegisterDefaultValidatableObjectAdapterFactory(null),
- "factory");
- }
- // Default adapter factory for unknown attribute type
- [Fact]
- public void UnknownValidationAttributeGetsDefaultAdapter()
- {
- // Arrange
- var provider = new DataAnnotationsModelValidatorProvider();
- var metadata = _metadataProvider.GetMetadataForType(() => null, typeof(DummyClassWithDummyValidationAttribute));
- // Act
- IEnumerable<ModelValidator> validators = provider.GetValidators(metadata, _noValidatorProviders);
- // Assert
- var validator = validators.Single();
- Assert.IsType<DataAnnotationsModelValidator>(validator);
- }
- private class DummyValidationAttribute : ValidationAttribute
- {
- }
- [DummyValidation]
- private class DummyClassWithDummyValidationAttribute
- {
- }
- // Default IValidatableObject adapter factory
- [Fact]
- public void IValidatableObjectGetsAValidator()
- {
- // Arrange
- var provider = new DataAnnotationsModelValidatorProvider();
- var mockValidatable = new Mock<IValidatableObject>();
- var metadata = _metadataProvider.GetMetadataForType(() => null, mockValidatable.Object.GetType());
- // Act
- IEnumerable<ModelValidator> validators = provider.GetValidators(metadata, _noValidatorProviders);
- // Assert
- Assert.Single(validators);
- }
- // Integration with metadata system
- [Fact]
- public void DoesNotReadPropertyValue()
- {
- // Arrange
- var provider = new DataAnnotationsModelValidatorProvider();
- var model = new ObservableModel();
- ModelMetadata metadata = _metadataProvider.GetMetadataForProperty(() => model.TheProperty, typeof(ObservableModel), "TheProperty");
- // Act
- ModelValidator[] validators = provider.GetValidators(metadata, _noValidatorProviders).ToArray();
- ModelValidationResult[] results = validators.SelectMany(o => o.Validate(model)).ToArray();
- // Assert
- Assert.Empty(validators);
- Assert.False(model.PropertyWasRead());
- }
- private class ObservableModel
- {
- private bool _propertyWasRead;
- public string TheProperty
- {
- get
- {
- _propertyWasRead = true;
- return "Hello";
- }
- }
- public bool PropertyWasRead()
- {
- return _propertyWasRead;
- }
- }
- private class BaseModel
- {
- public virtual string MyProperty { get; set; }
- }
- private class DerivedModel : BaseModel
- {
- [StringLength(10)]
- public override string MyProperty
- {
- get { return base.MyProperty; }
- set { base.MyProperty = value; }
- }
- }
- }
- }