public void GetDescriptors_ReturnsCatchAllsWithEveryTagName()
        {
            // Arrange
            var divDescriptor      = new TagHelperDescriptor("div", "foo1", "SomeAssembly");
            var spanDescriptor     = new TagHelperDescriptor("span", "foo2", "SomeAssembly");
            var catchAllDescriptor = new TagHelperDescriptor(
                TagHelperDescriptorProvider.CatchAllDescriptorTarget,
                "foo3",
                "SomeAssembly");
            var descriptors = new TagHelperDescriptor[] { divDescriptor, spanDescriptor, catchAllDescriptor };
            var provider    = new TagHelperDescriptorProvider(descriptors);

            // Act
            var divDescriptors  = provider.GetDescriptors("div", attributeNames: Enumerable.Empty <string>());
            var spanDescriptors = provider.GetDescriptors("span", attributeNames: Enumerable.Empty <string>());

            // Assert
            // For divs
            Assert.Equal(2, divDescriptors.Count());
            Assert.Contains(divDescriptor, divDescriptors);
            Assert.Contains(catchAllDescriptor, divDescriptors);

            // For spans
            Assert.Equal(2, spanDescriptors.Count());
            Assert.Contains(spanDescriptor, spanDescriptors);
            Assert.Contains(catchAllDescriptor, spanDescriptors);
        }
        public void GetDescriptors_ReturnsNothingForUnprefixedTags(string tagName)
        {
            // Arrange
            var divDescriptor = CreatePrefixedDescriptor("th:", tagName, "foo1");
            var descriptors   = new[] { divDescriptor };
            var provider      = new TagHelperDescriptorProvider(descriptors);

            // Act
            var retrievedDescriptorsDiv = provider.GetDescriptors("div", attributeNames: Enumerable.Empty <string>());

            // Assert
            Assert.Empty(retrievedDescriptorsDiv);
        }
        public void Rewrite_CanHandleInvalidChildrenWithWhitespace()
        {
            // Arrange
            var factory = CreateDefaultSpanFactory();
            var blockFactory = new BlockFactory(factory);
            var documentContent = $"<p>{Environment.NewLine}    <strong>{Environment.NewLine}        Hello" +
                $"{Environment.NewLine}    </strong>{Environment.NewLine}</p>";
            var newLineLength = Environment.NewLine.Length;
            var expectedErrors = new[] {
                new RazorError(
                    RazorResources.FormatTagHelperParseTreeRewriter_InvalidNestedTag("strong", "p", "br"),
                    absoluteIndex: 7 + newLineLength,
                    lineIndex: 1,
                    columnIndex: 9 + newLineLength,
                    length: 8),
                new RazorError(
                    RazorResources.FormatTagHelperParseTreeRewriter_CannotHaveNonTagContent("p", "br"),
                    absoluteIndex: 23 + newLineLength * 2,
                    lineIndex: 2,
                    columnIndex: 23 + newLineLength * 2,
                    length: 5),
                new RazorError(
                    RazorResources.FormatTagHelperParseTreeRewriter_InvalidNestedTag("strong", "p", "br"),
                    absoluteIndex: 32 + newLineLength * 3,
                    lineIndex: 3,
                    columnIndex: 32 + newLineLength * 3,
                    length: 9),
            };
            var expectedOutput = new MarkupBlock(
                new MarkupTagHelperBlock("p",
                    factory.Markup(Environment.NewLine + "    "),
                    blockFactory.MarkupTagBlock("<strong>"),
                    factory.Markup(Environment.NewLine + "        Hello" + Environment.NewLine + "    "),
                    blockFactory.MarkupTagBlock("</strong>"),
                    factory.Markup(Environment.NewLine)));
            var descriptors = new TagHelperDescriptor[]
                {
                    new TagHelperDescriptor
                    {
                        TagName = "p",
                        TypeName = "PTagHelper",
                        AssemblyName = "SomeAssembly",
                        AllowedChildren = new[] { "br" },
                    }
                };
            var descriptorProvider = new TagHelperDescriptorProvider(descriptors);

            // Act & Assert
            EvaluateData(descriptorProvider, documentContent, expectedOutput, expectedErrors);
        }
        public void GetDescriptors_ReturnsNothingForUnregisteredTags()
        {
            // Arrange
            var divDescriptor  = new TagHelperDescriptor("div", "foo1", "SomeAssembly");
            var spanDescriptor = new TagHelperDescriptor("span", "foo2", "SomeAssembly");
            var descriptors    = new TagHelperDescriptor[] { divDescriptor, spanDescriptor };
            var provider       = new TagHelperDescriptorProvider(descriptors);

            // Act
            var retrievedDescriptors = provider.GetDescriptors("foo", attributeNames: Enumerable.Empty <string>());

            // Assert
            Assert.Empty(retrievedDescriptors);
        }
        public void GetDescriptors_ReturnsDescriptorsForPrefixedTags()
        {
            // Arrange
            var divDescriptor = CreatePrefixedDescriptor("th:", "div", "foo1");
            var descriptors   = new[] { divDescriptor };
            var provider      = new TagHelperDescriptorProvider(descriptors);

            // Act
            var retrievedDescriptors = provider.GetDescriptors("th:div", attributeNames: Enumerable.Empty <string>());

            // Assert
            var descriptor = Assert.Single(retrievedDescriptors);

            Assert.Same(divDescriptor, descriptor);
        }
        public void GetDescriptors_DuplicateDescriptorsAreNotPartOfTagHelperDescriptorPool()
        {
            // Arrange
            var divDescriptor = new TagHelperDescriptor("div", "foo1", "SomeAssembly");
            var descriptors   = new TagHelperDescriptor[] { divDescriptor, divDescriptor };
            var provider      = new TagHelperDescriptorProvider(descriptors);

            // Act
            var retrievedDescriptors = provider.GetDescriptors("div", attributeNames: Enumerable.Empty <string>());

            // Assert
            var descriptor = Assert.Single(retrievedDescriptors);

            Assert.Same(divDescriptor, descriptor);
        }
        public void GetDescriptors_ReturnsDescriptorsWithRequiredAttributes(
            string tagName,
            IEnumerable <string> providedAttributes,
            IEnumerable <TagHelperDescriptor> availableDescriptors,
            IEnumerable <TagHelperDescriptor> expectedDescriptors)
        {
            // Arrange
            var provider = new TagHelperDescriptorProvider(availableDescriptors);

            // Act
            var resolvedDescriptors = provider.GetDescriptors(tagName, providedAttributes);

            // Assert
            Assert.Equal(expectedDescriptors, resolvedDescriptors, TagHelperDescriptorComparer.Default);
        }
        public void GetDescriptors_ReturnsEmptyDescriptorsWithPrefixAsTagName()
        {
            // Arrange
            var catchAllDescriptor = CreatePrefixedDescriptor(
                "th",
                TagHelperDescriptorProvider.ElementCatchAllTarget,
                "foo1");
            var descriptors = new[] { catchAllDescriptor };
            var provider    = new TagHelperDescriptorProvider(descriptors);

            // Act
            var resolvedDescriptors = provider.GetDescriptors("th", attributeNames: Enumerable.Empty <string>());

            // Assert
            Assert.Empty(resolvedDescriptors);
        }
        public void EvaluateData(
            TagHelperDescriptorProvider provider,
            string documentContent,
            MarkupBlock expectedOutput,
            IEnumerable<RazorError> expectedErrors)
        {
            var errorSink = new ErrorSink();
            var results = ParseDocument(documentContent, errorSink);
            var rewritingContext = new RewritingContext(results.Document, errorSink);
            new TagHelperParseTreeRewriter(provider).Rewrite(rewritingContext);
            var rewritten = rewritingContext.SyntaxTree;
            var actualErrors = errorSink.Errors.OrderBy(error => error.Location.AbsoluteIndex)
                                               .ToList();

            EvaluateRazorErrors(actualErrors, expectedErrors.ToList());
            EvaluateParseTree(rewritten, expectedOutput);
        }
        public void GetDescriptors_OnlyUnderstandsSinglePrefix()
        {
            // Arrange
            var divDescriptor  = CreatePrefixedDescriptor("th:", "div", "foo1");
            var spanDescriptor = CreatePrefixedDescriptor("th2:", "span", "foo2");
            var descriptors    = new[] { divDescriptor, spanDescriptor };
            var provider       = new TagHelperDescriptorProvider(descriptors);

            // Act
            var retrievedDescriptorsDiv  = provider.GetDescriptors("th:div", attributeNames: Enumerable.Empty <string>());
            var retrievedDescriptorsSpan = provider.GetDescriptors("th2:span", attributeNames: Enumerable.Empty <string>());

            // Assert
            var descriptor = Assert.Single(retrievedDescriptorsDiv);

            Assert.Same(divDescriptor, descriptor);
            Assert.Empty(retrievedDescriptorsSpan);
        }
        public void GetDescriptors_ReturnsCatchAllDescriptorsForPrefixedTags()
        {
            // Arrange
            var catchAllDescriptor = CreatePrefixedDescriptor("th:", TagHelperDescriptorProvider.ElementCatchAllTarget, "foo1");
            var descriptors        = new[] { catchAllDescriptor };
            var provider           = new TagHelperDescriptorProvider(descriptors);

            // Act
            var retrievedDescriptorsDiv  = provider.GetDescriptors("th:div", attributeNames: Enumerable.Empty <string>());
            var retrievedDescriptorsSpan = provider.GetDescriptors("th:span", attributeNames: Enumerable.Empty <string>());

            // Assert
            var descriptor = Assert.Single(retrievedDescriptorsDiv);

            Assert.Same(catchAllDescriptor, descriptor);
            descriptor = Assert.Single(retrievedDescriptorsSpan);
            Assert.Same(catchAllDescriptor, descriptor);
        }
        public void GetDescriptors_ReturnsDescriptorsWithRequiredAttributes(
            string tagName,
            string parentTagName,
            IEnumerable<TagHelperDescriptor> availableDescriptors,
            IEnumerable<TagHelperDescriptor> expectedDescriptors)
        {
            // Arrange
            var provider = new TagHelperDescriptorProvider(availableDescriptors);

            // Act
            var resolvedDescriptors = provider.GetDescriptors(
                tagName,
                attributeNames: Enumerable.Empty<string>(),
                parentTagName: parentTagName);

            // Assert
            Assert.Equal(expectedDescriptors, resolvedDescriptors, CaseSensitiveTagHelperDescriptorComparer.Default);
        }
        public void GetDescriptors_DoesNotReturnNonCatchAllTagsForCatchAll()
        {
            // Arrange
            var divDescriptor      = new TagHelperDescriptor("div", "foo1", "SomeAssembly");
            var spanDescriptor     = new TagHelperDescriptor("span", "foo2", "SomeAssembly");
            var catchAllDescriptor = new TagHelperDescriptor(
                TagHelperDescriptorProvider.CatchAllDescriptorTarget,
                "foo3",
                "SomeAssembly");
            var descriptors = new TagHelperDescriptor[] { divDescriptor, spanDescriptor, catchAllDescriptor };
            var provider    = new TagHelperDescriptorProvider(descriptors);

            // Act
            var retrievedDescriptors = provider.GetDescriptors(TagHelperDescriptorProvider.CatchAllDescriptorTarget, attributeNames: Enumerable.Empty <string>());

            // Assert
            var descriptor = Assert.Single(retrievedDescriptors);

            Assert.Same(catchAllDescriptor, descriptor);
        }
Example #14
0
        public void Rewrite_UnderstandsMinimizedAttributes(
            string documentContent,
            MarkupBlock expectedOutput,
            RazorError[] expectedErrors)
        {
            // Arrange
            var descriptors = new TagHelperDescriptor[]
                {
                    new TagHelperDescriptor(
                        tagName: "input",
                        typeName: "InputTagHelper1",
                        assemblyName: "SomeAssembly",
                        attributes: new[]
                        {
                            new TagHelperAttributeDescriptor(
                                "bound-required-string",
                                "BoundRequiredString",
                                typeof(string).FullName,
                                isIndexer: false,
                                designTimeDescriptor: null)
                        },
                        requiredAttributes: new[] { "unbound-required" }),
                    new TagHelperDescriptor(
                        tagName: "input",
                        typeName: "InputTagHelper1",
                        assemblyName: "SomeAssembly",
                        attributes: new[]
                        {
                            new TagHelperAttributeDescriptor(
                                "bound-required-string",
                                "BoundRequiredString",
                                typeof(string).FullName,
                                isIndexer: false,
                                designTimeDescriptor: null)
                        },
                        requiredAttributes: new[] { "bound-required-string" }),
                    new TagHelperDescriptor(
                        tagName: "input",
                        typeName: "InputTagHelper2",
                        assemblyName: "SomeAssembly",
                        attributes: new[]
                        {
                            new TagHelperAttributeDescriptor(
                                "bound-required-int",
                                "BoundRequiredInt",
                                typeof(int).FullName,
                                isIndexer: false,
                                designTimeDescriptor: null)
                        },
                        requiredAttributes: new[] { "bound-required-int" }),
                    new TagHelperDescriptor(
                        tagName: "input",
                        typeName: "InputTagHelper3",
                        assemblyName: "SomeAssembly",
                        attributes: new[]
                        {
                            new TagHelperAttributeDescriptor(
                                "int-dictionary",
                                "DictionaryOfIntProperty",
                                typeof(IDictionary<string, int>).FullName,
                                isIndexer: false,
                                designTimeDescriptor: null),
                            new TagHelperAttributeDescriptor(
                                "string-dictionary",
                                "DictionaryOfStringProperty",
                                typeof(IDictionary<string, string>).FullName,
                                isIndexer: false,
                                designTimeDescriptor: null),
                            new TagHelperAttributeDescriptor(
                                "int-prefix-",
                                "DictionaryOfIntProperty",
                                typeof(int).FullName,
                                isIndexer: true,
                                designTimeDescriptor: null),
                            new TagHelperAttributeDescriptor(
                                "string-prefix-",
                                "DictionaryOfStringProperty",
                                typeof(string).FullName,
                                isIndexer: true,
                                designTimeDescriptor: null),
                        },
                        requiredAttributes: Enumerable.Empty<string>()),
                    new TagHelperDescriptor(
                        tagName: "p",
                        typeName: "PTagHelper",
                        assemblyName: "SomeAssembly",
                        attributes: new[]
                        {
                            new TagHelperAttributeDescriptor(
                                "bound-string",
                                "BoundRequiredString",
                                typeof(string).FullName,
                                isIndexer: false,
                                designTimeDescriptor: null),
                            new TagHelperAttributeDescriptor(
                                "bound-int",
                                "BoundRequiredString",
                                typeof(int).FullName,
                                isIndexer: false,
                                designTimeDescriptor: null)
                        },
                        requiredAttributes: Enumerable.Empty<string>()),
                };
            var descriptorProvider = new TagHelperDescriptorProvider(descriptors);

            // Act & Assert
            EvaluateData(descriptorProvider, documentContent, expectedOutput, expectedErrors);
        }
        public void Rewrite_RequiredAttributeDescriptorsCreateTagHelperBlocksCorrectly(
            string documentContent,
            MarkupBlock expectedOutput)
        {
            // Arrange
            var descriptors = new TagHelperDescriptor[]
                {
                    new TagHelperDescriptor
                    {
                        TagName = "p",
                        TypeName = "pTagHelper",
                        AssemblyName = "SomeAssembly",
                        RequiredAttributes = new[] { "class" }
                    },
                    new TagHelperDescriptor
                    {
                        TagName = "div",
                        TypeName = "divTagHelper",
                        AssemblyName = "SomeAssembly",
                        RequiredAttributes = new[] { "class", "style" }
                    },
                    new TagHelperDescriptor
                    {
                        TagName = "*",
                        TypeName = "catchAllTagHelper",
                        AssemblyName = "SomeAssembly",
                        RequiredAttributes = new[] { "catchAll" }
                    }
                };
            var descriptorProvider = new TagHelperDescriptorProvider(descriptors);

            // Act & Assert
            EvaluateData(descriptorProvider, documentContent, expectedOutput, expectedErrors: new RazorError[0]);
        }
        public void GetDescriptors_ReturnsCatchAllsWithEveryTagName()
        {
            // Arrange
            var divDescriptor = new TagHelperDescriptor
            {
                TagName = "div",
                TypeName = "foo1",
                AssemblyName = "SomeAssembly",
            };
            var spanDescriptor = new TagHelperDescriptor
            {
                TagName = "span",
                TypeName = "foo2",
                AssemblyName = "SomeAssembly",
            };
            var catchAllDescriptor = new TagHelperDescriptor
            {
                TagName = TagHelperDescriptorProvider.ElementCatchAllTarget,
                TypeName = "foo3",
                AssemblyName = "SomeAssembly",
            };
            var descriptors = new TagHelperDescriptor[] { divDescriptor, spanDescriptor, catchAllDescriptor };
            var provider = new TagHelperDescriptorProvider(descriptors);

            // Act
            var divDescriptors = provider.GetDescriptors("div", attributeNames: Enumerable.Empty<string>());
            var spanDescriptors = provider.GetDescriptors("span", attributeNames: Enumerable.Empty<string>());

            // Assert
            // For divs
            Assert.Equal(2, divDescriptors.Count());
            Assert.Contains(divDescriptor, divDescriptors);
            Assert.Contains(catchAllDescriptor, divDescriptors);

            // For spans
            Assert.Equal(2, spanDescriptors.Count());
            Assert.Contains(spanDescriptor, spanDescriptors);
            Assert.Contains(catchAllDescriptor, spanDescriptors);
        }
        public void TagHelperParseTreeRewriter_CreatesMarkupCodeSpansForNonStringTagHelperAttributes(
            string documentContent,
            MarkupBlock expectedOutput)
        {
            // Arrange
            var descriptors = new TagHelperDescriptor[]
            {
                new TagHelperDescriptor
                {
                    TagName = "person",
                    TypeName = "PersonTagHelper",
                    AssemblyName = "personAssembly",
                    Attributes = new[]
                    {
                        new TagHelperAttributeDescriptor
                        {
                            Name = "age",
                            PropertyName = "Age",
                            TypeName = typeof(int).FullName
                        },
                        new TagHelperAttributeDescriptor
                        {
                            Name = "birthday",
                            PropertyName = "BirthDay",
                            TypeName = typeof(DateTime).FullName
                        },
                        new TagHelperAttributeDescriptor
                        {
                            Name = "name",
                            PropertyName = "Name",
                            TypeName = typeof(string).FullName
                        }
                    }
                }
            };
            var providerContext = new TagHelperDescriptorProvider(descriptors);

            // Act & Assert
            EvaluateData(providerContext,
                         documentContent,
                         expectedOutput,
                         expectedErrors: Enumerable.Empty<RazorError>());
        }
        public void GetDescriptors_ReturnsEmptyDescriptorsWithPrefixAsTagName()
        {
            // Arrange
            var catchAllDescriptor = CreatePrefixedDescriptor(
                "th",
                TagHelperDescriptorProvider.ElementCatchAllTarget,
                "foo1");
            var descriptors = new[] { catchAllDescriptor };
            var provider = new TagHelperDescriptorProvider(descriptors);

            // Act
            var resolvedDescriptors = provider.GetDescriptors("th", attributeNames: Enumerable.Empty<string>());

            // Assert
            Assert.Empty(resolvedDescriptors);
        }
        public void Rewrite_CanHandleSymbolBoundAttributes(string documentContent, MarkupBlock expectedOutput)
        {
            // Arrange
            var descriptors = new[]
            {
                new TagHelperDescriptor
                {
                    TagName = "*",
                    TypeName = "CatchAllTagHelper",
                    AssemblyName = "SomeAssembly",
                    Attributes = new[]
                    {
                        new TagHelperAttributeDescriptor
                        {
                            Name = "[item]",
                            PropertyName = "ListItems",
                            TypeName = typeof(List<string>).FullName
                        },
                        new TagHelperAttributeDescriptor
                        {
                            Name = "[(item)]",
                            PropertyName = "ArrayItems",
                            TypeName = typeof(string[]).FullName
                        },
                        new TagHelperAttributeDescriptor
                        {
                            Name = "(click)",
                            PropertyName = "Event1",
                            TypeName = typeof(Action).FullName
                        },
                        new TagHelperAttributeDescriptor
                        {
                            Name = "(^click)",
                            PropertyName = "Event2",
                            TypeName = typeof(Action).FullName
                        },
                        new TagHelperAttributeDescriptor
                        {
                            Name = "*something",
                            PropertyName = "StringProperty1",
                            TypeName = typeof(string).FullName
                        },
                        new TagHelperAttributeDescriptor
                        {
                            Name = "#local",
                            PropertyName = "StringProperty2",
                            TypeName = typeof(string).FullName
                        },
                    },
                    RequiredAttributes = new[] { "bound" },
                },
            };
            var descriptorProvider = new TagHelperDescriptorProvider(descriptors);

            // Act & Assert
            EvaluateData(descriptorProvider, documentContent, expectedOutput, expectedErrors: new RazorError[0]);
        }
        public void TagHelperParseTreeRewriter_CreatesMarkupCodeSpansForNonStringTagHelperAttributes(
            string documentContent,
            MarkupBlock expectedOutput)
        {
            // Arrange
            var descriptors = new TagHelperDescriptor[]
            {
                new TagHelperDescriptor("person", "PersonTagHelper", "personAssembly",
                    attributes: new[]
                    {
                        new TagHelperAttributeDescriptor("age", "Age", typeof(int).FullName, isIndexer: false),
                        new TagHelperAttributeDescriptor(
                            "birthday",
                            "BirthDay",
                            typeof(DateTime).FullName,
                            isIndexer: false),
                        new TagHelperAttributeDescriptor("name", "Name", typeof(string).FullName, isIndexer: false),
                    })
            };
            var providerContext = new TagHelperDescriptorProvider(descriptors);

            // Act & Assert
            EvaluateData(providerContext,
                         documentContent,
                         expectedOutput,
                         expectedErrors: Enumerable.Empty<RazorError>());
        }
Example #21
0
        private ParserResults ParseCore(ITextDocument input)
        {
            // Setup the parser context
            var errorSink = new ParserErrorSink();
            var context = new ParserContext(input, CodeParser, MarkupParser, MarkupParser, errorSink)
            {
                DesignTimeMode = DesignTimeMode
            };

            MarkupParser.Context = context;
            CodeParser.Context = context;

            // Execute the parse
            MarkupParser.ParseDocument();

            // Get the result
            var results = context.CompleteParse();

            // Rewrite whitespace if supported
            var rewritingContext = new RewritingContext(results.Document, errorSink);
            foreach (ISyntaxTreeRewriter rewriter in Optimizers)
            {
                rewriter.Rewrite(rewritingContext);
            }

            var descriptors = Enumerable.Empty<TagHelperDescriptor>();

            if (TagHelperDescriptorResolver != null)
            {
                descriptors = GetTagHelperDescriptors(rewritingContext.SyntaxTree, rewritingContext.ErrorSink);
                var tagHelperProvider = new TagHelperDescriptorProvider(descriptors);

                var tagHelperParseTreeRewriter = new TagHelperParseTreeRewriter(tagHelperProvider);
                // Rewrite the document to utilize tag helpers
                tagHelperParseTreeRewriter.Rewrite(rewritingContext);
            }

            var syntaxTree = rewritingContext.SyntaxTree;

            // Link the leaf nodes into a chain
            Span prev = null;
            foreach (Span node in syntaxTree.Flatten())
            {
                node.Previous = prev;
                if (prev != null)
                {
                    prev.Next = node;
                }
                prev = node;
            }

            // Return the new result
            return new ParserResults(syntaxTree, descriptors, errorSink);
        }
        public void Rewrite_CanHandleWithoutEndTagTagStructure(string documentContent, MarkupBlock expectedOutput)
        {
            // Arrange
            var descriptors = new TagHelperDescriptor[]
                {
                    new TagHelperDescriptor
                    {
                        TagName = "input",
                        TypeName = "InputTagHelper",
                        AssemblyName = "SomeAssembly",
                        TagStructure = TagStructure.WithoutEndTag,
                    }
                };
            var descriptorProvider = new TagHelperDescriptorProvider(descriptors);

            // Act & Assert
            EvaluateData(descriptorProvider, documentContent, expectedOutput, expectedErrors: new RazorError[0]);
        }
        public void Rewrite_UnderstandsMinimizedAttributes(
            string documentContent,
            MarkupBlock expectedOutput,
            RazorError[] expectedErrors)
        {
            // Arrange
            var descriptors = new TagHelperDescriptor[]
                {
                    new TagHelperDescriptor
                    {
                        TagName = "input",
                        TypeName = "InputTagHelper1",
                        AssemblyName = "SomeAssembly",
                        Attributes = new[]
                        {
                            new TagHelperAttributeDescriptor
                            {
                                Name = "bound-required-string",
                                PropertyName = "BoundRequiredString",
                                TypeName = typeof(string).FullName
                            }
                        },
                        RequiredAttributes = new[] { "unbound-required" }
                    },
                    new TagHelperDescriptor
                    {
                        TagName = "input",
                        TypeName = "InputTagHelper1",
                        AssemblyName = "SomeAssembly",
                        Attributes = new[]
                        {
                            new TagHelperAttributeDescriptor
                            {
                                Name = "bound-required-string",
                                PropertyName = "BoundRequiredString",
                                TypeName = typeof(string).FullName
                            }
                        },
                        RequiredAttributes = new[] { "bound-required-string" }
                    },
                    new TagHelperDescriptor
                    {
                        TagName = "input",
                        TypeName = "InputTagHelper2",
                        AssemblyName = "SomeAssembly",
                        Attributes = new[]
                        {
                            new TagHelperAttributeDescriptor
                            {
                                Name = "bound-required-int",
                                PropertyName = "BoundRequiredInt",
                                TypeName = typeof(int).FullName
                            }
                        },
                        RequiredAttributes = new[] { "bound-required-int" }
                    },
                    new TagHelperDescriptor
                    {
                        TagName = "input",
                        TypeName = "InputTagHelper3",
                        AssemblyName = "SomeAssembly",
                        Attributes = new[]
                        {
                            new TagHelperAttributeDescriptor
                            {
                                Name = "int-dictionary",
                                PropertyName ="DictionaryOfIntProperty",
                                TypeName = typeof(IDictionary<string, int>).FullName
                            },
                            new TagHelperAttributeDescriptor
                            {
                                Name = "string-dictionary",
                                PropertyName = "DictionaryOfStringProperty",
                                TypeName = typeof(IDictionary<string, string>).FullName
                            },
                            new TagHelperAttributeDescriptor
                            {
                                Name = "int-prefix-",
                                PropertyName = "DictionaryOfIntProperty",
                                TypeName = typeof(int).FullName,
                                IsIndexer = true
                            },
                            new TagHelperAttributeDescriptor
                            {
                                Name = "string-prefix-",
                                PropertyName = "DictionaryOfStringProperty",
                                TypeName = typeof(string).FullName,
                                IsIndexer = true
                            }
                        }
                    },
                    new TagHelperDescriptor
                    {
                        TagName = "p",
                        TypeName = "PTagHelper",
                        AssemblyName = "SomeAssembly",
                        Attributes = new[]
                        {
                            new TagHelperAttributeDescriptor
                            {
                                Name = "bound-string",
                                PropertyName = "BoundRequiredString",
                                TypeName = typeof(string).FullName
                            },
                            new TagHelperAttributeDescriptor
                            {
                                Name = "bound-int",
                                PropertyName = "BoundRequiredString",
                                TypeName = typeof(int).FullName
                            }
                        }
                    }
                };
            var descriptorProvider = new TagHelperDescriptorProvider(descriptors);

            // Act & Assert
            EvaluateData(descriptorProvider, documentContent, expectedOutput, expectedErrors);
        }
        public void Rewrite_CreatesErrorForEmptyTagHelperBoundAttributes(
            string documentContent,
            MarkupBlock expectedOutput,
            RazorError[] expectedErrors)
        {
            // Arrange
            var descriptors = new TagHelperDescriptor[]
                {
                    new TagHelperDescriptor
                    {
                        TagName = "myth",
                        TypeName = "mythTagHelper",
                        AssemblyName = "SomeAssembly",
                        Attributes = new[]
                        {
                            new TagHelperAttributeDescriptor
                            {
                                Name = "bound",
                                PropertyName = "Bound",
                                TypeName = typeof(bool).FullName
                            },
                            new TagHelperAttributeDescriptor
                            {
                                Name = "name",
                                PropertyName = "Name",
                                TypeName = typeof(string).FullName
                            }
                        }
                    }
                };
            var descriptorProvider = new TagHelperDescriptorProvider(descriptors);

            // Act & Assert
            EvaluateData(descriptorProvider, documentContent, expectedOutput, expectedErrors);
        }
        public void Rewrite_AllowsCompatibleTagStructures(
            string documentContent,
            TagStructure structure1,
            TagStructure structure2,
            MarkupBlock expectedOutput)
        {
            // Arrange
            var factory = CreateDefaultSpanFactory();
            var blockFactory = new BlockFactory(factory);
            var descriptors = new TagHelperDescriptor[]
                {
                    new TagHelperDescriptor
                    {
                        TagName = "input",
                        TypeName = "InputTagHelper1",
                        AssemblyName = "SomeAssembly",
                        TagStructure = structure1
                    },
                    new TagHelperDescriptor
                    {
                        TagName = "input",
                        TypeName = "InputTagHelper2",
                        AssemblyName = "SomeAssembly",
                        TagStructure = structure2
                    }
                };
            var descriptorProvider = new TagHelperDescriptorProvider(descriptors);

            // Act & Assert
            EvaluateData(descriptorProvider, documentContent, expectedOutput, expectedErrors: new RazorError[0]);
        }
        public void Rewrite_AllowsPrefixedTagHelpers(
            string documentContent,
            MarkupBlock expectedOutput,
            IEnumerable<TagHelperDescriptor> availableDescriptors)
        {
            // Arrange
            var descriptorProvider = new TagHelperDescriptorProvider(availableDescriptors);

            // Act & Assert
            EvaluateData(
                descriptorProvider,
                documentContent,
                expectedOutput,
                expectedErrors: Enumerable.Empty<RazorError>());
        }
        public void Rewrite_CreatesErrorForEmptyTagHelperBoundAttributes(
            string documentContent,
            MarkupBlock expectedOutput,
            RazorError[] expectedErrors)
        {
            // Arrange
            var descriptors = new TagHelperDescriptor[]
                {
                    new TagHelperDescriptor(
                        tagName: "myth",
                        typeName: "mythTagHelper",
                        assemblyName: "SomeAssembly",
                        attributes: new[]
                        {
                            new TagHelperAttributeDescriptor(
                                name: "bound",
                                propertyName: "Bound",
                                typeName: typeof(bool).FullName,
                                isIndexer: false),
                            new TagHelperAttributeDescriptor(
                                name: "name",
                                propertyName: "Name",
                                typeName: typeof(string).FullName,
                                isIndexer: false)
                        })
                };
            var descriptorProvider = new TagHelperDescriptorProvider(descriptors);

            // Act & Assert
            EvaluateData(descriptorProvider, documentContent, expectedOutput, expectedErrors);
        }
        public void Rewrite_CreatesErrorForInconsistentTagStructures()
        {
            // Arrange
            var factory = CreateDefaultSpanFactory();
            var blockFactory = new BlockFactory(factory);
            var expectedError = new RazorError(
                RazorResources.FormatTagHelperParseTreeRewriter_InconsistentTagStructure(
                    "InputTagHelper1",
                    "InputTagHelper2",
                    "input",
                    nameof(TagHelperDescriptor.TagStructure)),
                absoluteIndex: 0,
                lineIndex: 0,
                columnIndex: 0,
                length: 7);
            var documentContent = "<input>";
            var expectedOutput = new MarkupBlock(new MarkupTagHelperBlock("input", TagMode.StartTagOnly));
            var descriptors = new TagHelperDescriptor[]
                {
                    new TagHelperDescriptor
                    {
                        TagName = "input",
                        TypeName = "InputTagHelper1",
                        AssemblyName = "SomeAssembly",
                        TagStructure = TagStructure.WithoutEndTag
                    },
                    new TagHelperDescriptor
                    {
                        TagName = "input",
                        TypeName = "InputTagHelper2",
                        AssemblyName = "SomeAssembly",
                        TagStructure = TagStructure.NormalOrSelfClosing
                    }
                };
            var descriptorProvider = new TagHelperDescriptorProvider(descriptors);

            // Act & Assert
            EvaluateData(descriptorProvider, documentContent, expectedOutput, expectedErrors: new[] { expectedError });
        }
        public void Rewrite_RequiredAttributeDescriptorsCreateMalformedTagHelperBlocksCorrectly(
            string documentContent,
            MarkupBlock expectedOutput,
            RazorError[] expectedErrors)
        {
            // Arrange
            var descriptors = new TagHelperDescriptor[]
                {
                    new TagHelperDescriptor(
                        tagName: "p",
                        typeName: "pTagHelper",
                        assemblyName: "SomeAssembly",
                        attributes: new TagHelperAttributeDescriptor[0],
                        requiredAttributes: new[] { "class" })
                };
            var descriptorProvider = new TagHelperDescriptorProvider(descriptors);

            // Act & Assert
            EvaluateData(descriptorProvider, documentContent, expectedOutput, expectedErrors);
        }
        public void GetDescriptors_ReturnsCatchAllDescriptorsForPrefixedTags()
        {
            // Arrange
            var catchAllDescriptor = CreatePrefixedDescriptor("th:", TagHelperDescriptorProvider.ElementCatchAllTarget, "foo1");
            var descriptors = new[] { catchAllDescriptor };
            var provider = new TagHelperDescriptorProvider(descriptors);

            // Act
            var retrievedDescriptorsDiv = provider.GetDescriptors("th:div", attributeNames: Enumerable.Empty<string>());
            var retrievedDescriptorsSpan = provider.GetDescriptors("th:span", attributeNames: Enumerable.Empty<string>());

            // Assert
            var descriptor = Assert.Single(retrievedDescriptorsDiv);
            Assert.Same(catchAllDescriptor, descriptor);
            descriptor = Assert.Single(retrievedDescriptorsSpan);
            Assert.Same(catchAllDescriptor, descriptor);
        }
        public void GetDescriptors_ReturnsDescriptorsWithRequiredAttributes(
            string tagName,
            IEnumerable<string> providedAttributes,
            IEnumerable<TagHelperDescriptor> availableDescriptors,
            IEnumerable<TagHelperDescriptor> expectedDescriptors)
        {
            // Arrange
            var provider = new TagHelperDescriptorProvider(availableDescriptors);

            // Act
            var resolvedDescriptors = provider.GetDescriptors(tagName, providedAttributes);

            // Assert
            Assert.Equal(expectedDescriptors, resolvedDescriptors, TagHelperDescriptorComparer.Default);
        }
        public void GetDescriptors_ReturnsNothingForUnprefixedTags(string tagName)
        {
            // Arrange
            var divDescriptor = CreatePrefixedDescriptor("th:", tagName, "foo1");
            var descriptors = new[] { divDescriptor };
            var provider = new TagHelperDescriptorProvider(descriptors);

            // Act
            var retrievedDescriptorsDiv = provider.GetDescriptors("div", attributeNames: Enumerable.Empty<string>());

            // Assert
            Assert.Empty(retrievedDescriptorsDiv);
        }
        public void GetDescriptors_OnlyUnderstandsSinglePrefix()
        {
            // Arrange
            var divDescriptor = CreatePrefixedDescriptor("th:", "div", "foo1");
            var spanDescriptor = CreatePrefixedDescriptor("th2:", "span", "foo2");
            var descriptors = new[] { divDescriptor, spanDescriptor };
            var provider = new TagHelperDescriptorProvider(descriptors);

            // Act
            var retrievedDescriptorsDiv = provider.GetDescriptors("th:div", attributeNames: Enumerable.Empty<string>());
            var retrievedDescriptorsSpan = provider.GetDescriptors("th2:span", attributeNames: Enumerable.Empty<string>());

            // Assert
            var descriptor = Assert.Single(retrievedDescriptorsDiv);
            Assert.Same(divDescriptor, descriptor);
            Assert.Empty(retrievedDescriptorsSpan);
        }
 public TagHelperParseTreeRewriter(TagHelperDescriptorProvider provider)
 {
     _provider = provider;
     _trackerStack = new Stack<TagHelperBlockTracker>();
     _blockStack = new Stack<BlockBuilder>();
 }
        public void GetDescriptors_ReturnsDescriptorsForPrefixedTags()
        {
            // Arrange
            var divDescriptor = CreatePrefixedDescriptor("th:", "div", "foo1");
            var descriptors = new[] { divDescriptor };
            var provider = new TagHelperDescriptorProvider(descriptors);

            // Act
            var retrievedDescriptors = provider.GetDescriptors("th:div", attributeNames: Enumerable.Empty<string>());

            // Assert
            var descriptor = Assert.Single(retrievedDescriptors);
            Assert.Same(divDescriptor, descriptor);
        }
        public void Rewrite_CreatesErrorForWithoutEndTagTagStructureForEndTags()
        {
            // Arrange
            var factory = CreateDefaultSpanFactory();
            var blockFactory = new BlockFactory(factory);
            var expectedError = new RazorError(
                RazorResources.FormatTagHelperParseTreeRewriter_EndTagTagHelperMustNotHaveAnEndTag(
                    "input",
                    "InputTagHelper",
                    TagStructure.WithoutEndTag),
                absoluteIndex: 0,
                lineIndex: 0,
                columnIndex: 0,
                length: 8);
            var documentContent = "</input>";
            var expectedOutput = new MarkupBlock(blockFactory.MarkupTagBlock("</input>"));
            var descriptors = new TagHelperDescriptor[]
                {
                    new TagHelperDescriptor
                    {
                        TagName = "input",
                        TypeName = "InputTagHelper",
                        AssemblyName = "SomeAssembly",
                        TagStructure = TagStructure.WithoutEndTag
                    }
                };
            var descriptorProvider = new TagHelperDescriptorProvider(descriptors);

            // Act & Assert
            EvaluateData(descriptorProvider, documentContent, expectedOutput, expectedErrors: new[] { expectedError });
        }
        public void GetDescriptors_ReturnsNothingForUnregisteredTags()
        {
            // Arrange
            var divDescriptor = new TagHelperDescriptor
            {
                TagName = "div",
                TypeName = "foo1",
                AssemblyName = "SomeAssembly",
            };
            var spanDescriptor = new TagHelperDescriptor
            {
                TagName = "span",
                TypeName = "foo2",
                AssemblyName = "SomeAssembly",
            };
            var descriptors = new TagHelperDescriptor[] { divDescriptor, spanDescriptor };
            var provider = new TagHelperDescriptorProvider(descriptors);

            // Act
            var retrievedDescriptors = provider.GetDescriptors("foo", attributeNames: Enumerable.Empty<string>());

            // Assert
            Assert.Empty(retrievedDescriptors);
        }
        public void Rewrite_CanHandleStartTagOnlyTagTagMode()
        {
            // Arrange
            var documentContent = "<input>";
            var expectedOutput = new MarkupBlock(new MarkupTagHelperBlock("input", TagMode.StartTagOnly));
            var descriptors = new TagHelperDescriptor[]
                {
                    new TagHelperDescriptor
                    {
                        TagName = "input",
                        TypeName = "InputTagHelper",
                        AssemblyName = "SomeAssembly",
                        TagStructure = TagStructure.WithoutEndTag
                    }
                };
            var descriptorProvider = new TagHelperDescriptorProvider(descriptors);

            // Act & Assert
            EvaluateData(descriptorProvider, documentContent, expectedOutput, expectedErrors: new RazorError[0]);
        }
        public void GetDescriptors_DuplicateDescriptorsAreNotPartOfTagHelperDescriptorPool()
        {
            // Arrange
            var divDescriptor = new TagHelperDescriptor
            {
                TagName = "div",
                TypeName = "foo1",
                AssemblyName = "SomeAssembly",
            };
            var descriptors = new TagHelperDescriptor[] { divDescriptor, divDescriptor };
            var provider = new TagHelperDescriptorProvider(descriptors);

            // Act
            var retrievedDescriptors = provider.GetDescriptors("div", attributeNames: Enumerable.Empty<string>());

            // Assert
            var descriptor = Assert.Single(retrievedDescriptors);
            Assert.Same(divDescriptor, descriptor);
        }
        public void Rewrite_RecoversWhenRequiredAttributeMismatchAndRestrictedChildren()
        {
            // Arrange
            var factory = CreateDefaultSpanFactory();
            var blockFactory = new BlockFactory(factory);
            var documentContent = "<strong required><strong></strong></strong>";

            var expectedErrors = new[] {
                new RazorError(
                    RazorResources.FormatTagHelperParseTreeRewriter_InvalidNestedTag("strong", "strong", "br"),
                    absoluteIndex: 17,
                    lineIndex: 0,
                    columnIndex: 17,
                    length: 8),
                new RazorError(
                    RazorResources.FormatTagHelperParseTreeRewriter_InvalidNestedTag("strong", "strong", "br"),
                    absoluteIndex: 25,
                    lineIndex: 0,
                    columnIndex: 25,
                    length: 9),
            };
            var expectedOutput = new MarkupBlock(
                new MarkupTagHelperBlock("strong",
                    new List<KeyValuePair<string, SyntaxTreeNode>>
                    {
                        new KeyValuePair<string, SyntaxTreeNode>("required", null)
                    },
                    blockFactory.MarkupTagBlock("<strong>"),
                    blockFactory.MarkupTagBlock("</strong>")));
            var descriptors = new TagHelperDescriptor[]
                {
                    new TagHelperDescriptor
                    {
                        TagName = "strong",
                        TypeName = "StrongTagHelper",
                        AssemblyName = "SomeAssembly",
                        RequiredAttributes = new[] { "required" },
                        AllowedChildren = new[] { "br" }
                    }
                };
            var descriptorProvider = new TagHelperDescriptorProvider(descriptors);

            // Act & Assert
            EvaluateData(descriptorProvider, documentContent, expectedOutput, expectedErrors);
        }