diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/TypeMatchModelBinderTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/TypeMatchModelBinderTest.cs new file mode 100644 index 0000000000..8683fe75fe --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/TypeMatchModelBinderTest.cs @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.Framework.Internal; +using Xunit; + +namespace Microsoft.AspNet.Mvc.ModelBinding.Test +{ + public class TypeMatchModelBinderTest + { + [Fact] + public async Task BindModel_InvalidValueProviderResult_ReturnsFalse() + { + // Arrange + var bindingContext = GetBindingContext(); + bindingContext.ValueProvider = new SimpleHttpValueProvider + { + { "theModelName", "not an integer" } + }; + + var binder = new TypeMatchModelBinder(); + var modelState = bindingContext.ModelState; + + // Act + var result = await binder.BindModelAsync(bindingContext); + + // Assert + Assert.Null(result); + Assert.Empty(modelState.Keys); + Assert.True(modelState.IsValid); + } + + [Fact] + public async Task BindModel_ValidValueProviderResult_ReturnsTrue() + { + // Arrange + var bindingContext = GetBindingContext(); + bindingContext.ValueProvider = new SimpleHttpValueProvider + { + { "theModelName", 42 } + }; + + var binder = new TypeMatchModelBinder(); + var modelState = bindingContext.ModelState; + + // Act + var result = await binder.BindModelAsync(bindingContext); + + // Assert + Assert.NotNull(result); + Assert.True(result.IsModelSet); + Assert.Equal(42, result.Model); + var key = Assert.Single(modelState.Keys); + Assert.Equal("theModelName", key); + Assert.Equal("42", modelState[key].Value.AttemptedValue); + Assert.Equal(42, modelState[key].Value.RawValue); + } + + [Fact] + public async Task GetCompatibleValueProviderResult_ValueProviderResultRawValueIncorrect_ReturnsNull() + { + // Arrange + var bindingContext = GetBindingContext(); + bindingContext.ValueProvider = new SimpleHttpValueProvider + { + { "theModelName", "not an integer" } + }; + + // Act + var vpResult = await TypeMatchModelBinder.GetCompatibleValueProviderResult(bindingContext); + + // Assert + Assert.Null(vpResult); // Raw value is the wrong type + } + + [Fact] + public async Task GetCompatibleValueProviderResult_ValueProviderResultValid_ReturnsValueProviderResult() + { + // Arrange + var bindingContext = GetBindingContext(); + bindingContext.ValueProvider = new SimpleHttpValueProvider + { + { "theModelName", 42 } + }; + + // Act + var vpResult = await TypeMatchModelBinder.GetCompatibleValueProviderResult(bindingContext); + + // Assert + Assert.NotNull(vpResult); + } + + [Fact] + public async Task GetCompatibleValueProviderResult_ValueProviderReturnsNull_ReturnsNull() + { + // Arrange + var bindingContext = GetBindingContext(); + bindingContext.ValueProvider = new SimpleHttpValueProvider(); + + // Act + var vpResult = await TypeMatchModelBinder.GetCompatibleValueProviderResult(bindingContext); + + // Assert + Assert.Null(vpResult); // No key matched + } + + private static ModelBindingContext GetBindingContext() + { + return GetBindingContext(typeof(int)); + } + + private static ModelBindingContext GetBindingContext(Type modelType) + { + return new ModelBindingContext + { + ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(modelType), + ModelName = "theModelName" + }; + } + } +} diff --git a/test/Microsoft.AspNet.Mvc.IntegrationTests/BinderTypeBasedModelBinderIntegrationTest.cs b/test/Microsoft.AspNet.Mvc.IntegrationTests/BinderTypeBasedModelBinderIntegrationTest.cs new file mode 100644 index 0000000000..0b7e6b36a9 --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.IntegrationTests/BinderTypeBasedModelBinderIntegrationTest.cs @@ -0,0 +1,312 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Threading.Tasks; +using Microsoft.AspNet.Mvc.ModelBinding; +using Xunit; + +namespace Microsoft.AspNet.Mvc.IntegrationTests +{ + public class BinderTypeBasedModelBinderIntegrationTest + { + // The NullModelBinder and NullModelNotSetModelBinder return a non null ModelBindingResult but a null model. + [Theory(Skip = "ModelBindingResult should be non null if a model binder returns a non null resul #2473.")] + [InlineData(typeof(NullModelBinder), true)] + [InlineData(typeof(NullModelNotSetModelBinder), false)] + public async Task BindParameter_WithModelBinderType_NoData(Type modelBinderType, bool isModelSet) + { + // Arrange + var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); + var parameter = new ParameterDescriptor() + { + Name = "Parameter1", + BindingInfo = new BindingInfo() + { + BinderType = modelBinderType + }, + + ParameterType = typeof(string) + }; + + // No data is passed. + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { }); + var modelState = new ModelStateDictionary(); + + // Act + var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext); + + // Assert + + // ModelBindingResult + Assert.NotNull(modelBindingResult); + Assert.Null(modelBindingResult.Model); + Assert.Equal(isModelSet, modelBindingResult.IsModelSet); + + // ModelState + Assert.True(modelState.IsValid); + var key = Assert.Single(modelState.Keys); + Assert.Equal("CustomParameter", key); + Assert.Equal(0, modelState.ErrorCount); + Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); + Assert.Null(modelState[key].Value); // value is only set if the custom model binder sets it. + } + + private class Person2 + { + } + + // Since the NullResultModelBinder returns a null ModelBindingResult, it acts + // as a non greedy model binder, however since it is applied using a BinderTypeBasedModelBinder, + // which wraps this model binder and behaves as a greed model binder, we get a non null result. + [Fact(Skip = "ModelBindingResult should be non null if a model binder returns a non null resul #2473.")] + public async Task BindParameter_WithModelBinderType_NonGreedy_NoData() + { + // Arrange + var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); + var parameter = new ParameterDescriptor() + { + Name = "Parameter1", + BindingInfo = new BindingInfo() + { + BinderType = typeof(NullResultModelBinder) + }, + + ParameterType = typeof(Person2) + }; + + // No data is passed. + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { }); + var modelState = new ModelStateDictionary(); + + // Act + var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext); + + // Assert + + // ModelBindingResult + Assert.NotNull(modelBindingResult); + + // ModelState + Assert.True(modelState.IsValid); + Assert.Empty(modelState.Keys); + } + + // ModelBinderAttribute can be used without specifing the binder type. + // In such cases BinderTypeBasedModelBinder acts like a non greedy binder where + // it returns a null ModelBindingResult allowing other ModelBinders to run. + [Fact] + public async Task BindParameter_WithOutModelBinderType_NoData() + { + // Arrange + var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); + var parameter = new ParameterDescriptor() + { + Name = "Parameter1", + BindingInfo = new BindingInfo() + { + BinderType = typeof(NullResultModelBinder) + }, + + ParameterType = typeof(Person2) + }; + + // No data is passed. + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { }); + var modelState = new ModelStateDictionary(); + + // Act + var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext); + + // Assert + + // ModelBindingResult + Assert.Null(modelBindingResult); + + // ModelState + Assert.True(modelState.IsValid); + Assert.Empty(modelState.Keys); + } + + // Ensures that prefix is part of the result returned back. + [Fact] + public async Task BindParameter_WithData_WithPrefix_GetsBound() + { + // Arrange + var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); + var parameter = new ParameterDescriptor() + { + Name = "Parameter1", + BindingInfo = new BindingInfo() + { + BinderType = typeof(SuccessModelBinder), + BinderModelName = "CustomParameter" + }, + + ParameterType = typeof(Person2) + }; + + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { }); + var modelState = new ModelStateDictionary(); + + // Act + var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext); + + // Assert + + // ModelBindingResult + Assert.NotNull(modelBindingResult); + Assert.Equal("Success", modelBindingResult.Model); + Assert.Equal("CustomParameter", modelBindingResult.Key); + + // ModelState + Assert.True(modelState.IsValid); + var key = Assert.Single(modelState.Keys); + Assert.Equal("CustomParameter", key); + Assert.Null(modelState[key].Value); // value is only set if the custom model binder sets it. + } + + private class Person + { + public Address Address { get; set; } + } + + [ModelBinder(BinderType = typeof(AddressModelBinder))] + private class Address + { + public string Street { get; set; } + } + + [Fact(Skip = "Extra entries in model state #2446")] + public async Task BindProperty_WithData_EmptyPrefix_GetsBound() + { + // Arrange + var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); + var parameter = new ParameterDescriptor() + { + Name = "Parameter1", + BindingInfo = new BindingInfo(), + ParameterType = typeof(Person) + }; + + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { }); + var modelState = new ModelStateDictionary(); + + // Act + var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext); + + // Assert + + // ModelBindingResult + Assert.NotNull(modelBindingResult); + Assert.Equal("Parameter1", modelBindingResult.Key); + + // Model + var boundPerson = Assert.IsType(modelBindingResult.Model); + Assert.NotNull(boundPerson.Address); + Assert.Equal("SomeStreet", boundPerson.Address.Street); + + // ModelState + Assert.True(modelState.IsValid); + + // Should there be another key for what is there in the complex object ? + // This should probably behave like body binder, where even the body gets validated by default. + Assert.Equal(2, modelState.Keys.Count); + var key = Assert.Single(modelState.Keys, k => k == "Parameter1.Address.Street"); + Assert.Null(modelState[key].Value); // value is only set if the custom model binder sets it. + key = Assert.Single(modelState.Keys, k => k == "Parameter1.Address"); + Assert.Null(modelState[key].Value); // value is only set if the custom model binder sets it. + } + + [Fact(Skip = "Extra entries in model state #2446")] + public async Task BindProperty_WithData_WithPrefix_GetsBound() + { + // Arrange + var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); + var parameter = new ParameterDescriptor() + { + Name = "Parameter1", + BindingInfo = new BindingInfo() + { + BinderModelName = "CustomParameter" + }, + ParameterType = typeof(Person) + }; + + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { }); + var modelState = new ModelStateDictionary(); + + // Act + var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext); + + // Assert + + // ModelBindingResult + Assert.NotNull(modelBindingResult); + Assert.Equal("CustomParameter", modelBindingResult.Key); + + // Model + var boundPerson = Assert.IsType(modelBindingResult.Model); + Assert.NotNull(boundPerson.Address); + Assert.Equal("SomeStreet", boundPerson.Address.Street); + + // ModelState + Assert.True(modelState.IsValid); + + // Should there be another key for what is there in the complex object ? + // This should probably behave like body binder, where even the body gets validated by default. + Assert.Equal(2, modelState.Keys.Count); + var key = Assert.Single(modelState.Keys, k => k == "CustomParameter.Address.Street"); + Assert.Null(modelState[key].Value); // value is only set if the custom model binder sets it. + key = Assert.Single(modelState.Keys, k => k == "CustomParameter.Address"); + Assert.Null(modelState[key].Value); // value is only set if the custom model binder sets it. + } + + private class AddressModelBinder : IModelBinder + { + public Task BindModelAsync(ModelBindingContext bindingContext) + { + if (bindingContext.ModelType != typeof(Address)) + { + return null; + } + + var address = new Address() { Street = "SomeStreet" }; + + return Task.FromResult(new ModelBindingResult(address, bindingContext.ModelName, true)); + } + } + + private class SuccessModelBinder : IModelBinder + { + public Task BindModelAsync(ModelBindingContext bindingContext) + { + return Task.FromResult(new ModelBindingResult("Success", bindingContext.ModelName, true)); + } + } + + private class NullModelBinder : IModelBinder + { + public Task BindModelAsync(ModelBindingContext bindingContext) + { + return Task.FromResult(new ModelBindingResult(null, bindingContext.ModelName, true)); + } + } + + private class NullModelNotSetModelBinder : IModelBinder + { + public Task BindModelAsync(ModelBindingContext bindingContext) + { + return Task.FromResult(new ModelBindingResult(null, bindingContext.ModelName, false)); + } + } + + private class NullResultModelBinder : IModelBinder + { + public Task BindModelAsync(ModelBindingContext bindingContext) + { + return Task.FromResult(null); + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.IntegrationTests/FormCollectionModelBindingIntegrationTest.cs b/test/Microsoft.AspNet.Mvc.IntegrationTests/FormCollectionModelBindingIntegrationTest.cs new file mode 100644 index 0000000000..d7ebc232ac --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.IntegrationTests/FormCollectionModelBindingIntegrationTest.cs @@ -0,0 +1,184 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Collections; +using Microsoft.AspNet.Mvc.ModelBinding; +using Xunit; + +namespace Microsoft.AspNet.Mvc.IntegrationTests +{ + public class FormCollectionModelBindingIntegrationTest + { + private class Person + { + public Address Address { get; set; } + } + + private class Address + { + public int Zip { get; set; } + + public FormCollection FileCollection { get; set; } + } + + [Fact(Skip = "ModelState.Value not set due to #2445, Extra entries in model state #2446.")] + public async Task BindProperty_WithData_WithEmptyPrefix_GetsBound() + { + // Arrange + var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); + var parameter = new ParameterDescriptor() + { + Name = "Parameter1", + BindingInfo = new BindingInfo(), + ParameterType = typeof(Person) + }; + + var data = "Some Data Is Better Than No Data."; + var operationContext = ModelBindingTestHelper.GetOperationBindingContext( + request => + { + request.QueryString = new QueryString("Address.Zip", "12345"); + UpdateRequest(request, data, "Address.File"); + }); + + var modelState = new ModelStateDictionary(); + + // Act + var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext); + + // Assert + + // ModelBindingResult + Assert.NotNull(modelBindingResult); + Assert.True(modelBindingResult.IsModelSet); + + // Model + var boundPerson = Assert.IsType(modelBindingResult.Model); + Assert.NotNull(boundPerson.Address); + var formCollection = Assert.IsAssignableFrom(boundPerson.Address.FileCollection); + var file = Assert.Single(formCollection.Files); + Assert.Equal("form-data; name=Address.File; filename=text.txt", file.ContentDisposition); + var reader = new StreamReader(file.OpenReadStream()); + Assert.Equal(data, reader.ReadToEnd()); + + // ModelState + Assert.True(modelState.IsValid); + Assert.Equal(2, modelState.Count); + Assert.Single(modelState.Keys, k => k == "Address.Zip"); + var key = Assert.Single(modelState.Keys, k => k == "Address.File"); // Should be only one key. bug #2446 + Assert.NotNull(modelState[key].Value); // should be non null bug #2445. + Assert.Empty(modelState[key].Errors); + Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); + } + + [Fact(Skip = "Extra entries in model state #2446.")] + public async Task BindParameter_WithData_GetsBound() + { + // Arrange + var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); + var parameter = new ParameterDescriptor() + { + Name = "Parameter1", + BindingInfo = new BindingInfo() + { + // Setting a custom parameter prevents it from falling back to an empty prefix. + BinderModelName = "CustomParameter", + }, + + ParameterType = typeof(FormCollection) + }; + + var data = "Some Data Is Better Than No Data."; + var operationContext = ModelBindingTestHelper.GetOperationBindingContext( + request => + { + UpdateRequest(request, data, "CustomParameter"); + }); + + var modelState = new ModelStateDictionary(); + + // Act + var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext); + + // Assert + // ModelBindingResult + Assert.NotNull(modelBindingResult); + Assert.True(modelBindingResult.IsModelSet); + + // Model + var formCollection = Assert.IsType(modelBindingResult.Model); + Assert.NotNull(formCollection); + var file = Assert.Single(formCollection.Files); + Assert.NotNull(file); + Assert.Equal("form-data; name=CustomParameter; filename=text.txt", file.ContentDisposition); + var reader = new StreamReader(file.OpenReadStream()); + Assert.Equal(data, reader.ReadToEnd()); + + // ModelState + Assert.True(modelState.IsValid); + + // Validation should be skipped because we do not validate any parameters and since IFormFile is not + // IValidatableObject, we should have no entries in the model state dictionary. + Assert.Empty(modelState.Keys); // Enable when we fix #2446. + } + + [Fact(Skip = "Extra entries in model state #2446.")] + public async Task BindParameter_NoData_DoesNotGetBound() + { + // Arrange + var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); + var parameter = new ParameterDescriptor() + { + Name = "Parameter1", + BindingInfo = new BindingInfo() + { + BinderModelName = "CustomParameter", + }, + + ParameterType = typeof(FormCollection) + }; + + // No data is passed. + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => + { + request.ContentType = "multipart/form-data"; + }); + + var modelState = new ModelStateDictionary(); + + // Act + var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext); + + // Assert + + // ModelBindingResult + Assert.NotNull(modelBindingResult); // Fails due to bug #2456 + Assert.Null(modelBindingResult.Model); + + // ModelState + Assert.True(modelState.IsValid); + Assert.Empty(modelState.Keys); + } + + private void UpdateRequest(HttpRequest request, string data, string name) + { + var fileCollection = new FormFileCollection(); + var formCollection = new FormCollection(new Dictionary(), fileCollection); + var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(data)); + + request.Form = formCollection; + request.ContentType = "multipart/form-data"; + request.Headers["Content-Disposition"] = "form-data; name=" + name + "; filename=text.txt"; + fileCollection.Add(new FormFile(memoryStream, 0, data.Length) + { + Headers = request.Headers + }); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.IntegrationTests/TypeConverterModelBinderIntegrationTest.cs b/test/Microsoft.AspNet.Mvc.IntegrationTests/TypeConverterModelBinderIntegrationTest.cs new file mode 100644 index 0000000000..741b4321c6 --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.IntegrationTests/TypeConverterModelBinderIntegrationTest.cs @@ -0,0 +1,200 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Threading.Tasks; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.Mvc.ModelBinding; +using Xunit; + +namespace Microsoft.AspNet.Mvc.IntegrationTests +{ + public class TypeConverterModelBinderIntegrationTest + { + private class Person + { + public Address Address { get; set; } + } + + private class Address + { + public int Zip { get; set; } + } + + [Fact(Skip = "Extra entries in model state dictionary. #2466")] + public async Task BindProperty_WithData_WithPrefix_GetsBound() + { + // Arrange + var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); + var parameter = new ParameterDescriptor() + { + Name = "Parameter1", + BindingInfo = new BindingInfo() + { + BinderModelName = "CustomParameter", + }, + + ParameterType = typeof(Person) + }; + + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => + { + request.QueryString = new QueryString("CustomParameter.Address.Zip", "1"); + }); + + var modelState = new ModelStateDictionary(); + + // Act + var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext); + + // Assert + + // ModelBindingResult + Assert.NotNull(modelBindingResult); + Assert.True(modelBindingResult.IsModelSet); + + // Model + var boundPerson = Assert.IsType(modelBindingResult.Model); + Assert.NotNull(boundPerson); + Assert.NotNull(boundPerson.Address); + Assert.Equal(1, boundPerson.Address.Zip); + + // ModelState + Assert.True(modelState.IsValid); + + Assert.Equal(1, modelState.Keys.Count); + var key = Assert.Single(modelState.Keys, k => k == "CustomParameter.Address.Street"); + Assert.NotNull(modelState[key].Value); + Assert.Equal("1", modelState[key].Value.AttemptedValue); + Assert.Equal(1, modelState[key].Value.RawValue); + Assert.NotNull(modelState[key].Value); + Assert.Empty(modelState[key].Errors); + Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); + } + + [Fact(Skip = "Extra entries in model state dictionary. #2466")] + public async Task BindProperty_WithData_WithEmptyPrefix_GetsBound() + { + // Arrange + var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); + var parameter = new ParameterDescriptor() + { + Name = "Parameter1", + BindingInfo = new BindingInfo(), + ParameterType = typeof(Person) + }; + + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => + { + request.QueryString = new QueryString("Address.Zip", "1"); + }); + + var modelState = new ModelStateDictionary(); + + // Act + var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext); + + // Assert + + // ModelBindingResult + Assert.NotNull(modelBindingResult); + Assert.True(modelBindingResult.IsModelSet); + + // Model + var boundPerson = Assert.IsType(modelBindingResult.Model); + Assert.NotNull(boundPerson); + Assert.NotNull(boundPerson.Address); + Assert.Equal(1, boundPerson.Address.Zip); + + // ModelState + Assert.True(modelState.IsValid); + + Assert.Equal(1, modelState.Keys.Count); + var key = Assert.Single(modelState.Keys, k => k == "Address.Zip"); + Assert.NotNull(modelState[key].Value); + Assert.Equal("1", modelState[key].Value.AttemptedValue); + Assert.Equal(1, modelState[key].Value.RawValue); + Assert.NotNull(modelState[key].Value); + Assert.Empty(modelState[key].Errors); + Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); + } + + [Fact] + public async Task BindParameter_WithData_GetsBound() + { + // Arrange + var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); + var parameter = new ParameterDescriptor() + { + Name = "Parameter1", + BindingInfo = new BindingInfo(), + + ParameterType = typeof(string) + }; + + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => + { + request.QueryString = new QueryString("Parameter1", "someValue"); + }); + + var modelState = new ModelStateDictionary(); + + // Act + var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext); + + // Assert + + // ModelBindingResult + Assert.NotNull(modelBindingResult); + Assert.True(modelBindingResult.IsModelSet); + + // Model + var model = Assert.IsType(modelBindingResult.Model); + Assert.Equal("someValue", model); + + // ModelState + Assert.True(modelState.IsValid); + + Assert.Equal(1, modelState.Keys.Count); + var key = Assert.Single(modelState.Keys); + Assert.Equal("Parameter1", key); + Assert.NotNull(modelState[key].Value); + Assert.Equal("someValue", modelState[key].Value.AttemptedValue); + Assert.Equal("someValue", modelState[key].Value.RawValue); + Assert.Empty(modelState[key].Errors); + Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); + } + + [Fact] + public async Task BindParameter_NoData_DoesNotGetBound() + { + // Arrange + var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); + var parameter = new ParameterDescriptor() + { + Name = "Parameter1", + BindingInfo = new BindingInfo(), + + ParameterType = typeof(string) + }; + + // No Data. + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => + { + }); + + var modelState = new ModelStateDictionary(); + + // Act + var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext); + + // Assert + + // ModelBindingResult + Assert.Null(modelBindingResult); + + // ModelState + Assert.True(modelState.IsValid); + Assert.Empty(modelState.Keys); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.IntegrationTests/project.json b/test/Microsoft.AspNet.Mvc.IntegrationTests/project.json index 56bc2d2937..ab1b654f09 100644 --- a/test/Microsoft.AspNet.Mvc.IntegrationTests/project.json +++ b/test/Microsoft.AspNet.Mvc.IntegrationTests/project.json @@ -3,7 +3,7 @@ "warningsAsErrors": "true" }, "dependencies": { - "Microsoft.AspNet.Mvc":"6.0.0-*", + "Microsoft.AspNet.Mvc": "6.0.0-*", "Microsoft.AspNet.Mvc.TestCommon": { "version": "6.0.0-*", "type": "build" }, "Microsoft.AspNet.Testing": "1.0.0-*", "Moq": "4.2.1312.1622",