Adds test for proposal in #7014
This commit is contained in:
parent
3a132e4af5
commit
711a618310
|
|
@ -3,8 +3,11 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Internal;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
using Microsoft.AspNetCore.Testing;
|
using Microsoft.AspNetCore.Testing;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
@ -132,6 +135,76 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
||||||
AssertErrorEquals(contactUsMax + contactusRegEx, modelStateErrors["[1].Contact"]);
|
AssertErrorEquals(contactUsMax + contactusRegEx, modelStateErrors["[1].Contact"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidationVisitor_ValidateComplexTypesIfChildValidationFailsSetToTrue_AddsModelLevelErrors()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var testContext = ModelBindingTestHelper.GetTestContext();
|
||||||
|
var modelState = testContext.ModelState;
|
||||||
|
var model = new ModelLevelErrorTest();
|
||||||
|
var controller = CreateController(testContext, testContext.MetadataProvider);
|
||||||
|
controller.ObjectValidator = new CustomObjectValidator(testContext.MetadataProvider, TestModelValidatorProvider.CreateDefaultProvider().ValidatorProviders)
|
||||||
|
{
|
||||||
|
ValidateComplexTypesIfChildValidationFails = true
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = controller.TryValidateModel(model);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.False(modelState.IsValid);
|
||||||
|
var modelStateErrors = GetModelStateErrors(modelState);
|
||||||
|
Assert.Equal(2, modelStateErrors.Count);
|
||||||
|
AssertErrorEquals("Property", modelStateErrors["Message"]);
|
||||||
|
AssertErrorEquals("Model", modelStateErrors[""]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ValidationVisitor_ValidateComplexTypesIfChildValidationFailsSetToFalse_DoesNotAddModelLevelErrors()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var testContext = ModelBindingTestHelper.GetTestContext();
|
||||||
|
var modelState = testContext.ModelState;
|
||||||
|
var model = new ModelLevelErrorTest();
|
||||||
|
var controller = CreateController(testContext, testContext.MetadataProvider);
|
||||||
|
controller.ObjectValidator = new CustomObjectValidator(testContext.MetadataProvider, TestModelValidatorProvider.CreateDefaultProvider().ValidatorProviders)
|
||||||
|
{
|
||||||
|
ValidateComplexTypesIfChildValidationFails= false
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = controller.TryValidateModel(model);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.False(modelState.IsValid);
|
||||||
|
var modelStateErrors = GetModelStateErrors(modelState);
|
||||||
|
Assert.Single(modelStateErrors); // single error from the required attribute
|
||||||
|
AssertErrorEquals("Property", modelStateErrors.Single().Value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[ModelLevelError]
|
||||||
|
private class ModelLevelErrorTest
|
||||||
|
{
|
||||||
|
[Required(ErrorMessage = "Property")]
|
||||||
|
public string Message { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ModelLevelErrorAttribute : ValidationAttribute
|
||||||
|
{
|
||||||
|
public ModelLevelErrorAttribute()
|
||||||
|
{
|
||||||
|
ErrorMessage = "Model";
|
||||||
|
}
|
||||||
|
public override bool IsValid(object value)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void AssertErrorEquals(string expected, string actual)
|
private void AssertErrorEquals(string expected, string actual)
|
||||||
{
|
{
|
||||||
// OrderBy is used because the order of the results may very depending on the platform / client.
|
// OrderBy is used because the order of the results may very depending on the platform / client.
|
||||||
|
|
@ -179,5 +252,37 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
||||||
private class TestController : Controller
|
private class TestController : Controller
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class CustomObjectValidator : IObjectModelValidator
|
||||||
|
{
|
||||||
|
private readonly IModelMetadataProvider _modelMetadataProvider;
|
||||||
|
private readonly IList<IModelValidatorProvider> _validatorProviders;
|
||||||
|
private ValidatorCache _validatorCache;
|
||||||
|
private CompositeModelValidatorProvider _validatorProvider;
|
||||||
|
|
||||||
|
public CustomObjectValidator(IModelMetadataProvider modelMetadataProvider, IList<IModelValidatorProvider> validatorProviders)
|
||||||
|
{
|
||||||
|
_modelMetadataProvider = modelMetadataProvider;
|
||||||
|
_validatorProviders = validatorProviders;
|
||||||
|
_validatorCache = new ValidatorCache();
|
||||||
|
_validatorProvider = new CompositeModelValidatorProvider(validatorProviders);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Validate(ActionContext actionContext, ValidationStateDictionary validationState, string prefix, object model)
|
||||||
|
{
|
||||||
|
var visitor = new ValidationVisitor(
|
||||||
|
actionContext,
|
||||||
|
_validatorProvider,
|
||||||
|
_validatorCache,
|
||||||
|
_modelMetadataProvider,
|
||||||
|
validationState);
|
||||||
|
|
||||||
|
var metadata = model == null ? null : _modelMetadataProvider.GetMetadataForType(model.GetType());
|
||||||
|
visitor.ValidateComplexTypesIfChildValidationFails = ValidateComplexTypesIfChildValidationFails;
|
||||||
|
visitor.Validate(metadata, prefix, model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ValidateComplexTypesIfChildValidationFails { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue