Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@@ -0,0 +1,179 @@
// 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.Web.Http.Controllers;
using System.Web.Http.Metadata;
using System.Web.Http.Metadata.Providers;
using System.Web.Http.ModelBinding;
using Microsoft.TestCommon;
using Xunit;
using Xunit.Extensions;
using Assert = Microsoft.TestCommon.AssertEx;
namespace System.Web.Http.Validation
{
public class DefaultBodyModelValidatorTest
{
private static Person LonelyPerson;
static DefaultBodyModelValidatorTest()
{
LonelyPerson = new Person() { Name = "Reallllllllly Long Name" };
LonelyPerson.Friend = LonelyPerson;
}
public static IEnumerable<object[]> ValidationErrors
{
get
{
return new TheoryDataSet<object, Type, Dictionary<string, string>>()
{
// Primitives
{ null, typeof(Person), new Dictionary<string, string>() },
{ 14, typeof(int), new Dictionary<string, string>() },
{ "foo", typeof(string), new Dictionary<string, string>() },
// Object Traversal : make sure we can traverse the object graph without throwing
{ new ValueType() { Reference = "ref", Value = 256}, typeof(ValueType), new Dictionary<string, string>()},
{ new ReferenceType() { Reference = "ref", Value = 256}, typeof(ReferenceType), new Dictionary<string, string>()},
// Classes
{ new Person() { Name = "Rick", Profession = "Astronaut" }, typeof(Person), new Dictionary<string, string>() },
{ new Person(), typeof(Person), new Dictionary<string, string>()
{
{ "Name", "The Name field is required." },
{ "Profession", "The Profession field is required." }
}
},
{ new Person() { Name = "Rick", Friend = new Person() }, typeof(Person), new Dictionary<string, string>()
{
{ "Profession", "The Profession field is required." },
{ "Friend.Name", "The Name field is required." },
{ "Friend.Profession", "The Profession field is required." }
}
},
// Collections
{ new Person[] { new Person(), new Person() }, typeof(Person[]), new Dictionary<string, string>()
{
{ "[0].Name", "The Name field is required." },
{ "[0].Profession", "The Profession field is required." },
{ "[1].Name", "The Name field is required." },
{ "[1].Profession", "The Profession field is required." }
}
},
{ new List<Person> { new Person(), new Person() }, typeof(Person[]), new Dictionary<string, string>()
{
{ "[0].Name", "The Name field is required." },
{ "[0].Profession", "The Profession field is required." },
{ "[1].Name", "The Name field is required." },
{ "[1].Profession", "The Profession field is required." }
}
},
{ new Dictionary<string, Person> { { "Joe", new Person() } , { "Mark", new Person() } }, typeof(Dictionary<string, Person>), new Dictionary<string, string>()
{
{ "[0].Value.Name", "The Name field is required." },
{ "[0].Value.Profession", "The Profession field is required." },
{ "[1].Value.Name", "The Name field is required." },
{ "[1].Value.Profession", "The Profession field is required." }
}
},
// Testing we don't blow up on cycles
{ LonelyPerson, typeof(Person), new Dictionary<string, string>()
{
{ "Name", "The field Name must be a string with a maximum length of 10." },
{ "Profession", "The Profession field is required." }
}
},
};
}
}
[Theory]
[PropertyData("ValidationErrors")]
public void ExpectedValidationErrorsRaised(object model, Type type, Dictionary<string, string> expectedErrors)
{
// Arrange
ModelMetadataProvider metadataProvider = new DataAnnotationsModelMetadataProvider();
HttpActionContext actionContext = ContextUtil.CreateActionContext();
// Act
Assert.DoesNotThrow(() =>
new DefaultBodyModelValidator().Validate(model, type, metadataProvider, actionContext, string.Empty)
);
// Assert
Dictionary<string, string> actualErrors = new Dictionary<string, string>();
foreach (KeyValuePair<string, ModelState> keyStatePair in actionContext.ModelState)
{
foreach (ModelError error in keyStatePair.Value.Errors)
{
actualErrors.Add(keyStatePair.Key, error.ErrorMessage);
}
}
Assert.Equal(expectedErrors.Count, actualErrors.Count);
foreach (KeyValuePair<string, string> keyErrorPair in expectedErrors)
{
Assert.Contains(keyErrorPair.Key, actualErrors.Keys);
Assert.Equal(keyErrorPair.Value, actualErrors[keyErrorPair.Key]);
}
}
[Fact]
public void MultipleValidationErrorsOnSameMemberReported()
{
// Arrange
ModelMetadataProvider metadataProvider = new DataAnnotationsModelMetadataProvider();
HttpActionContext actionContext = ContextUtil.CreateActionContext();
object model = new Address() { Street = "Microsoft Way" };
// Act
Assert.DoesNotThrow(() =>
new DefaultBodyModelValidator().Validate(model, typeof(Address), metadataProvider, actionContext, string.Empty)
);
// Assert
Assert.Contains("Street", actionContext.ModelState.Keys);
ModelState streetState = actionContext.ModelState["Street"];
Assert.Equal(2, streetState.Errors.Count);
}
}
public class Person
{
[Required]
[StringLength(10)]
public string Name { get; set; }
[Required]
public string Profession { get; set; }
public Person Friend { get; set; }
}
public class Address
{
[StringLength(5)]
[RegularExpression("hehehe")]
public string Street { get; set; }
}
public struct ValueType
{
public int Value;
public string Reference;
}
public class ReferenceType
{
public static string StaticProperty { get { return "static"; } }
public int Value;
public string Reference;
}
}

View File

@@ -0,0 +1,333 @@
// 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.Web.Http.Controllers;
using System.Web.Http.Metadata;
using System.Web.Http.Metadata.Providers;
using Xunit;
using Assert = Microsoft.TestCommon.AssertEx;
namespace System.Web.Http.Validation
{
public class ModelValidationNodeTest
{
[Fact]
public void ConstructorSetsCollectionInstance()
{
// Arrange
ModelMetadata metadata = GetModelMetadata();
string modelStateKey = "someKey";
ModelValidationNode[] childNodes = new[]
{
new ModelValidationNode(metadata, "someKey0"),
new ModelValidationNode(metadata, "someKey1")
};
// Act
ModelValidationNode node = new ModelValidationNode(metadata, modelStateKey, childNodes);
// Assert
Assert.Equal(childNodes, node.ChildNodes.ToArray());
}
[Fact]
public void ConstructorThrowsIfModelMetadataIsNull()
{
// Act & assert
Assert.ThrowsArgumentNull(
() => new ModelValidationNode(null, "someKey"),
"modelMetadata");
}
[Fact]
public void ConstructorThrowsIfModelStateKeyIsNull()
{
// Arrange
ModelMetadata metadata = GetModelMetadata();
// Act & assert
Assert.ThrowsArgumentNull(
() => new ModelValidationNode(metadata, null),
"modelStateKey");
}
[Fact]
public void PropertiesAreSet()
{
// Arrange
ModelMetadata metadata = GetModelMetadata();
string modelStateKey = "someKey";
// Act
ModelValidationNode node = new ModelValidationNode(metadata, modelStateKey);
// Assert
Assert.Equal(metadata, node.ModelMetadata);
Assert.Equal(modelStateKey, node.ModelStateKey);
Assert.NotNull(node.ChildNodes);
Assert.Empty(node.ChildNodes);
}
[Fact]
public void CombineWith()
{
// Arrange
List<string> log = new List<string>();
ModelValidationNode[] allChildNodes = new[]
{
new ModelValidationNode(GetModelMetadata(), "key1"),
new ModelValidationNode(GetModelMetadata(), "key2"),
new ModelValidationNode(GetModelMetadata(), "key3"),
};
ModelValidationNode parentNode1 = new ModelValidationNode(GetModelMetadata(), "parent1");
parentNode1.ChildNodes.Add(allChildNodes[0]);
parentNode1.Validating += (sender, e) => log.Add("Validating parent1.");
parentNode1.Validated += (sender, e) => log.Add("Validated parent1.");
ModelValidationNode parentNode2 = new ModelValidationNode(GetModelMetadata(), "parent2");
parentNode2.ChildNodes.Add(allChildNodes[1]);
parentNode2.ChildNodes.Add(allChildNodes[2]);
parentNode2.Validating += (sender, e) => log.Add("Validating parent2.");
parentNode2.Validated += (sender, e) => log.Add("Validated parent2.");
// Act
parentNode1.CombineWith(parentNode2);
parentNode1.Validate(ContextUtil.CreateActionContext());
// Assert
Assert.Equal(new[] { "Validating parent1.", "Validating parent2.", "Validated parent1.", "Validated parent2." }, log.ToArray());
Assert.Equal(allChildNodes, parentNode1.ChildNodes.ToArray());
}
[Fact]
public void CombineWith_OtherNodeIsSuppressed_DoesNothing()
{
// Arrange
List<string> log = new List<string>();
ModelValidationNode[] allChildNodes = new[]
{
new ModelValidationNode(GetModelMetadata(), "key1"),
new ModelValidationNode(GetModelMetadata(), "key2"),
new ModelValidationNode(GetModelMetadata(), "key3"),
};
ModelValidationNode[] expectedChildNodes = new[]
{
allChildNodes[0]
};
ModelValidationNode parentNode1 = new ModelValidationNode(GetModelMetadata(), "parent1");
parentNode1.ChildNodes.Add(allChildNodes[0]);
parentNode1.Validating += (sender, e) => log.Add("Validating parent1.");
parentNode1.Validated += (sender, e) => log.Add("Validated parent1.");
ModelValidationNode parentNode2 = new ModelValidationNode(GetModelMetadata(), "parent2");
parentNode2.ChildNodes.Add(allChildNodes[1]);
parentNode2.ChildNodes.Add(allChildNodes[2]);
parentNode2.Validating += (sender, e) => log.Add("Validating parent2.");
parentNode2.Validated += (sender, e) => log.Add("Validated parent2.");
parentNode2.SuppressValidation = true;
// Act
parentNode1.CombineWith(parentNode2);
parentNode1.Validate(ContextUtil.CreateActionContext());
// Assert
Assert.Equal(new[] { "Validating parent1.", "Validated parent1." }, log.ToArray());
Assert.Equal(expectedChildNodes, parentNode1.ChildNodes.ToArray());
}
[Fact]
public void Validate_Ordering()
{
// Proper order of invocation:
// 1. OnValidating()
// 2. Child validators
// 3. This validator
// 4. OnValidated()
// Arrange
List<string> log = new List<string>();
LoggingValidatableObject model = new LoggingValidatableObject(log);
ModelMetadata modelMetadata = GetModelMetadata(model);
ModelMetadata childMetadata = new EmptyModelMetadataProvider().GetMetadataForProperty(() => model, model.GetType(), "ValidStringProperty");
ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey");
node.Validating += (sender, e) => log.Add("In OnValidating()");
node.Validated += (sender, e) => log.Add("In OnValidated()");
node.ChildNodes.Add(new ModelValidationNode(childMetadata, "theKey.ValidStringProperty"));
// Act
node.Validate(ContextUtil.CreateActionContext());
// Assert
Assert.Equal(new[] { "In OnValidating()", "In LoggingValidatonAttribute.IsValid()", "In IValidatableObject.Validate()", "In OnValidated()" }, log.ToArray());
}
[Fact]
public void Validate_SkipsRemainingValidationIfModelStateIsInvalid()
{
// Because a property validator fails, the model validator shouldn't run
// Arrange
List<string> log = new List<string>();
LoggingValidatableObject model = new LoggingValidatableObject(log);
ModelMetadata modelMetadata = GetModelMetadata(model);
ModelMetadata childMetadata = new EmptyModelMetadataProvider().GetMetadataForProperty(() => model, model.GetType(), "InvalidStringProperty");
ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey");
node.ChildNodes.Add(new ModelValidationNode(childMetadata, "theKey.InvalidStringProperty"));
node.Validating += (sender, e) => log.Add("In OnValidating()");
node.Validated += (sender, e) => log.Add("In OnValidated()");
HttpActionContext context = ContextUtil.CreateActionContext();
// Act
node.Validate(context);
// Assert
Assert.Equal(new[] { "In OnValidating()", "In IValidatableObject.Validate()", "In OnValidated()" }, log.ToArray());
Assert.Equal("Sample error message", context.ModelState["theKey.InvalidStringProperty"].Errors[0].ErrorMessage);
}
[Fact]
public void Validate_SkipsValidationIfHandlerCancels()
{
// Arrange
List<string> log = new List<string>();
LoggingValidatableObject model = new LoggingValidatableObject(log);
ModelMetadata modelMetadata = GetModelMetadata(model);
ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey");
node.Validating += (sender, e) =>
{
log.Add("In OnValidating()");
e.Cancel = true;
};
node.Validated += (sender, e) => log.Add("In OnValidated()");
// Act
node.Validate(ContextUtil.CreateActionContext());
// Assert
Assert.Equal(new[] { "In OnValidating()" }, log.ToArray());
}
[Fact]
public void Validate_SkipsValidationIfSuppressed()
{
// Arrange
List<string> log = new List<string>();
LoggingValidatableObject model = new LoggingValidatableObject(log);
ModelMetadata modelMetadata = GetModelMetadata(model);
ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey")
{
SuppressValidation = true
};
node.Validating += (sender, e) => log.Add("In OnValidating()");
node.Validated += (sender, e) => log.Add("In OnValidated()");
// Act
node.Validate(ContextUtil.CreateActionContext());
// Assert
Assert.Empty(log);
}
[Fact]
public void Validate_ThrowsIfControllerContextIsNull()
{
// Arrange
ModelValidationNode node = new ModelValidationNode(GetModelMetadata(), "someKey");
// Act & assert
Assert.ThrowsArgumentNull(
() => node.Validate(null),
"actionContext");
}
[Fact]
public void Validate_ValidateAllProperties_AddsValidationErrors()
{
// Arrange
ValidateAllPropertiesModel model = new ValidateAllPropertiesModel
{
RequiredString = null /* error */,
RangedInt = 0 /* error */,
ValidString = "dog"
};
ModelMetadata modelMetadata = GetModelMetadata(model);
HttpActionContext context = ContextUtil.CreateActionContext();
ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey")
{
ValidateAllProperties = true
};
context.ModelState.AddModelError("theKey.RequiredString.Dummy", "existing Error Text");
// Act
node.Validate(context);
// Assert
Assert.Null(context.ModelState["theKey.RequiredString"]);
Assert.Equal("existing Error Text", context.ModelState["theKey.RequiredString.Dummy"].Errors[0].ErrorMessage);
Assert.Equal("The field RangedInt must be between 10 and 30.", context.ModelState["theKey.RangedInt"].Errors[0].ErrorMessage);
Assert.Null(context.ModelState["theKey.ValidString"]);
Assert.Null(context.ModelState["theKey"]);
}
private static ModelMetadata GetModelMetadata()
{
return new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(object));
}
private static ModelMetadata GetModelMetadata(object o)
{
return new DataAnnotationsModelMetadataProvider().GetMetadataForType(() => o, o.GetType());
}
private sealed class LoggingValidatableObject : IValidatableObject
{
private readonly IList<string> _log;
public LoggingValidatableObject(IList<string> log)
{
_log = log;
}
[LoggingValidation]
public string ValidStringProperty { get; set; }
public string InvalidStringProperty { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
_log.Add("In IValidatableObject.Validate()");
yield return new ValidationResult("Sample error message", new[] { "InvalidStringProperty" });
}
private sealed class LoggingValidationAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
LoggingValidatableObject lvo = (LoggingValidatableObject)value;
lvo._log.Add("In LoggingValidatonAttribute.IsValid()");
return ValidationResult.Success;
}
}
}
private class ValidateAllPropertiesModel
{
[Required]
public string RequiredString { get; set; }
[Range(10, 30)]
public int RangedInt { get; set; }
[RegularExpression("dog")]
public string ValidString { get; set; }
}
}
}

View File

@@ -0,0 +1,41 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.ComponentModel.DataAnnotations;
using System.Net.Http.Formatting;
using System.Runtime.Serialization;
using Xunit.Extensions;
using Assert = Microsoft.TestCommon.AssertEx;
namespace System.Web.Http.Validation
{
public class ModelValidationRequiredMemberSelectorTest
{
[Theory]
[InlineData("Customer", true)]
[InlineData("ID", true)]
[InlineData("Item", true)]
[InlineData("UselessInfo", false)]
public void RequiredMembersRecognized(string propertyName, bool isRequired)
{
HttpConfiguration config = new HttpConfiguration();
IRequiredMemberSelector selector = new ModelValidationRequiredMemberSelector(config.Services.GetModelMetadataProvider(), config.Services.GetModelValidatorProviders());
Assert.Equal(isRequired, selector.IsRequiredMember(typeof(PurchaseOrder).GetProperty(propertyName)));
}
}
[DataContract]
public class PurchaseOrder
{
[Required]
public string Customer { get; set; }
[DataMember(IsRequired=true)]
public int ID { get; set; }
[Required]
[DataMember(IsRequired=true)]
public string Item { get; set; }
public string UselessInfo { get; set; }
}
}

View File

@@ -0,0 +1,30 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Web.TestUtil;
using Xunit;
namespace System.Web.Http.Validation
{
public class ModelValidationResultTest
{
[Fact]
public void MemberNameProperty()
{
// Arrange
ModelValidationResult result = new ModelValidationResult();
// Act & assert
MemberHelper.TestStringProperty(result, "MemberName", String.Empty);
}
[Fact]
public void MessageProperty()
{
// Arrange
ModelValidationResult result = new ModelValidationResult();
// Act & assert
MemberHelper.TestStringProperty(result, "Message", String.Empty);
}
}
}

View File

@@ -0,0 +1,124 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using System.Web.Http.Metadata;
using System.Web.Http.Metadata.Providers;
using Xunit;
using Assert = Microsoft.TestCommon.AssertEx;
namespace System.Web.Http.Validation
{
public class ModelValidatorTest
{
private static DataAnnotationsModelMetadataProvider _metadataProvider = new DataAnnotationsModelMetadataProvider();
private static IEnumerable<ModelValidatorProvider> _noValidatorProviders = Enumerable.Empty<ModelValidatorProvider>();
[Fact]
public void ConstructorGuards()
{
// Arrange
ModelMetadata metadata = _metadataProvider.GetMetadataForType(null, typeof(object));
// Act & Assert
Assert.ThrowsArgumentNull(
() => new TestableModelValidator(validatorProviders: null),
"validatorProviders");
}
[Fact]
public void ValuesSet()
{
// Arrange
ModelMetadata metadata = _metadataProvider.GetMetadataForProperty(() => 15, typeof(string), "Length");
// Act
TestableModelValidator validator = new TestableModelValidator(_noValidatorProviders);
// Assert
Assert.Same(_noValidatorProviders, validator.ValidatorProviders);
}
[Fact]
public void IsRequiredFalseByDefault()
{
// Arrange
ModelMetadata metadata = _metadataProvider.GetMetadataForProperty(() => 15, typeof(string), "Length");
// Act
TestableModelValidator validator = new TestableModelValidator(_noValidatorProviders);
// Assert
Assert.False(validator.IsRequired);
}
[Fact]
public void GetModelValidator_DoesNotReadPropertyValues()
{
// Arrange
IEnumerable<ModelValidatorProvider> validatorProviders = new[] { new ObservableModelValidatorProvider() };
ObservableModel model = new ObservableModel();
ModelMetadata metadata = new EmptyModelMetadataProvider().GetMetadataForType(() => model, typeof(ObservableModel));
// Act
ModelValidator validator = ModelValidator.GetModelValidator(validatorProviders);
ModelValidationResult[] results = validator.Validate(metadata, model).ToArray();
// Assert
Assert.False(model.PropertyWasRead());
}
private class ObservableModelValidatorProvider : ModelValidatorProvider
{
public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, IEnumerable<ModelValidatorProvider> validatorProviders)
{
return new ModelValidator[] { new ObservableModelValidator(validatorProviders) };
}
private class ObservableModelValidator : ModelValidator
{
public ObservableModelValidator(IEnumerable<ModelValidatorProvider> validatorProviders)
: base(validatorProviders)
{
}
public override IEnumerable<ModelValidationResult> Validate(ModelMetadata metadata, object container)
{
return Enumerable.Empty<ModelValidationResult>();
}
}
}
private class ObservableModel
{
private bool _propertyWasRead;
public int TheProperty
{
get
{
_propertyWasRead = true;
return 42;
}
}
public bool PropertyWasRead()
{
return _propertyWasRead;
}
}
private class TestableModelValidator : ModelValidator
{
public TestableModelValidator(IEnumerable<ModelValidatorProvider> validatorProviders)
: base(validatorProviders)
{
}
public override IEnumerable<ModelValidationResult> Validate(ModelMetadata metadata, object container)
{
throw new NotImplementedException();
}
}
}
}

View File

@@ -0,0 +1,127 @@
// 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.Web.Http.Metadata;
using System.Web.Http.Metadata.Providers;
using Moq;
using Xunit;
using Assert = Microsoft.TestCommon.AssertEx;
namespace System.Web.Http.Validation.Providers
{
public class AssociatedValidatorProviderTest
{
private static DataAnnotationsModelMetadataProvider _metadataProvider = new DataAnnotationsModelMetadataProvider();
private static IEnumerable<ModelValidatorProvider> _noValidatorProviders = Enumerable.Empty<ModelValidatorProvider>();
[Fact]
public void GetValidatorsGuardClauses()
{
// Arrange
ModelMetadata metadata = _metadataProvider.GetMetadataForType(null, typeof(object));
Mock<AssociatedValidatorProvider> provider = new Mock<AssociatedValidatorProvider> { CallBase = true };
// Act & Assert
Assert.ThrowsArgumentNull(
() => provider.Object.GetValidators(metadata: null, validatorProviders: _noValidatorProviders),
"metadata");
Assert.ThrowsArgumentNull(
() => provider.Object.GetValidators(metadata, validatorProviders: null),
"validatorProviders");
}
[Fact]
public void GetValidatorsForPropertyWithLocalAttributes()
{
// Arrange
IEnumerable<Attribute> callbackAttributes = null;
ModelMetadata metadata = _metadataProvider.GetMetadataForProperty(null, typeof(PropertyModel), "LocalAttributes");
Mock<TestableAssociatedValidatorProvider> provider = new Mock<TestableAssociatedValidatorProvider> { CallBase = true };
provider.Setup(p => p.AbstractGetValidators(metadata, _noValidatorProviders, It.IsAny<IEnumerable<Attribute>>()))
.Callback<ModelMetadata, IEnumerable<ModelValidatorProvider>, IEnumerable<Attribute>>((m, c, attributes) => callbackAttributes = attributes)
.Returns(() => null)
.Verifiable();
// Act
provider.Object.GetValidators(metadata, _noValidatorProviders);
// Assert
provider.Verify();
Assert.True(callbackAttributes.Any(a => a is RequiredAttribute));
}
[Fact]
public void GetValidatorsForPropertyWithMetadataAttributes()
{
// Arrange
IEnumerable<Attribute> callbackAttributes = null;
ModelMetadata metadata = _metadataProvider.GetMetadataForProperty(null, typeof(PropertyModel), "MetadataAttributes");
Mock<TestableAssociatedValidatorProvider> provider = new Mock<TestableAssociatedValidatorProvider> { CallBase = true };
provider.Setup(p => p.AbstractGetValidators(metadata, _noValidatorProviders, It.IsAny<IEnumerable<Attribute>>()))
.Callback<ModelMetadata, IEnumerable<ModelValidatorProvider>, IEnumerable<Attribute>>((m, c, attributes) => callbackAttributes = attributes)
.Returns(() => null)
.Verifiable();
// Act
provider.Object.GetValidators(metadata, _noValidatorProviders);
// Assert
provider.Verify();
Assert.True(callbackAttributes.Any(a => a is RangeAttribute));
}
[Fact]
public void GetValidatorsForPropertyWithMixedAttributes()
{
// Arrange
IEnumerable<Attribute> callbackAttributes = null;
ModelMetadata metadata = _metadataProvider.GetMetadataForProperty(null, typeof(PropertyModel), "MixedAttributes");
Mock<TestableAssociatedValidatorProvider> provider = new Mock<TestableAssociatedValidatorProvider> { CallBase = true };
provider.Setup(p => p.AbstractGetValidators(metadata, _noValidatorProviders, It.IsAny<IEnumerable<Attribute>>()))
.Callback<ModelMetadata, IEnumerable<ModelValidatorProvider>, IEnumerable<Attribute>>((m, c, attributes) => callbackAttributes = attributes)
.Returns(() => null)
.Verifiable();
// Act
provider.Object.GetValidators(metadata, _noValidatorProviders);
// Assert
provider.Verify();
Assert.True(callbackAttributes.Any(a => a is RangeAttribute));
Assert.True(callbackAttributes.Any(a => a is RequiredAttribute));
}
[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; }
}
}
public abstract class TestableAssociatedValidatorProvider : AssociatedValidatorProvider
{
protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, IEnumerable<ModelValidatorProvider> validatorProviders, IEnumerable<Attribute> attributes)
{
return AbstractGetValidators(metadata, validatorProviders, attributes);
}
public abstract IEnumerable<ModelValidator> AbstractGetValidators(ModelMetadata metadata, IEnumerable<ModelValidatorProvider> validatorProviders, IEnumerable<Attribute> attributes);
}
}
}

View File

@@ -0,0 +1,97 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Web.Http.Metadata.Providers;
using Xunit;
using Assert = Microsoft.TestCommon.AssertEx;
namespace System.Web.Http.Validation.Providers
{
public class DataMemberModelValidatorProviderTest
{
private static DataAnnotationsModelMetadataProvider _metadataProvider = new DataAnnotationsModelMetadataProvider();
[Fact]
public void ClassWithoutAttributes_NoValidator()
{
// Arrange
var provider = new DataMemberModelValidatorProvider();
var metadata = _metadataProvider.GetMetadataForProperty(() => null, typeof(ClassWithoutAttributes), "TheProperty");
// Act
IEnumerable<ModelValidator> validators = provider.GetValidators(metadata, new[] { provider });
// Assert
Assert.Empty(validators);
}
class ClassWithoutAttributes
{
public int TheProperty { get; set; }
}
[Fact]
public void ClassWithDataMemberIsRequiredTrue_Validator()
{
// Arrange
var provider = new DataMemberModelValidatorProvider();
var metadata = _metadataProvider.GetMetadataForProperty(() => null, typeof(ClassWithDataMemberIsRequiredTrue), "TheProperty");
// Act
IEnumerable<ModelValidator> validators = provider.GetValidators(metadata, new[] { provider });
// Assert
ModelValidator validator = Assert.Single(validators);
Assert.True(validator.IsRequired);
}
[DataContract]
class ClassWithDataMemberIsRequiredTrue
{
[DataMember(IsRequired = true)]
public int TheProperty { get; set; }
}
[Fact]
public void ClassWithDataMemberIsRequiredFalse_NoValidator()
{
// Arrange
var provider = new DataMemberModelValidatorProvider();
var metadata = _metadataProvider.GetMetadataForProperty(() => null, typeof(ClassWithDataMemberIsRequiredFalse), "TheProperty");
// Act
IEnumerable<ModelValidator> validators = provider.GetValidators(metadata, new[] { provider });
// Assert
Assert.Empty(validators);
}
[DataContract]
class ClassWithDataMemberIsRequiredFalse
{
[DataMember(IsRequired = false)]
public int TheProperty { get; set; }
}
[Fact]
public void ClassWithDataMemberIsRequiredTrueWithoutDataContract_NoValidator()
{
// Arrange
var provider = new DataMemberModelValidatorProvider();
var metadata = _metadataProvider.GetMetadataForProperty(() => null, typeof(ClassWithDataMemberIsRequiredTrueWithoutDataContract), "TheProperty");
// Act
IEnumerable<ModelValidator> validators = provider.GetValidators(metadata, new[] { provider });
// Assert
Assert.Empty(validators);
}
class ClassWithDataMemberIsRequiredTrueWithoutDataContract
{
[DataMember(IsRequired = true)]
public int TheProperty { get; set; }
}
}
}

View File

@@ -0,0 +1,118 @@
// 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.Web.Http.Metadata;
using System.Web.Http.Metadata.Providers;
using Moq;
using Moq.Protected;
using Xunit;
using Assert = Microsoft.TestCommon.AssertEx;
namespace System.Web.Http.Validation.Validators
{
public class DataAnnotationsModelValidatorTest
{
private static DataAnnotationsModelMetadataProvider _metadataProvider = new DataAnnotationsModelMetadataProvider();
private static IEnumerable<ModelValidatorProvider> _noValidatorProviders = Enumerable.Empty<ModelValidatorProvider>();
[Fact]
public void ConstructorGuards()
{
// Arrange
ModelMetadata metadata = _metadataProvider.GetMetadataForType(null, typeof(object));
var attribute = new RequiredAttribute();
// Act & Assert
Assert.ThrowsArgumentNull(
() => new DataAnnotationsModelValidator(null, attribute),
"validatorProviders");
Assert.ThrowsArgumentNull(
() => new DataAnnotationsModelValidator(_noValidatorProviders, null),
"attribute");
}
[Fact]
public void ValuesSet()
{
// Arrange
ModelMetadata metadata = _metadataProvider.GetMetadataForProperty(() => 15, typeof(string), "Length");
var attribute = new RequiredAttribute();
// Act
var validator = new DataAnnotationsModelValidator(_noValidatorProviders, attribute);
// Assert
Assert.Same(attribute, validator.Attribute);
}
[Fact]
public void ValidateWithIsValidTrue()
{
// Arrange
ModelMetadata metadata = _metadataProvider.GetMetadataForProperty(() => 15, typeof(string), "Length");
Mock<ValidationAttribute> attribute = new Mock<ValidationAttribute> { CallBase = true };
attribute.Setup(a => a.IsValid(metadata.Model)).Returns(true);
DataAnnotationsModelValidator validator = new DataAnnotationsModelValidator(_noValidatorProviders, attribute.Object);
// Act
IEnumerable<ModelValidationResult> result = validator.Validate(metadata, null);
// Assert
Assert.Empty(result);
}
[Fact]
public void ValidateWithIsValidFalse()
{
// Arrange
ModelMetadata metadata = _metadataProvider.GetMetadataForProperty(() => 15, typeof(string), "Length");
Mock<ValidationAttribute> attribute = new Mock<ValidationAttribute> { CallBase = true };
attribute.Setup(a => a.IsValid(metadata.Model)).Returns(false);
DataAnnotationsModelValidator validator = new DataAnnotationsModelValidator(_noValidatorProviders, attribute.Object);
// Act
IEnumerable<ModelValidationResult> result = validator.Validate(metadata, null);
// Assert
var validationResult = result.Single();
Assert.Equal("", validationResult.MemberName);
Assert.Equal(attribute.Object.FormatErrorMessage("Length"), validationResult.Message);
}
[Fact]
public void ValidatateWithValidationResultSuccess()
{
// Arrange
ModelMetadata metadata = _metadataProvider.GetMetadataForProperty(() => 15, typeof(string), "Length");
Mock<ValidationAttribute> attribute = new Mock<ValidationAttribute> { CallBase = true };
attribute.Protected()
.Setup<ValidationResult>("IsValid", ItExpr.IsAny<object>(), ItExpr.IsAny<ValidationContext>())
.Returns(ValidationResult.Success);
DataAnnotationsModelValidator validator = new DataAnnotationsModelValidator(_noValidatorProviders, attribute.Object);
// Act
IEnumerable<ModelValidationResult> result = validator.Validate(metadata, null);
// Assert
Assert.Empty(result);
}
[Fact]
public void IsRequiredTests()
{
// Arrange
ModelMetadata metadata = _metadataProvider.GetMetadataForProperty(() => 15, typeof(string), "Length");
// Act & Assert
Assert.False(new DataAnnotationsModelValidator(_noValidatorProviders, new RangeAttribute(10, 20)).IsRequired);
Assert.True(new DataAnnotationsModelValidator(_noValidatorProviders, new RequiredAttribute()).IsRequired);
Assert.True(new DataAnnotationsModelValidator(_noValidatorProviders, new DerivedRequiredAttribute()).IsRequired);
}
class DerivedRequiredAttribute : RequiredAttribute
{
}
}
}