// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Xunit; namespace Microsoft.AspNetCore.Mvc.FunctionalTests { public class InputValidationTests : IClassFixture> { public InputValidationTests(MvcTestFixture fixture) { Client = fixture.Client; } public HttpClient Client { get; } [Fact] public async Task ValidRequest_IsAccepted() { // Arrange var content = new FormUrlEncodedContent(new Dictionary { { "RequiredProp", "1" }, { "BindRequiredProp", "2" }, { "RequiredAndBindRequiredProp", "3" }, { "requiredParam", "4" }, { "bindRequiredParam", "5" }, { "requiredAndBindRequiredParam", "6" }, { "UnboundRequiredProp", "100" }, // Value should not be used { "UnboundBindRequiredProp", "101" }, // Value should not be used { "BindNeverRequiredProp", "ignoredValue" }, // Value should not be used }); // Act var response = await Client.PostAsync("http://localhost/TopLevelValidation", content); var responseText = await response.Content.ReadAsStringAsync(); // Assert Assert.Contains("[OptionalProp:0]", responseText); Assert.Contains("[RequiredProp:1]", responseText); Assert.Contains("[BindRequiredProp:2]", responseText); Assert.Contains("[RequiredAndBindRequiredProp:3]", responseText); Assert.Contains("[OptionalStringLengthProp:]", responseText); Assert.Contains("[OptionalRangeDisplayNameProp:0]", responseText); Assert.Contains("[UnboundRequiredProp:0]", responseText); Assert.Contains("[UnboundBindRequiredProp:0]", responseText); Assert.Contains("[BindNeverRequiredProp:]", responseText); Assert.Contains("[optionalParam:0]", responseText); Assert.Contains("[requiredParam:4]", responseText); Assert.Contains("[bindRequiredParam:5]", responseText); Assert.Contains("[requiredAndBindRequiredParam:6]", responseText); Assert.Contains("[optionalStringLengthParam:]", responseText); Assert.Contains("[optionalRangeDisplayNameParam:0]", responseText); Assert.Equal(HttpStatusCode.OK, response.StatusCode); } [Fact] public async Task InvalidRequest_IsRejected() { // Arrange var content = new FormUrlEncodedContent(new Dictionary { { "OptionalStringLengthProp", "ThisStringIsTooLongForTheProperty" }, { "OptionalRangeDisplayNameProp", "123" }, { "optionalStringLengthParam", "ThisStringIsTooLongForTheParameter" }, { "optionalRangeDisplayNameParam", "456" }, }); // Act var response = await Client.PostAsync("http://localhost/TopLevelValidation", content); var responseText = await response.Content.ReadAsStringAsync(); var errors = JsonConvert.DeserializeObject(responseText) .Properties() .ToDictionary( prop => prop.Name, prop => ((JArray)prop.Value).Single().Value()); // Assert Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); Assert.Equal(10, errors.Count); Assert.Equal( "The RequiredProp field is required.", errors["RequiredProp"]); Assert.Equal( "A value for the 'BindRequiredProp' property was not provided.", errors["BindRequiredProp"]); Assert.Equal( "A value for the 'RequiredAndBindRequiredProp' property was not provided.", errors["RequiredAndBindRequiredProp"]); Assert.Equal( "The field OptionalStringLengthProp must be a string with a maximum length of 5.", errors["OptionalStringLengthProp"]); Assert.Equal( "The field Some Display Name For Prop must be between 1 and 100.", errors["OptionalRangeDisplayNameProp"]); Assert.Equal( "The requiredParam field is required.", errors["requiredParam"]); Assert.Equal( "A value for the 'bindRequiredParam' property was not provided.", errors["bindRequiredParam"]); Assert.Equal( "A value for the 'requiredAndBindRequiredParam' property was not provided.", errors["requiredAndBindRequiredParam"]); Assert.Equal( "The field optionalStringLengthParam must be a string with a maximum length of 5.", errors["optionalStringLengthParam"]); Assert.Equal( "The field Some Display Name For Param must be between 1 and 100.", errors["optionalRangeDisplayNameParam"]); } } }