public async Task BindModel_CallsSelectedInputFormatterOnce() { // Arrange var mockInputFormatter = new Mock<IInputFormatter>(); mockInputFormatter.Setup(f => f.CanRead(It.IsAny<InputFormatterContext>())) .Returns(true) .Verifiable(); mockInputFormatter.Setup(o => o.ReadAsync(It.IsAny<InputFormatterContext>())) .Returns(InputFormatterResult.SuccessAsync(new Person())) .Verifiable(); var inputFormatter = mockInputFormatter.Object; var provider = new TestModelMetadataProvider(); provider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body); var bindingContext = GetBindingContext( typeof(Person), new[] { inputFormatter }, metadataProvider: provider); var binder = new BodyModelBinder(); // Act var binderResult = await binder.BindModelAsync(bindingContext); // Assert mockInputFormatter.Verify(v => v.CanRead(It.IsAny<InputFormatterContext>()), Times.Once); mockInputFormatter.Verify(v => v.ReadAsync(It.IsAny<InputFormatterContext>()), Times.Once); Assert.NotNull(binderResult); Assert.True(binderResult.IsModelSet); }
public async Task BindModelAsync_ValueProviderContainPrefix_Succeeds() { // Arrange var valueProvider = new SimpleValueProvider { { "someName[0]", "42" }, { "someName[1]", "84" }, }; var bindingContext = GetBindingContext(valueProvider); var metadataProvider = new TestModelMetadataProvider(); bindingContext.ModelMetadata = metadataProvider.GetMetadataForProperty( typeof(ModelWithIntArrayProperty), nameof(ModelWithIntArrayProperty.ArrayProperty)); var binder = new ArrayModelBinder<int>(new SimpleTypeModelBinder(typeof(int))); // Act await binder.BindModelAsync(bindingContext); // Assert Assert.True(bindingContext.Result.IsModelSet); var array = Assert.IsType<int[]>(bindingContext.Result.Model); Assert.Equal(new[] { 42, 84 }, array); }
public void AddValidation_CorrectValidationTypeAndOverriddenErrorMessage() { // Arrange var expectedMessage = "Error message about 'DisplayId' from override."; var provider = new TestModelMetadataProvider(); provider .ForProperty(typeof(TypeWithNumericProperty), nameof(TypeWithNumericProperty.Id)) .BindingDetails(d => d.ModelBindingMessageProvider.ValueMustBeANumberAccessor = name => $"Error message about '{ name }' from override."); var metadata = provider.GetMetadataForProperty( typeof(TypeWithNumericProperty), nameof(TypeWithNumericProperty.Id)); 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 void Create_ForModelMetadataReadOnly_ReturnsNull() { // Arrange var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForProperty( typeof(ModelWithIntArrayProperty), nameof(ModelWithIntArrayProperty.ArrayProperty)).BindingDetails(bd => bd.IsReadOnly = true); var modelMetadata = metadataProvider.GetMetadataForProperty( typeof(ModelWithIntArrayProperty), nameof(ModelWithIntArrayProperty.ArrayProperty)); var provider = new ArrayModelBinderProvider(); var context = new TestModelBinderProviderContext(typeof(int[])); context.OnCreatingBinder((m) => { // Expect to be called with the element type to create a binder for elements. Assert.Equal(typeof(int), m.ModelType); return Mock.Of<IModelBinder>(); }); // Act var result = provider.GetBinder(context); // Assert Assert.IsType<ArrayModelBinder<int>>(result); }
public async Task BindModel_NoInputFormatterFound_SetsModelStateError_RespectsBinderModelName() { // Arrange var provider = new TestModelMetadataProvider(); provider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body); var bindingContext = GetBindingContext(typeof(Person), metadataProvider: provider); bindingContext.BinderModelName = "custom"; var binder = CreateBinder(); // Act var binderResult = await binder.BindModelResultAsync(bindingContext); // Assert // Returns non-null because it understands the metadata type. Assert.NotNull(binderResult); Assert.False(binderResult.IsModelSet); Assert.Null(binderResult.Model); // Key is the bindermodelname because this was a top-level binding. var entry = Assert.Single(bindingContext.ModelState); Assert.Equal("custom", entry.Key); Assert.Single(entry.Value.Errors); }
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 void GetValidators_DoesNotCacheValidatorsWithIsReusableFalse() { // Arrange var cache = new ValidatorCache(); var metadata = new TestModelMetadataProvider().GetMetadataForProperty(typeof(TypeWithProperty), "Property1"); var validatorProvider = new ProviderWithNonReusableValidators(); // Act - 1 var validators1 = cache.GetValidators(metadata, validatorProvider); // Assert - 1 var validator1 = Assert.IsType<DataAnnotationsModelValidator>(validators1[0]); var validator2 = Assert.IsType<DataAnnotationsModelValidator>(validators1[1]); Assert.Contains(validator1.Attribute, metadata.ValidatorMetadata); // Copied by provider Assert.Contains(validator2.Attribute, metadata.ValidatorMetadata); // Copied by provider // Act - 2 var validators2 = cache.GetValidators(metadata, validatorProvider); // Assert - 2 Assert.NotSame(validators1, validators2); var requiredValidator = Assert.Single(validators2.Where(v => (v as DataAnnotationsModelValidator).Attribute is RequiredAttribute)); Assert.Contains(requiredValidator, validators1); // cached var stringLengthValidator = Assert.Single(validators2.Where(v => (v as DataAnnotationsModelValidator).Attribute is StringLengthAttribute)); Assert.DoesNotContain(stringLengthValidator, validators1); // not cached }
public void GetValidators_CachesAllValidators() { // Arrange var cache = new ValidatorCache(); var metadata = new TestModelMetadataProvider().GetMetadataForProperty(typeof(TypeWithProperty), "Property1"); var validatorProvider = TestModelValidatorProvider.CreateDefaultProvider(); // Act - 1 var validators1 = cache.GetValidators(metadata, validatorProvider); // Assert - 1 var attribute1 = Assert.IsType<DataAnnotationsModelValidator>(validators1[0]).Attribute; var attribute2 = Assert.IsType<DataAnnotationsModelValidator>(validators1[1]).Attribute; Assert.Contains(attribute1, metadata.ValidatorMetadata); // Copied by provider Assert.Contains(attribute2, metadata.ValidatorMetadata); // Copied by provider // Act - 2 var validators2 = cache.GetValidators(metadata, validatorProvider); // Assert - 2 Assert.Same(validators1, validators2); Assert.Contains(validators1[0], validators2); // Cached Assert.Contains(validators1[1], validators2); // Cached }
public void GetValidators_DoesNotCacheValidatorsWithIsReusableFalse() { // Arrange var cache = new ClientValidatorCache(); var metadata = new TestModelMetadataProvider().GetMetadataForProperty(typeof(TypeWithProperty), "Property1"); var validatorProvider = new ProviderWithNonReusableValidators(); // Act - 1 var validators1 = cache.GetValidators(metadata, validatorProvider); // Assert - 1 var validator1 = Assert.Single(validators1.OfType<RequiredAttributeAdapter>()); var validator2 = Assert.Single(validators1.OfType<StringLengthAttributeAdapter>()); Assert.Contains(validator1.Attribute, metadata.ValidatorMetadata); // Copied by provider Assert.Contains(validator2.Attribute, metadata.ValidatorMetadata); // Copied by provider // Act - 2 var validators2 = cache.GetValidators(metadata, validatorProvider); // Assert - 2 Assert.NotSame(validators1, validators2); Assert.Same(validator1, Assert.Single(validators2.OfType<RequiredAttributeAdapter>())); // cached Assert.NotSame(validator2, Assert.Single(validators2.OfType<StringLengthAttributeAdapter>())); // not cached }
public async Task BindModel_NoInputFormatterFound_SetsModelStateError() { // Arrange var provider = new TestModelMetadataProvider(); provider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body); var bindingContext = GetBindingContext(typeof(Person), metadataProvider: provider); var binder = bindingContext.OperationBindingContext.ModelBinder; // Act var binderResult = await binder.BindModelAsync(bindingContext); // Assert // Returns non-null because it understands the metadata type. Assert.NotNull(binderResult); Assert.False(binderResult.IsModelSet); Assert.Null(binderResult.Model); // Key is empty because this was a top-level binding. var entry = Assert.Single(bindingContext.ModelState); Assert.Equal(string.Empty, entry.Key); Assert.Single(entry.Value.Errors); }
public void GetValidators_CachesAllValidators() { // Arrange var cache = new ClientValidatorCache(); var metadata = new TestModelMetadataProvider().GetMetadataForProperty(typeof(TypeWithProperty), "Property1"); var validatorProvider = TestClientModelValidatorProvider.CreateDefaultProvider(); // Act - 1 var validators1 = cache.GetValidators(metadata, validatorProvider); // Assert - 1 var attribute1 = Assert.Single(validators1.OfType<RequiredAttributeAdapter>()).Attribute; var attribute2 = Assert.Single(validators1.OfType<StringLengthAttributeAdapter>()).Attribute; Assert.Contains(attribute1, metadata.ValidatorMetadata); // Copied by provider Assert.Contains(attribute2, metadata.ValidatorMetadata); // Copied by provider // Act - 2 var validators2 = cache.GetValidators(metadata, validatorProvider); // Assert - 2 Assert.Same(validators1, validators2); Assert.Contains(validators1[0], validators2); // Cached Assert.Contains(validators1[1], validators2); // Cached }
public async Task ProcessAsync_GeneratesExpectedOutput() { // Arrange var expectedTagName = "not-div"; var metadataProvider = new TestModelMetadataProvider(); var htmlGenerator = new TestableHtmlGenerator(metadataProvider); var validationSummaryTagHelper = new ValidationSummaryTagHelper(htmlGenerator) { ValidationSummary = ValidationSummary.All, }; var expectedPreContent = "original pre-content"; var expectedContent = "original 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("Something"); return Task.FromResult<TagHelperContent>(tagHelperContent); }); var output = new TagHelperOutput( expectedTagName, attributes: new TagHelperAttributeList { { "class", "form-control" } }); output.PreContent.SetContent(expectedPreContent); output.Content.SetContent(expectedContent); output.PostContent.SetContent("Custom Content"); Model model = null; var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider); validationSummaryTagHelper.ViewContext = viewContext; // Act await validationSummaryTagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal(2, output.Attributes.Count); var attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("class")); Assert.Equal("form-control validation-summary-valid", attribute.Value); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("data-valmsg-summary")); Assert.Equal("true", attribute.Value); Assert.Equal(expectedPreContent, output.PreContent.GetContent()); Assert.Equal(expectedContent, output.Content.GetContent()); Assert.Equal("Custom Content<ul><li style=\"display:none\"></li>" + Environment.NewLine + "</ul>", output.PostContent.GetContent()); Assert.Equal(expectedTagName, output.TagName); }
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 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 ObjectTemplateDisplaysNullDisplayTextWhenObjectIsNull() { // Arrange var provider = new TestModelMetadataProvider(); provider.ForType<DefaultTemplatesUtilities.ObjectTemplateModel>().DisplayDetails(dd => { dd.NullDisplayText = "(null value)"; }); var html = DefaultTemplatesUtilities.GetHtmlHelper(provider: provider); // Act var result = DefaultDisplayTemplates.ObjectTemplate(html); // Assert Assert.Equal("(null value)", HtmlContentUtilities.HtmlContentToString(result)); }
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 DisplayTextFor_ReturnsNullDisplayText_IfSetAndValueNull() { // Arrange var provider = new TestModelMetadataProvider(); provider.ForType<OverriddenToStringModel>().DisplayDetails(dd => { dd.NullDisplayText = "Null display Text"; }); var helper = DefaultTemplatesUtilities.GetHtmlHelper<OverriddenToStringModel>(model: null, provider: provider); // Act var result = helper.DisplayTextFor(m => m); // Assert Assert.Equal("Null display Text", result); }
public async Task BindModel_IsGreedy() { // Arrange var provider = new TestModelMetadataProvider(); provider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body); var bindingContext = GetBindingContext(typeof(Person), metadataProvider: provider); var binder = bindingContext.OperationBindingContext.ModelBinder; // Act var binderResult = await binder.BindModelAsync(bindingContext); // Assert Assert.NotNull(binderResult); Assert.False(binderResult.IsModelSet); }
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 void AddModelError_ForSingleExpression_AddsExpectedException() { // Arrange var dictionary = new ModelStateDictionary(); var exception = new Exception(); var provider = new TestModelMetadataProvider(); var metadata = provider.GetMetadataForProperty(typeof(TestModel), nameof(TestModel.Text)); // Act dictionary.AddModelError<TestModel>(model => model.Text, exception, metadata); // Assert var modelState = Assert.Single(dictionary); var modelError = Assert.Single(modelState.Value.Errors); Assert.Equal("Text", modelState.Key); Assert.Same(exception, modelError.Exception); }
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)); }
public void DisplayNameHelpers_ReturnDisplayNameForProperty_IfNonNull(string displayName) { // Arrange var provider = new TestModelMetadataProvider(); provider .ForProperty<DefaultTemplatesUtilities.ObjectTemplateModel>("Property1") .DisplayDetails(dd => dd.DisplayName = () => displayName); var helper = DefaultTemplatesUtilities.GetHtmlHelper(provider: provider); var enumerableHelper = DefaultTemplatesUtilities.GetHtmlHelperForEnumerable(provider: provider); // Act var displayNameResult = helper.DisplayName("Property1"); var displayNameForResult = helper.DisplayNameFor(m => m.Property1); var displayNameForEnumerableResult = enumerableHelper.DisplayNameFor(m => m.Property1); // Assert Assert.Equal(displayName, displayNameResult); Assert.Equal(displayName, displayNameForResult); Assert.Equal(displayName, displayNameForEnumerableResult); }
public async Task ArrayModelBinder_DoesNotCreateCollection_IfNotIsTopLevelObject(string prefix) { // Arrange var binder = new ArrayModelBinder<string>(new SimpleTypeModelBinder(typeof(string))); var bindingContext = CreateContext(); bindingContext.ModelName = ModelNames.CreatePropertyModelName(prefix, "ArrayProperty"); var metadataProvider = new TestModelMetadataProvider(); bindingContext.ModelMetadata = metadataProvider.GetMetadataForProperty( typeof(ModelWithArrayProperty), nameof(ModelWithArrayProperty.ArrayProperty)); bindingContext.ValueProvider = new TestValueProvider(new Dictionary<string, object>()); // Act await binder.BindModelAsync(bindingContext); // Assert Assert.False(bindingContext.Result.IsModelSet); }
public async Task BindModel_NoInputFormatterFound_SetsModelStateError() { // Arrange var provider = new TestModelMetadataProvider(); provider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body); var bindingContext = GetBindingContext(typeof(Person), metadataProvider: provider); var binder = bindingContext.OperationBindingContext.ModelBinder; // Act var binderResult = await binder.BindModelAsync(bindingContext); // Assert // Returns true because it understands the metadata type. Assert.NotNull(binderResult); Assert.False(binderResult.IsModelSet); Assert.Null(binderResult.Model); Assert.True(bindingContext.ModelState.ContainsKey("someName")); }
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 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 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 BindModel_NoInputFormatterFound_SetsModelStateError() { // Arrange var provider = new TestModelMetadataProvider(); provider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body); var bindingContext = GetBindingContext(typeof(Person), metadataProvider: provider); var binder = CreateBinder(new List<IInputFormatter>()); // Act await binder.BindModelAsync(bindingContext); // Assert Assert.False(bindingContext.Result.IsModelSet); Assert.Null(bindingContext.Result.Model); // Key is the empty string because this was a top-level binding. var entry = Assert.Single(bindingContext.ModelState); Assert.Equal(string.Empty, entry.Key); Assert.Single(entry.Value.Errors); }
public async Task BindModel_CallsSelectedInputFormatterOnce() { // Arrange var mockInputFormatter = new Mock<IInputFormatter>(); mockInputFormatter.Setup(f => f.CanRead(It.IsAny<InputFormatterContext>())) .Returns(true) .Verifiable(); mockInputFormatter.Setup(o => o.ReadAsync(It.IsAny<InputFormatterContext>())) .Returns(Task.FromResult<object>(new Person())) .Verifiable(); var inputFormatter = mockInputFormatter.Object; var provider = new TestModelMetadataProvider(); provider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body); var bindingContext = GetBindingContext( typeof(Person), new[] { inputFormatter }, metadataProvider: provider); var binder = new BodyModelBinder(); // Act var binderResult = await binder.BindModelAsync(bindingContext); // Assert mockInputFormatter.Verify(v => v.CanRead(It.IsAny<InputFormatterContext>()), Times.Once); mockInputFormatter.Verify(v => v.ReadAsync(It.IsAny<InputFormatterContext>()), Times.Once); Assert.NotNull(binderResult); Assert.True(binderResult.IsModelSet); Assert.NotNull(binderResult.ValidationNode); Assert.True(binderResult.ValidationNode.ValidateAllProperties); Assert.False(binderResult.ValidationNode.SuppressValidation); Assert.Empty(binderResult.ValidationNode.ChildNodes); Assert.Equal(binderResult.Key, binderResult.ValidationNode.Key); Assert.Equal(bindingContext.ModelMetadata, binderResult.ValidationNode.ModelMetadata); Assert.Same(binderResult.Model, binderResult.ValidationNode.Model); }
public static HtmlHelper <TModel> GetHtmlHelper <TModel>( TModel model, ICompositeViewEngine viewEngine) { return(GetHtmlHelper(model, CreateUrlHelper(), viewEngine, TestModelMetadataProvider.CreateDefaultProvider())); }
public async Task ProcessAsync_GeneratesExpectedOutput_WithRoute() { // Arrange var expectedTagName = "not-button-or-submit"; var metadataProvider = new TestModelMetadataProvider(); var tagHelperContext = new TagHelperContext( tagName: "form-action", allAttributes: new TagHelperAttributeList { { "id", "my-id" }, }, items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( expectedTagName, attributes: new TagHelperAttributeList { { "id", "my-id" }, }, getChildContentAsync: (useCachedResult, encoder) => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something Else"); // ignored return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); var urlHelper = new Mock <IUrlHelper>(MockBehavior.Strict); urlHelper .Setup(mock => mock.RouteUrl(It.IsAny <UrlRouteContext>())) .Returns <UrlRouteContext>(c => $"{c.RouteName}/{(c.Values as RouteValueDictionary)["name"]}"); var viewContext = new ViewContext(); var urlHelperFactory = new Mock <IUrlHelperFactory>(MockBehavior.Strict); urlHelperFactory .Setup(f => f.GetUrlHelper(viewContext)) .Returns(urlHelper.Object); var tagHelper = new FormActionTagHelper(urlHelperFactory.Object) { Route = "routine", RouteValues = { { "name", "value" }, }, ViewContext = viewContext, }; // Act await tagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Collection( output.Attributes, attribute => { Assert.Equal("id", attribute.Name, StringComparer.Ordinal); Assert.Equal("my-id", attribute.Value as string, StringComparer.Ordinal); }, attribute => { Assert.Equal("formaction", attribute.Name, StringComparer.Ordinal); Assert.Equal("routine/value", attribute.Value as string, StringComparer.Ordinal); }); Assert.False(output.IsContentModified); Assert.False(output.PostContent.IsModified); Assert.False(output.PostElement.IsModified); Assert.False(output.PreContent.IsModified); Assert.False(output.PreElement.IsModified); Assert.Equal(TagMode.StartTagAndEndTag, output.TagMode); Assert.Equal(expectedTagName, output.TagName); }
public async Task ModelBinderFactory_BindsPropertiesOnPageModel() { // Arrange var type = typeof(PageModelWithProperty).GetTypeInfo(); var actionDescriptor = new CompiledPageActionDescriptor { BoundProperties = new[] { new PageBoundPropertyDescriptor() { Name = nameof(PageModelWithProperty.Id), ParameterType = typeof(int), Property = type.GetProperty(nameof(PageModelWithProperty.Id)), }, new PageBoundPropertyDescriptor() { Name = nameof(PageModelWithProperty.RouteDifferentValue), ParameterType = typeof(string), Property = type.GetProperty(nameof(PageModelWithProperty.RouteDifferentValue)), }, new PageBoundPropertyDescriptor() { Name = nameof(PageModelWithProperty.PropertyWithNoValue), ParameterType = typeof(string), Property = type.GetProperty(nameof(PageModelWithProperty.PropertyWithNoValue)), } }, HandlerTypeInfo = typeof(PageModelWithProperty).GetTypeInfo(), PageTypeInfo = typeof(PageWithProperty).GetTypeInfo(), ModelTypeInfo = typeof(PageModelWithProperty).GetTypeInfo(), }; var binder = new TestParameterBinder(new Dictionary <string, object> { { nameof(PageModelWithProperty.Id), 10 }, { nameof(PageModelWithProperty.RouteDifferentValue), "route-value" } }); var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(); var factory = PagePropertyBinderFactory.CreateBinder(binder, modelMetadataProvider, actionDescriptor); var page = new PageWithProperty { PageContext = new PageContext() { HttpContext = new DefaultHttpContext(), } }; var model = new PageModelWithProperty(); // Act await factory(page.PageContext, model); // Assert // Verify that the page properties were not bound. Assert.Equal(default(int), page.Id); Assert.Null(page.RouteDifferentValue); Assert.Equal(10, model.Id); Assert.Equal("route-value", model.RouteDifferentValue); Assert.Null(model.PropertyWithNoValue); }
public LegacyTemplateNameSourceTest() { _metadataProvider = new TestModelMetadataProvider(); _templateNameSource = new LegacyTemplateNameSource(new LegacyTypeExplorer()); }
public async Task ProcessAsync_GeneratesExpectedOutput() { // Arrange var expectedTagName = "not-form"; var metadataProvider = new TestModelMetadataProvider(); var tagHelperContext = new TagHelperContext( allAttributes: new TagHelperAttributeList { { "id", "myform" }, { "asp-route-name", "value" }, { "asp-action", "index" }, { "asp-controller", "home" }, { "method", "post" }, { "asp-antiforgery", true } }, items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( expectedTagName, attributes: new TagHelperAttributeList { { "id", "myform" }, }, getChildContentAsync: (useCachedResult, encoder) => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something Else"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); output.PostContent.SetContent("Something"); var urlHelper = new Mock <IUrlHelper>(); urlHelper .Setup(mock => mock.Action(It.IsAny <UrlActionContext>())).Returns("home/index"); var htmlGenerator = new TestableHtmlGenerator(metadataProvider, urlHelper.Object); var viewContext = TestableHtmlGenerator.GetViewContext( model: null, htmlGenerator: htmlGenerator, metadataProvider: metadataProvider); var expectedPostContent = "Something" + HtmlContentUtilities.HtmlContentToString( htmlGenerator.GenerateAntiforgery(viewContext), HtmlEncoder.Default); var formTagHelper = new FormTagHelper(htmlGenerator) { Action = "index", Antiforgery = true, Controller = "home", ViewContext = viewContext, RouteValues = { { "name", "value" }, }, }; // Act await formTagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal(3, output.Attributes.Count); var attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("id")); Assert.Equal("myform", attribute.Value); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("method")); Assert.Equal("post", attribute.Value); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("action")); Assert.Equal("home/index", attribute.Value); Assert.Empty(output.PreContent.GetContent()); Assert.True(output.Content.GetContent().Length == 0); Assert.Equal(expectedPostContent, output.PostContent.GetContent()); Assert.Equal(expectedTagName, output.TagName); }
public async Task ProcessAsync_GeneratesExpectedOutput( object model, Type containerType, Func <object> modelAccessor, NameAndId nameAndId, string ignored) { // Arrange var originalAttributes = new TagHelperAttributeList { { "class", "form-control" }, }; var originalPostContent = "original content"; var expectedAttributes = new TagHelperAttributeList(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 ReadOnlyTagHelperAttributeList <IReadOnlyTagHelperAttribute>( Enumerable.Empty <IReadOnlyTagHelperAttribute>()), 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(htmlGenerator) { For = modelExpression, 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 async Task ProcessAsyncInTemplate_WithItems_GeneratesExpectedOutput_DoesNotChangeSelectList( object model, Type containerType, Func <object> modelAccessor, NameAndId nameAndId, string expectedOptions) { // Arrange var originalAttributes = new TagHelperAttributeList { { "class", "form-control" }, }; var originalPostContent = "original content"; var expectedAttributes = new TagHelperAttributeList(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 ReadOnlyTagHelperAttributeList <IReadOnlyTagHelperAttribute>( Enumerable.Empty <IReadOnlyTagHelperAttribute>()), 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(htmlGenerator) { For = modelExpression, 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() { // Arrange var expectedTagName = "not-a"; var metadataProvider = new TestModelMetadataProvider(); var tagHelperContext = new TagHelperContext( allAttributes: new TagHelperAttributeList { { "id", "myanchor" }, { "asp-route-name", "value" }, { "asp-action", "index" }, { "asp-controller", "home" }, { "asp-fragment", "hello=world" }, { "asp-host", "contoso.com" }, { "asp-protocol", "http" } }, items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( expectedTagName, attributes: new TagHelperAttributeList { { "id", "myanchor" }, }, getChildContentAsync: useCachedResult => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something Else"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); output.Content.SetContent("Something"); var urlHelper = new Mock <IUrlHelper>(); urlHelper .Setup(mock => mock.Action(It.IsAny <UrlActionContext>())).Returns("home/index"); var htmlGenerator = new TestableHtmlGenerator(metadataProvider, urlHelper.Object); var viewContext = TestableHtmlGenerator.GetViewContext(model: null, htmlGenerator: htmlGenerator, metadataProvider: metadataProvider); var anchorTagHelper = new AnchorTagHelper(htmlGenerator) { Action = "index", Controller = "home", Fragment = "hello=world", Host = "contoso.com", Protocol = "http", RouteValues = { { "name", "value" }, }, ViewContext = viewContext, }; // Act await anchorTagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal(2, output.Attributes.Count); var attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("id")); Assert.Equal("myanchor", attribute.Value); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("href")); Assert.Equal("home/index", attribute.Value); Assert.Equal("Something", output.Content.GetContent()); Assert.Equal(expectedTagName, output.TagName); }
public async void BindTheXmlBodyToTheParameterValue(XmlSerializerType xmlSerializerType, bool useXmlBinderOnly) { // Arrange byte[] bodyRequestContext = new byte[0]; var value = new PurchaseOrder(); var xmlWriterSettings = FormattingUtilities.GetDefaultXmlWriterSettings(); xmlWriterSettings.CloseOutput = false; var textw = new StringWriter(); var writer = XmlWriter.Create(textw, xmlWriterSettings); if (xmlSerializerType == XmlSerializerType.XmlSeriralizer) { var xmlSerializer = new XmlSerializer(value.GetType()); xmlSerializer.Serialize(writer, value); bodyRequestContext = Encoding.UTF8.GetBytes(textw.ToString()); } else { var xmlSerializer = new DataContractSerializer(value.GetType()); xmlSerializer.WriteObject(writer, value); writer.Flush(); bodyRequestContext = Encoding.UTF8.GetBytes(textw.ToString()); } var att = new FromXmlBodyAttribute() { XmlSerializerType = xmlSerializerType, UseXmlBinderOnly = useXmlBinderOnly }; var attList = new List <object>() { att }; var bindingInfo = BindingInfo.GetBindingInfo(attList); var parameterDescriptor = new ParameterDescriptor { Name = "value", ParameterType = typeof(PurchaseOrder), BindingInfo = bindingInfo }; var actionDescriptor = new ActionDescriptor() { Parameters = new List <ParameterDescriptor>() { parameterDescriptor } }; var actionContext = GetActionContext(actionDescriptor); actionContext.HttpContext.Request.Body.Write(bodyRequestContext, 0, bodyRequestContext.Length); actionContext.HttpContext.Request.Body.Seek(0, SeekOrigin.Begin); ServiceCollection services = CreateServices(); var servicesProvider = services.BuildServiceProvider(); actionContext.HttpContext.RequestServices = servicesProvider; var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForType(parameterDescriptor.ParameterType).BindingDetails ( (b) => { b.BindingSource = BindingSource.Body; b.BinderType = att.BinderType; } ); ModelMetadata parameterModelMetadata = metadataProvider.GetMetadataForType(parameterDescriptor.ParameterType); var original = CreateDefaultValueProvider(); //*1 ModelBindingContext modelBindingContext = DefaultModelBindingContext.CreateBindingContext( actionContext, original, parameterModelMetadata, parameterDescriptor.BindingInfo, "model"); //*2 ModelBinderProviderContext modelBinderProviderContext = new TestModelBinderProviderContext(parameterModelMetadata, parameterDescriptor.BindingInfo, metadataProvider); BinderTypeModelBinderProvider binderTypeModelBinderProvider = new BinderTypeModelBinderProvider(); // Act var binderforType = binderTypeModelBinderProvider.GetBinder(modelBinderProviderContext); // Assert Assert.NotNull(binderforType); await binderforType.BindModelAsync(modelBindingContext); var newValue = modelBindingContext.Result.Model as PurchaseOrder; Assert.NotNull(newValue); Assert.Equal(value.billTo.street, newValue.billTo.street); Assert.Equal(value.shipTo.street, newValue.shipTo.street); }
public async Task ProcessAsync_AspFragmentAddsFragmentToAction() { // Arrange var expectedTagName = "form"; var metadataProvider = new TestModelMetadataProvider(); var tagHelperContext = new TagHelperContext( tagName: "form", allAttributes: new TagHelperAttributeList { { "id", "myform" }, { "asp-route-name", "value" }, { "asp-action", "index" }, { "asp-controller", "home" }, { "asp-fragment", "test" }, { "method", "post" }, { "asp-antiforgery", true } }, items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( expectedTagName, attributes: new TagHelperAttributeList { { "id", "myform" }, }, getChildContentAsync: (useCachedResult, encoder) => { var tagHelperContent = new DefaultTagHelperContent(); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); var urlHelper = new Mock <IUrlHelper>(); urlHelper .Setup(mock => mock.Action(It.IsAny <UrlActionContext>())).Returns("home/index"); var htmlGenerator = new TestableHtmlGenerator(metadataProvider, urlHelper.Object); var viewContext = TestableHtmlGenerator.GetViewContext( model: null, htmlGenerator: htmlGenerator, metadataProvider: metadataProvider); var formTagHelper = new FormTagHelper(htmlGenerator) { Action = "index", Antiforgery = true, Controller = "home", Fragment = "test", ViewContext = viewContext, RouteValues = { { "name", "value" }, }, }; // Act await formTagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal("form", output.TagName); Assert.Equal(TagMode.StartTagAndEndTag, output.TagMode); var attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("action")); Assert.Equal("home/index#test", attribute.Value); }
public async Task ProcessAsync_GeneratesExpectedOutput_WithModelErrorForIEnumerable() { // Arrange var expectedError = "Something went wrong."; var expectedTagName = "not-div"; var expectedAttributes = new TagHelperAttributeList { new TagHelperAttribute("class", "form-control validation-summary-errors"), new TagHelperAttribute("data-valmsg-summary", "true"), }; var metadataProvider = new TestModelMetadataProvider(); var htmlGenerator = new TestableHtmlGenerator(metadataProvider); var validationSummaryTagHelper = new ValidationSummaryTagHelper(htmlGenerator) { ValidationSummary = ValidationSummary.All, }; var expectedPreContent = "original pre-content"; var expectedContent = "original content"; var tagHelperContext = new TagHelperContext( tagName: "not-div", allAttributes: new TagHelperAttributeList(), items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( expectedTagName, attributes: new TagHelperAttributeList { { "class", "form-control" } }, getChildContentAsync: (useCachedResult, encoder) => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); output.PreContent.SetContent(expectedPreContent); output.Content.SetContent(expectedContent); output.PostContent.SetContent("Custom Content"); var model = new FormMetadata(); var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider); validationSummaryTagHelper.ViewContext = viewContext; viewContext.ModelState.AddModelError(key: nameof(FormMetadata.ID), errorMessage: expectedError); // Act await validationSummaryTagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal(expectedAttributes, output.Attributes, CaseSensitiveTagHelperAttributeComparer.Default); Assert.Equal(expectedPreContent, output.PreContent.GetContent()); Assert.Equal(expectedContent, output.Content.GetContent()); Assert.Equal( $"Custom Content<ul><li>{expectedError}</li>{Environment.NewLine}</ul>", output.PostContent.GetContent()); Assert.Equal(expectedTagName, output.TagName); }
public async Task ProcessAsync_WithItems_AndNoModelExpression_GeneratesExpectedOutput() { // Arrange var originalAttributes = new TagHelperAttributeList { { "class", "form-control" }, }; var originalPostContent = "original content"; var expectedAttributes = new TagHelperAttributeList(originalAttributes); var selectItems = new SelectList(Enumerable.Range(0, 5)); var expectedOptions = "<option>HtmlEncode[[0]]</option>" + Environment.NewLine + "<option>HtmlEncode[[1]]</option>" + Environment.NewLine + "<option>HtmlEncode[[2]]</option>" + Environment.NewLine + "<option>HtmlEncode[[3]]</option>" + Environment.NewLine + "<option>HtmlEncode[[4]]</option>" + Environment.NewLine; var expectedPreContent = "original pre-content"; var expectedContent = "original content"; var expectedPostContent = originalPostContent + expectedOptions; var expectedTagName = "select"; var tagHelperContext = new TagHelperContext( tagName: "select", allAttributes: new TagHelperAttributeList( Enumerable.Empty <TagHelperAttribute>()), items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( expectedTagName, originalAttributes, getChildContentAsync: (useCachedResult, encoder) => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.AppendHtml("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }) { TagMode = TagMode.SelfClosing, }; output.PreContent.AppendHtml(expectedPreContent); output.Content.AppendHtml(expectedContent); output.PostContent.AppendHtml(originalPostContent); var metadataProvider = new TestModelMetadataProvider(); var htmlGenerator = new TestableHtmlGenerator(metadataProvider); var viewContext = TestableHtmlGenerator.GetViewContext( model: null, htmlGenerator: htmlGenerator, metadataProvider: metadataProvider); var tagHelper = new SelectTagHelper(htmlGenerator) { Items = selectItems, ViewContext = viewContext, }; // Act tagHelper.Init(tagHelperContext); await tagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal(TagMode.SelfClosing, output.TagMode); Assert.Equal(expectedAttributes, output.Attributes); Assert.Equal(expectedPreContent, output.PreContent.GetContent()); Assert.Equal(expectedContent, output.Content.GetContent()); Assert.Equal(expectedPostContent, HtmlContentUtilities.HtmlContentToString(output.PostContent)); Assert.Equal(expectedTagName, output.TagName); var kvp = Assert.Single(tagHelperContext.Items); Assert.Equal(typeof(SelectTagHelper), kvp.Key); Assert.Null(kvp.Value); }
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), NullLoggerFactory.Instance), new ComplexTypeModelBinder(new Dictionary <ModelMetadata, IModelBinder>() { { valueMetadata.Properties["Id"], new SimpleTypeModelBinder(typeof(int), NullLoggerFactory.Instance) }, { valueMetadata.Properties["Name"], new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance) }, }, NullLoggerFactory.Instance), NullLoggerFactory.Instance); // 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 async Task ProcessAsync_WithItems_GeneratesExpectedOutput_DoesNotChangeSelectList( object model, Type containerType, Func <object> modelAccessor, NameAndId nameAndId, string expectedOptions) { // Arrange var originalAttributes = new TagHelperAttributeList { { "class", "form-control" }, }; var originalPostContent = "original content"; var expectedAttributes = new TagHelperAttributeList(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(nameAndId.Name, modelExplorer); var tagHelperContext = new TagHelperContext( tagName: "select", allAttributes: new TagHelperAttributeList( Enumerable.Empty <TagHelperAttribute>()), items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( expectedTagName, originalAttributes, getChildContentAsync: (useCachedResult, encoder) => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.AppendHtml("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }) { TagMode = TagMode.SelfClosing, }; output.PreContent.AppendHtml(expectedPreContent); output.Content.AppendHtml(expectedContent); output.PostContent.AppendHtml(originalPostContent); var htmlGenerator = new TestableHtmlGenerator(metadataProvider) { ValidationAttributes = { { "valid", "from validation attributes" }, } }; var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider); 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(htmlGenerator) { For = modelExpression, Items = items, ViewContext = viewContext, }; // Act tagHelper.Init(tagHelperContext); await tagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal(TagMode.SelfClosing, output.TagMode); Assert.Equal(expectedAttributes, output.Attributes); Assert.Equal(expectedPreContent, output.PreContent.GetContent()); Assert.Equal(expectedContent, output.Content.GetContent()); Assert.Equal(expectedPostContent, HtmlContentUtilities.HtmlContentToString(output.PostContent)); Assert.Equal(expectedTagName, output.TagName); Assert.Single( tagHelperContext.Items, entry => (Type)entry.Key == typeof(SelectTagHelper)); 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, 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 ProcessAsync_CallsGenerateTextBox_AddsExpectedAttributes( string dataTypeName, string expectedFormat, string expectedType) { // Arrange var expectedAttributes = new TagHelperAttributeList { { "type", expectedType }, // Calculated; not passed to HtmlGenerator. }; var expectedTagName = "not-input"; var context = new TagHelperContext( allAttributes: new TagHelperAttributeList( Enumerable.Empty <TagHelperAttribute>()), items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( expectedTagName, attributes: new TagHelperAttributeList(), getChildContentAsync: (useCachedResult, encoder) => Task.FromResult <TagHelperContent>( new DefaultTagHelperContent())) { TagMode = TagMode.SelfClosing, }; var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForProperty <Model>("Text").DisplayDetails(dd => dd.DataTypeName = dataTypeName); var htmlGenerator = new Mock <IHtmlGenerator>(MockBehavior.Strict); var tagHelper = GetTagHelper( htmlGenerator.Object, model: null, propertyName: nameof(Model.Text), metadataProvider: metadataProvider); var tagBuilder = new TagBuilder("input"); var htmlAttributes = new Dictionary <string, object> { { "type", expectedType } }; if (string.Equals(dataTypeName, TemplateRenderer.IEnumerableOfIFormFileName)) { htmlAttributes["multiple"] = "multiple"; } htmlGenerator .Setup(mock => mock.GenerateTextBox( tagHelper.ViewContext, tagHelper.For.ModelExplorer, tagHelper.For.Name, null, // value expectedFormat, htmlAttributes)) // htmlAttributes .Returns(tagBuilder) .Verifiable(); // Act await tagHelper.ProcessAsync(context, output); // Assert htmlGenerator.Verify(); Assert.Equal(TagMode.SelfClosing, output.TagMode); Assert.Equal(expectedAttributes, output.Attributes); Assert.Empty(output.PreContent.GetContent()); Assert.Equal(string.Empty, output.Content.GetContent()); Assert.Empty(output.PostContent.GetContent()); Assert.Equal(expectedTagName, output.TagName); }
public async Task ModelBinderFactory_BindsPropertyWithoutSupportsGet_WhenRequestIsNotGet() { // Arrange var type = typeof(PageModelWithSupportsGetProperty).GetTypeInfo(); var actionDescriptor = new CompiledPageActionDescriptor { BoundProperties = new[] { new PageBoundPropertyDescriptor() { Name = nameof(PageModelWithSupportsGetProperty.SupportsGet), ParameterType = typeof(string), Property = type.GetProperty(nameof(PageModelWithSupportsGetProperty.SupportsGet)), BindingInfo = new BindingInfo() { RequestPredicate = ((IRequestPredicateProvider) new BindPropertyAttribute() { SupportsGet = true }).RequestPredicate, } }, new PageBoundPropertyDescriptor() { Name = nameof(PageModelWithSupportsGetProperty.Default), ParameterType = typeof(string), Property = type.GetProperty(nameof(PageModelWithSupportsGetProperty.Default)), }, }, HandlerTypeInfo = type, PageTypeInfo = typeof(PageWithProperty).GetTypeInfo(), ModelTypeInfo = type, }; var binder = new TestParameterBinder(new Dictionary <string, object>() { { "SupportsGet", "value" }, { "Default", "value" }, }); var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(); var factory = PagePropertyBinderFactory.CreateBinder(binder, modelMetadataProvider, actionDescriptor); var page = new PageWithProperty { PageContext = new PageContext() { HttpContext = new DefaultHttpContext(), } }; page.HttpContext.Request.Method = "Post"; var model = new PageModelWithSupportsGetProperty(); // Act await factory(page.PageContext, model); // Assert Assert.Equal("value", model.SupportsGet); Assert.Equal("value", model.Default); }
public async Task BindParameter_NonConvertibleValue_GetsCustomErrorMessage() { // Arrange var parameterType = typeof(int); var metadataProvider = new TestModelMetadataProvider(); metadataProvider .ForType(parameterType) .BindingDetails(binding => { // A real details provider could customize message based on BindingMetadataProviderContext. binding.ModelBindingMessageProvider.SetNonPropertyAttemptedValueIsInvalidAccessor( (value) => $"Hmm, '{ value }' is not a valid value."); }); var testContext = ModelBindingTestHelper.GetTestContext( request => { request.QueryString = QueryString.Create("Parameter1", "abcd"); }, metadataProvider: metadataProvider); var modelState = testContext.ModelState; var parameterBinder = ModelBindingTestHelper.GetParameterBinder(testContext.HttpContext.RequestServices); var parameter = new ParameterDescriptor() { Name = "Parameter1", BindingInfo = new BindingInfo(), ParameterType = parameterType }; // Act var modelBindingResult = await parameterBinder.BindModelAsync(parameter, testContext); // Assert // ModelBindingResult Assert.False(modelBindingResult.IsModelSet); // Model Assert.Null(modelBindingResult.Model); // ModelState Assert.False(modelState.IsValid); Assert.Single(modelState); Assert.Equal(1, modelState.ErrorCount); var key = Assert.Single(modelState.Keys); Assert.Equal("Parameter1", key); var entry = modelState[key]; Assert.Equal("abcd", entry.RawValue); Assert.Equal("abcd", entry.AttemptedValue); Assert.Equal(ModelValidationState.Invalid, entry.ValidationState); var error = Assert.Single(entry.Errors); Assert.Null(error.Exception); Assert.Equal($"Hmm, 'abcd' is not a valid value.", error.ErrorMessage); }
public async Task ProcessAsync_GeneratesExpectedOutput_WithDisplayName( string displayName, string originalChildContent, string htmlFieldPrefix, string expectedContent, string expectedId) { // Arrange var expectedAttributes = new TagHelperAttributeList { { "for", expectedId } }; var name = nameof(NestedModel.Text); var metadataProvider = new TestModelMetadataProvider(); metadataProvider .ForProperty <NestedModel>(name) .DisplayDetails(metadata => metadata.DisplayName = () => displayName); var htmlGenerator = new TestableHtmlGenerator(metadataProvider); var viewContext = TestableHtmlGenerator.GetViewContext( model: null, htmlGenerator: htmlGenerator, metadataProvider: metadataProvider); var viewData = new ViewDataDictionary <NestedModel>(metadataProvider, viewContext.ModelState); viewData.TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix; viewContext.ViewData = viewData; var containerExplorer = metadataProvider.GetModelExplorerForType(typeof(NestedModel), model: null); var modelExplorer = containerExplorer.GetExplorerForProperty(name); var modelExpression = new ModelExpression(name, modelExplorer); var tagHelper = new LabelTagHelper(htmlGenerator) { For = modelExpression, ViewContext = viewContext, }; var tagHelperContext = new TagHelperContext( tagName: "label", allAttributes: new TagHelperAttributeList(), items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( "label", new TagHelperAttributeList(), getChildContentAsync: (useCachedResult, encoder) => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.AppendHtml(originalChildContent); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); // Act await tagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal(expectedAttributes, output.Attributes); Assert.Equal(expectedContent, HtmlContentUtilities.HtmlContentToString(output.Content)); }
public TemplateNameSourceTests() { _typeExplorer = new Mock <ITypeExplorer>(MockBehavior.Strict); _nameSource = new TemplateNameSource(_typeExplorer.Object); _metadataProvider = new TestModelMetadataProvider(); }
public async Task ProcessAsync_GeneratesExpectedOutput_WithModelError(ValidationSummary validationSummary) { // Arrange var expectedError = "I am an error."; var expectedTagName = "not-div"; var metadataProvider = new TestModelMetadataProvider(); var htmlGenerator = new TestableHtmlGenerator(metadataProvider); var validationSummaryTagHelper = new ValidationSummaryTagHelper(htmlGenerator) { ValidationSummary = validationSummary, }; var expectedPreContent = "original pre-content"; var expectedContent = "original content"; var tagHelperContext = new TagHelperContext( tagName: "not-div", allAttributes: new TagHelperAttributeList(), items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( expectedTagName, attributes: new TagHelperAttributeList { { "class", "form-control" } }, getChildContentAsync: (useCachedResult, encoder) => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); output.PreContent.SetContent(expectedPreContent); output.Content.SetContent(expectedContent); output.PostContent.SetContent("Custom Content"); var model = new Model(); var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider); validationSummaryTagHelper.ViewContext = viewContext; var modelState = viewContext.ModelState; SetValidModelState(modelState); modelState.AddModelError(string.Empty, expectedError); // Act await validationSummaryTagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.InRange(output.Attributes.Count, low: 1, high: 2); var attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("class")); Assert.Equal( new TagHelperAttribute("class", "form-control validation-summary-errors"), attribute, CaseSensitiveTagHelperAttributeComparer.Default); Assert.Equal(expectedPreContent, output.PreContent.GetContent()); Assert.Equal(expectedContent, output.Content.GetContent()); Assert.Equal( $"Custom Content<ul><li>{expectedError}</li>{Environment.NewLine}</ul>", output.PostContent.GetContent()); Assert.Equal(expectedTagName, output.TagName); }
public async Task ProcessAsync_GeneratesExpectedOutput() { // Arrange var expectedTagName = "not-span"; var metadataProvider = new TestModelMetadataProvider(); var modelExpression = CreateModelExpression("Name"); var htmlGenerator = new TestableHtmlGenerator(metadataProvider); var validationMessageTagHelper = new ValidationMessageTagHelper(htmlGenerator) { For = modelExpression }; var expectedPreContent = "original pre-content"; var expectedContent = "original content"; var expectedPostContent = "original post-content"; var tagHelperContext = new TagHelperContext( tagName: "not-span", allAttributes: new TagHelperAttributeList { { "id", "myvalidationmessage" }, { "for", modelExpression }, }, items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( expectedTagName, attributes: new TagHelperAttributeList { { "id", "myvalidationmessage" } }, getChildContentAsync: (useCachedResult, encoder) => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); output.PreContent.SetContent(expectedPreContent); output.Content.SetContent(expectedContent); output.PostContent.SetContent(expectedPostContent); var viewContext = TestableHtmlGenerator.GetViewContext( model: null, htmlGenerator: htmlGenerator, metadataProvider: metadataProvider); validationMessageTagHelper.ViewContext = viewContext; // Act await validationMessageTagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal(4, output.Attributes.Count); var attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("id")); Assert.Equal("myvalidationmessage", attribute.Value); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("class")); Assert.Equal("field-validation-valid", attribute.Value); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("data-valmsg-for")); Assert.Equal("Name", attribute.Value); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("data-valmsg-replace")); Assert.Equal("true", attribute.Value); Assert.Equal(expectedPreContent, output.PreContent.GetContent()); Assert.Equal(expectedContent, output.Content.GetContent()); Assert.Equal(expectedPostContent, output.PostContent.GetContent()); Assert.Equal(expectedTagName, output.TagName); }
public void CreateBinder_Caches_NonRootNodes_FixesUpPlaceholderBinder() { // Arrange var metadataProvider = new TestModelMetadataProvider(); var options = Options.Create(new MvcOptions()); IModelBinder inner = null; IModelBinder innerInner = 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); innerInner = c.CreateBinder(c.Metadata); 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, }; // 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.NotSame(inner, innerInner); var placeholder = Assert.IsType <PlaceholderBinder>(innerInner); Assert.IsType <NoOpBinder>(placeholder.Inner); Assert.Equal(1, widgetProvider.SuccessCount); Assert.Equal(0, widgetIdProvider.SuccessCount); }
public async Task BindModelAsync_WithBindPageProperty_EnforcesBindRequired(int?input, bool isValid) { // Arrange var propertyInfo = typeof(TestPage).GetProperty(nameof(TestPage.BindRequiredProperty)); var propertyDescriptor = new PageBoundPropertyDescriptor { BindingInfo = BindingInfo.GetBindingInfo(new[] { new FromQueryAttribute { Name = propertyInfo.Name }, }), Name = propertyInfo.Name, ParameterType = propertyInfo.PropertyType, Property = propertyInfo, }; var typeInfo = typeof(TestPage).GetTypeInfo(); var actionDescriptor = new CompiledPageActionDescriptor { BoundProperties = new[] { propertyDescriptor }, HandlerTypeInfo = typeInfo, ModelTypeInfo = typeInfo, PageTypeInfo = typeInfo, }; var testContext = ModelBindingTestHelper.GetTestContext(request => { request.Method = "POST"; if (input.HasValue) { request.QueryString = new QueryString($"?{propertyDescriptor.Name}={input.Value}"); } }); var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(); var parameterBinder = ModelBindingTestHelper.GetParameterBinder(modelMetadataProvider); var modelBinderFactory = ModelBindingTestHelper.GetModelBinderFactory(modelMetadataProvider); var modelMetadata = modelMetadataProvider .GetMetadataForProperty(typeof(TestPage), propertyDescriptor.Name); var pageBinder = PageBinderFactory.CreatePropertyBinder( parameterBinder, modelMetadataProvider, modelBinderFactory, actionDescriptor); var pageContext = new PageContext { ActionDescriptor = actionDescriptor, HttpContext = testContext.HttpContext, RouteData = testContext.RouteData, ValueProviderFactories = testContext.ValueProviderFactories, }; var page = new TestPage(); // Act await pageBinder(pageContext, page); // Assert Assert.Equal(isValid, pageContext.ModelState.IsValid); if (isValid) { Assert.Equal(input.Value, page.BindRequiredProperty); } }
public async Task ProcessAsync_CallsGenerateTextBox_WithExpectedParameters( string dataTypeName, string inputTypeName, string model) { // Arrange var contextAttributes = new TagHelperAttributeList { { "class", "form-control" }, }; if (!string.IsNullOrEmpty(inputTypeName)) { contextAttributes["type"] = inputTypeName; // Support restoration of type attribute, if any. } var expectedAttributes = new TagHelperAttributeList { { "class", "form-control text-control" }, { "type", inputTypeName ?? "text" }, // Generator restores type attribute; adds "text" if none. }; var expectedPreContent = "original pre-content"; var expectedContent = "original content"; var expectedPostContent = "original post-content"; var expectedTagName = "not-input"; var context = new TagHelperContext( allAttributes: contextAttributes, items: new Dictionary <object, object>(), uniqueId: "test"); var originalAttributes = new TagHelperAttributeList { { "class", "form-control" }, }; var output = new TagHelperOutput( expectedTagName, originalAttributes, getChildContentAsync: useCachedResult => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }) { TagMode = TagMode.StartTagOnly, }; output.PreContent.SetContent(expectedPreContent); output.Content.SetContent(expectedContent); output.PostContent.SetContent(expectedPostContent); var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForProperty <Model>("Text").DisplayDetails(dd => dd.DataTypeName = dataTypeName); var htmlGenerator = new Mock <IHtmlGenerator>(MockBehavior.Strict); var tagHelper = GetTagHelper( htmlGenerator.Object, model, nameof(Model.Text), metadataProvider: metadataProvider); tagHelper.InputTypeName = inputTypeName; var tagBuilder = new TagBuilder("input") { Attributes = { { "class", "text-control" }, }, }; htmlGenerator .Setup(mock => mock.GenerateTextBox( tagHelper.ViewContext, tagHelper.For.ModelExplorer, tagHelper.For.Name, model, // value null, // format It.Is <Dictionary <string, object> >(m => m.ContainsKey("type")))) // htmlAttributes .Returns(tagBuilder) .Verifiable(); // Act await tagHelper.ProcessAsync(context, output); // Assert htmlGenerator.Verify(); Assert.Equal(TagMode.StartTagOnly, output.TagMode); 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); }
public async Task ProcessAsync_GeneratesExpectedOutput_WithPropertyErrors() { // Arrange var expectedError0 = "I am an error."; var expectedError2 = "I am also an error."; var expectedTagName = "not-div"; var metadataProvider = new TestModelMetadataProvider(); var htmlGenerator = new TestableHtmlGenerator(metadataProvider); var validationSummaryTagHelper = new ValidationSummaryTagHelper(htmlGenerator) { ValidationSummary = ValidationSummary.All, }; var expectedPreContent = "original pre-content"; var expectedContent = "original content"; var tagHelperContext = new TagHelperContext( allAttributes: new TagHelperAttributeList( Enumerable.Empty <TagHelperAttribute>()), items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( expectedTagName, attributes: new TagHelperAttributeList { { "class", "form-control" } }, getChildContentAsync: (useCachedResult, encoder) => { var tagHelperContent = new DefaultTagHelperContent(); tagHelperContent.SetContent("Something"); return(Task.FromResult <TagHelperContent>(tagHelperContent)); }); output.PreContent.SetContent(expectedPreContent); output.Content.SetContent(expectedContent); output.PostContent.SetContent("Custom Content"); var model = new Model(); var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider); validationSummaryTagHelper.ViewContext = viewContext; var modelState = viewContext.ModelState; SetValidModelState(modelState); modelState.AddModelError(key: $"{nameof(Model.Strings)}[0]", errorMessage: expectedError0); modelState.AddModelError(key: $"{nameof(Model.Strings)}[2]", errorMessage: expectedError2); // Act await validationSummaryTagHelper.ProcessAsync(tagHelperContext, output); // Assert Assert.Equal(2, output.Attributes.Count); var attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("class")); Assert.Equal("form-control validation-summary-errors", attribute.Value); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("data-valmsg-summary")); Assert.Equal("true", attribute.Value); Assert.Equal(expectedPreContent, output.PreContent.GetContent()); Assert.Equal(expectedContent, output.Content.GetContent()); Assert.Equal( $"Custom Content<ul><li>{expectedError0}</li>{Environment.NewLine}" + $"<li>{expectedError2}</li>{Environment.NewLine}</ul>", output.PostContent.GetContent()); Assert.Equal(expectedTagName, output.TagName); }
public async Task ProcessAsync_CallsGenerateTextBox_AddsExpectedAttributesForRfc3339( string propertyName, Html5DateRenderingMode dateRenderingMode, string expectedFormat, string expectedType) { // Arrange var expectedAttributes = new TagHelperAttributeList { { "type", expectedType }, // Calculated; not passed to HtmlGenerator. }; var expectedTagName = "not-input"; var context = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList <IReadOnlyTagHelperAttribute>( Enumerable.Empty <IReadOnlyTagHelperAttribute>()), items: new Dictionary <object, object>(), uniqueId: "test"); var output = new TagHelperOutput( expectedTagName, attributes: new TagHelperAttributeList(), getChildContentAsync: (_) => Task.FromResult <TagHelperContent>(new DefaultTagHelperContent())) { TagMode = TagMode.SelfClosing, }; var htmlAttributes = new Dictionary <string, object> { { "type", expectedType } }; var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider(); var htmlGenerator = new Mock <IHtmlGenerator>(MockBehavior.Strict); var tagHelper = GetTagHelper( htmlGenerator.Object, model: null, propertyName: propertyName, metadataProvider: metadataProvider); tagHelper.ViewContext.Html5DateRenderingMode = dateRenderingMode; var tagBuilder = new TagBuilder("input"); htmlGenerator .Setup(mock => mock.GenerateTextBox( tagHelper.ViewContext, tagHelper.For.ModelExplorer, tagHelper.For.Name, null, // value expectedFormat, htmlAttributes)) // htmlAttributes .Returns(tagBuilder) .Verifiable(); // Act await tagHelper.ProcessAsync(context, output); // Assert htmlGenerator.Verify(); Assert.Equal(TagMode.SelfClosing, output.TagMode); Assert.Equal(expectedAttributes, output.Attributes); Assert.Empty(output.PreContent.GetContent()); Assert.Equal(string.Empty, output.Content.GetContent()); Assert.Empty(output.PostContent.GetContent()); Assert.Equal(expectedTagName, output.TagName); }
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); }