From 711a6183108b31d3f07f82dcce3b3420818c3780 Mon Sep 17 00:00:00 2001 From: Jeremy Skinner Date: Tue, 21 Nov 2017 20:45:13 +0000 Subject: [PATCH] Adds test for proposal in #7014 --- .../TryValidateModelIntegrationTest.cs | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/test/Microsoft.AspNetCore.Mvc.IntegrationTests/TryValidateModelIntegrationTest.cs b/test/Microsoft.AspNetCore.Mvc.IntegrationTests/TryValidateModelIntegrationTest.cs index 2d505f5420..68f63432a0 100644 --- a/test/Microsoft.AspNetCore.Mvc.IntegrationTests/TryValidateModelIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.IntegrationTests/TryValidateModelIntegrationTest.cs @@ -3,8 +3,11 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; +using Microsoft.AspNetCore.Mvc.Internal; using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -132,6 +135,76 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests 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) { // 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 CustomObjectValidator : IObjectModelValidator + { + private readonly IModelMetadataProvider _modelMetadataProvider; + private readonly IList _validatorProviders; + private ValidatorCache _validatorCache; + private CompositeModelValidatorProvider _validatorProvider; + + public CustomObjectValidator(IModelMetadataProvider modelMetadataProvider, IList 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; } + } } }