Esempio n. 1
0
        public async Task ProcessAsync_Throws_IfMultipleInvalid(string multiple)
        {
            // Arrange
            var contextAttributes  = new Dictionary <string, object>();
            var originalAttributes = new Dictionary <string, string>();
            var content            = "original content";
            var expectedTagName    = "select";
            var expectedMessage    = "Cannot parse 'multiple' value '" + multiple +
                                     "' for <select>. Acceptable values are 'false', 'true' and 'multiple'.";

            var tagHelperContext = new TagHelperContext(contextAttributes);
            var output           = new TagHelperOutput(expectedTagName, originalAttributes, content);

            var    metadataProvider = new EmptyModelMetadataProvider();
            string model            = null;
            var    metadata         = metadataProvider.GetMetadataForType(() => model, typeof(string));
            var    modelExpression  = new ModelExpression("Property1", metadata);

            var tagHelper = new SelectTagHelper
            {
                For      = modelExpression,
                Multiple = multiple,
            };

            // Act & Assert
            var exception = await Assert.ThrowsAsync <InvalidOperationException>(
                () => tagHelper.ProcessAsync(tagHelperContext, output));

            Assert.Equal(expectedMessage, exception.Message);
        }
Esempio n. 2
0
        public async Task ProcessAsync_GeneratesExpectedOutput(
            object model,
            Type containerType,
            Func <object> modelAccessor,
            NameAndId nameAndId,
            string ignored)
        {
            // Arrange
            var originalAttributes = new Dictionary <string, string>
            {
                { "class", "form-control" },
            };
            var originalContent = "original content";
            var originalTagName = "not-select";

            var expectedAttributes = new Dictionary <string, string>(originalAttributes)
            {
                { "id", nameAndId.Id },
                { "name", nameAndId.Name },
                { "valid", "from validation attributes" },
            };
            var expectedContent = originalContent;
            var expectedTagName = "select";

            var metadataProvider = new DataAnnotationsModelMetadataProvider();

            // Property name is either nameof(Model.Text) or nameof(NestedModel.Text).
            var metadata        = metadataProvider.GetMetadataForProperty(modelAccessor, containerType, propertyName: "Text");
            var modelExpression = new ModelExpression(nameAndId.Name, metadata);

            var tagHelperContext = new TagHelperContext(new Dictionary <string, object>());
            var output           = new TagHelperOutput(originalTagName, originalAttributes, expectedContent)
            {
                SelfClosing = true,
            };

            var htmlGenerator = new TestableHtmlGenerator(metadataProvider)
            {
                ValidationAttributes =
                {
                    { "valid", "from validation attributes" },
                }
            };
            var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider);
            var tagHelper   = new SelectTagHelper
            {
                For         = modelExpression,
                Generator   = htmlGenerator,
                ViewContext = viewContext,
            };

            // Act
            await tagHelper.ProcessAsync(tagHelperContext, output);

            // Assert
            Assert.Equal(expectedAttributes, output.Attributes);
            Assert.Equal(expectedContent, output.Content);
            Assert.False(output.SelfClosing);
            Assert.Equal(expectedTagName, output.TagName);
        }
Esempio n. 3
0
        public async Task ProcessAsync_CallsGeneratorWithExpectedValues_ItemsAndMultiple(
            IEnumerable <SelectListItem> inputItems,
            string multiple,
            IEnumerable <SelectListItem> expectedItems,
            bool expectedAllowMultiple)
        {
            // Arrange
            var contextAttributes = new Dictionary <string, object>
            {
                // Attribute will be restored if value matches "multiple".
                { "multiple", multiple },
            };
            var originalAttributes = new Dictionary <string, string>();
            var content            = "original content";
            var propertyName       = "Property1";
            var tagName            = "not-select";

            var tagHelperContext = new TagHelperContext(contextAttributes);
            var output           = new TagHelperOutput(tagName, originalAttributes, content);

            // TODO: In real (model => model) scenario, ModelExpression should have name "" and
            // TemplateInfo.HtmlFieldPrefix should be "Property1" but empty ModelExpression name is not currently
            // supported, see #1408.
            var    metadataProvider = new EmptyModelMetadataProvider();
            string model            = null;
            var    metadata         = metadataProvider.GetMetadataForType(() => model, typeof(string));
            var    modelExpression  = new ModelExpression(propertyName, metadata);

            var htmlGenerator = new Mock <IHtmlGenerator>(MockBehavior.Strict);
            var viewContext   = TestableHtmlGenerator.GetViewContext(model, htmlGenerator.Object, metadataProvider);

            htmlGenerator
            .Setup(real => real.GenerateSelect(
                       viewContext,
                       metadata,
                       null,         // optionLabel
                       propertyName, // name
                       expectedItems,
                       expectedAllowMultiple,
                       null))     // htmlAttributes
            .Returns((TagBuilder)null)
            .Verifiable();

            var tagHelper = new SelectTagHelper
            {
                For         = modelExpression,
                Items       = inputItems,
                Generator   = htmlGenerator.Object,
                Multiple    = multiple,
                ViewContext = viewContext,
            };

            // Act
            await tagHelper.ProcessAsync(tagHelperContext, output);

            // Assert
            htmlGenerator.Verify();
        }
Esempio n. 4
0
        public async Task TagHelper_CallsGeneratorWithExpectedValues_RealModelType(
            Type modelType,
            object model,
            bool allowMultiple)
        {
            // Arrange
            var contextAttributes  = new Dictionary <string, object>();
            var originalAttributes = new Dictionary <string, string>();
            var propertyName       = "Property1";
            var tagName            = "select";

            var tagHelperContext = new TagHelperContext(
                contextAttributes,
                uniqueId: "test",
                getChildContentAsync: () => Task.FromResult("Something"));
            var output = new TagHelperOutput(tagName, originalAttributes);

            var metadataProvider = new EmptyModelMetadataProvider();
            var metadata         = metadataProvider.GetMetadataForType(() => model, modelType);
            var modelExpression  = new ModelExpression(propertyName, metadata);

            var htmlGenerator = new Mock <IHtmlGenerator>(MockBehavior.Strict);
            var viewContext   = TestableHtmlGenerator.GetViewContext(model, htmlGenerator.Object, metadataProvider);
            ICollection <string> selectedValues = new string[0];

            htmlGenerator
            .Setup(real => real.GenerateSelect(
                       viewContext,
                       metadata,
                       null,         // optionLabel
                       propertyName, // name
                       It.IsAny <IEnumerable <SelectListItem> >(),
                       allowMultiple,
                       null,      // htmlAttributes
                       out selectedValues))
            .Returns((TagBuilder)null)
            .Verifiable();

            var tagHelper = new SelectTagHelper
            {
                For         = modelExpression,
                Generator   = htmlGenerator.Object,
                ViewContext = viewContext,
            };

            // Act
            await tagHelper.ProcessAsync(tagHelperContext, output);

            // Assert
            htmlGenerator.Verify();

            Assert.NotNull(viewContext.FormContext?.FormData);
            var keyValuePair = Assert.Single(
                viewContext.FormContext.FormData,
                entry => entry.Key == SelectTagHelper.SelectedValuesFormDataKey);

            Assert.Same(selectedValues, keyValuePair.Value);
        }
Esempio n. 5
0
        public async Task ProcessAsync_RestoresMultiple_IfForNotBound(string attributeName)
        {
            // Arrange
            var contextAttributes = new Dictionary <string, object>
            {
                { attributeName, "I'm more than one" },
            };
            var originalAttributes = new Dictionary <string, string>
            {
                { "class", "form-control" },
                { "size", "2" },
            };
            var expectedAttributes = new Dictionary <string, string>(originalAttributes);

            expectedAttributes[attributeName] = (string)contextAttributes[attributeName];
            var expectedPreContent  = "original pre-content";
            var expectedContent     = "original content";
            var expectedPostContent = "original post-content";
            var expectedTagName     = "select";

            var tagHelperContext = new TagHelperContext(
                contextAttributes,
                uniqueId: "test",
                getChildContentAsync: () => Task.FromResult("Something"));
            var output = new TagHelperOutput(expectedTagName, originalAttributes)
            {
                PreContent  = expectedPreContent,
                Content     = expectedContent,
                PostContent = expectedPostContent,
                SelfClosing = true,
            };

            var tagHelper = new SelectTagHelper
            {
                Multiple = "I'm more than one",
            };

            // Act
            await tagHelper.ProcessAsync(tagHelperContext, output);

            // Assert
            Assert.Equal(expectedAttributes, output.Attributes);
            Assert.Equal(expectedPreContent, output.PreContent);
            Assert.Equal(expectedContent, output.Content);
            Assert.Equal(expectedPostContent, output.PostContent);
            Assert.True(output.SelfClosing);
            Assert.Equal(expectedTagName, output.TagName);
        }
Esempio n. 6
0
        public async Task TagHelper_CallsGeneratorWithExpectedValues_RealModelType(
            Type modelType,
            object model,
            bool allowMultiple)
        {
            // Arrange
            var contextAttributes  = new Dictionary <string, object>();
            var originalAttributes = new Dictionary <string, string>();
            var content            = "original content";
            var propertyName       = "Property1";
            var tagName            = "not-select";

            var tagHelperContext = new TagHelperContext(contextAttributes);
            var output           = new TagHelperOutput(tagName, originalAttributes, content);

            var metadataProvider = new EmptyModelMetadataProvider();
            var metadata         = metadataProvider.GetMetadataForType(() => model, modelType);
            var modelExpression  = new ModelExpression(propertyName, metadata);

            var htmlGenerator = new Mock <IHtmlGenerator>(MockBehavior.Strict);
            var viewContext   = TestableHtmlGenerator.GetViewContext(model, htmlGenerator.Object, metadataProvider);

            htmlGenerator
            .Setup(real => real.GenerateSelect(
                       viewContext,
                       metadata,
                       null,         // optionLabel
                       propertyName, // name
                       It.IsAny <IEnumerable <SelectListItem> >(),
                       allowMultiple,
                       null))     // htmlAttributes
            .Returns((TagBuilder)null)
            .Verifiable();

            var tagHelper = new SelectTagHelper
            {
                For         = modelExpression,
                Generator   = htmlGenerator.Object,
                ViewContext = viewContext,
            };

            // Act
            await tagHelper.ProcessAsync(tagHelperContext, output);

            // Assert
            htmlGenerator.Verify();
        }
Esempio n. 7
0
        public async Task ProcessAsync_Throws_IfForNotBoundButItemsIs()
        {
            // Arrange
            var contextAttributes  = new Dictionary <string, object>();
            var originalAttributes = new Dictionary <string, string>();
            var content            = "original content";
            var expectedTagName    = "select";
            var expectedMessage    = "Cannot determine body for <select>. 'asp-items' must be null if 'asp-for' is null.";

            var tagHelperContext = new TagHelperContext(contextAttributes);
            var output           = new TagHelperOutput(expectedTagName, originalAttributes, content);
            var tagHelper        = new SelectTagHelper
            {
                Items = Enumerable.Empty <SelectListItem>(),
            };

            // Act & Assert
            var exception = await Assert.ThrowsAsync <InvalidOperationException>(
                () => tagHelper.ProcessAsync(tagHelperContext, output));

            Assert.Equal(expectedMessage, exception.Message);
        }
Esempio n. 8
0
        public async Task ProcessAsync_RestoresMultiple_IfForNotBound(string attributeName)
        {
            // Arrange
            var contextAttributes = new Dictionary <string, object>
            {
                { attributeName, "I'm more than one" },
            };
            var originalAttributes = new Dictionary <string, string>
            {
                { "class", "form-control" },
                { "size", "2" },
            };
            var expectedAttributes = new Dictionary <string, string>(originalAttributes);

            expectedAttributes[attributeName] = (string)contextAttributes[attributeName];
            var expectedContent = "original content";
            var expectedTagName = "not-select";

            var tagHelperContext = new TagHelperContext(contextAttributes);
            var output           = new TagHelperOutput(expectedTagName, originalAttributes, expectedContent)
            {
                SelfClosing = true,
            };

            var tagHelper = new SelectTagHelper
            {
                Multiple = "I'm more than one",
            };

            // Act
            await tagHelper.ProcessAsync(tagHelperContext, output);

            // Assert
            Assert.Equal(expectedAttributes, output.Attributes);
            Assert.Equal(expectedContent, output.Content);
            Assert.True(output.SelfClosing);
            Assert.Equal(expectedTagName, output.TagName);
        }
Esempio n. 9
0
        public async Task ProcessAsync_CallsGeneratorWithExpectedValues_ItemsAndAttribute(
            IEnumerable <SelectListItem> inputItems,
            string attributeName,
            string attributeValue,
            IEnumerable <SelectListItem> expectedItems)
        {
            // Arrange
            var contextAttributes = new TagHelperAttributeList
            {
                // Provided for completeness. Select tag helper does not confirm AllAttributes set is consistent.
                { attributeName, attributeValue },
            };
            var originalAttributes = new TagHelperAttributeList
            {
                { attributeName, attributeValue },
            };
            var propertyName    = "Property1";
            var expectedTagName = "select";

            var tagHelperContext = new TagHelperContext(
                contextAttributes,
                items: new Dictionary <object, object>(),
                uniqueId: "test");

            var output = new TagHelperOutput(
                expectedTagName,
                originalAttributes,
                getChildContentAsync: useCachedResult =>
            {
                var tagHelperContent = new DefaultTagHelperContent();
                tagHelperContent.SetContent("Something");
                return(Task.FromResult <TagHelperContent>(tagHelperContent));
            });
            var    metadataProvider = new EmptyModelMetadataProvider();
            string model            = null;
            var    modelExplorer    = metadataProvider.GetModelExplorerForType(typeof(string), model);

            var htmlGenerator = new Mock <IHtmlGenerator>(MockBehavior.Strict);
            var viewContext   = TestableHtmlGenerator.GetViewContext(model, htmlGenerator.Object, metadataProvider);

            // Simulate a (model => model) scenario. E.g. the calling helper may appear in a low-level template.
            var modelExpression = new ModelExpression(string.Empty, modelExplorer);

            viewContext.ViewData.TemplateInfo.HtmlFieldPrefix = propertyName;

            var currentValues = new string[0];

            htmlGenerator
            .Setup(real => real.GetCurrentValues(
                       viewContext,
                       modelExplorer,
                       string.Empty, // expression
                       false))       // allowMultiple
            .Returns(currentValues)
            .Verifiable();
            htmlGenerator
            .Setup(real => real.GenerateSelect(
                       viewContext,
                       modelExplorer,
                       null,         // optionLabel
                       string.Empty, // expression
                       expectedItems,
                       currentValues,
                       false,       // allowMultiple
                       null))       // htmlAttributes
            .Returns((TagBuilder)null)
            .Verifiable();

            var tagHelper = new SelectTagHelper(htmlGenerator.Object)
            {
                For         = modelExpression,
                Items       = inputItems,
                ViewContext = viewContext,
            };

            // Act
            tagHelper.Init(tagHelperContext);
            await tagHelper.ProcessAsync(tagHelperContext, output);

            // Assert
            htmlGenerator.Verify();

            var keyValuePair = Assert.Single(
                tagHelperContext.Items,
                entry => (Type)entry.Key == typeof(SelectTagHelper));

            Assert.Same(currentValues, keyValuePair.Value);
        }
Esempio n. 10
0
        public async Task ProcessAsync_GeneratesExpectedOutput_WithItems(
            object model,
            Type containerType,
            Func <object> modelAccessor,
            NameAndId nameAndId,
            string expectedOptions)
        {
            // Arrange
            var originalAttributes = new Dictionary <string, string>
            {
                { "class", "form-control" },
            };
            var originalContent = "original content";

            var expectedAttributes = new Dictionary <string, string>(originalAttributes)
            {
                { "id", nameAndId.Id },
                { "name", nameAndId.Name },
                { "valid", "from validation attributes" },
            };
            var expectedContent = originalContent + expectedOptions;
            var expectedTagName = "select";

            var metadataProvider = new DataAnnotationsModelMetadataProvider();

            // Property name is either nameof(Model.Text) or nameof(NestedModel.Text).
            var metadata        = metadataProvider.GetMetadataForProperty(modelAccessor, containerType, propertyName: "Text");
            var modelExpression = new ModelExpression(nameAndId.Name, metadata);

            var tagHelperContext = new TagHelperContext(new Dictionary <string, object>());
            var output           = new TagHelperOutput(expectedTagName, originalAttributes, originalContent)
            {
                SelfClosing = true,
            };

            var items         = new SelectList(new[] { "", "outer text", "inner text", "other text" });
            var htmlGenerator = new TestableHtmlGenerator(metadataProvider)
            {
                ValidationAttributes =
                {
                    { "valid", "from validation attributes" },
                }
            };
            var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider);
            var tagHelper   = new SelectTagHelper
            {
                For         = modelExpression,
                Generator   = htmlGenerator,
                Items       = items,
                ViewContext = viewContext,
            };

            // Act
            await tagHelper.ProcessAsync(tagHelperContext, output);

            // Assert
            Assert.Equal(expectedAttributes, output.Attributes);
            Assert.Equal(expectedContent, output.Content);
            Assert.False(output.SelfClosing);
            Assert.Equal(expectedTagName, output.TagName);

            Assert.NotNull(viewContext.FormContext?.FormData);
            var keyValuePair = Assert.Single(
                viewContext.FormContext.FormData,
                entry => entry.Key == SelectTagHelper.SelectedValuesFormDataKey);

            Assert.NotNull(keyValuePair.Value);
            var selectedValues = Assert.IsAssignableFrom <ICollection <string> >(keyValuePair.Value);

            Assert.InRange(selectedValues.Count, 0, 1);
        }
Esempio n. 11
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");
            var output = new TagHelperOutput(
                expectedTagName,
                originalAttributes,
                getChildContentAsync: useCachedResult =>
                {
                    var tagHelperContent = new DefaultTagHelperContent();
                    tagHelperContent.SetContent("Something");
                    return Task.FromResult<TagHelperContent>(tagHelperContent);
                })
            {
                TagMode = TagMode.SelfClosing,
            };
            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
            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, output.PostContent.GetContent());
            Assert.Equal(expectedTagName, output.TagName);

            Assert.Single(
                tagHelperContext.Items,
                entry => (Type)entry.Key == typeof(SelectTagHelper));
        }
Esempio n. 12
0
        public async Task ProcessAsync_CallsGeneratorWithExpectedValues_ItemsAndAttribute(
            IEnumerable<SelectListItem> inputItems,
            string attributeName,
            string attributeValue,
            IEnumerable<SelectListItem> expectedItems)
        {
            // Arrange
            var contextAttributes = new Dictionary<string, object>
            {
                // Provided for completeness. Select tag helper does not confirm AllAttributes set is consistent.
                { attributeName, attributeValue },
            };
            var originalAttributes = new Dictionary<string, object>
            {
                { attributeName, attributeValue },
            };
            var propertyName = "Property1";
            var expectedTagName = "select";

            var tagHelperContext = new TagHelperContext(
                contextAttributes,
                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);
            var metadataProvider = new EmptyModelMetadataProvider();
            string model = null;
            var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(string), model);

            var htmlGenerator = new Mock<IHtmlGenerator>(MockBehavior.Strict);
            var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator.Object, metadataProvider);

            // Simulate a (model => model) scenario. E.g. the calling helper may appear in a low-level template.
            var modelExpression = new ModelExpression(string.Empty, modelExplorer);
            viewContext.ViewData.TemplateInfo.HtmlFieldPrefix = propertyName;

            var currentValues = new string[0];
            htmlGenerator
                .Setup(real => real.GetCurrentValues(
                    viewContext,
                    modelExplorer,
                    string.Empty,   // expression
                    false))         // allowMultiple
                .Returns(currentValues)
                .Verifiable();
            htmlGenerator
                .Setup(real => real.GenerateSelect(
                    viewContext,
                    modelExplorer,
                    null,           // optionLabel
                    string.Empty,   // expression
                    expectedItems,
                    currentValues,
                    false,          // allowMultiple
                    null))          // htmlAttributes
                .Returns((TagBuilder)null)
                .Verifiable();

            var tagHelper = new SelectTagHelper
            {
                For = modelExpression,
                Items = inputItems,
                Generator = htmlGenerator.Object,
                ViewContext = viewContext,
            };

            // Act
            await tagHelper.ProcessAsync(tagHelperContext, output);

            // Assert
            htmlGenerator.Verify();

            Assert.NotNull(viewContext.FormContext?.FormData);
            var keyValuePair = Assert.Single(
                viewContext.FormContext.FormData,
                entry => entry.Key == SelectTagHelper.SelectedValuesFormDataKey);
            Assert.Same(currentValues, keyValuePair.Value);
        }
Esempio n. 13
0
        public async Task ProcessAsync_GeneratesExpectedOutput(
            object model,
            Type containerType,
            Func<object> modelAccessor,
            NameAndId nameAndId,
            string ignored)
        {
            // Arrange
            var originalAttributes = new Dictionary<string, object>
            {
                { "class", "form-control" },
            };
            var originalPostContent = "original content";

            var expectedAttributes = new Dictionary<string, object>(originalAttributes)
            {
                { "id", nameAndId.Id },
                { "name", nameAndId.Name },
                { "valid", "from validation attributes" },
            };
            var expectedPreContent = "original pre-content";
            var expectedContent = "original content";
            var expectedPostContent = originalPostContent;
            var expectedTagName = "not-select";

            var metadataProvider = new TestModelMetadataProvider();
            var containerMetadata = metadataProvider.GetMetadataForType(containerType);
            var containerExplorer = metadataProvider.GetModelExplorerForType(containerType, model);

            var propertyMetadata = metadataProvider.GetMetadataForProperty(containerType, "Text");
            var modelExplorer = containerExplorer.GetExplorerForExpression(propertyMetadata, modelAccessor());

            var modelExpression = new ModelExpression(nameAndId.Name, modelExplorer);

            var tagHelperContext = new TagHelperContext(
                allAttributes: new Dictionary<string, object>(),
                items: new Dictionary<object, object>(),
                uniqueId: "test",
                getChildContentAsync: () =>
                {
                    var tagHelperContent = new DefaultTagHelperContent();
                    tagHelperContent.SetContent("Something");
                    return Task.FromResult<TagHelperContent>(tagHelperContent);
                });
            var output = new TagHelperOutput(expectedTagName, originalAttributes)
            {
                SelfClosing = true,
            };
            output.PreContent.SetContent(expectedPreContent);
            output.Content.SetContent(expectedContent);
            output.PostContent.SetContent(originalPostContent);

            var htmlGenerator = new TestableHtmlGenerator(metadataProvider)
            {
                ValidationAttributes =
                {
                    {  "valid", "from validation attributes" },
                }
            };
            var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider);
            var tagHelper = new SelectTagHelper
            {
                For = modelExpression,
                Generator = htmlGenerator,
                ViewContext = viewContext,
            };

            // Act
            await tagHelper.ProcessAsync(tagHelperContext, output);

            // Assert
            Assert.True(output.SelfClosing);
            Assert.Equal(expectedAttributes, output.Attributes);
            Assert.Equal(expectedPreContent, output.PreContent.GetContent());
            Assert.Equal(expectedContent, output.Content.GetContent());
            Assert.Equal(expectedPostContent, output.PostContent.GetContent());
            Assert.Equal(expectedTagName, output.TagName);

            Assert.NotNull(viewContext.FormContext?.FormData);
            Assert.Single(
                viewContext.FormContext.FormData,
                entry => entry.Key == SelectTagHelper.SelectedValuesFormDataKey);
        }
Esempio n. 14
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");
            var output = new TagHelperOutput(
                expectedTagName,
                originalAttributes,
                getChildContentAsync: useCachedResult =>
            {
                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);

            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
            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. 15
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");
            var output = new TagHelperOutput(
                expectedTagName,
                originalAttributes,
                getChildContentAsync: useCachedResult =>
            {
                var tagHelperContent = new DefaultTagHelperContent();
                tagHelperContent.SetContent("Something");
                return(Task.FromResult <TagHelperContent>(tagHelperContent));
            })
            {
                TagMode = TagMode.SelfClosing,
            };

            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
            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, output.PostContent.GetContent());
            Assert.Equal(expectedTagName, output.TagName);

            Assert.Single(
                tagHelperContext.Items,
                entry => (Type)entry.Key == typeof(SelectTagHelper));
        }
Esempio n. 16
0
        public async Task ProcessAsync_CallsGeneratorWithExpectedValues_ItemsAndMultiple(
            IEnumerable <SelectListItem> inputItems,
            string multiple,
            IEnumerable <SelectListItem> expectedItems,
            bool expectedAllowMultiple)
        {
            // Arrange
            var contextAttributes = new Dictionary <string, object>
            {
                // Attribute will be restored if value matches "multiple".
                { "multiple", multiple },
            };
            var originalAttributes = new Dictionary <string, string>();
            var propertyName       = "Property1";
            var expectedTagName    = "select";

            var tagHelperContext = new TagHelperContext(
                contextAttributes,
                uniqueId: "test",
                getChildContentAsync: () => Task.FromResult("Something"));
            var output = new TagHelperOutput(expectedTagName, originalAttributes);

            var    metadataProvider = new EmptyModelMetadataProvider();
            string model            = null;
            var    metadata         = metadataProvider.GetMetadataForType(() => model, typeof(string));

            var htmlGenerator = new Mock <IHtmlGenerator>(MockBehavior.Strict);
            var viewContext   = TestableHtmlGenerator.GetViewContext(model, htmlGenerator.Object, metadataProvider);

            // Simulate a (model => model) scenario. E.g. the calling helper may appear in a low-level template.
            var modelExpression = new ModelExpression(string.Empty, metadata);

            viewContext.ViewData.TemplateInfo.HtmlFieldPrefix = propertyName;

            ICollection <string> selectedValues = new string[0];

            htmlGenerator
            .Setup(real => real.GenerateSelect(
                       viewContext,
                       metadata,
                       null,         // optionLabel
                       string.Empty, // name
                       expectedItems,
                       expectedAllowMultiple,
                       null,      // htmlAttributes
                       out selectedValues))
            .Returns((TagBuilder)null)
            .Verifiable();

            var tagHelper = new SelectTagHelper
            {
                For         = modelExpression,
                Items       = inputItems,
                Generator   = htmlGenerator.Object,
                Multiple    = multiple,
                ViewContext = viewContext,
            };

            // Act
            await tagHelper.ProcessAsync(tagHelperContext, output);

            // Assert
            htmlGenerator.Verify();

            Assert.NotNull(viewContext.FormContext?.FormData);
            var keyValuePair = Assert.Single(
                viewContext.FormContext.FormData,
                entry => entry.Key == SelectTagHelper.SelectedValuesFormDataKey);

            Assert.Same(selectedValues, keyValuePair.Value);
        }
Esempio n. 17
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(
                allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
                    Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
                items: new Dictionary<object, object>(),
                uniqueId: "test");
            var output = new TagHelperOutput(
                expectedTagName,
                originalAttributes,
                getChildContentAsync: useCachedResult =>
                {
                    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. 18
0
        public async Task ProcessAsyncInTemplate_WithItems_GeneratesExpectedOutput_DoesNotChangeSelectList(
            object model,
            Type containerType,
            Func<object> modelAccessor,
            NameAndId nameAndId,
            string expectedOptions)
        {
            // Arrange
            var originalAttributes = new Dictionary<string, object>
            {
                { "class", "form-control" },
            };
            var originalPostContent = "original content";

            var expectedAttributes = new Dictionary<string, object>(originalAttributes)
            {
                { "id", nameAndId.Id },
                { "name", nameAndId.Name },
                { "valid", "from validation attributes" },
            };
            var expectedPreContent = "original pre-content";
            var expectedContent = "original content";
            var expectedPostContent = originalPostContent + expectedOptions;
            var expectedTagName = "select";

            var metadataProvider = new TestModelMetadataProvider();

            var containerMetadata = metadataProvider.GetMetadataForType(containerType);
            var containerExplorer = metadataProvider.GetModelExplorerForType(containerType, model);

            var propertyMetadata = metadataProvider.GetMetadataForProperty(containerType, "Text");
            var modelExplorer = containerExplorer.GetExplorerForExpression(propertyMetadata, modelAccessor());

            var modelExpression = new ModelExpression(name: string.Empty, modelExplorer: modelExplorer);

            var tagHelperContext = new TagHelperContext(
                allAttributes: new Dictionary<string, object>(),
                items: new Dictionary<object, object>(),
                uniqueId: "test",
                getChildContentAsync: () =>
                {
                    var tagHelperContent = new DefaultTagHelperContent();
                    tagHelperContent.SetContent("Something");
                    return Task.FromResult<TagHelperContent>(tagHelperContent);
                });
            var output = new TagHelperOutput(expectedTagName, originalAttributes)
            {
                SelfClosing = true
            };
            output.PreContent.SetContent(expectedPreContent);
            output.Content.SetContent(expectedContent);
            output.PostContent.SetContent(originalPostContent);

            var htmlGenerator = new TestableHtmlGenerator(metadataProvider)
            {
                ValidationAttributes =
                {
                    {  "valid", "from validation attributes" },
                }
            };
            var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider);
            viewContext.ViewData.TemplateInfo.HtmlFieldPrefix = nameAndId.Name;

            var items = new SelectList(new[] { "", "outer text", "inner text", "other text" });
            var savedDisabled = items.Select(item => item.Disabled).ToList();
            var savedGroup = items.Select(item => item.Group).ToList();
            var savedSelected = items.Select(item => item.Selected).ToList();
            var savedText = items.Select(item => item.Text).ToList();
            var savedValue = items.Select(item => item.Value).ToList();
            var tagHelper = new SelectTagHelper
            {
                For = modelExpression,
                Generator = htmlGenerator,
                Items = items,
                ViewContext = viewContext,
            };

            // Act
            await tagHelper.ProcessAsync(tagHelperContext, output);

            // Assert
            Assert.True(output.SelfClosing);
            Assert.Equal(expectedAttributes, output.Attributes);
            Assert.Equal(expectedPreContent, output.PreContent.GetContent());
            Assert.Equal(expectedContent, output.Content.GetContent());
            Assert.Equal(expectedPostContent, output.PostContent.GetContent());
            Assert.Equal(expectedTagName, output.TagName);

            Assert.NotNull(viewContext.FormContext?.FormData);
            Assert.Single(
                viewContext.FormContext.FormData,
                entry => entry.Key == SelectTagHelper.SelectedValuesFormDataKey);

            Assert.Equal(savedDisabled, items.Select(item => item.Disabled));
            Assert.Equal(savedGroup, items.Select(item => item.Group));
            Assert.Equal(savedSelected, items.Select(item => item.Selected));
            Assert.Equal(savedText, items.Select(item => item.Text));
            Assert.Equal(savedValue, items.Select(item => item.Value));
        }
Esempio n. 19
0
        public async Task TagHelper_CallsGeneratorWithExpectedValues_RealModelType(
            Type modelType,
            object model,
            bool allowMultiple)
        {
            // Arrange
            var contextAttributes = new ReadOnlyTagHelperAttributeList <IReadOnlyTagHelperAttribute>(
                Enumerable.Empty <IReadOnlyTagHelperAttribute>());
            var originalAttributes = new TagHelperAttributeList();
            var propertyName       = "Property1";
            var tagName            = "select";

            var tagHelperContext = new TagHelperContext(
                contextAttributes,
                items: new Dictionary <object, object>(),
                uniqueId: "test");
            var output = new TagHelperOutput(
                tagName,
                originalAttributes,
                getChildContentAsync: useCachedResult =>
            {
                var tagHelperContent = new DefaultTagHelperContent();
                tagHelperContent.SetContent("Something");
                return(Task.FromResult <TagHelperContent>(tagHelperContent));
            });
            var metadataProvider = new EmptyModelMetadataProvider();
            var modelExplorer    = metadataProvider.GetModelExplorerForType(modelType, model);
            var modelExpression  = new ModelExpression(propertyName, modelExplorer);

            var htmlGenerator = new Mock <IHtmlGenerator>(MockBehavior.Strict);
            var viewContext   = TestableHtmlGenerator.GetViewContext(model, htmlGenerator.Object, metadataProvider);
            var currentValues = new string[0];

            htmlGenerator
            .Setup(real => real.GetCurrentValues(
                       viewContext,
                       modelExplorer,
                       propertyName, // expression
                       allowMultiple))
            .Returns(currentValues)
            .Verifiable();
            htmlGenerator
            .Setup(real => real.GenerateSelect(
                       viewContext,
                       modelExplorer,
                       null,         // optionLabel
                       propertyName, // expression
                       It.IsAny <IEnumerable <SelectListItem> >(),
                       currentValues,
                       allowMultiple,
                       null))       // htmlAttributes
            .Returns((TagBuilder)null)
            .Verifiable();

            var tagHelper = new SelectTagHelper(htmlGenerator.Object)
            {
                For         = modelExpression,
                ViewContext = viewContext,
            };

            // Act
            tagHelper.Init(tagHelperContext);
            await tagHelper.ProcessAsync(tagHelperContext, output);

            // Assert
            htmlGenerator.Verify();

            var keyValuePair = Assert.Single(
                tagHelperContext.Items,
                entry => (Type)entry.Key == typeof(SelectTagHelper));

            Assert.Same(currentValues, keyValuePair.Value);
        }
Esempio n. 20
0
        public async Task TagHelper_CallsGeneratorWithExpectedValues_RealModelType(
            Type modelType,
            object model,
            bool allowMultiple)
        {
            // Arrange
            var contextAttributes = new Dictionary<string, object>();
            var originalAttributes = new Dictionary<string, object>();
            var propertyName = "Property1";
            var tagName = "select";

            var tagHelperContext = new TagHelperContext(
                contextAttributes,
                items: new Dictionary<object, object>(),
                uniqueId: "test",
                getChildContentAsync: () =>
                {
                    var tagHelperContent = new DefaultTagHelperContent();
                    tagHelperContent.SetContent("Something");
                    return Task.FromResult<TagHelperContent>(tagHelperContent);
                });
            var output = new TagHelperOutput(tagName, originalAttributes);
            var metadataProvider = new EmptyModelMetadataProvider();
            var modelExplorer = metadataProvider.GetModelExplorerForType(modelType, model);
            var modelExpression = new ModelExpression(propertyName, modelExplorer);

            var htmlGenerator = new Mock<IHtmlGenerator>(MockBehavior.Strict);
            var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator.Object, metadataProvider);
            var currentValues = new string[0];
            htmlGenerator
                .Setup(real => real.GetCurrentValues(
                    viewContext,
                    modelExplorer,
                    propertyName,   // expression
                    allowMultiple))
                .Returns(currentValues)
                .Verifiable();
            htmlGenerator
                .Setup(real => real.GenerateSelect(
                    viewContext,
                    modelExplorer,
                    null,           // optionLabel
                    propertyName,   // expression
                    It.IsAny<IEnumerable<SelectListItem>>(),
                    currentValues,
                    allowMultiple,
                    null))          // htmlAttributes
                .Returns((TagBuilder)null)
                .Verifiable();

            var tagHelper = new SelectTagHelper
            {
                For = modelExpression,
                Generator = htmlGenerator.Object,
                ViewContext = viewContext,
            };

            // Act
            await tagHelper.ProcessAsync(tagHelperContext, output);

            // Assert
            htmlGenerator.Verify();

            Assert.NotNull(viewContext.FormContext?.FormData);
            var keyValuePair = Assert.Single(
                viewContext.FormContext.FormData,
                entry => entry.Key == SelectTagHelper.SelectedValuesFormDataKey);
            Assert.Same(currentValues, keyValuePair.Value);
        }
Esempio n. 21
0
        public async Task ProcessAsync_WithItems_GeneratesExpectedOutput_DoesNotChangeSelectList(
            object model,
            Type containerType,
            Func <object> modelAccessor,
            NameAndId nameAndId,
            string expectedOptions)
        {
            // Arrange
            var originalAttributes = new Dictionary <string, object>
            {
                { "class", "form-control" },
            };
            var originalPostContent = "original content";

            var expectedAttributes = new Dictionary <string, object>(originalAttributes)
            {
                { "id", nameAndId.Id },
                { "name", nameAndId.Name },
                { "valid", "from validation attributes" },
            };
            var expectedPreContent  = "original pre-content";
            var expectedContent     = "original content";
            var expectedPostContent = originalPostContent + expectedOptions;
            var expectedTagName     = "select";

            var metadataProvider = new TestModelMetadataProvider();

            var containerMetadata = metadataProvider.GetMetadataForType(containerType);
            var containerExplorer = metadataProvider.GetModelExplorerForType(containerType, model);

            var propertyMetadata = metadataProvider.GetMetadataForProperty(containerType, "Text");
            var modelExplorer    = containerExplorer.GetExplorerForExpression(propertyMetadata, modelAccessor());

            var modelExpression = new ModelExpression(nameAndId.Name, modelExplorer);

            var tagHelperContext = new TagHelperContext(
                allAttributes: new Dictionary <string, object>(),
                items: new Dictionary <object, object>(),
                uniqueId: "test",
                getChildContentAsync: () =>
            {
                var tagHelperContent = new DefaultTagHelperContent();
                tagHelperContent.SetContent("Something");
                return(Task.FromResult <TagHelperContent>(tagHelperContent));
            });
            var output = new TagHelperOutput(expectedTagName, originalAttributes)
            {
                SelfClosing = true,
            };

            output.PreContent.SetContent(expectedPreContent);
            output.Content.SetContent(expectedContent);
            output.PostContent.SetContent(originalPostContent);

            var htmlGenerator = new TestableHtmlGenerator(metadataProvider)
            {
                ValidationAttributes =
                {
                    { "valid", "from validation attributes" },
                }
            };
            var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider);

            var items         = new SelectList(new[] { "", "outer text", "inner text", "other text" });
            var savedDisabled = items.Select(item => item.Disabled).ToList();
            var savedGroup    = items.Select(item => item.Group).ToList();
            var savedSelected = items.Select(item => item.Selected).ToList();
            var savedText     = items.Select(item => item.Text).ToList();
            var savedValue    = items.Select(item => item.Value).ToList();
            var tagHelper     = new SelectTagHelper
            {
                For         = modelExpression,
                Generator   = htmlGenerator,
                Items       = items,
                ViewContext = viewContext,
            };

            // Act
            await tagHelper.ProcessAsync(tagHelperContext, output);

            // Assert
            Assert.True(output.SelfClosing);
            Assert.Equal(expectedAttributes, output.Attributes);
            Assert.Equal(expectedPreContent, output.PreContent.GetContent());
            Assert.Equal(expectedContent, output.Content.GetContent());
            Assert.Equal(expectedPostContent, output.PostContent.GetContent());
            Assert.Equal(expectedTagName, output.TagName);

            Assert.NotNull(viewContext.FormContext?.FormData);
            Assert.Single(
                viewContext.FormContext.FormData,
                entry => entry.Key == SelectTagHelper.SelectedValuesFormDataKey);

            Assert.Equal(savedDisabled, items.Select(item => item.Disabled));
            Assert.Equal(savedGroup, items.Select(item => item.Group));
            Assert.Equal(savedSelected, items.Select(item => item.Selected));
            Assert.Equal(savedText, items.Select(item => item.Text));
            Assert.Equal(savedValue, items.Select(item => item.Value));
        }