Esempio n. 1
0
        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);
        }
Esempio n. 2
0
        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);
        }
Esempio n. 5
0
        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);
        }
Esempio n. 6
0
        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;
        }
Esempio n. 7
0
        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
        }
Esempio n. 8
0
        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
        }
Esempio n. 9
0
        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
        }
Esempio n. 10
0
        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);
        }
Esempio n. 11
0
        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();
        }
Esempio n. 14
0
        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);
        }
Esempio n. 17
0
        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);
        }
Esempio n. 18
0
        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);
        }
Esempio n. 19
0
        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);
        }
Esempio n. 24
0
        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);
        }
Esempio n. 25
0
        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);
        }
Esempio n. 29
0
        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);
        }
Esempio n. 30
0
        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);
        }
Esempio n. 31
0
 public static HtmlHelper <TModel> GetHtmlHelper <TModel>(
     TModel model,
     ICompositeViewEngine viewEngine)
 {
     return(GetHtmlHelper(model, CreateUrlHelper(), viewEngine, TestModelMetadataProvider.CreateDefaultProvider()));
 }
Esempio n. 32
0
    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);
        }
Esempio n. 34
0
 public LegacyTemplateNameSourceTest()
 {
     _metadataProvider   = new TestModelMetadataProvider();
     _templateNameSource = new LegacyTemplateNameSource(new LegacyTypeExplorer());
 }
Esempio n. 35
0
        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);
        }
Esempio n. 36
0
        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);
        }
Esempio n. 37
0
        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));
        }
Esempio n. 38
0
        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);
        }
Esempio n. 40
0
    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);
    }
Esempio n. 41
0
    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);
    }
Esempio n. 42
0
        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);
        }
Esempio n. 43
0
        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));
        }
Esempio n. 44
0
        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));
        }
Esempio n. 45
0
        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);
        }
Esempio n. 46
0
        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);
        }
Esempio n. 48
0
    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);
    }
Esempio n. 49
0
        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();
 }
Esempio n. 51
0
        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);
        }
Esempio n. 53
0
    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);
    }
Esempio n. 54
0
        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);
            }
        }
Esempio n. 55
0
        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);
        }
Esempio n. 56
0
        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);
        }
Esempio n. 57
0
        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);
        }
Esempio n. 58
0
        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);
        }