aspnetcore/test/Microsoft.AspNet.Mvc.Integr.../CollectionModelBinderIntegr...

661 lines
25 KiB
C#

// 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.ComponentModel.DataAnnotations;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.ModelBinding;
using Xunit;
namespace Microsoft.AspNet.Mvc.IntegrationTests
{
// Integration tests targeting the behavior of the CollectionModelBinder with other model binders.
//
// Note that CollectionModelBinder handles both ICollection{T} and IList{T}
public class CollectionModelBinderIntegrationTest
{
[Fact]
public async Task CollectionModelBinder_BindsListOfSimpleType_WithPrefix_Success()
{
// Arrange
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "parameter",
ParameterType = typeof(List<int>)
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
{
request.QueryString = new QueryString("?parameter[0]=10&parameter[1]=11");
});
var modelState = new ModelStateDictionary();
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
var model = Assert.IsType<List<int>>(modelBindingResult.Model);
Assert.Equal(new List<int>() { 10, 11 }, model);
Assert.Equal(2, modelState.Count);
Assert.Equal(0, modelState.ErrorCount);
Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[0]").Value;
Assert.Equal("10", entry.Value.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[1]").Value;
Assert.Equal("11", entry.Value.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue);
}
[Fact]
public async Task CollectionModelBinder_BindsListOfSimpleType_WithExplicitPrefix_Success()
{
// Arrange
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "parameter",
BindingInfo = new BindingInfo()
{
BinderModelName = "prefix",
},
ParameterType = typeof(List<int>)
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
{
request.QueryString = new QueryString("?prefix[0]=10&prefix[1]=11");
});
var modelState = new ModelStateDictionary();
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
var model = Assert.IsType<List<int>>(modelBindingResult.Model);
Assert.Equal(new List<int>() { 10, 11 }, model);
Assert.Equal(2, modelState.Count);
Assert.Equal(0, modelState.ErrorCount);
Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[0]").Value;
Assert.Equal("10", entry.Value.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[1]").Value;
Assert.Equal("11", entry.Value.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue);
}
[Fact]
public async Task CollectionModelBinder_BindsCollectionOfSimpleType_EmptyPrefix_Success()
{
// Arrange
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "parameter",
ParameterType = typeof(ICollection<int>)
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
{
request.QueryString = new QueryString("?[0]=10&[1]=11");
});
var modelState = new ModelStateDictionary();
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
var model = Assert.IsType<List<int>>(modelBindingResult.Model);
Assert.Equal(new List<int> { 10, 11 }, model);
Assert.Equal(2, modelState.Count);
Assert.Equal(0, modelState.ErrorCount);
Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "[0]").Value;
Assert.Equal("10", entry.Value.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "[1]").Value;
Assert.Equal("11", entry.Value.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue);
}
[Fact]
public async Task CollectionModelBinder_BindsListOfSimpleType_NoData()
{
// Arrange
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "parameter",
ParameterType = typeof(List<int>)
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
{
request.QueryString = new QueryString("?");
});
var modelState = new ModelStateDictionary();
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
Assert.Empty(Assert.IsType<List<int>>(modelBindingResult.Model));
Assert.Equal(0, modelState.Count);
Assert.Equal(0, modelState.ErrorCount);
Assert.True(modelState.IsValid);
}
private class Person
{
public int Id { get; set; }
}
[Fact]
public async Task CollectionModelBinder_BindsListOfComplexType_WithPrefix_Success()
{
// Arrange
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "parameter",
ParameterType = typeof(List<Person>)
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
{
request.QueryString = new QueryString("?parameter[0].Id=10&parameter[1].Id=11");
});
var modelState = new ModelStateDictionary();
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
var model = Assert.IsType<List<Person>>(modelBindingResult.Model);
Assert.Equal(10, model[0].Id);
Assert.Equal(11, model[1].Id);
Assert.Equal(2, modelState.Count);
Assert.Equal(0, modelState.ErrorCount);
Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[0].Id").Value;
Assert.Equal("10", entry.Value.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[1].Id").Value;
Assert.Equal("11", entry.Value.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue);
}
[Fact]
public async Task CollectionModelBinder_BindsListOfComplexType_WithExplicitPrefix_Success()
{
// Arrange
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "parameter",
BindingInfo = new BindingInfo()
{
BinderModelName = "prefix",
},
ParameterType = typeof(List<Person>)
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
{
request.QueryString = new QueryString("?prefix[0].Id=10&prefix[1].Id=11");
});
var modelState = new ModelStateDictionary();
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
var model = Assert.IsType<List<Person>>(modelBindingResult.Model);
Assert.Equal(10, model[0].Id);
Assert.Equal(11, model[1].Id);
Assert.Equal(2, modelState.Count);
Assert.Equal(0, modelState.ErrorCount);
Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[0].Id").Value;
Assert.Equal("10", entry.Value.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[1].Id").Value;
Assert.Equal("11", entry.Value.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue);
}
[Fact]
public async Task CollectionModelBinder_BindsCollectionOfComplexType_EmptyPrefix_Success()
{
// Arrange
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "parameter",
ParameterType = typeof(List<Person>)
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
{
request.QueryString = new QueryString("?[0].Id=10&[1].Id=11");
});
var modelState = new ModelStateDictionary();
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
var model = Assert.IsType<List<Person>>(modelBindingResult.Model);
Assert.Equal(10, model[0].Id);
Assert.Equal(11, model[1].Id);
Assert.Equal(2, modelState.Count);
Assert.Equal(0, modelState.ErrorCount);
Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "[0].Id").Value;
Assert.Equal("10", entry.Value.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "[1].Id").Value;
Assert.Equal("11", entry.Value.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue);
}
[Fact]
public async Task CollectionModelBinder_BindsListOfComplexType_NoData()
{
// Arrange
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "parameter",
ParameterType = typeof(List<Person>)
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
{
request.QueryString = new QueryString("?");
});
var modelState = new ModelStateDictionary();
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
Assert.Empty(Assert.IsType<List<Person>>(modelBindingResult.Model));
Assert.Equal(0, modelState.Count);
Assert.Equal(0, modelState.ErrorCount);
Assert.True(modelState.IsValid);
}
private class Person2
{
public int Id { get; set; }
[BindRequired]
public string Name { get; set; }
}
[Fact]
public async Task CollectionModelBinder_BindsListOfComplexType_WithRequiredProperty_WithPrefix_PartialData()
{
// Arrange
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "parameter",
ParameterType = typeof(List<Person2>)
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
{
request.QueryString = new QueryString("?parameter[0].Id=10&parameter[1].Id=11");
});
var modelState = new ModelStateDictionary();
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
var model = Assert.IsType<List<Person2>>(modelBindingResult.Model);
Assert.Equal(10, model[0].Id);
Assert.Equal(11, model[1].Id);
Assert.Null(model[0].Name);
Assert.Null(model[1].Name);
Assert.Equal(4, modelState.Count);
Assert.Equal(2, modelState.ErrorCount);
Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[0].Id").Value;
Assert.Equal("10", entry.Value.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[1].Id").Value;
Assert.Equal("11", entry.Value.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[0].Name").Value;
Assert.Null(entry.Value);
Assert.Equal(ModelValidationState.Invalid, entry.ValidationState);
var error = Assert.Single(entry.Errors);
Assert.Equal("A value for the 'Name' property was not provided.", error.ErrorMessage);
entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[1].Name").Value;
Assert.Null(entry.Value);
Assert.Equal(ModelValidationState.Invalid, entry.ValidationState);
error = Assert.Single(entry.Errors);
Assert.Equal("A value for the 'Name' property was not provided.", error.ErrorMessage);
}
[Fact]
public async Task CollectionModelBinder_BindsListOfComplexType_WithRequiredProperty_WithExplicitPrefix_PartialData()
{
// Arrange
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "parameter",
BindingInfo = new BindingInfo()
{
BinderModelName = "prefix",
},
ParameterType = typeof(List<Person2>)
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
{
request.QueryString = new QueryString("?prefix[0].Id=10&prefix[1].Id=11");
});
var modelState = new ModelStateDictionary();
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
var model = Assert.IsType<List<Person2>>(modelBindingResult.Model);
Assert.Equal(10, model[0].Id);
Assert.Null(model[0].Name);
Assert.Equal(11, model[1].Id);
Assert.Null(model[1].Name);
Assert.Equal(4, modelState.Count);
Assert.Equal(2, modelState.ErrorCount);
Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[0].Id").Value;
Assert.Equal("10", entry.Value.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[1].Id").Value;
Assert.Equal("11", entry.Value.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[0].Name").Value;
Assert.Null(entry.Value);
Assert.Equal(ModelValidationState.Invalid, entry.ValidationState);
entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[1].Name").Value;
Assert.Null(entry.Value);
Assert.Equal(ModelValidationState.Invalid, entry.ValidationState);
}
[Fact]
public async Task CollectionModelBinder_BindsCollectionOfComplexType_WithRequiredProperty_EmptyPrefix_PartialData()
{
// Arrange
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "parameter",
ParameterType = typeof(ICollection<Person2>)
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
{
request.QueryString = new QueryString("?[0].Id=10&[1].Id=11");
});
var modelState = new ModelStateDictionary();
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
var model = Assert.IsType<List<Person2>>(modelBindingResult.Model);
Assert.Equal(10, model[0].Id);
Assert.Null(model[0].Name);
Assert.Equal(11, model[1].Id);
Assert.Null(model[1].Name);
Assert.Equal(4, modelState.Count);
Assert.Equal(2, modelState.ErrorCount);
Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "[0].Id").Value;
Assert.Equal("10", entry.Value.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "[1].Id").Value;
Assert.Equal("11", entry.Value.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "[0].Name").Value;
Assert.Null(entry.Value);
Assert.Equal(ModelValidationState.Invalid, entry.ValidationState);
entry = Assert.Single(modelState, kvp => kvp.Key == "[1].Name").Value;
Assert.Null(entry.Value);
Assert.Equal(ModelValidationState.Invalid, entry.ValidationState);
}
[Fact]
public async Task CollectionModelBinder_BindsListOfComplexType_WithRequiredProperty_NoData()
{
// Arrange
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "parameter",
ParameterType = typeof(List<Person2>)
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
{
request.QueryString = new QueryString("?");
});
var modelState = new ModelStateDictionary();
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
Assert.Empty(Assert.IsType<List<Person2>>(modelBindingResult.Model));
Assert.Equal(0, modelState.Count);
Assert.Equal(0, modelState.ErrorCount);
Assert.True(modelState.IsValid);
}
private class Person4
{
public IList<Address4> Addresses { get; set; }
}
private class Address4
{
public int Zip { get; set; }
public string Street { get; set; }
}
[Fact]
public async Task CollectionModelBinder_UsesCustomIndexes()
{
// Arrange
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "parameter",
ParameterType = typeof(Person4)
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
{
var formCollection = new FormCollection(new Dictionary<string, string[]>()
{
{ "Addresses.index", new [] { "Key1", "Key2" } },
{ "Addresses[Key1].Street", new [] { "Street1" } },
{ "Addresses[Key2].Street", new [] { "Street2" } },
});
request.Form = formCollection;
request.ContentType = "application/x-www-form-urlencoded";
});
var modelState = new ModelStateDictionary();
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
Assert.IsType<Person4>(modelBindingResult.Model);
Assert.Equal(2, modelState.Count);
Assert.Equal(0, modelState.ErrorCount);
Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "Addresses[Key1].Street").Value;
Assert.Equal("Street1", entry.Value.AttemptedValue);
Assert.Equal("Street1", entry.Value.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "Addresses[Key2].Street").Value;
Assert.Equal("Street2", entry.Value.AttemptedValue);
Assert.Equal("Street2", entry.Value.RawValue);
}
private class Person5
{
public IList<Address5> Addresses { get; set; }
}
private class Address5
{
public int Zip { get; set; }
[StringLength(3)]
public string Street { get; set; }
}
[Fact]
public async Task CollectionModelBinder_UsesCustomIndexes_AddsErrorsWithCorrectKeys()
{
// Arrange
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "parameter",
ParameterType = typeof(Person5)
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
{
var formCollection = new FormCollection(new Dictionary<string, string[]>()
{
{ "Addresses.index", new [] { "Key1" } },
{ "Addresses[Key1].Street", new [] { "Street1" } },
});
request.Form = formCollection;
request.ContentType = "application/x-www-form-urlencoded";
});
var modelState = new ModelStateDictionary();
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
Assert.IsType<Person5>(modelBindingResult.Model);
Assert.Equal(1, modelState.Count);
Assert.Equal(1, modelState.ErrorCount);
Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "Addresses[Key1].Street").Value;
var error = Assert.Single(entry.Errors);
Assert.Equal("The field Street must be a string with a maximum length of 3.", error.ErrorMessage);
}
}
}