Correct test expectations

- use valid `multipart/form-data` content type; include a `boundary`
- correct expectations of `FormCollection` model binder's operation
 - restore tests actually skipped for either of the above reasons
- add more tests with `ModelBindingResult.Model==null` and both `IsModelSet` values

#### Remove test references to Won't Fix bug #2473
- restore #2473 tests; update test expectations
- expect `null` composite results whenever binding fails

#### Restore test skipped due to "#2646"
- that issue does not exist; was likely #2466 or similar fixed bug

#### Rename model binding tests that still mention ReturnsFalse or ReturnsTrue

#### Minor src changes
- remove unused variable and unnecessary nesting in `DefaultControllerActionArgumentBinder`
- remove dangling mention of `[DefaultValue]` in `ComplexModelDtoModelBinder`

#### nits:
- remove empty delegates from some `GetOperationBindingContext` calls; `null` fine
- do some `using` cleanup
- combine two test methods in `KeyValuePairModelBinderTest`
- name a few more arguments
This commit is contained in:
Doug Bunting 2015-06-01 12:15:39 -07:00
parent e0b8532735
commit 26795bd4b5
19 changed files with 158 additions and 137 deletions

View File

@ -81,24 +81,21 @@ namespace Microsoft.AspNet.Mvc
operationContext); operationContext);
var modelBindingResult = await operationContext.ModelBinder.BindModelAsync(modelBindingContext); var modelBindingResult = await operationContext.ModelBinder.BindModelAsync(modelBindingContext);
if (modelBindingResult != null && modelBindingResult.IsModelSet) if (modelBindingResult != null &&
modelBindingResult.IsModelSet &&
modelBindingResult.ValidationNode != null)
{ {
var key = modelBindingResult.Key;
var modelExplorer = new ModelExplorer( var modelExplorer = new ModelExplorer(
_modelMetadataProvider, _modelMetadataProvider,
metadata, metadata,
modelBindingResult.Model); modelBindingResult.Model);
var validationContext = new ModelValidationContext(
modelBindingContext.BindingSource,
operationContext.ValidatorProvider,
modelState,
modelExplorer);
if (modelBindingResult.ValidationNode != null) _validator.Validate(validationContext, modelBindingResult.ValidationNode);
{
var validationContext = new ModelValidationContext(
modelBindingContext.BindingSource,
operationContext.ValidatorProvider,
modelState,
modelExplorer);
_validator.Validate(validationContext, modelBindingResult.ValidationNode);
}
} }
return modelBindingResult; return modelBindingResult;

View File

@ -32,7 +32,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
await bindingContext.OperationBindingContext.ModelBinder.BindModelAsync(propertyBindingContext); await bindingContext.OperationBindingContext.ModelBinder.BindModelAsync(propertyBindingContext);
if (modelBindingResult == null) if (modelBindingResult == null)
{ {
// Could not bind. Add a result so MutableObjectModelBinder will check for [DefaultValue]. // Could not bind. Let MutableObjectModelBinder know explicitly.
dto.Results[propertyMetadata] = dto.Results[propertyMetadata] =
new ModelBindingResult(model: null, key: propertyModelName, isModelSet: false); new ModelBindingResult(model: null, key: propertyModelName, isModelSet: false);
} }

View File

@ -15,7 +15,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public class BinderTypeBasedModelBinderModelBinderTest public class BinderTypeBasedModelBinderModelBinderTest
{ {
[Fact] [Fact]
public async Task BindModel_ReturnsFalseIfNoBinderTypeIsSet() public async Task BindModel_ReturnsNull_IfNoBinderTypeIsSet()
{ {
// Arrange // Arrange
var bindingContext = GetBindingContext(typeof(Person)); var bindingContext = GetBindingContext(typeof(Person));
@ -30,10 +30,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
} }
[Fact] [Fact]
public async Task BindModel_ReturnsTrueEvenIfSelectedBinderReturnsFalse() public async Task BindModel_ReturnsNotNull_EvenIfSelectedBinderReturnsNull()
{ {
// Arrange // Arrange
var bindingContext = GetBindingContext(typeof(Person), binderType: typeof(FalseModelBinder)); var bindingContext = GetBindingContext(typeof(Person), binderType: typeof(NullModelBinder));
var binder = new BinderTypeBasedModelBinder(); var binder = new BinderTypeBasedModelBinder();
@ -48,7 +48,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public async Task BindModel_CallsBindAsync_OnProvidedModelBinder() public async Task BindModel_CallsBindAsync_OnProvidedModelBinder()
{ {
// Arrange // Arrange
var bindingContext = GetBindingContext(typeof(Person), binderType: typeof(TrueModelBinder)); var bindingContext = GetBindingContext(typeof(Person), binderType: typeof(NotNullModelBinder));
var model = new Person(); var model = new Person();
var serviceProvider = new ServiceCollection() var serviceProvider = new ServiceCollection()
@ -121,7 +121,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public int Age { get; set; } public int Age { get; set; }
} }
private class FalseModelBinder : IModelBinder private class NullModelBinder : IModelBinder
{ {
public Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext) public Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
{ {
@ -129,11 +129,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
} }
} }
private class TrueModelBinder : IModelBinder private class NotNullModelBinder : IModelBinder
{ {
private readonly object _model; private readonly object _model;
public TrueModelBinder() public NotNullModelBinder()
{ {
_model = new Person(); _model = new Person();
} }

View File

@ -27,20 +27,20 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Act & Assert // Act & Assert
var exception = Assert.Throws<ArgumentException>( var exception = Assert.Throws<ArgumentException>(
() => new TestableBindingSourceModelBinder(bindingSource)); () => new TestableBindingSourceModelBinder(bindingSource, isModelSet: false));
Assert.Equal(expected, exception.Message); Assert.Equal(expected, exception.Message);
} }
[Fact] [Fact]
public async Task BindingSourceModelBinder_ReturnsFalse_WithNoSource() public async Task BindingSourceModelBinder_ReturnsNull_WithNoSource()
{ {
// Arrange // Arrange
var context = new ModelBindingContext(); var context = new ModelBindingContext();
context.ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(string)); context.ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(string));
var binder = new TestableBindingSourceModelBinder(BindingSource.Body); var binder = new TestableBindingSourceModelBinder(BindingSource.Body, isModelSet: false);
// Act // Act
var result = await binder.BindModelAsync(context); var result = await binder.BindModelAsync(context);
// Assert // Assert
@ -49,7 +49,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
} }
[Fact] [Fact]
public async Task BindingSourceModelBinder_ReturnsFalse_NonMatchingSource() public async Task BindingSourceModelBinder_ReturnsNull_NonMatchingSource()
{ {
// Arrange // Arrange
var provider = new TestModelMetadataProvider(); var provider = new TestModelMetadataProvider();
@ -58,9 +58,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var context = new ModelBindingContext(); var context = new ModelBindingContext();
context.ModelMetadata = provider.GetMetadataForType(typeof(string)); context.ModelMetadata = provider.GetMetadataForType(typeof(string));
var binder = new TestableBindingSourceModelBinder(BindingSource.Body); var binder = new TestableBindingSourceModelBinder(BindingSource.Body, isModelSet: false);
// Act // Act
var result = await binder.BindModelAsync(context); var result = await binder.BindModelAsync(context);
// Assert // Assert
@ -68,8 +68,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
Assert.False(binder.WasBindModelCoreCalled); Assert.False(binder.WasBindModelCoreCalled);
} }
[Fact] [Theory]
public async Task BindingSourceModelBinder_ReturnsTrue_MatchingSource() [InlineData(false)]
[InlineData(true)]
public async Task BindingSourceModelBinder_ReturnsNonNull_MatchingSource(bool isModelSet)
{ {
// Arrange // Arrange
var provider = new TestModelMetadataProvider(); var provider = new TestModelMetadataProvider();
@ -82,30 +84,35 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
BinderModelName = modelMetadata.BinderModelName BinderModelName = modelMetadata.BinderModelName
}; };
var binder = new TestableBindingSourceModelBinder(BindingSource.Body); var binder = new TestableBindingSourceModelBinder(BindingSource.Body, isModelSet);
// Act // Act
var result = await binder.BindModelAsync(context); var result = await binder.BindModelAsync(context);
// Assert // Assert
Assert.NotNull(result); Assert.NotNull(result);
Assert.True(result.IsModelSet); Assert.Equal(isModelSet, result.IsModelSet);
Assert.Null(result.Model);
Assert.True(binder.WasBindModelCoreCalled); Assert.True(binder.WasBindModelCoreCalled);
} }
private class TestableBindingSourceModelBinder : BindingSourceModelBinder private class TestableBindingSourceModelBinder : BindingSourceModelBinder
{ {
public bool WasBindModelCoreCalled { get; private set; } bool _isModelSet;
public TestableBindingSourceModelBinder(BindingSource source) public TestableBindingSourceModelBinder(BindingSource source, bool isModelSet)
: base(source) : base(source)
{ {
_isModelSet = isModelSet;
} }
public bool WasBindModelCoreCalled { get; private set; }
protected override Task<ModelBindingResult> BindModelCoreAsync([NotNull] ModelBindingContext bindingContext) protected override Task<ModelBindingResult> BindModelCoreAsync([NotNull] ModelBindingContext bindingContext)
{ {
WasBindModelCoreCalled = true; WasBindModelCoreCalled = true;
return Task.FromResult(new ModelBindingResult(null, bindingContext.ModelName, true)); return Task.FromResult(
new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: _isModelSet));
} }
} }
} }

View File

@ -3,7 +3,6 @@
#if DNX451 #if DNX451
using System; using System;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Testing; using Microsoft.AspNet.Testing;
using Xunit; using Xunit;
@ -81,7 +80,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
} }
[Fact] [Fact]
public async Task BindModelReturnsFalseWhenValueNotFound() public async Task BindModel_ReturnsNull_WhenValueNotFound()
{ {
// Arrange // Arrange
var valueProvider = new SimpleHttpValueProvider() var valueProvider = new SimpleHttpValueProvider()
@ -100,7 +99,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
} }
[Fact] [Fact]
public async Task ByteArrayModelBinderReturnsFalseForOtherTypes() public async Task BindModel_ReturnsNull_ForOtherTypes()
{ {
// Arrange // Arrange
var bindingContext = GetBindingContext(null, typeof(int[])); var bindingContext = GetBindingContext(null, typeof(int[]));

View File

@ -12,7 +12,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public class CancellationTokenModelBinderTests public class CancellationTokenModelBinderTests
{ {
[Fact] [Fact]
public async Task CancellationTokenModelBinder_ReturnsTrue_ForCancellationTokenType() public async Task CancellationTokenModelBinder_ReturnsNotNull_ForCancellationTokenType()
{ {
// Arrange // Arrange
var bindingContext = GetBindingContext(typeof(CancellationToken)); var bindingContext = GetBindingContext(typeof(CancellationToken));
@ -30,7 +30,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
[InlineData(typeof(int))] [InlineData(typeof(int))]
[InlineData(typeof(object))] [InlineData(typeof(object))]
[InlineData(typeof(CancellationTokenModelBinderTests))] [InlineData(typeof(CancellationTokenModelBinderTests))]
public async Task CancellationTokenModelBinder_ReturnsFalse_ForNonCancellationTokenType(Type t) public async Task CancellationTokenModelBinder_ReturnsNull_ForNonCancellationTokenType(Type t)
{ {
// Arrange // Arrange
var bindingContext = GetBindingContext(t); var bindingContext = GetBindingContext(t);

View File

@ -5,7 +5,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.ModelBinding.Validation; using Microsoft.AspNet.Mvc.ModelBinding.Validation;
using Moq; using Moq;
@ -268,10 +267,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
} }
[Fact] [Fact]
public async Task ModelBinder_ReturnsTrue_SetsNullValue_SetsModelStateKey() public async Task ModelBinder_ReturnsNotNull_SetsNullValue_SetsModelStateKey()
{ {
// Arrange // Arrange
var bindingContext = new ModelBindingContext var bindingContext = new ModelBindingContext
{ {
FallbackToEmptyPrefix = true, FallbackToEmptyPrefix = true,
@ -291,7 +289,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
var modelBinder = new Mock<IModelBinder>(); var modelBinder = new Mock<IModelBinder>();
modelBinder modelBinder
.Setup(mb => mb.BindModelAsync(It.IsAny<ModelBindingContext>())) .Setup(mb => mb.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Returns(Task.FromResult(new ModelBindingResult(null, "someName", true))); .Returns(Task.FromResult(new ModelBindingResult(model: null, key: "someName", isModelSet: true)));
var composite = CreateCompositeBinder(modelBinder.Object); var composite = CreateCompositeBinder(modelBinder.Object);
@ -455,7 +453,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
var result = await binder.BindModelAsync(bindingContext); var result = await binder.BindModelAsync(bindingContext);
// Assert // Assert
// The result is null because of issue #2473
Assert.Null(result); Assert.Null(result);
} }

View File

@ -33,8 +33,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
[Theory] [Theory]
[InlineData("application/x-www-form-urlencoded")] [InlineData("application/x-www-form-urlencoded")]
[InlineData("application/x-www-form-urlencoded;charset=utf-8")] [InlineData("application/x-www-form-urlencoded;charset=utf-8")]
[InlineData("multipart/form-data")] [InlineData("multipart/form-data; boundary=----WebKitFormBoundarymx2fSWqWSd0OxQqq")]
[InlineData("multipart/form-data;charset=utf-8")] [InlineData("multipart/form-data; boundary=----WebKitFormBoundarymx2fSWqWSd0OxQqq; charset=utf-8")]
public void GetValueProvider_ReturnsValueProviderInstanceWithInvariantCulture(string contentType) public void GetValueProvider_ReturnsValueProviderInstanceWithInvariantCulture(string contentType)
{ {
// Arrange // Arrange

View File

@ -17,7 +17,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
[InlineData(typeof(int))] [InlineData(typeof(int))]
[InlineData(typeof(int[]))] [InlineData(typeof(int[]))]
[InlineData(typeof(BindingSource))] [InlineData(typeof(BindingSource))]
public async Task BindModelAsync_ReturnsTrue_ForAllTypes(Type type) public async Task BindModelAsync_ReturnsNotNull_ForAllTypes(Type type)
{ {
// Arrange // Arrange
var binder = new HeaderModelBinder(); var binder = new HeaderModelBinder();

View File

@ -115,38 +115,27 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
Assert.Empty(validationNode.ChildNodes); Assert.Empty(validationNode.ChildNodes);
} }
[Fact] [Theory]
public async Task TryBindStrongModel_BinderExists_BinderReturnsCorrectlyTypedObject_ReturnsTrue() [InlineData(null, false)]
{ [InlineData(null, true)]
// Arrange [InlineData(42, false)]
var bindingContext = GetBindingContext(new SimpleHttpValueProvider()); [InlineData(42, true)]
var binder = new KeyValuePairModelBinder<int, string>(); public async Task TryBindStrongModel_InnerBinderReturnsNotNull_ReturnsInnerBinderResult(
var modelValidationNodeList = new List<ModelValidationNode>(); object model,
bool isModelSet)
// Act
var result = await binder.TryBindStrongModel<int>(bindingContext, "key", modelValidationNodeList);
// Assert
Assert.True(result.IsModelSet);
Assert.Equal(42, result.Model);
Assert.Empty(bindingContext.ModelState);
}
[Fact]
public async Task TryBindStrongModel_BinderExists_BinderReturnsIncorrectlyTypedObject_ReturnsTrue()
{ {
// Arrange // Arrange
var innerResult = new ModelBindingResult(model, key: string.Empty, isModelSet: isModelSet);
var innerBinder = new Mock<IModelBinder>(); var innerBinder = new Mock<IModelBinder>();
innerBinder innerBinder
.Setup(o => o.BindModelAsync(It.IsAny<ModelBindingContext>())) .Setup(o => o.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Returns((ModelBindingContext mbc) => .Returns((ModelBindingContext context) =>
{ {
Assert.Equal("someName.key", mbc.ModelName); Assert.Equal("someName.key", context.ModelName);
return Task.FromResult(new ModelBindingResult(null, string.Empty, true)); return Task.FromResult(innerResult);
}); });
var bindingContext = GetBindingContext(new SimpleHttpValueProvider(), innerBinder.Object); var bindingContext = GetBindingContext(new SimpleHttpValueProvider(), innerBinder.Object);
var binder = new KeyValuePairModelBinder<int, string>(); var binder = new KeyValuePairModelBinder<int, string>();
var modelValidationNodeList = new List<ModelValidationNode>(); var modelValidationNodeList = new List<ModelValidationNode>();
@ -154,8 +143,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
var result = await binder.TryBindStrongModel<int>(bindingContext, "key", modelValidationNodeList); var result = await binder.TryBindStrongModel<int>(bindingContext, "key", modelValidationNodeList);
// Assert // Assert
Assert.True(result.IsModelSet); Assert.Same(innerResult, result);
Assert.Null(result.Model);
Assert.Empty(bindingContext.ModelState); Assert.Empty(bindingContext.ModelState);
} }

View File

@ -15,7 +15,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
[InlineData(typeof(object))] [InlineData(typeof(object))]
[InlineData(typeof(Calendar))] [InlineData(typeof(Calendar))]
[InlineData(typeof(TestClass))] [InlineData(typeof(TestClass))]
public async Task BindModel_ReturnsFalse_IfTypeCannotBeConverted(Type destinationType) public async Task BindModel_ReturnsNull_IfTypeCannotBeConverted(Type destinationType)
{ {
// Arrange // Arrange
var bindingContext = GetBindingContext(destinationType); var bindingContext = GetBindingContext(destinationType);
@ -42,7 +42,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
[InlineData(typeof(DateTimeOffset))] [InlineData(typeof(DateTimeOffset))]
[InlineData(typeof(double))] [InlineData(typeof(double))]
[InlineData(typeof(DayOfWeek))] [InlineData(typeof(DayOfWeek))]
public async Task BindModel_ReturnsTrue_IfTypeCanBeConverted(Type destinationType) public async Task BindModel_ReturnsNotNull_IfTypeCanBeConverted(Type destinationType)
{ {
if (TestPlatformHelper.IsMono && if (TestPlatformHelper.IsMono &&
destinationType == typeof(DateTimeOffset)) destinationType == typeof(DateTimeOffset))
@ -92,7 +92,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
} }
[Fact] [Fact]
public async Task BindModel_NullValueProviderResult_ReturnsFalse() public async Task BindModel_NullValueProviderResult_ReturnsNull()
{ {
// Arrange // Arrange
var bindingContext = GetBindingContext(typeof(int)); var bindingContext = GetBindingContext(typeof(int));

View File

@ -1,9 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information. // Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Framework.Internal;
using Xunit; using Xunit;
namespace Microsoft.AspNet.Mvc.ModelBinding.Test namespace Microsoft.AspNet.Mvc.ModelBinding.Test
@ -11,7 +9,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public class TypeMatchModelBinderTest public class TypeMatchModelBinderTest
{ {
[Fact] [Fact]
public async Task BindModel_InvalidValueProviderResult_ReturnsFalse() public async Task BindModel_InvalidValueProviderResult_ReturnsNull()
{ {
// Arrange // Arrange
var bindingContext = GetBindingContext(); var bindingContext = GetBindingContext();
@ -33,7 +31,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
} }
[Fact] [Fact]
public async Task BindModel_ValidValueProviderResult_ReturnsTrue() public async Task BindModel_ValidValueProviderResult_ReturnsNotNull()
{ {
// Arrange // Arrange
var bindingContext = GetBindingContext(); var bindingContext = GetBindingContext();

View File

@ -17,7 +17,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
public class ControllerActionArgumentBinderTests public class ControllerActionArgumentBinderTests
{ {
[Fact] [Fact]
public async Task BindActionArgumentsAsync_DoesNotAddActionArguments_IfBinderReturnsFalse() public async Task BindActionArgumentsAsync_DoesNotAddActionArguments_IfBinderReturnsNull()
{ {
// Arrange // Arrange
var actionDescriptor = GetActionDescriptor(); var actionDescriptor = GetActionDescriptor();
@ -91,7 +91,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
} }
[Fact] [Fact]
public async Task BindActionArgumentsAsync_AddsActionArguments_IfBinderReturnsTrue() public async Task BindActionArgumentsAsync_AddsActionArguments_IfBinderReturnsNotNull()
{ {
// Arrange // Arrange
Func<object, int> method = foo => 1; Func<object, int> method = foo => 1;
@ -114,7 +114,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
{ {
context.ModelMetadata = metadataProvider.GetMetadataForType(typeof(string)); context.ModelMetadata = metadataProvider.GetMetadataForType(typeof(string));
}) })
.Returns(Task.FromResult(result: new ModelBindingResult(value, "", true))); .Returns(Task.FromResult(result: new ModelBindingResult(value, key: string.Empty, isModelSet: true)));
var actionContext = new ActionContext( var actionContext = new ActionContext(
new DefaultHttpContext(), new DefaultHttpContext(),
@ -342,8 +342,10 @@ namespace Microsoft.AspNet.Mvc.Core.Test
Assert.Null(controller.UntouchedProperty); Assert.Null(controller.UntouchedProperty);
} }
[Fact] [Theory]
public async Task BindActionArgumentsAsync_DoesNotSetNullValues_ForNonNullableProperties() [InlineData(false)]
[InlineData(true)]
public async Task BindActionArgumentsAsync_DoesNotSetNullValues_ForNonNullableProperties(bool isModelSet)
{ {
// Arrange // Arrange
var actionDescriptor = GetActionDescriptor(); var actionDescriptor = GetActionDescriptor();
@ -361,7 +363,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
binder binder
.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>())) .Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Returns(Task.FromResult( .Returns(Task.FromResult(
result: new ModelBindingResult(model: null, key: string.Empty, isModelSet: true))); result: new ModelBindingResult(model: null, key: string.Empty, isModelSet: isModelSet)));
var actionBindingContext = new ActionBindingContext() var actionBindingContext = new ActionBindingContext()
{ {
ModelBinder = binder.Object, ModelBinder = binder.Object,

View File

@ -19,7 +19,7 @@ namespace Microsoft.AspNet.Mvc.Test
public class ModelBindingHelperTest public class ModelBindingHelperTest
{ {
[Fact] [Fact]
public async Task TryUpdateModel_ReturnsFalse_IfBinderReturnsFalse() public async Task TryUpdateModel_ReturnsFalse_IfBinderReturnsNull()
{ {
// Arrange // Arrange
var metadataProvider = new EmptyModelMetadataProvider(); var metadataProvider = new EmptyModelMetadataProvider();
@ -28,7 +28,7 @@ namespace Microsoft.AspNet.Mvc.Test
binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>())) binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Returns(Task.FromResult<ModelBindingResult>(null)); .Returns(Task.FromResult<ModelBindingResult>(null));
var model = new MyModel(); var model = new MyModel();
// Act // Act
var result = await ModelBindingHelper.TryUpdateModelAsync( var result = await ModelBindingHelper.TryUpdateModelAsync(
model, model,
@ -130,7 +130,7 @@ namespace Microsoft.AspNet.Mvc.Test
} }
[Fact] [Fact]
public async Task TryUpdateModel_UsingIncludePredicateOverload_ReturnsFalse_IfBinderReturnsFalse() public async Task TryUpdateModel_UsingIncludePredicateOverload_ReturnsFalse_IfBinderReturnsNull()
{ {
// Arrange // Arrange
var metadataProvider = new EmptyModelMetadataProvider(); var metadataProvider = new EmptyModelMetadataProvider();
@ -219,7 +219,7 @@ namespace Microsoft.AspNet.Mvc.Test
} }
[Fact] [Fact]
public async Task TryUpdateModel_UsingIncludeExpressionOverload_ReturnsFalse_IfBinderReturnsFalse() public async Task TryUpdateModel_UsingIncludeExpressionOverload_ReturnsFalse_IfBinderReturnsNull()
{ {
// Arrange // Arrange
var metadataProvider = new EmptyModelMetadataProvider(); var metadataProvider = new EmptyModelMetadataProvider();
@ -475,7 +475,7 @@ namespace Microsoft.AspNet.Mvc.Test
} }
[Fact] [Fact]
public async Task TryUpdateModelNonGeneric_PredicateOverload_ReturnsFalse_IfBinderReturnsFalse() public async Task TryUpdateModelNonGeneric_PredicateOverload_ReturnsFalse_IfBinderReturnsNull()
{ {
// Arrange // Arrange
var metadataProvider = new EmptyModelMetadataProvider(); var metadataProvider = new EmptyModelMetadataProvider();
@ -568,7 +568,7 @@ namespace Microsoft.AspNet.Mvc.Test
} }
[Fact] [Fact]
public async Task TryUpdateModelNonGeneric_ModelTypeOverload_ReturnsFalse_IfBinderReturnsFalse() public async Task TryUpdateModelNonGeneric_ModelTypeOverload_ReturnsFalse_IfBinderReturnsNull()
{ {
// Arrange // Arrange
var metadataProvider = new EmptyModelMetadataProvider(); var metadataProvider = new EmptyModelMetadataProvider();
@ -774,7 +774,7 @@ namespace Microsoft.AspNet.Mvc.Test
dictionary["product.Category.Name"] = new ModelState { ValidationState = ModelValidationState.Valid }; dictionary["product.Category.Name"] = new ModelState { ValidationState = ModelValidationState.Valid };
dictionary["product.Order[0].Name"] = new ModelState { ValidationState = ModelValidationState.Invalid }; dictionary["product.Order[0].Name"] = new ModelState { ValidationState = ModelValidationState.Invalid };
dictionary.AddModelError("product.Order[0].Name", "Order name invalid."); dictionary.AddModelError("product.Order[0].Name", "Order name invalid.");
dictionary["product.Order[0].Address.Street"] = dictionary["product.Order[0].Address.Street"] =
new ModelState { ValidationState = ModelValidationState.Invalid }; new ModelState { ValidationState = ModelValidationState.Invalid };
dictionary.AddModelError("product.Order[0].Address.Street", "Street invalid."); dictionary.AddModelError("product.Order[0].Address.Street", "Street invalid.");
dictionary["product.Order[1].Name"] = new ModelState { ValidationState = ModelValidationState.Valid }; dictionary["product.Order[1].Name"] = new ModelState { ValidationState = ModelValidationState.Valid };

View File

@ -1,7 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Globalization; using System.Globalization;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
@ -12,11 +11,9 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
{ {
public class BinderTypeBasedModelBinderIntegrationTest public class BinderTypeBasedModelBinderIntegrationTest
{ {
// The NullModelBinder and NullModelNotSetModelBinder return a non null ModelBindingResult but a null model. [Fact]
[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)] [InlineData(typeof(NullModelNotSetModelBinder), false)]
public async Task BindParameter_WithModelBinderType_NoData(Type modelBinderType, bool isModelSet) public async Task BindParameter_WithModelBinderType_NullData_ReturnsNull()
{ {
// Arrange // Arrange
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
@ -25,14 +22,14 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Name = "Parameter1", Name = "Parameter1",
BindingInfo = new BindingInfo() BindingInfo = new BindingInfo()
{ {
BinderType = modelBinderType BinderType = typeof(NullModelBinder)
}, },
ParameterType = typeof(string) ParameterType = typeof(string)
}; };
// No data is passed. // No data is passed.
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { }); var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
var modelState = new ModelStateDictionary(); var modelState = new ModelStateDictionary();
// Act // Act
@ -42,27 +39,53 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
// ModelBindingResult // ModelBindingResult
Assert.NotNull(modelBindingResult); Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
Assert.Null(modelBindingResult.Model); Assert.Null(modelBindingResult.Model);
Assert.Equal(isModelSet, modelBindingResult.IsModelSet);
// ModelState // ModelState (not set unless inner binder sets it)
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var key = Assert.Single(modelState.Keys); Assert.Empty(modelState);
Assert.Equal("CustomParameter", key); }
Assert.Equal(0, modelState.ErrorCount);
Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); [Fact]
Assert.Null(modelState[key].Value); // value is only set if the custom model binder sets it. public async Task BindParameter_WithModelBinderType_NoData_ReturnsNull()
{
// Arrange
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "Parameter1",
BindingInfo = new BindingInfo()
{
BinderType = typeof(NullModelNotSetModelBinder)
},
ParameterType = typeof(string)
};
// No data is passed.
var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
var modelState = new ModelStateDictionary();
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
// ModelBindingResult
Assert.Null(modelBindingResult);
// ModelState (not set unless inner binder sets it)
Assert.True(modelState.IsValid);
Assert.Empty(modelState);
} }
private class Person2 private class Person2
{ {
} }
// Since the NullResultModelBinder returns a null ModelBindingResult, it acts [Fact]
// as a non greedy model binder, however since it is applied using a BinderTypeBasedModelBinder, public async Task BindParameter_WithModelBinderType_NonGreedy_NoData_ReturnsNull()
// 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 // Arrange
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
@ -78,7 +101,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
}; };
// No data is passed. // No data is passed.
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { }); var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
var modelState = new ModelStateDictionary(); var modelState = new ModelStateDictionary();
// Act // Act
@ -87,14 +110,14 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
// Assert // Assert
// ModelBindingResult // ModelBindingResult
Assert.NotNull(modelBindingResult); Assert.Null(modelBindingResult);
// ModelState // ModelState
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
Assert.Empty(modelState.Keys); Assert.Empty(modelState.Keys);
} }
// ModelBinderAttribute can be used without specifing the binder type. // ModelBinderAttribute can be used without specifying the binder type.
// In such cases BinderTypeBasedModelBinder acts like a non greedy binder where // In such cases BinderTypeBasedModelBinder acts like a non greedy binder where
// it returns a null ModelBindingResult allowing other ModelBinders to run. // it returns a null ModelBindingResult allowing other ModelBinders to run.
[Fact] [Fact]
@ -114,7 +137,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
}; };
// No data is passed. // No data is passed.
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { }); var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
var modelState = new ModelStateDictionary(); var modelState = new ModelStateDictionary();
// Act // Act
@ -149,7 +172,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
ParameterType = typeof(Person2) ParameterType = typeof(Person2)
}; };
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { }); var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
var modelState = new ModelStateDictionary(); var modelState = new ModelStateDictionary();
// Act // Act
@ -193,7 +216,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
ParameterType = typeof(Person) ParameterType = typeof(Person)
}; };
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { }); var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
var modelState = new ModelStateDictionary(); var modelState = new ModelStateDictionary();
// Act // Act
@ -234,7 +257,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
ParameterType = typeof(Person) ParameterType = typeof(Person)
}; };
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { }); var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
var modelState = new ModelStateDictionary(); var modelState = new ModelStateDictionary();
// Act // Act

View File

@ -128,8 +128,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Empty(modelState.Keys); Assert.Empty(modelState.Keys);
} }
[Fact(Skip = "FormCollection should not return null modelBindingResult for a type that matches. #2456")] [Fact]
public async Task BindParameter_NoData_DoesNotGetBound() public async Task BindParameter_NoData_BindsWithEmptyCollection()
{ {
// Arrange // Arrange
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
@ -158,11 +158,16 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
// ModelBindingResult // ModelBindingResult
Assert.NotNull(modelBindingResult); Assert.NotNull(modelBindingResult);
Assert.Null(modelBindingResult.Model); var collection = Assert.IsType<FormCollection>(modelBindingResult.Model);
// ModelState // ModelState
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
Assert.Empty(modelState.Keys); Assert.Empty(modelState.Keys);
// FormCollection
Assert.Empty(collection);
Assert.Empty(collection.Files);
Assert.Empty(collection.Keys);
} }
private void UpdateRequest(HttpRequest request, string data, string name) private void UpdateRequest(HttpRequest request, string data, string name)
@ -172,7 +177,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(data)); var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(data));
request.Form = formCollection; request.Form = formCollection;
request.ContentType = "multipart/form-data"; request.ContentType = "multipart/form-data; boundary=----WebKitFormBoundarymx2fSWqWSd0OxQqq";
request.Headers["Content-Disposition"] = "form-data; name=" + name + "; filename=text.txt"; request.Headers["Content-Disposition"] = "form-data; name=" + name + "; filename=text.txt";
fileCollection.Add(new FormFile(memoryStream, 0, data.Length) fileCollection.Add(new FormFile(memoryStream, 0, data.Length)
{ {

View File

@ -125,7 +125,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Empty(modelState.Keys); Assert.Empty(modelState.Keys);
} }
[Fact(Skip = "FormFile Should not return null modelBindingResult for a type that matches. #2456")] [Fact]
public async Task BindParameter_NoData_DoesNotGetBound() public async Task BindParameter_NoData_DoesNotGetBound()
{ {
// Arrange // Arrange
@ -142,10 +142,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
}; };
// No data is passed. // No data is passed.
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => var operationContext = ModelBindingTestHelper.GetOperationBindingContext(
{ request => UpdateRequest(request, data: null, name: null));
request.ContentType = "multipart/form-data";
});
var modelState = new ModelStateDictionary(); var modelState = new ModelStateDictionary();
@ -154,9 +152,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
// Assert // Assert
// ModelBindingResult // ModelBindingResult; expect null because binding failed.
Assert.NotNull(modelBindingResult); // Fails due to bug #2456 Assert.Null(modelBindingResult);
Assert.Null(modelBindingResult.Model);
// ModelState // ModelState
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
@ -167,11 +164,19 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
{ {
var fileCollection = new FormFileCollection(); var fileCollection = new FormFileCollection();
var formCollection = new FormCollection(new Dictionary<string, string[]>(), fileCollection); var formCollection = new FormCollection(new Dictionary<string, string[]>(), fileCollection);
var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(data));
request.Form = formCollection; request.Form = formCollection;
request.ContentType = "multipart/form-data"; request.ContentType = "multipart/form-data; boundary=----WebKitFormBoundarymx2fSWqWSd0OxQqq";
if (string.IsNullOrEmpty(data) || string.IsNullOrEmpty(name))
{
// Leave the submission empty.
return;
}
request.Headers["Content-Disposition"] = "form-data; name=" + name + "; filename=text.txt"; request.Headers["Content-Disposition"] = "form-data; name=" + name + "; filename=text.txt";
var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(data));
fileCollection.Add(new FormFile(memoryStream, 0, data.Length) fileCollection.Add(new FormFile(memoryStream, 0, data.Length)
{ {
Headers = request.Headers Headers = request.Headers

View File

@ -41,7 +41,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
}; };
// Do not add any headers. // Do not add any headers.
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { }); var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
var modelState = new ModelStateDictionary(); var modelState = new ModelStateDictionary();
// Act // Act

View File

@ -397,7 +397,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
// We don't provide enough data in this test for the 'Person' model to be created. So even though there is // We don't provide enough data in this test for the 'Person' model to be created. So even though there is
// a [FromServices], it won't be used. // a [FromServices], it won't be used.
[Fact(Skip = "Extra entries in model state #2646.")] [Fact]
public async Task MutableObjectModelBinder_BindsNestedPOCO_WithServicesModelBinder_WithPrefix_NoData() public async Task MutableObjectModelBinder_BindsNestedPOCO_WithServicesModelBinder_WithPrefix_NoData()
{ {
// Arrange // Arrange
@ -2043,7 +2043,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(content)); var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(content));
request.Form = formCollection; request.Form = formCollection;
request.ContentType = "multipart/form-data"; request.ContentType = "multipart/form-data; boundary=----WebKitFormBoundarymx2fSWqWSd0OxQqq";
request.Headers["Content-Disposition"] = "form-data; name=" + name + "; filename=text.txt"; request.Headers["Content-Disposition"] = "form-data; name=" + name + "; filename=text.txt";
fileCollection.Add(new FormFile(memoryStream, 0, memoryStream.Length) fileCollection.Add(new FormFile(memoryStream, 0, memoryStream.Length)