public void GenerateDisplay_CorrectlyCallsTemplateService() { // Arrange var purpose = TemplatePurposes.Display; var expression = "Age"; var templateName = "templateName"; var htmlFieldName = "htmlFieldName"; var additionalViewData = new { additional = "view data" }; var expected = new Mock <IHtmlContent>(MockBehavior.Strict); var containerMetadata = _metadataProvider.GetMetadataForType(typeof(TestModel)); var propertyMetadata = _metadataProvider.GetMetadataForProperty(typeof(TestModel), expression); _templateService.Setup(m => m.RenderTemplate( _viewContext, _viewContext.ViewData, It.Is <ModelExplorer>(exp => exp.Metadata == propertyMetadata && exp.Container.Metadata == containerMetadata), purpose, htmlFieldName, templateName, additionalViewData)) .Returns(expected.Object) .Verifiable(); // Act var result = _htmlHelper.Display(expression, templateName, htmlFieldName, additionalViewData); // Assert result.Should().BeSameAs(expected.Object); _templateService.Verify(); }
private static ModelBindingContext GetBindingContext(Type modelType, Type binderType = null) { var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForType(modelType).BindingDetails(bd => bd.BinderType = binderType); var operationBindingContext = new OperationBindingContext { MetadataProvider = metadataProvider, HttpContext = new DefaultHttpContext(), ValidatorProvider = Mock.Of <IModelValidatorProvider>(), }; var bindingContext = new ModelBindingContext { ModelMetadata = metadataProvider.GetMetadataForType(modelType), ModelName = "someName", ValueProvider = Mock.Of <IValueProvider>(), ModelState = new ModelStateDictionary(), OperationBindingContext = operationBindingContext, BinderType = binderType }; return(bindingContext); }
private static ModelBindingContext GetModelBindingContext( IValueProvider valueProvider, bool isReadOnly = false) { var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForType <IList <int> >().BindingDetails(bd => bd.IsReadOnly = isReadOnly); var bindingContext = new ModelBindingContext { ModelMetadata = metadataProvider.GetMetadataForType(typeof(IList <int>)), ModelName = "someName", ModelState = new ModelStateDictionary(), ValueProvider = valueProvider, OperationBindingContext = new OperationBindingContext { ModelBinder = CreateIntBinder(), MetadataProvider = metadataProvider }, ValidationState = new ValidationStateDictionary(), FieldName = "testfieldname", }; return(bindingContext); }
public void GetBindingInfo_WithAttributesAndModelMetadata_UsesBinderNameFromModelMetadata_WhenNotFoundViaAttributes() { // Arrange var attributes = new object[] { new ModelBinderAttribute(typeof(ComplexObjectModelBinder)), new ControllerAttribute(), new BindNeverAttribute(), }; var modelType = typeof(Guid); var provider = new TestModelMetadataProvider(); provider.ForType(modelType).BindingDetails(metadata => { metadata.BindingSource = BindingSource.Special; metadata.BinderType = typeof(SimpleTypeModelBinder); metadata.BinderModelName = "Different"; }); var modelMetadata = provider.GetMetadataForType(modelType); // Act var bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata); // Assert Assert.NotNull(bindingInfo); Assert.Same(typeof(ComplexObjectModelBinder), bindingInfo.BinderType); Assert.Same("Different", bindingInfo.BinderModelName); Assert.Same(BindingSource.Custom, bindingInfo.BindingSource); }
public void CreateBinder_Caches_NonRootNodes_WhenNonRootNodeReturnsNull() { // Arrange var metadataProvider = new TestModelMetadataProvider(); var options = Options.Create(new MvcOptions()); IModelBinder inner = null; var widgetProvider = new TestModelBinderProvider(c => { if (c.Metadata.ModelType == typeof(Widget)) { var binder = c.CreateBinder(c.Metadata.Properties[nameof(Widget.Id)]); Assert.IsType <NoOpBinder>(binder); if (inner == null) { inner = binder; } else { Assert.Same(inner, binder); } return(Mock.Of <IModelBinder>()); } return(null); }); var widgetIdProvider = new TestModelBinderProvider(c => { Assert.Equal(typeof(WidgetId), c.Metadata.ModelType); return(null); }); options.Value.ModelBinderProviders.Add(widgetProvider); options.Value.ModelBinderProviders.Add(widgetIdProvider); var factory = new ModelBinderFactory( metadataProvider, options, GetServices()); var context = new ModelBinderFactoryContext() { Metadata = metadataProvider.GetMetadataForType(typeof(Widget)), CacheToken = null, // We want the outermost provider to run twice. }; // Act var result1 = factory.CreateBinder(context); var result2 = factory.CreateBinder(context); // Assert Assert.NotSame(result1, result2); Assert.Equal(2, widgetProvider.SuccessCount); Assert.Equal(0, widgetIdProvider.SuccessCount); }
public void GetBindingInfo_WithAttributesAndModelMetadata_UsesBinderSourceFromModelMetadata_WhenNotFoundViaAttributes() { // Arrange var attributes = new object[] { new BindPropertyAttribute(), new ControllerAttribute(), new BindNeverAttribute(), }; var modelType = typeof(Guid); var provider = new TestModelMetadataProvider(); provider.ForType(modelType).BindingDetails(metadata => { metadata.BindingSource = BindingSource.Services; }); var modelMetadata = provider.GetMetadataForType(modelType); // Act var bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata); // Assert Assert.NotNull(bindingInfo); Assert.Same(BindingSource.Services, bindingInfo.BindingSource); }
private static DefaultModelBindingContext GetBindingContext(Type modelType) { var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForType(modelType).BindingDetails(d => d.BindingSource = BindingSource.Services); var modelMetadata = metadataProvider.GetMetadataForType(modelType); var services = new ServiceCollection(); services.AddSingleton <IService>(new Service()); var bindingContext = new DefaultModelBindingContext { ActionContext = new ActionContext() { HttpContext = new DefaultHttpContext() { RequestServices = services.BuildServiceProvider(), } }, ModelMetadata = modelMetadata, ModelName = "modelName", FieldName = "modelName", ModelState = new ModelStateDictionary(), BinderModelName = modelMetadata.BinderModelName, BindingSource = modelMetadata.BindingSource, ValidationState = new ValidationStateDictionary(), }; return(bindingContext); }
public async Task DictionaryModelBinder_CreatesEmptyCollection_IfIsTopLevelObject() { // Arrange var binder = new DictionaryModelBinder <string, string>( new SimpleTypeModelBinder(typeof(string)), new SimpleTypeModelBinder(typeof(string))); var bindingContext = CreateContext(); bindingContext.IsTopLevelObject = true; // Lack of prefix and non-empty model name both ignored. bindingContext.ModelName = "modelName"; var metadataProvider = new TestModelMetadataProvider(); bindingContext.ModelMetadata = metadataProvider.GetMetadataForType(typeof(Dictionary <string, string>)); bindingContext.ValueProvider = new TestValueProvider(new Dictionary <string, object>()); // Act await binder.BindModelAsync(bindingContext); // Assert Assert.Empty(Assert.IsType <Dictionary <string, string> >(bindingContext.Result.Model)); Assert.True(bindingContext.Result.IsModelSet); }
public void EnterNestedScope_FiltersValueProviders_ForValueProviderSource() { // Arrange var metadataProvider = new TestModelMetadataProvider(); metadataProvider .ForProperty(typeof(string), nameof(string.Length)) .BindingDetails(b => b.BindingSource = BindingSource.Query); var original = CreateDefaultValueProvider(); var context = DefaultModelBindingContext.CreateBindingContext( GetActionContext(), original, metadataProvider.GetMetadataForType(typeof(string)), new BindingInfo(), "model"); var propertyMetadata = metadataProvider.GetMetadataForProperty(typeof(string), nameof(string.Length)); // Act context.EnterNestedScope(propertyMetadata, "Length", "Length", model: null); // Assert Assert.Collection( Assert.IsType <CompositeValueProvider>(context.ValueProvider), vp => Assert.Same(original[1], vp)); }
private static ModelBindingContext GetBindingContext(Type modelType) { var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForType(modelType).BindingDetails(d => d.BindingSource = BindingSource.Header); var modelMetadata = metadataProvider.GetMetadataForType(modelType); var bindingContext = new ModelBindingContext { ModelMetadata = modelMetadata, ModelName = "modelName", FieldName = "modelName", ModelState = new ModelStateDictionary(), OperationBindingContext = new OperationBindingContext { ActionContext = new ActionContext() { HttpContext = new DefaultHttpContext(), }, ModelBinder = new HeaderModelBinder(), MetadataProvider = metadataProvider, }, BinderModelName = modelMetadata.BinderModelName, BindingSource = modelMetadata.BindingSource, }; return(bindingContext); }
private static ModelBindingContext GetModelBindingContext(bool isReadOnly) { var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForType <List <int> >().BindingDetails(bd => bd.IsReadOnly = isReadOnly); var valueProvider = new SimpleHttpValueProvider { { "someName[0]", new KeyValuePair <int, string>(42, "forty-two") }, { "someName[1]", new KeyValuePair <int, string>(84, "eighty-four") }, }; var bindingContext = new ModelBindingContext { ModelMetadata = metadataProvider.GetMetadataForType(typeof(IDictionary <int, string>)), ModelName = "someName", ValueProvider = valueProvider, OperationBindingContext = new OperationBindingContext { ModelBinder = CreateKvpBinder(), MetadataProvider = metadataProvider } }; return(bindingContext); }
public async Task ArrayModelBinder_CreatesEmptyCollection_IfIsTopLevelObject() { // Arrange var binder = new ArrayModelBinder <string>(new SimpleTypeModelBinder(typeof(string))); var context = CreateContext(); context.IsTopLevelObject = true; // Lack of prefix and non-empty model name both ignored. context.ModelName = "modelName"; var metadataProvider = new TestModelMetadataProvider(); context.ModelMetadata = metadataProvider.GetMetadataForType(typeof(string[])); context.ValueProvider = new TestValueProvider(new Dictionary <string, object>()); // Act var result = await binder.BindModelResultAsync(context); // Assert Assert.NotEqual(default(ModelBindingResult), result); Assert.Empty(Assert.IsType <string[]>(result.Model)); Assert.Equal("modelName", result.Key); Assert.True(result.IsModelSet); }
public void AddValidation_CorrectValidationTypeAndOverriddenErrorMessage_WithType() { // Arrange var expectedMessage = "Error message from override."; var provider = new TestModelMetadataProvider(); provider .ForType(typeof(int)) .BindingDetails(d => d.ModelBindingMessageProvider.SetNonPropertyValueMustBeANumberAccessor( () => $"Error message from override.")); var metadata = provider.GetMetadataForType(typeof(int)); var adapter = new NumericClientModelValidator(); var actionContext = new ActionContext(); var context = new ClientModelValidationContext(actionContext, metadata, provider, new AttributeDictionary()); // Act adapter.AddValidation(context); // Assert Assert.Collection( context.Attributes, kvp => { Assert.Equal("data-val", kvp.Key); Assert.Equal("true", kvp.Value); }, kvp => { Assert.Equal("data-val-number", kvp.Key); Assert.Equal(expectedMessage, kvp.Value); }); }
public async Task CollectionModelBinder_DoesNotCreateEmptyCollection_IfModelNonNull() { // Arrange var binder = new CollectionModelBinder <string>( new StubModelBinder(result: ModelBindingResult.Failed()), NullLoggerFactory.Instance); var bindingContext = CreateContext(); bindingContext.IsTopLevelObject = true; var list = new List <string>(); bindingContext.Model = list; // Lack of prefix and non-empty model name both ignored. bindingContext.ModelName = "modelName"; var metadataProvider = new TestModelMetadataProvider(); bindingContext.ModelMetadata = metadataProvider.GetMetadataForType(typeof(List <string>)); bindingContext.ValueProvider = new TestValueProvider(new Dictionary <string, object>()); // Act await binder.BindModelAsync(bindingContext); // Assert Assert.Same(list, bindingContext.Result.Model); Assert.Empty(list); Assert.True(bindingContext.Result.IsModelSet); }
public async Task BindModel_ReturnsProvidedWhitespaceString_WhenNotConvertEmptyStringToNull(string value) { // Arrange var bindingContext = GetBindingContext(typeof(string)); bindingContext.ValueProvider = new SimpleValueProvider { { "theModelName", value } }; var metadataProvider = new TestModelMetadataProvider(); metadataProvider .ForType(typeof(string)) .DisplayDetails(d => d.ConvertEmptyStringToNull = false); bindingContext.ModelMetadata = metadataProvider.GetMetadataForType(typeof(string)); var binder = new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance); // Act await binder.BindModelAsync(bindingContext); // Assert Assert.Same(value, bindingContext.Result.Model); Assert.True(bindingContext.ModelState.ContainsKey("theModelName")); }
public void GetBindingInfo_WithAttributesAndModelMetadata_UsesValuesFromBindingInfo_IfAttributesPresent() { // Arrange var attributes = new object[] { new ModelBinderAttribute { BinderType = typeof(ComplexObjectModelBinder), Name = "Test" }, }; var modelType = typeof(Guid); var provider = new TestModelMetadataProvider(); provider.ForType(modelType).BindingDetails(metadata => { metadata.BindingSource = BindingSource.Special; metadata.BinderType = typeof(SimpleTypeModelBinder); metadata.BinderModelName = "Different"; }); var modelMetadata = provider.GetMetadataForType(modelType); // Act var bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata); // Assert Assert.NotNull(bindingInfo); Assert.Same(typeof(ComplexObjectModelBinder), bindingInfo.BinderType); Assert.Same("Test", bindingInfo.BinderModelName); }
public void GetBindingInfo_WithAttributesAndModelMetadata_UsesPropertyPredicateProviderFromModelMetadata_WhenNotFoundViaAttributes() { // Arrange var attributes = new object[] { new ModelBinderAttribute(typeof(ComplexObjectModelBinder)), new ControllerAttribute(), new BindNeverAttribute(), }; var propertyFilterProvider = Mock.Of <IPropertyFilterProvider>(); var modelType = typeof(Guid); var provider = new TestModelMetadataProvider(); provider.ForType(modelType).BindingDetails(metadata => { metadata.PropertyFilterProvider = propertyFilterProvider; }); var modelMetadata = provider.GetMetadataForType(modelType); // Act var bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata); // Assert Assert.NotNull(bindingInfo); Assert.Same(propertyFilterProvider, bindingInfo.PropertyFilterProvider); }
public void CreateBinder_Caches_WhenTokenIsNotNull() { // Arrange var metadataProvider = new TestModelMetadataProvider(); var options = Options.Create(new MvcOptions()); options.Value.ModelBinderProviders.Add(new TestModelBinderProvider(c => { Assert.Equal(typeof(Employee), c.Metadata.ModelType); return(Mock.Of <IModelBinder>()); })); var factory = new ModelBinderFactory( metadataProvider, options, GetServices()); var context = new ModelBinderFactoryContext() { Metadata = metadataProvider.GetMetadataForType(typeof(Employee)), CacheToken = new object(), }; // Act var result1 = factory.CreateBinder(context); var result2 = factory.CreateBinder(context); // Assert Assert.Same(result1, result2); }
public async Task CollectionModelBinder_DoesNotCreateEmptyCollection_IfModelNonNull() { // Arrange var binder = new CollectionModelBinder <string>(new StubModelBinder(result: null)); var context = CreateContext(); context.IsTopLevelObject = true; var list = new List <string>(); context.Model = list; // Lack of prefix and non-empty model name both ignored. context.ModelName = "modelName"; var metadataProvider = new TestModelMetadataProvider(); context.ModelMetadata = metadataProvider.GetMetadataForType(typeof(List <string>)); context.ValueProvider = new TestValueProvider(new Dictionary <string, object>()); // Act var result = await binder.BindModelResultAsync(context); // Assert Assert.NotEqual(default(ModelBindingResult), result); Assert.Same(list, result.Model); Assert.Empty(list); Assert.Equal("modelName", result.Key); Assert.True(result.IsModelSet); }
public void CreateBinder_CreatesNoOpBinder_WhenPropertyDoesntHaveABinder() { // Arrange var metadataProvider = new TestModelMetadataProvider(); // There isn't a provider that can handle WidgetId. var options = Options.Create(new MvcOptions()); options.Value.ModelBinderProviders.Add(new TestModelBinderProvider(c => { if (c.Metadata.ModelType == typeof(Widget)) { Assert.NotNull(c.CreateBinder(c.Metadata.Properties[nameof(Widget.Id)])); return(Mock.Of <IModelBinder>()); } return(null); })); var factory = new ModelBinderFactory( metadataProvider, options, GetServices()); var context = new ModelBinderFactoryContext() { Metadata = metadataProvider.GetMetadataForType(typeof(Widget)), }; // Act var result = factory.CreateBinder(context); // Assert Assert.NotNull(result); }
public async Task KeyValuePairModelBinder_CreatesEmptyCollection_IfIsTopLevelObject() { // Arrange var binder = new KeyValuePairModelBinder <string, string>( new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance), new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance), NullLoggerFactory.Instance); var bindingContext = CreateContext(); bindingContext.IsTopLevelObject = true; // Lack of prefix and non-empty model name both ignored. bindingContext.ModelName = "modelName"; var metadataProvider = new TestModelMetadataProvider(); bindingContext.ModelMetadata = metadataProvider.GetMetadataForType(typeof(KeyValuePair <string, string>)); bindingContext.ValueProvider = new TestValueProvider(new Dictionary <string, object>()); // Act await binder.BindModelAsync(bindingContext); // Assert var model = Assert.IsType <KeyValuePair <string, string> >(bindingContext.Result.Model); Assert.Equal(default(KeyValuePair <string, string>), model); Assert.True(bindingContext.Result.IsModelSet); }
private static ModelMetadata GetMetadataForType(Type modelType) { var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForType(modelType).BindingDetails(d => d.BindingSource = BindingSource.Header); return(metadataProvider.GetMetadataForType(modelType)); }
private static DefaultModelBindingContext GetBindingContext(Type modelType) { var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForType(modelType).BindingDetails(d => d.BindingSource = BindingSource.Services); var modelMetadata = metadataProvider.GetMetadataForType(modelType); var services = new ServiceCollection(); services.AddSingleton<IService>(new Service()); var bindingContext = new DefaultModelBindingContext { ActionContext = new ActionContext() { HttpContext = new DefaultHttpContext() { RequestServices = services.BuildServiceProvider(), } }, ModelMetadata = modelMetadata, ModelName = "modelName", FieldName = "modelName", ModelState = new ModelStateDictionary(), BinderModelName = modelMetadata.BinderModelName, BindingSource = modelMetadata.BindingSource, ValidationState = new ValidationStateDictionary(), }; return bindingContext; }
public async Task BindModelAsync_PassesExpectedBindingInfoAndMetadata_IfPrefixDoesNotMatch( BindingInfo parameterBindingInfo, string metadataBinderModelName, string parameterName, string expectedModelName) { // Arrange var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForType <Person>().BindingDetails(binding => { binding.BinderModelName = metadataBinderModelName; }); var metadata = metadataProvider.GetMetadataForType(typeof(Person)); var modelBinder = new Mock <IModelBinder>(); modelBinder .Setup(b => b.BindModelAsync(It.IsAny <ModelBindingContext>())) .Callback((ModelBindingContext context) => { Assert.Equal(expectedModelName, context.ModelName, StringComparer.Ordinal); }) .Returns(TaskCache.CompletedTask); var parameterDescriptor = new ParameterDescriptor { BindingInfo = parameterBindingInfo, Name = parameterName, ParameterType = typeof(Person), }; var factory = new Mock <IModelBinderFactory>(MockBehavior.Strict); factory .Setup(f => f.CreateBinder(It.IsAny <ModelBinderFactoryContext>())) .Callback((ModelBinderFactoryContext context) => { // Confirm expected data is passed through to ModelBindingFactory. Assert.Same(parameterDescriptor.BindingInfo, context.BindingInfo); Assert.Same(parameterDescriptor, context.CacheToken); Assert.Equal(metadata, context.Metadata); }) .Returns(modelBinder.Object); var argumentBinder = new DefaultControllerArgumentBinder( metadataProvider, factory.Object, CreateMockValidator()); var controllerContext = GetControllerContext(); controllerContext.ActionDescriptor.Parameters.Add(parameterDescriptor); // Act & Assert await argumentBinder.BindModelAsync(parameterDescriptor, controllerContext); }
public async Task BindModelAsync_ForOverlappingParametersWithSuppressions_InValid_WithValidSecondParameter() { // Arrange var parameterDescriptor = new ParameterDescriptor { Name = "patchDocument", ParameterType = typeof(IJsonPatchDocument), }; var actionContext = GetControllerContext(); var modelState = actionContext.ModelState; // First ModelState key is not empty to match SimpleTypeModelBinder. modelState.SetModelValue("id", "notAGuid", "notAGuid"); modelState.AddModelError("id", "This is not valid."); var modelMetadataProvider = new TestModelMetadataProvider(); modelMetadataProvider.ForType <IJsonPatchDocument>().ValidationDetails(v => v.ValidateChildren = false); var modelMetadata = modelMetadataProvider.GetMetadataForType(typeof(IJsonPatchDocument)); var parameterBinder = new ParameterBinder( modelMetadataProvider, Mock.Of <IModelBinderFactory>(), new DefaultObjectValidator( modelMetadataProvider, new[] { TestModelValidatorProvider.CreateDefaultProvider() }, new MvcOptions()), _optionsAccessor, NullLoggerFactory.Instance); // BodyModelBinder does not update ModelState in success case. var modelBindingResult = ModelBindingResult.Success(new JsonPatchDocument()); var modelBinder = CreateMockModelBinder(modelBindingResult); // Act var result = await parameterBinder.BindModelAsync( actionContext, modelBinder, new SimpleValueProvider(), parameterDescriptor, modelMetadata, value : null); // Assert Assert.True(result.IsModelSet); Assert.False(modelState.IsValid); Assert.Collection( modelState, kvp => { Assert.Equal("id", kvp.Key); Assert.Equal(ModelValidationState.Invalid, kvp.Value.ValidationState); var error = Assert.Single(kvp.Value.Errors); Assert.Equal("This is not valid.", error.ErrorMessage); }); }
private static DefaultModelBindingContext GetBindingContext(Type modelType) { var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForType(modelType).BindingDetails(d => d.BindingSource = BindingSource.Header); var modelMetadata = metadataProvider.GetMetadataForType(modelType); return(GetBindingContext(metadataProvider, modelMetadata)); }
public async Task BindModelAsync_PassesExpectedBindingInfoAndMetadata_IfPrefixMatches() { // Arrange var expectedModelName = "expectedName"; var metadataProvider = new TestModelMetadataProvider(); var metadata = metadataProvider.GetMetadataForType(typeof(Person)); var modelBinder = new Mock <IModelBinder>(); modelBinder .Setup(b => b.BindModelAsync(It.IsAny <ModelBindingContext>())) .Callback((ModelBindingContext context) => { Assert.Equal(expectedModelName, context.ModelName, StringComparer.Ordinal); }) .Returns(TaskCache.CompletedTask); var parameterDescriptor = new ParameterDescriptor { Name = expectedModelName, ParameterType = typeof(Person), }; var factory = new Mock <IModelBinderFactory>(MockBehavior.Strict); factory .Setup(f => f.CreateBinder(It.IsAny <ModelBinderFactoryContext>())) .Callback((ModelBinderFactoryContext context) => { // Confirm expected data is passed through to ModelBindingFactory. Assert.Null(context.BindingInfo); Assert.Same(parameterDescriptor, context.CacheToken); Assert.Equal(metadata, context.Metadata); }) .Returns(modelBinder.Object); var argumentBinder = new DefaultControllerArgumentBinder( metadataProvider, factory.Object, CreateMockValidator()); var valueProvider = new SimpleValueProvider { { expectedModelName, new object() }, }; var valueProviderFactory = new SimpleValueProviderFactory(valueProvider); var controllerContext = GetControllerContext(); controllerContext.ActionDescriptor.Parameters.Add(parameterDescriptor); controllerContext.ValueProviderFactories.Insert(0, valueProviderFactory); // Act & Assert await argumentBinder.BindModelAsync(parameterDescriptor, controllerContext); }
public void CreateBinder_Caches_NonRootNodes_UsesModelMetadataAsToken() { // Arrange var metadataProvider = new TestModelMetadataProvider(); var options = Options.Create(new MvcOptions()); IModelBinder inner = null; var widgetProvider = new TestModelBinderProvider(c => { if (c.Metadata.ModelType == typeof(Widget)) { inner = c.CreateBinder(c.Metadata.Properties[nameof(Widget.Id)]); return(Mock.Of <IModelBinder>()); } return(null); }); var widgetIdProvider = new TestModelBinderProvider(c => { Assert.Equal(typeof(WidgetId), c.Metadata.ModelType); return(Mock.Of <IModelBinder>()); }); options.Value.ModelBinderProviders.Add(widgetProvider); options.Value.ModelBinderProviders.Add(widgetIdProvider); var factory = new ModelBinderFactory( metadataProvider, options, GetServices()); var context = new ModelBinderFactoryContext() { Metadata = metadataProvider.GetMetadataForType(typeof(Widget)), CacheToken = null, }; // Act 1 var result1 = factory.CreateBinder(context); context.Metadata = context.Metadata.Properties[nameof(Widget.Id)]; context.CacheToken = context.Metadata; // Act 2 var result2 = factory.CreateBinder(context); // Assert Assert.Same(inner, result2); Assert.Equal(1, widgetProvider.SuccessCount); Assert.Equal(1, widgetIdProvider.SuccessCount); }
public void GetTemplateNames_WithNoRegression(Type fieldType) { // Arrange var metadata = _metadataProvider.GetMetadataForType(fieldType); var expected = TemplateRenderer.GetTypeNames(metadata, metadata.UnderlyingOrModelType); // Act var actual = _templateNameSource.GetTemplateNames(metadata); // Assert actual.Should().BeEquivalentTo(expected, cfg => cfg.WithStrictOrdering()); }
public void CreateBinder_PassesExpectedBindingInfo( BindingInfo parameterBindingInfo, BindingMetadata bindingMetadata, BindingInfo expectedInfo) { // Arrange var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForType <Employee>().BindingDetails(binding => { binding.BinderModelName = bindingMetadata.BinderModelName; binding.BinderType = bindingMetadata.BinderType; binding.BindingSource = bindingMetadata.BindingSource; if (bindingMetadata.PropertyFilterProvider != null) { binding.PropertyFilterProvider = bindingMetadata.PropertyFilterProvider; } }); var modelBinder = Mock.Of <IModelBinder>(); var modelBinderProvider = new TestModelBinderProvider(context => { Assert.Equal(typeof(Employee), context.Metadata.ModelType); Assert.NotNull(context.BindingInfo); Assert.Equal(expectedInfo.BinderModelName, context.BindingInfo.BinderModelName, StringComparer.Ordinal); Assert.Equal(expectedInfo.BinderType, context.BindingInfo.BinderType); Assert.Equal(expectedInfo.BindingSource, context.BindingInfo.BindingSource); Assert.Same(expectedInfo.PropertyFilterProvider, context.BindingInfo.PropertyFilterProvider); return(modelBinder); }); var options = Options.Create(new MvcOptions()); options.Value.ModelBinderProviders.Insert(0, modelBinderProvider); var factory = new ModelBinderFactory( metadataProvider, options, GetServices()); var factoryContext = new ModelBinderFactoryContext { BindingInfo = parameterBindingInfo, Metadata = metadataProvider.GetMetadataForType(typeof(Employee)), }; // Act & Assert var result = factory.CreateBinder(factoryContext); // Confirm our IModelBinderProvider was called. Assert.Same(modelBinder, result); }
public async Task BindModelAsync_ForOverlappingParameters_InValid_WithInValidFirstParameterAndSecondNull() { // Arrange var parameterDescriptor = new ParameterDescriptor { BindingInfo = new BindingInfo { BinderModelName = "id", }, Name = "identifier", ParameterType = typeof(string), }; var actionContext = GetControllerContext(); var modelState = actionContext.ModelState; // Mimic ModelStateEntry when first parameter is [FromRoute] int id and request URI is /api/values/notAnInt modelState.SetModelValue("id", "notAnInt", "notAnInt"); modelState.AddModelError("id", "This is not valid."); var modelMetadataProvider = new TestModelMetadataProvider(); var modelMetadata = modelMetadataProvider.GetMetadataForType(typeof(string)); var parameterBinder = new ParameterBinder( modelMetadataProvider, Mock.Of <IModelBinderFactory>(), new DefaultObjectValidator( modelMetadataProvider, new[] { TestModelValidatorProvider.CreateDefaultProvider() }, new MvcOptions()), _optionsAccessor, NullLoggerFactory.Instance); // Mimic result when second parameter is [FromQuery(Name = "id")] string identifier and query is ?id var modelBindingResult = ModelBindingResult.Success(null); var modelBinder = CreateMockModelBinder(modelBindingResult); // Act var result = await parameterBinder.BindModelAsync( actionContext, modelBinder, new SimpleValueProvider(), parameterDescriptor, modelMetadata, value : null); // Assert Assert.True(result.IsModelSet); Assert.False(modelState.IsValid); var keyValuePair = Assert.Single(modelState); Assert.Equal("id", keyValuePair.Key); Assert.Equal(ModelValidationState.Invalid, keyValuePair.Value.ValidationState); }
public void GetTypeNames_ReturnsExpectedResults(Type fieldType, string[] expectedResult) { // Arrange var metadataProvider = new TestModelMetadataProvider(); var metadata = metadataProvider.GetMetadataForType(fieldType); // Act var typeNames = TemplateRenderer.GetTypeNames(metadata, fieldType); // Assert var collectionAssertions = expectedResult.Select<string, Action<string>>(expected => actual => Assert.Equal(expected, actual)); Assert.Collection(typeNames, collectionAssertions.ToArray()); }
public void EnterNestedScope_CopiesProperties() { // Arrange var bindingContext = new DefaultModelBindingContext { Model = new object(), ModelMetadata = new TestModelMetadataProvider().GetMetadataForType(typeof(object)), ModelName = "theName", OperationBindingContext = new OperationBindingContext(), ValueProvider = new SimpleValueProvider(), ModelState = new ModelStateDictionary(), }; var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForType<object>().BindingDetails(d => { d.BindingSource = BindingSource.Custom; d.BinderType = typeof(TestModelBinder); d.BinderModelName = "custom"; }); var newModelMetadata = metadataProvider.GetMetadataForType(typeof(object)); // Act var originalBinderModelName = bindingContext.BinderModelName; var originalBindingSource = bindingContext.BindingSource; var originalModelState = bindingContext.ModelState; var originalOperationBindingContext = bindingContext.OperationBindingContext; var originalValueProvider = bindingContext.ValueProvider; var disposable = bindingContext.EnterNestedScope( modelMetadata: newModelMetadata, fieldName: "fieldName", modelName: "modelprefix.fieldName", model: null); // Assert Assert.Same(newModelMetadata.BinderModelName, bindingContext.BinderModelName); Assert.Same(newModelMetadata.BindingSource, bindingContext.BindingSource); Assert.Equal("fieldName", bindingContext.FieldName); Assert.False(bindingContext.IsTopLevelObject); Assert.Null(bindingContext.Model); Assert.Same(newModelMetadata, bindingContext.ModelMetadata); Assert.Equal("modelprefix.fieldName", bindingContext.ModelName); Assert.Same(originalModelState, bindingContext.ModelState); Assert.Same(originalOperationBindingContext, bindingContext.OperationBindingContext); Assert.Same(originalValueProvider, bindingContext.ValueProvider); disposable.Dispose(); }
public async Task CanCreateModel_ReturnsTrue_IfIsTopLevelObjectAndNotIsFirstChanceBinding( bool isTopLevelObject, bool isFirstChanceBinding, string binderModelName, string modelName, bool expectedCanCreate) { var mockValueProvider = new Mock<IValueProvider>(); mockValueProvider .Setup(o => o.ContainsPrefixAsync(It.IsAny<string>())) .Returns(Task.FromResult(false)); var metadataProvider = new TestModelMetadataProvider(); var bindingContext = new MutableObjectBinderContext { ModelBindingContext = new ModelBindingContext { IsTopLevelObject = isTopLevelObject, IsFirstChanceBinding = isFirstChanceBinding, // Random type. ModelMetadata = metadataProvider.GetMetadataForType(typeof(Person)), ValueProvider = mockValueProvider.Object, OperationBindingContext = new OperationBindingContext { ValueProvider = mockValueProvider.Object, MetadataProvider = metadataProvider, ValidatorProvider = Mock.Of<IModelValidatorProvider>(), }, // CanCreateModel() ignores the BinderModelName and ModelName properties. BinderModelName = binderModelName, ModelName = modelName, }, }; var mutableBinder = new TestableMutableObjectModelBinder(); bindingContext.PropertyMetadata = mutableBinder.GetMetadataForProperties(bindingContext.ModelBindingContext).ToArray(); // Act var canCreate = await mutableBinder.CanCreateModel(bindingContext); // Assert Assert.Equal(expectedCanCreate, canCreate); }
public void CreateChildBindingContext_CopiesProperties() { // Arrange var originalBindingContext = new ModelBindingContext { Model = new object(), ModelMetadata = new TestModelMetadataProvider().GetMetadataForType(typeof(object)), ModelName = "theName", OperationBindingContext = new OperationBindingContext(), ValueProvider = new SimpleValueProvider(), ModelState = new ModelStateDictionary(), }; var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForType<object>().BindingDetails(d => { d.BindingSource = BindingSource.Custom; d.BinderType = typeof(TestModelBinder); d.BinderModelName = "custom"; }); var newModelMetadata = metadataProvider.GetMetadataForType(typeof(object)); // Act var newBindingContext = ModelBindingContext.CreateChildBindingContext( originalBindingContext, newModelMetadata, fieldName: "fieldName", modelName: "modelprefix.fieldName", model: null); // Assert Assert.Same(newModelMetadata.BinderModelName, newBindingContext.BinderModelName); Assert.Same(newModelMetadata.BinderType, newBindingContext.BinderType); Assert.Same(newModelMetadata.BindingSource, newBindingContext.BindingSource); Assert.False(newBindingContext.FallbackToEmptyPrefix); Assert.Equal("fieldName", newBindingContext.FieldName); Assert.False(newBindingContext.IsTopLevelObject); Assert.Null(newBindingContext.Model); Assert.Same(newModelMetadata, newBindingContext.ModelMetadata); Assert.Equal("modelprefix.fieldName", newBindingContext.ModelName); Assert.Same(originalBindingContext.ModelState, newBindingContext.ModelState); Assert.Same(originalBindingContext.OperationBindingContext, newBindingContext.OperationBindingContext); Assert.Same(originalBindingContext.ValueProvider, newBindingContext.ValueProvider); }
public async Task BindingSourceModelBinder_ReturnsFalse_NonMatchingSource() { // Arrange var provider = new TestModelMetadataProvider(); provider.ForType<string>().BindingDetails(d => d.BindingSource = BindingSource.Query); var context = new ModelBindingContext(); context.ModelMetadata = provider.GetMetadataForType(typeof(string)); var binder = new TestableBindingSourceModelBinder(BindingSource.Body); // Act var result = await binder.BindModelAsync(context); // Assert Assert.Null(result); Assert.False(binder.WasBindModelCoreCalled); }
public void CreateBindingContext_FiltersValueProviders_ForValueProviderSource() { // Arrange var metadataProvider = new TestModelMetadataProvider(); var original = CreateDefaultValueProvider(); // Act var context = DefaultModelBindingContext.CreateBindingContext( new ActionContext(), original, metadataProvider.GetMetadataForType(typeof(object)), new BindingInfo() { BindingSource = BindingSource.Query }, "model"); // Assert Assert.Collection( Assert.IsType<CompositeValueProvider>(context.ValueProvider), vp => Assert.Same(original[1], vp)); }
private static ModelBindingContext GetBindingContext(Type modelType) { var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForType(modelType).BindingDetails(d => d.BindingSource = BindingSource.Header); var modelMetadata = metadataProvider.GetMetadataForType(modelType); var bindingContext = new ModelBindingContext { ModelMetadata = modelMetadata, ModelName = "modelName", OperationBindingContext = new OperationBindingContext { ModelBinder = new HeaderModelBinder(), MetadataProvider = metadataProvider, HttpContext = new DefaultHttpContext() }, BinderModelName = modelMetadata.BinderModelName, BindingSource = modelMetadata.BindingSource, }; return bindingContext; }
public void CanCreateModel_ReturnsTrue_IfIsTopLevelObject( bool isTopLevelObject, bool expectedCanCreate) { var mockValueProvider = new Mock<IValueProvider>(); mockValueProvider .Setup(o => o.ContainsPrefix(It.IsAny<string>())) .Returns(false); var metadataProvider = new TestModelMetadataProvider(); var bindingContext = new MutableObjectBinderContext { ModelBindingContext = new ModelBindingContext { IsTopLevelObject = isTopLevelObject, // Random type. ModelMetadata = metadataProvider.GetMetadataForType(typeof(Person)), ValueProvider = mockValueProvider.Object, OperationBindingContext = new OperationBindingContext { ValueProvider = mockValueProvider.Object, MetadataProvider = metadataProvider, ValidatorProvider = Mock.Of<IModelValidatorProvider>(), }, ModelState = new ModelStateDictionary(), }, }; var mutableBinder = new TestableMutableObjectModelBinder(); bindingContext.PropertyMetadata = mutableBinder.GetMetadataForProperties(bindingContext.ModelBindingContext).ToArray(); // Act var canCreate = mutableBinder.CanCreateModel(bindingContext); // Assert Assert.Equal(expectedCanCreate, canCreate); }
public async Task CanCreateModel_CreatesModel_ForTopLevelObjectIfThereIsExplicitPrefix( Type modelType, bool isPrefixProvided) { var mockValueProvider = new Mock<IValueProvider>(); mockValueProvider.Setup(o => o.ContainsPrefixAsync(It.IsAny<string>())) .Returns(Task.FromResult(false)); var metadataProvider = new TestModelMetadataProvider(); var bindingContext = new MutableObjectBinderContext { ModelBindingContext = new ModelBindingContext { // Random type. ModelMetadata = metadataProvider.GetMetadataForType(typeof(Person)), ValueProvider = mockValueProvider.Object, OperationBindingContext = new OperationBindingContext { ValueProvider = mockValueProvider.Object, MetadataProvider = metadataProvider, ValidatorProvider = Mock.Of<IModelValidatorProvider>(), }, // Setting it to empty ensures that model does not get created becasue of no model name. ModelName = "dummyModelName", BinderModelName = isPrefixProvided ? "prefix" : null, } }; var mutableBinder = new TestableMutableObjectModelBinder(); bindingContext.PropertyMetadata = mutableBinder.GetMetadataForProperties( bindingContext.ModelBindingContext); // Act var retModel = await mutableBinder.CanCreateModel(bindingContext); // Assert Assert.Equal(isPrefixProvided, retModel); }
public async Task ArrayModelBinder_CreatesEmptyCollection_IfIsTopLevelObject() { // Arrange var binder = new ArrayModelBinder<string>(new SimpleTypeModelBinder(typeof(string))); var bindingContext = CreateContext(); bindingContext.IsTopLevelObject = true; // Lack of prefix and non-empty model name both ignored. bindingContext.ModelName = "modelName"; var metadataProvider = new TestModelMetadataProvider(); bindingContext.ModelMetadata = metadataProvider.GetMetadataForType(typeof(string[])); bindingContext.ValueProvider = new TestValueProvider(new Dictionary<string, object>()); // Act await binder.BindModelAsync(bindingContext); // Assert Assert.Empty(Assert.IsType<string[]>(bindingContext.Result.Model)); Assert.True(bindingContext.Result.IsModelSet); }
public async Task BindingSourceModelBinder_ReturnsTrue_MatchingSource() { // Arrange var provider = new TestModelMetadataProvider(); provider.ForType<string>().BindingDetails(d => d.BindingSource = BindingSource.Body); var modelMetadata = provider.GetMetadataForType(typeof(string)); var context = new ModelBindingContext() { ModelMetadata = modelMetadata, BindingSource = modelMetadata.BindingSource, BinderModelName = modelMetadata.BinderModelName }; var binder = new TestableBindingSourceModelBinder(BindingSource.Body); // Act var result = await binder.BindModelAsync(context); // Assert Assert.NotNull(result); Assert.True(result.IsModelSet); Assert.True(binder.WasBindModelCoreCalled); }
public void GetChildModelBindingContext() { // Arrange var originalBindingContext = new ModelBindingContext { ModelMetadata = new TestModelMetadataProvider().GetMetadataForType(typeof(object)), ModelName = "theName", ModelState = new ModelStateDictionary(), ValueProvider = new SimpleHttpValueProvider() }; var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForType<object>().BindingDetails(d => { d.BindingSource = BindingSource.Custom; d.BinderType = typeof(TestModelBinder); d.BinderModelName = "custom"; }); var newModelMetadata = metadataProvider.GetMetadataForType(typeof(object)); // Act var newBindingContext = ModelBindingContext.GetChildModelBindingContext( originalBindingContext, string.Empty, newModelMetadata); // Assert Assert.Same(newModelMetadata, newBindingContext.ModelMetadata); Assert.Same(newModelMetadata.BindingSource, newBindingContext.BindingSource); Assert.Same(newModelMetadata.BinderModelName, newBindingContext.BinderModelName); Assert.Same(newModelMetadata.BinderType, newBindingContext.BinderType); Assert.Equal("", newBindingContext.ModelName); Assert.Equal(originalBindingContext.ModelState, newBindingContext.ModelState); Assert.Equal(originalBindingContext.ValueProvider, newBindingContext.ValueProvider); }
private static ModelBindingContext GetModelBindingContext(bool isReadOnly) { var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForType<List<int>>().BindingDetails(bd => bd.IsReadOnly = isReadOnly); var valueProvider = new SimpleHttpValueProvider { { "someName[0]", new KeyValuePair<int, string>(42, "forty-two") }, { "someName[1]", new KeyValuePair<int, string>(84, "eighty-four") }, }; var bindingContext = new ModelBindingContext { ModelMetadata = metadataProvider.GetMetadataForType(typeof(IDictionary<int, string>)), ModelName = "someName", ValueProvider = valueProvider, OperationBindingContext = new OperationBindingContext { ModelBinder = CreateKvpBinder(), MetadataProvider = metadataProvider } }; return bindingContext; }
public void CreateBinder_CreatesNoOpBinder_WhenPropertyDoesntHaveABinder() { // Arrange var metadataProvider = new TestModelMetadataProvider(); // There isn't a provider that can handle WidgetId. var options = new TestOptionsManager<MvcOptions>(); options.Value.ModelBinderProviders.Add(new TestModelBinderProvider(c => { if (c.Metadata.ModelType == typeof(Widget)) { Assert.NotNull(c.CreateBinder(c.Metadata.Properties[nameof(Widget.Id)])); return Mock.Of<IModelBinder>(); } return null; })); var factory = new ModelBinderFactory(metadataProvider, options); var context = new ModelBinderFactoryContext() { Metadata = metadataProvider.GetMetadataForType(typeof(Widget)), }; // Act var result = factory.CreateBinder(context); // Assert Assert.NotNull(result); }
public async Task ProcessAsync_GeneratesExpectedOutput( object model, Type containerType, Func<object> modelAccessor, string propertyPath, TagHelperOutputContent tagHelperOutputContent) { // Arrange var expectedTagName = "not-label"; var expectedAttributes = new TagHelperAttributeList { { "class", "form-control" }, { "for", tagHelperOutputContent.ExpectedId } }; var metadataProvider = new TestModelMetadataProvider(); var containerMetadata = metadataProvider.GetMetadataForType(containerType); var containerExplorer = metadataProvider.GetModelExplorerForType(containerType, model); var propertyMetadata = metadataProvider.GetMetadataForProperty(containerType, "Text"); var modelExplorer = containerExplorer.GetExplorerForExpression(propertyMetadata, modelAccessor()); var htmlGenerator = new TestableHtmlGenerator(metadataProvider); var modelExpression = new ModelExpression(propertyPath, modelExplorer); var tagHelper = new LabelTagHelper(htmlGenerator) { For = modelExpression, }; var expectedPreContent = "original pre-content"; var expectedPostContent = "original post-content"; var tagHelperContext = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>( Enumerable.Empty<IReadOnlyTagHelperAttribute>()), items: new Dictionary<object, object>(), uniqueId: "test", getChildContentAsync: useCachedResult => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent(tagHelperOutputContent.OriginalChildContent); return Task.FromResult<TagHelperContent>(tagHelperContent); }); var htmlAttributes = new TagHelperAttributeList { { "class", "form-control" }, }; var output = new TagHelperOutput(expectedTagName, htmlAttributes); output.PreContent.SetContent(expectedPreContent); output.PostContent.SetContent(expectedPostContent); // LabelTagHelper checks IsContentModified so we don't want to forcibly set it if // tagHelperOutputContent.OriginalContent is going to be null or empty. if (!string.IsNullOrEmpty(tagHelperOutputContent.OriginalContent)) { output.Content.SetContent(tagHelperOutputContent.OriginalContent); } var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider); tagHelper.ViewContext = viewContext; // Act await tagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal(expectedAttributes, output.Attributes); Assert.Equal(expectedPreContent, output.PreContent.GetContent()); Assert.Equal( tagHelperOutputContent.ExpectedContent, HtmlContentUtilities.HtmlContentToString(output.Content)); Assert.Equal(expectedPostContent, output.PostContent.GetContent()); Assert.Equal(TagMode.StartTagAndEndTag, output.TagMode); Assert.Equal(expectedTagName, output.TagName); }
public async Task ProcessAsyncInTemplate_WithItems_GeneratesExpectedOutput_DoesNotChangeSelectList( object model, Type containerType, Func<object> modelAccessor, NameAndId nameAndId, string expectedOptions) { // Arrange var originalAttributes = new Dictionary<string, object> { { "class", "form-control" }, }; var originalPostContent = "original content"; var expectedAttributes = new Dictionary<string, object>(originalAttributes) { { "id", nameAndId.Id }, { "name", nameAndId.Name }, { "valid", "from validation attributes" }, }; var expectedPreContent = "original pre-content"; var expectedContent = "original content"; var expectedPostContent = originalPostContent + expectedOptions; var expectedTagName = "select"; var metadataProvider = new TestModelMetadataProvider(); var containerMetadata = metadataProvider.GetMetadataForType(containerType); var containerExplorer = metadataProvider.GetModelExplorerForType(containerType, model); var propertyMetadata = metadataProvider.GetMetadataForProperty(containerType, "Text"); var modelExplorer = containerExplorer.GetExplorerForExpression(propertyMetadata, modelAccessor()); var modelExpression = new ModelExpression(name: string.Empty, modelExplorer: modelExplorer); var tagHelperContext = new TagHelperContext( allAttributes: new Dictionary<string, object>(), items: new Dictionary<object, object>(), uniqueId: "test", getChildContentAsync: () => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return Task.FromResult<TagHelperContent>(tagHelperContent); }); var output = new TagHelperOutput(expectedTagName, originalAttributes) { SelfClosing = true }; output.PreContent.SetContent(expectedPreContent); output.Content.SetContent(expectedContent); output.PostContent.SetContent(originalPostContent); var htmlGenerator = new TestableHtmlGenerator(metadataProvider) { ValidationAttributes = { { "valid", "from validation attributes" }, } }; var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider); viewContext.ViewData.TemplateInfo.HtmlFieldPrefix = nameAndId.Name; var items = new SelectList(new[] { "", "outer text", "inner text", "other text" }); var savedDisabled = items.Select(item => item.Disabled).ToList(); var savedGroup = items.Select(item => item.Group).ToList(); var savedSelected = items.Select(item => item.Selected).ToList(); var savedText = items.Select(item => item.Text).ToList(); var savedValue = items.Select(item => item.Value).ToList(); var tagHelper = new SelectTagHelper { For = modelExpression, Generator = htmlGenerator, Items = items, ViewContext = viewContext, }; // Act await tagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.True(output.SelfClosing); Assert.Equal(expectedAttributes, output.Attributes); Assert.Equal(expectedPreContent, output.PreContent.GetContent()); Assert.Equal(expectedContent, output.Content.GetContent()); Assert.Equal(expectedPostContent, output.PostContent.GetContent()); Assert.Equal(expectedTagName, output.TagName); Assert.NotNull(viewContext.FormContext?.FormData); Assert.Single( viewContext.FormContext.FormData, entry => entry.Key == SelectTagHelper.SelectedValuesFormDataKey); Assert.Equal(savedDisabled, items.Select(item => item.Disabled)); Assert.Equal(savedGroup, items.Select(item => item.Group)); Assert.Equal(savedSelected, items.Select(item => item.Selected)); Assert.Equal(savedText, items.Select(item => item.Text)); Assert.Equal(savedValue, items.Select(item => item.Value)); }
public async Task ProcessAsync_GeneratesExpectedOutput( object model, Type containerType, Func<object> modelAccessor, NameAndId nameAndId, string ignored) { // Arrange var originalAttributes = new Dictionary<string, object> { { "class", "form-control" }, }; var originalPostContent = "original content"; var expectedAttributes = new Dictionary<string, object>(originalAttributes) { { "id", nameAndId.Id }, { "name", nameAndId.Name }, { "valid", "from validation attributes" }, }; var expectedPreContent = "original pre-content"; var expectedContent = "original content"; var expectedPostContent = originalPostContent; var expectedTagName = "not-select"; var metadataProvider = new TestModelMetadataProvider(); var containerMetadata = metadataProvider.GetMetadataForType(containerType); var containerExplorer = metadataProvider.GetModelExplorerForType(containerType, model); var propertyMetadata = metadataProvider.GetMetadataForProperty(containerType, "Text"); var modelExplorer = containerExplorer.GetExplorerForExpression(propertyMetadata, modelAccessor()); var modelExpression = new ModelExpression(nameAndId.Name, modelExplorer); var tagHelperContext = new TagHelperContext( allAttributes: new Dictionary<string, object>(), items: new Dictionary<object, object>(), uniqueId: "test", getChildContentAsync: () => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return Task.FromResult<TagHelperContent>(tagHelperContent); }); var output = new TagHelperOutput(expectedTagName, originalAttributes) { SelfClosing = true, }; output.PreContent.SetContent(expectedPreContent); output.Content.SetContent(expectedContent); output.PostContent.SetContent(originalPostContent); var htmlGenerator = new TestableHtmlGenerator(metadataProvider) { ValidationAttributes = { { "valid", "from validation attributes" }, } }; var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider); var tagHelper = new SelectTagHelper { For = modelExpression, Generator = htmlGenerator, ViewContext = viewContext, }; // Act await tagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.True(output.SelfClosing); Assert.Equal(expectedAttributes, output.Attributes); Assert.Equal(expectedPreContent, output.PreContent.GetContent()); Assert.Equal(expectedContent, output.Content.GetContent()); Assert.Equal(expectedPostContent, output.PostContent.GetContent()); Assert.Equal(expectedTagName, output.TagName); Assert.NotNull(viewContext.FormContext?.FormData); Assert.Single( viewContext.FormContext.FormData, entry => entry.Key == SelectTagHelper.SelectedValuesFormDataKey); }
public void CreateBinder_Throws_WhenBinderNotCreated() { // Arrange var metadataProvider = new TestModelMetadataProvider(); var options = new TestOptionsManager<MvcOptions>(); var factory = new ModelBinderFactory(metadataProvider, options); var context = new ModelBinderFactoryContext() { Metadata = metadataProvider.GetMetadataForType(typeof(string)), }; // Act var exception = Assert.Throws<InvalidOperationException>(() => factory.CreateBinder(context)); // Assert Assert.Equal( $"Could not create a model binder for model object of type '{typeof(string).FullName}'.", exception.Message); }
private static DefaultModelBindingContext GetBindingContext( IValueProvider valueProvider, Type keyValuePairType) { var metadataProvider = new TestModelMetadataProvider(); var bindingContext = new DefaultModelBindingContext { ModelMetadata = metadataProvider.GetMetadataForType(keyValuePairType), ModelName = "someName", ModelState = new ModelStateDictionary(), ValueProvider = valueProvider, }; return bindingContext; }
private static ModelBindingContext GetBindingContext( IValueProvider valueProvider, bool isReadOnly = false) { var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForType<int[]>().BindingDetails(bd => bd.IsReadOnly = isReadOnly); var bindingContext = new ModelBindingContext { ModelMetadata = metadataProvider.GetMetadataForType(typeof(int[])), ModelName = "someName", ValueProvider = valueProvider, OperationBindingContext = new OperationBindingContext { ModelBinder = CreateIntBinder(), MetadataProvider = metadataProvider }, }; return bindingContext; }
public void CreateBinder_NestedProperties() { // Arrange var metadataProvider = new TestModelMetadataProvider(); var options = new TestOptionsManager<MvcOptions>(); options.Value.ModelBinderProviders.Add(new TestModelBinderProvider(c => { if (c.Metadata.ModelType == typeof(Widget)) { Assert.NotNull(c.CreateBinder(c.Metadata.Properties[nameof(Widget.Id)])); return Mock.Of<IModelBinder>(); } else if (c.Metadata.ModelType == typeof(WidgetId)) { return Mock.Of<IModelBinder>(); } return null; })); var factory = new ModelBinderFactory(metadataProvider, options); var context = new ModelBinderFactoryContext() { Metadata = metadataProvider.GetMetadataForType(typeof(Widget)), }; // Act var result = factory.CreateBinder(context); // Assert Assert.NotNull(result); }
public void CreateBinder_PassesExpectedBindingInfo( BindingInfo parameterBindingInfo, BindingMetadata bindingMetadata, BindingInfo expectedInfo) { // Arrange var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForType<Employee>().BindingDetails(binding => { binding.BinderModelName = bindingMetadata.BinderModelName; binding.BinderType = bindingMetadata.BinderType; binding.BindingSource = bindingMetadata.BindingSource; if (bindingMetadata.PropertyFilterProvider != null) { binding.PropertyFilterProvider = bindingMetadata.PropertyFilterProvider; } }); var modelBinder = Mock.Of<IModelBinder>(); var modelBinderProvider = new TestModelBinderProvider(context => { Assert.Equal(typeof(Employee), context.Metadata.ModelType); Assert.NotNull(context.BindingInfo); Assert.Equal(expectedInfo.BinderModelName, context.BindingInfo.BinderModelName, StringComparer.Ordinal); Assert.Equal(expectedInfo.BinderType, context.BindingInfo.BinderType); Assert.Equal(expectedInfo.BindingSource, context.BindingInfo.BindingSource); Assert.Same(expectedInfo.PropertyFilterProvider, context.BindingInfo.PropertyFilterProvider); return modelBinder; }); var options = new TestOptionsManager<MvcOptions>(); options.Value.ModelBinderProviders.Insert(0, modelBinderProvider); var factory = new ModelBinderFactory(metadataProvider, options); var factoryContext = new ModelBinderFactoryContext { BindingInfo = parameterBindingInfo, Metadata = metadataProvider.GetMetadataForType(typeof(Employee)), }; // Act & Assert var result = factory.CreateBinder(factoryContext); // Confirm our IModelBinderProvider was called. Assert.Same(modelBinder, result); }
public void EnterNestedScope_FiltersValueProviders_BasedOnTopLevelValueProviders() { // Arrange var metadataProvider = new TestModelMetadataProvider(); metadataProvider .ForProperty(typeof(string), nameof(string.Length)) .BindingDetails(b => b.BindingSource = BindingSource.Form); var original = CreateDefaultValueProvider(); var context = DefaultModelBindingContext.CreateBindingContext( new ActionContext(), original, metadataProvider.GetMetadataForType(typeof(string)), new BindingInfo() { BindingSource = BindingSource.Query }, "model"); var propertyMetadata = metadataProvider.GetMetadataForProperty(typeof(string), nameof(string.Length)); // Act context.EnterNestedScope(propertyMetadata, "Length", "Length", model: null); // Assert Assert.Collection( Assert.IsType<CompositeValueProvider>(context.ValueProvider), vp => Assert.Same(original[2], vp)); }
public void CreateBinder_Caches_NonRootNodes_WhenNonRootNodeReturnsNull() { // Arrange var metadataProvider = new TestModelMetadataProvider(); var options = new TestOptionsManager<MvcOptions>(); IModelBinder inner = null; var widgetProvider = new TestModelBinderProvider(c => { if (c.Metadata.ModelType == typeof(Widget)) { var binder = c.CreateBinder(c.Metadata.Properties[nameof(Widget.Id)]); Assert.IsType<NoOpBinder>(binder); if (inner == null) { inner = binder; } else { Assert.Same(inner, binder); } return Mock.Of<IModelBinder>(); } return null; }); var widgetIdProvider = new TestModelBinderProvider(c => { Assert.Equal(typeof(WidgetId), c.Metadata.ModelType); return null; }); options.Value.ModelBinderProviders.Add(widgetProvider); options.Value.ModelBinderProviders.Add(widgetIdProvider); var factory = new ModelBinderFactory(metadataProvider, options); var context = new ModelBinderFactoryContext() { Metadata = metadataProvider.GetMetadataForType(typeof(Widget)), CacheToken = null, // We want the outermost provider to run twice. }; // Act var result1 = factory.CreateBinder(context); var result2 = factory.CreateBinder(context); // Assert Assert.NotSame(result1, result2); Assert.Equal(2, widgetProvider.SuccessCount); Assert.Equal(0, widgetIdProvider.SuccessCount); }
public async Task Process_GeneratesExpectedOutput( object container, Type containerType, object model, NameAndId nameAndId, string expectedContent) { // Arrange var expectedAttributes = new TagHelperAttributeList { { "class", "form-control" }, { "id", nameAndId.Id }, { "name", nameAndId.Name }, { "valid", "from validation attributes" }, }; var expectedTagName = "not-textarea"; var metadataProvider = new TestModelMetadataProvider(); var containerMetadata = metadataProvider.GetMetadataForType(containerType); var containerExplorer = metadataProvider.GetModelExplorerForType(containerType, container); var propertyMetadata = metadataProvider.GetMetadataForProperty(containerType, "Text"); var modelExplorer = containerExplorer.GetExplorerForExpression(propertyMetadata, model); var htmlGenerator = new TestableHtmlGenerator(metadataProvider) { ValidationAttributes = { { "valid", "from validation attributes" }, } }; // Property name is either nameof(Model.Text) or nameof(NestedModel.Text). var modelExpression = new ModelExpression(nameAndId.Name, modelExplorer); var tagHelper = new TextAreaTagHelper(htmlGenerator) { For = modelExpression, }; var tagHelperContext = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>( Enumerable.Empty<IReadOnlyTagHelperAttribute>()), items: new Dictionary<object, object>(), uniqueId: "test", getChildContentAsync: useCachedResult => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return Task.FromResult<TagHelperContent>(tagHelperContent); }); var htmlAttributes = new TagHelperAttributeList { { "class", "form-control" }, }; var output = new TagHelperOutput(expectedTagName, htmlAttributes) { TagMode = TagMode.SelfClosing, }; output.Content.SetContent("original content"); var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider); tagHelper.ViewContext = viewContext; // Act await tagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal(TagMode.SelfClosing, output.TagMode); Assert.Equal(expectedAttributes, output.Attributes); Assert.Equal(expectedContent, HtmlContentUtilities.HtmlContentToString(output.Content)); Assert.Equal(expectedTagName, output.TagName); }
public async Task BindModel_FallsBackToBindingValues_WithComplexValues() { // Arrange var dictionary = new Dictionary<int, ModelWithProperties> { { 23, new ModelWithProperties { Id = 43, Name = "Wilma" } }, { 27, new ModelWithProperties { Id = 98, Name = "Fred" } }, }; var stringDictionary = new Dictionary<string, string> { { "prefix[23].Id", "43" }, { "prefix[23].Name", "Wilma" }, { "prefix[27].Id", "98" }, { "prefix[27].Name", "Fred" }, }; var bindingContext = CreateContext(); bindingContext.ModelName = "prefix"; bindingContext.ValueProvider = CreateEnumerableValueProvider("{0}", stringDictionary); bindingContext.FieldName = bindingContext.ModelName; var metadataProvider = new TestModelMetadataProvider(); bindingContext.ModelMetadata = metadataProvider.GetMetadataForProperty( typeof(ModelWithDictionaryProperties), nameof(ModelWithDictionaryProperties.DictionaryWithComplexValuesProperty)); var valueMetadata = metadataProvider.GetMetadataForType(typeof(ModelWithProperties)); var binder = new DictionaryModelBinder<int, ModelWithProperties>( new SimpleTypeModelBinder(typeof(int)), new ComplexTypeModelBinder(new Dictionary<ModelMetadata, IModelBinder>() { { valueMetadata.Properties["Id"], new SimpleTypeModelBinder(typeof(int)) }, { valueMetadata.Properties["Name"], new SimpleTypeModelBinder(typeof(string)) }, })); // Act await binder.BindModelAsync(bindingContext); // Assert Assert.True(bindingContext.Result.IsModelSet); var resultDictionary = Assert.IsAssignableFrom<IDictionary<int, ModelWithProperties>>(bindingContext.Result.Model); Assert.Equal(dictionary, resultDictionary); // This requires a non-default IValidationStrategy Assert.Contains(bindingContext.Result.Model, bindingContext.ValidationState.Keys); var entry = bindingContext.ValidationState[bindingContext.Result.Model]; var strategy = Assert.IsType<ShortFormDictionaryValidationStrategy<int, ModelWithProperties>>(entry.Strategy); Assert.Equal( new KeyValuePair<string, int>[] { new KeyValuePair<string, int>("23", 23), new KeyValuePair<string, int>("27", 27), }.OrderBy(kvp => kvp.Key), strategy.KeyMappings.OrderBy(kvp => kvp.Key)); }
public void CreateBinder_BreaksCycles() { // Arrange var metadataProvider = new TestModelMetadataProvider(); var callCount = 0; var options = new TestOptionsManager<MvcOptions>(); options.Value.ModelBinderProviders.Add(new TestModelBinderProvider(c => { var currentCallCount = ++callCount; Assert.Equal(typeof(Employee), c.Metadata.ModelType); var binder = c.CreateBinder(c.Metadata.Properties[nameof(Employee.Manager)]); if (currentCallCount == 2) { Assert.IsType<PlaceholderBinder>(binder); } return Mock.Of<IModelBinder>(); })); var factory = new ModelBinderFactory(metadataProvider, options); var context = new ModelBinderFactoryContext() { Metadata = metadataProvider.GetMetadataForType(typeof(Employee)), }; // Act var result = factory.CreateBinder(context); // Assert Assert.NotNull(result); }
public void CreateBinder_DoesNotCache_WhenTokenIsNull() { // Arrange var metadataProvider = new TestModelMetadataProvider(); var options = new TestOptionsManager<MvcOptions>(); options.Value.ModelBinderProviders.Add(new TestModelBinderProvider(c => { Assert.Equal(typeof(Employee), c.Metadata.ModelType); return Mock.Of<IModelBinder>(); })); var factory = new ModelBinderFactory(metadataProvider, options); var context = new ModelBinderFactoryContext() { Metadata = metadataProvider.GetMetadataForType(typeof(Employee)), }; // Act var result1 = factory.CreateBinder(context); var result2 = factory.CreateBinder(context); // Assert Assert.NotSame(result1, result2); }
private static ModelBindingContext GetBindingContext(Type modelType, Type binderType = null) { var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForType(modelType).BindingDetails(bd => bd.BinderType = binderType); var operationBindingContext = new OperationBindingContext { ActionContext = new ActionContext() { HttpContext = new DefaultHttpContext(), }, MetadataProvider = metadataProvider, ValidatorProvider = Mock.Of<IModelValidatorProvider>(), }; var bindingContext = new ModelBindingContext { ModelMetadata = metadataProvider.GetMetadataForType(modelType), ModelName = "someName", ValueProvider = Mock.Of<IValueProvider>(), ModelState = new ModelStateDictionary(), OperationBindingContext = operationBindingContext, BinderType = binderType }; return bindingContext; }