From 23e6264715b0055218611b3f36ac45098f6b0fb1 Mon Sep 17 00:00:00 2001 From: Youngjune Hong Date: Tue, 10 Feb 2015 09:30:47 -0800 Subject: [PATCH] Fix1571 - Supporting self-closing tags for taghelpers --- .../TagHelpers/TagHelperExecutionContext.cs | 13 +- .../TagHelpers/TagHelperOutput.cs | 45 +++-- .../TagHelpers/TagHelperRunner.cs | 5 +- .../TagHelpers/TagHelperScopeManager.cs | 5 + .../CSharp/CSharpTagHelperCodeRenderer.cs | 9 +- .../Chunks/TagHelpers/TagHelperChunk.cs | 28 +++ .../Generator/TagHelperCodeGenerator.cs | 11 +- .../Parser/TagHelpers/TagHelperBlock.cs | 6 + .../TagHelpers/TagHelperBlockBuilder.cs | 14 +- .../TagHelpers/TagHelperBlockRewriter.cs | 10 +- .../TagHelpers/TagHelperParseTreeRewriter.cs | 11 +- .../TagHelperExecutionContextTest.cs | 27 ++- .../TagHelpers/TagHelperOutputTest.cs | 75 +++++++- .../TagHelpers/TagHelperRunnerTest.cs | 28 ++- .../TagHelpers/TagHelperScopeManagerTest.cs | 112 ++++++++---- .../Framework/BlockTypes.cs | 38 +++- .../Framework/ParserTestBase.cs | 17 ++ .../CSharpTagHelperRenderingUnitTest.cs | 9 +- .../TagHelperParseTreeRewriterTest.cs | 171 ++++++++++-------- ...TagHelpers.CustomAttributeCodeGenerator.cs | 8 +- .../CS/Output/BasicTagHelpers.cs | 8 +- .../CS/Output/ComplexTagHelpers.cs | 30 +-- .../CS/Output/EmptyAttributeTagHelpers.cs | 6 +- .../CS/Output/EscapedTagHelpers.cs | 2 +- .../CS/Output/SingleTagHelper.cs | 2 +- .../CS/Output/TagHelpersInHelper.cs | 8 +- .../CS/Output/TagHelpersInSection.cs | 4 +- 27 files changed, 498 insertions(+), 204 deletions(-) diff --git a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperExecutionContext.cs b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperExecutionContext.cs index 03593d80fa..ada91b1458 100644 --- a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperExecutionContext.cs +++ b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperExecutionContext.cs @@ -22,8 +22,9 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers /// /// Internal for testing purposes only. /// - internal TagHelperExecutionContext(string tagName) + internal TagHelperExecutionContext(string tagName, bool selfClosing) : this(tagName, + selfClosing, uniqueId: string.Empty, executeChildContentAsync: async () => await Task.FromResult(result: true), startWritingScope: () => { }, @@ -35,11 +36,15 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers /// Instantiates a new . /// /// The HTML tag name in the Razor source. + /// + /// indicating whether or not the tag in the Razor source was self-closing. + /// /// An identifier unique to the HTML element this context is for. /// A delegate used to execute the child content asynchronously. /// A delegate used to start a writing scope in a Razor page. /// A delegate used to end a writing scope in a Razor page. public TagHelperExecutionContext([NotNull] string tagName, + bool selfClosing, [NotNull] string uniqueId, [NotNull] Func executeChildContentAsync, [NotNull] Action startWritingScope, @@ -50,12 +55,18 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers _startWritingScope = startWritingScope; _endWritingScope = endWritingScope; + SelfClosing = selfClosing; AllAttributes = new Dictionary(StringComparer.OrdinalIgnoreCase); HTMLAttributes = new Dictionary(StringComparer.OrdinalIgnoreCase); TagName = tagName; UniqueId = uniqueId; } + /// + /// Gets a value indicating whether or not the tag in the Razor source was self-closing. + /// + public bool SelfClosing { get; } + /// /// Indicates if has been called. /// diff --git a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperOutput.cs b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperOutput.cs index 54e54e9f9c..b94aed2c03 100644 --- a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperOutput.cs +++ b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperOutput.cs @@ -16,6 +16,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { private string _content; private bool _contentSet; + private bool _isTagNameNullOrWhitespace; + private string _tagName; // Internal for testing internal TagHelperOutput(string tagName) @@ -44,7 +46,18 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers /// /// A whitespace or null value results in no start or end tag being rendered. /// - public string TagName { get; set; } + public string TagName + { + get + { + return _tagName; + } + set + { + _tagName = value; + _isTagNameNullOrWhitespace = string.IsNullOrWhiteSpace(_tagName); + } + } /// /// The HTML element's pre content. @@ -88,7 +101,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers } /// - /// Indicates whether or not the tag is self closing. + /// Indicates whether or not the tag is self-closing. /// public bool SelfClosing { get; set; } @@ -100,12 +113,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers /// /// Generates the 's start tag. /// - /// string.Empty if is string.Empty or whitespace. Otherwise, the + /// string.Empty if is null or whitespace. Otherwise, the /// representation of the 's start tag. public string GenerateStartTag() { // Only render a start tag if the tag name is not whitespace - if (string.IsNullOrWhiteSpace(TagName)) + if (_isTagNameNullOrWhitespace) { return string.Empty; } @@ -138,12 +151,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers /// /// Generates the 's . /// - /// string.Empty if is true. - /// otherwise. - /// + /// string.Empty if is not null or whitespace + /// and is true. Otherwise, . public string GeneratePreContent() { - if (SelfClosing) + if (!_isTagNameNullOrWhitespace && SelfClosing) { return string.Empty; } @@ -154,11 +166,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers /// /// Generates the 's body. /// - /// string.Empty if is true. otherwise. - /// + /// string.Empty if is not null or whitespace + /// and is true. Otherwise, . public string GenerateContent() { - if (SelfClosing) + if (!_isTagNameNullOrWhitespace && SelfClosing) { return string.Empty; } @@ -169,12 +181,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers /// /// Generates the 's . /// - /// string.Empty if is true. - /// otherwise. - /// + /// string.Empty if is not null or whitespace + /// and is true. Otherwise, . public string GeneratePostContent() { - if (SelfClosing) + if (!_isTagNameNullOrWhitespace && SelfClosing) { return string.Empty; } @@ -185,11 +196,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers /// /// Generates the 's end tag. /// - /// string.Empty if is string.Empty or whitespace. Otherwise, the + /// string.Empty if is null or whitespace. Otherwise, the /// representation of the 's end tag. public string GenerateEndTag() { - if (SelfClosing || string.IsNullOrWhiteSpace(TagName)) + if (SelfClosing || _isTagNameNullOrWhitespace) { return string.Empty; } diff --git a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperRunner.cs b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperRunner.cs index add873c256..5325bf2d8c 100644 --- a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperRunner.cs +++ b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperRunner.cs @@ -24,7 +24,10 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers executionContext.AllAttributes, executionContext.UniqueId, executionContext.GetChildContentAsync); - var tagHelperOutput = new TagHelperOutput(executionContext.TagName, executionContext.HTMLAttributes); + var tagHelperOutput = new TagHelperOutput(executionContext.TagName, executionContext.HTMLAttributes) + { + SelfClosing = executionContext.SelfClosing, + }; var orderedTagHelpers = executionContext.TagHelpers.OrderBy(tagHelper => tagHelper.Order); foreach (var tagHelper in orderedTagHelpers) diff --git a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperScopeManager.cs b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperScopeManager.cs index b89eb89eda..2ab6163840 100644 --- a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperScopeManager.cs +++ b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperScopeManager.cs @@ -27,18 +27,23 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers /// Starts a scope. /// /// The HTML tag name that the scope is associated with. + /// + /// indicating whether or not the tag of this scope is self-closing. + /// /// An identifier unique to the HTML element this scope is for. /// A delegate used to execute the child content asynchronously. /// A delegate used to start a writing scope in a Razor page. /// A delegate used to end a writing scope in a Razor page. /// A to use. public TagHelperExecutionContext Begin([NotNull] string tagName, + bool selfClosing, [NotNull] string uniqueId, [NotNull] Func executeChildContentAsync, [NotNull] Action startWritingScope, [NotNull] Func endWritingScope) { var executionContext = new TagHelperExecutionContext(tagName, + selfClosing, uniqueId, executeChildContentAsync, startWritingScope, diff --git a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/CSharpTagHelperCodeRenderer.cs b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/CSharpTagHelperCodeRenderer.cs index 25be0ecb81..e11bf194b7 100644 --- a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/CSharpTagHelperCodeRenderer.cs +++ b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/CSharpTagHelperCodeRenderer.cs @@ -58,7 +58,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp { var tagHelperDescriptors = chunk.Descriptors; - RenderBeginTagHelperScope(chunk.TagName, chunk.Children); + RenderBeginTagHelperScope(chunk.TagName, chunk.SelfClosing, chunk.Children); RenderTagHelpersCreation(chunk); @@ -89,7 +89,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp return "__" + descriptor.TypeName.Replace('.', '_'); } - private void RenderBeginTagHelperScope(string tagName, IList children) + private void RenderBeginTagHelperScope(string tagName, bool selfClosing, IList children) { // Scopes/execution contexts are a runtime feature. if (_designTimeMode) @@ -108,6 +108,8 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp // Assign a unique ID for this instance of the source HTML tag. This must be unique // per call site, e.g. if the tag is on the view twice, there should be two IDs. _writer.WriteStringLiteral(tagName) + .WriteParameterSeparator() + .WriteBooleanLiteral(selfClosing) .WriteParameterSeparator() .WriteStringLiteral(GenerateUniqueId()) .WriteParameterSeparator(); @@ -466,8 +468,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp _writer.Write(ExecutionContextVariableName) .Write(".") - .Write(_tagHelperContext.ExecutionContextOutputPropertyName) - .Write(" = ") + .WriteStartAssignment(_tagHelperContext.ExecutionContextOutputPropertyName) .WriteStartInstanceMethodInvocation(RunnerVariableName, _tagHelperContext.RunnerRunAsyncMethodName); diff --git a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeTree/Chunks/TagHelpers/TagHelperChunk.cs b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeTree/Chunks/TagHelpers/TagHelperChunk.cs index 4e5f5c1478..2db0761d18 100644 --- a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeTree/Chunks/TagHelpers/TagHelperChunk.cs +++ b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeTree/Chunks/TagHelpers/TagHelperChunk.cs @@ -11,6 +11,29 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler /// public class TagHelperChunk : ChunkBlock { + /// + /// Instantiates a new . + /// + /// The tag name associated with the tag helpers HTML element. + /// + /// indicating whether or not the tag of the tag helpers HTML element is self-closing. + /// + /// The attributes associated with the tag helpers HTML element. + /// + /// The s associated with this tag helpers HTML element. + /// + public TagHelperChunk( + string tagName, + bool selfClosing, + IDictionary attributes, + IEnumerable descriptors) + { + TagName = tagName; + SelfClosing = selfClosing; + Attributes = attributes; + Descriptors = descriptors; + } + /// /// The HTML attributes. /// @@ -29,5 +52,10 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler /// The HTML tag name. /// public string TagName { get; set; } + + /// + /// Gets a value indicating whether or not the tag of the tag helpers HTML element is self-closing. + /// + public bool SelfClosing { get; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Razor/Generator/TagHelperCodeGenerator.cs b/src/Microsoft.AspNet.Razor/Generator/TagHelperCodeGenerator.cs index d09b718051..a25b393964 100644 --- a/src/Microsoft.AspNet.Razor/Generator/TagHelperCodeGenerator.cs +++ b/src/Microsoft.AspNet.Razor/Generator/TagHelperCodeGenerator.cs @@ -76,12 +76,11 @@ namespace Microsoft.AspNet.Razor.Generator } context.CodeTreeBuilder.StartChunkBlock( - new TagHelperChunk - { - TagName = tagHelperBlock.TagName, - Attributes = attributes, - Descriptors = _tagHelperDescriptors - }, + new TagHelperChunk( + tagHelperBlock.TagName, + tagHelperBlock.SelfClosing, + attributes, + _tagHelperDescriptors), target, topLevel: false); } diff --git a/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlock.cs b/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlock.cs index 798b99771f..01ce3eda60 100644 --- a/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlock.cs +++ b/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlock.cs @@ -31,6 +31,7 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers Descriptors = source.Descriptors; Attributes = new Dictionary(source.Attributes); _start = source.Start; + SelfClosing = source.SelfClosing; source.Reset(); @@ -40,6 +41,11 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers } } + /// + /// Indicates whether or not the tag is self closing. + /// + public bool SelfClosing { get; } + /// /// s for the HTML element. /// diff --git a/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockBuilder.cs b/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockBuilder.cs index 629e955d90..5854125e45 100644 --- a/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockBuilder.cs +++ b/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockBuilder.cs @@ -33,29 +33,36 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers /// and from the . /// /// An HTML tag name. + /// + /// indicating whether or not the tag in the Razor source was self-closing. + /// /// Starting location of the . /// Attributes of the . /// The s associated with the current HTML /// tag. public TagHelperBlockBuilder(string tagName, + bool selfClosing, SourceLocation start, IDictionary attributes, IEnumerable descriptors) { TagName = tagName; + SelfClosing = selfClosing; Start = start; Descriptors = descriptors; + Attributes = new Dictionary(attributes); Type = BlockType.Tag; CodeGenerator = new TagHelperCodeGenerator(descriptors); - Attributes = new Dictionary(attributes); } // Internal for testing internal TagHelperBlockBuilder(string tagName, + bool selfClosing, IDictionary attributes, IEnumerable children) { TagName = tagName; + SelfClosing = selfClosing; Attributes = attributes; Type = BlockType.Tag; CodeGenerator = new TagHelperCodeGenerator(tagHelperDescriptors: null); @@ -67,6 +74,11 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers } } + /// + /// Gets a value indicating whether or not the tag in the Razor source was self-closing. + /// + public bool SelfClosing { get; } + /// /// s for the HTML element. /// diff --git a/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockRewriter.cs b/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockRewriter.cs index 410fdc9ad4..5f04ad04f1 100644 --- a/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockRewriter.cs +++ b/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperBlockRewriter.cs @@ -26,8 +26,9 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal // There will always be at least one child for the '<'. var start = tag.Children.First().Start; var attributes = GetTagAttributes(tagName, validStructure, tag, descriptors, errorSink); + var selfClosing = IsSelfClosing(tag); - return new TagHelperBlockBuilder(tagName, start, attributes, descriptors); + return new TagHelperBlockBuilder(tagName, selfClosing, start, attributes, descriptors); } private static IDictionary GetTagAttributes( @@ -94,6 +95,13 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal return attributes; } + private static bool IsSelfClosing(Block beginTagBlock) + { + var childSpan = beginTagBlock.FindLastDescendentSpan(); + + return childSpan?.Content.EndsWith("/>") ?? false; + } + // This method handles cases when the attribute is a simple span attribute such as // class="something moresomething". This does not handle complex attributes such as // class="@myclass". Therefore the span.Content is equivalent to the entire attribute. diff --git a/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperParseTreeRewriter.cs b/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperParseTreeRewriter.cs index da8b97b3b9..2be211dbe7 100644 --- a/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperParseTreeRewriter.cs +++ b/src/Microsoft.AspNet.Razor/Parser/TagHelpers/TagHelperParseTreeRewriter.cs @@ -132,7 +132,7 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal // If it's a self closing block then we don't have to worry about nested children // within the tag... complete it. - if (IsSelfClosing(tagBlock)) + if (builder.SelfClosing) { BuildCurrentlyTrackedTagHelperBlock(); } @@ -334,15 +334,6 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal return textSymbol.Type == HtmlSymbolType.WhiteSpace ? null : textSymbol.Content; } - private static bool IsSelfClosing(Block beginTagBlock) - { - EnsureTagBlock(beginTagBlock); - - var childSpan = beginTagBlock.Children.Last() as Span; - - return childSpan?.Content.EndsWith("/>") ?? false; - } - private static bool IsEndTag(Block tagBlock) { EnsureTagBlock(tagBlock); diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperExecutionContextTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperExecutionContextTest.cs index 909eae7a5e..8a39681239 100644 --- a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperExecutionContextTest.cs +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperExecutionContextTest.cs @@ -12,6 +12,19 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { public class TagHelperExecutionContextTest { + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void SelfClosing_ReturnsTrueOrFalseAsExpected(bool selfClosing) + { + // Arrange & Act + var executionContext = new TagHelperExecutionContext("p", selfClosing); + + // Assert + Assert.Equal(selfClosing, executionContext.SelfClosing); + } + [Fact] public async Task GetChildContentAsync_CachesValue() { @@ -20,6 +33,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var expectedContent = string.Empty; var executionContext = new TagHelperExecutionContext( "p", + selfClosing: false, uniqueId: string.Empty, executeChildContentAsync: () => { @@ -52,6 +66,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var childContentExecutionCount = 0; var executionContext = new TagHelperExecutionContext( "p", + selfClosing: false, uniqueId: string.Empty, executeChildContentAsync: () => { @@ -88,7 +103,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers public void HtmlAttributes_IgnoresCase(string originalName, string updatedName) { // Arrange - var executionContext = new TagHelperExecutionContext("p"); + var executionContext = new TagHelperExecutionContext("p", selfClosing: false); executionContext.HTMLAttributes[originalName] = "hello"; // Act @@ -103,7 +118,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers public void AllAttributes_IgnoresCase(string originalName, string updatedName) { // Arrange - var executionContext = new TagHelperExecutionContext("p"); + var executionContext = new TagHelperExecutionContext("p", selfClosing: false); executionContext.AllAttributes[originalName] = false; // Act @@ -118,7 +133,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers public void AddHtmlAttribute_MaintainsHTMLAttributes() { // Arrange - var executionContext = new TagHelperExecutionContext("p"); + var executionContext = new TagHelperExecutionContext("p", selfClosing: false); var expectedAttributes = new Dictionary { { "class", "btn" }, @@ -137,7 +152,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers public void TagHelperExecutionContext_MaintainsAllAttributes() { // Arrange - var executionContext = new TagHelperExecutionContext("p"); + var executionContext = new TagHelperExecutionContext("p", selfClosing: false); var expectedAttributes = new Dictionary { { "class", "btn" }, @@ -158,7 +173,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers public void Add_MaintainsTagHelpers() { // Arrange - var executionContext = new TagHelperExecutionContext("p"); + var executionContext = new TagHelperExecutionContext("p", selfClosing: false); var tagHelper = new PTagHelper(); // Act @@ -173,7 +188,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers public void Add_MaintainsMultipleTagHelpers() { // Arrange - var executionContext = new TagHelperExecutionContext("p"); + var executionContext = new TagHelperExecutionContext("p", selfClosing: false); var tagHelper1 = new PTagHelper(); var tagHelper2 = new PTagHelper(); diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperOutputTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperOutputTest.cs index 343853447e..11e1837377 100644 --- a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperOutputTest.cs +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperOutputTest.cs @@ -191,7 +191,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers } [Fact] - public void GeneratePreContent_ReturnsNothingIfSelfClosing() + public void GeneratePreContent_ReturnsNothingIfSelfClosingWhenTagNameIsNotNullOrWhitespace() { // Arrange var tagHelperOutput = new TagHelperOutput("p") @@ -207,6 +207,29 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers Assert.Empty(output); } + [Theory] + [InlineData(null, true)] + [InlineData("\t", true )] + [InlineData(null, false)] + [InlineData("\t", false)] + public void GeneratePreContent_ReturnsPreContentIfTagNameIsNullOrWhitespace(string tagName, bool selfClosing) + { + // Arrange + var expectedContent = "Hello World"; + + var tagHelperOutput = new TagHelperOutput(tagName) + { + SelfClosing = selfClosing, + PreContent = expectedContent + }; + + // Act + var output = tagHelperOutput.GeneratePreContent(); + + // Assert + Assert.Same(expectedContent, output); + } + [Fact] public void GenerateContent_ReturnsContent() { @@ -225,7 +248,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers [Fact] - public void GenerateContent_ReturnsNothingIfSelfClosing() + public void GenerateContent_ReturnsNothingIfSelfClosingWhenTagNameIsNotNullOrWhitespace() { // Arrange var tagHelperOutput = new TagHelperOutput("p") @@ -241,6 +264,29 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers Assert.Empty(output); } + [Theory] + [InlineData(null, true)] + [InlineData("\t", true )] + [InlineData(null, false)] + [InlineData("\t", false)] + public void GenerateContent_ReturnsContentIfTagNameIsNullOrWhitespace(string tagName, bool selfClosing) + { + // Arrange + var expectedContent = "Hello World"; + + var tagHelperOutput = new TagHelperOutput(tagName) + { + SelfClosing = selfClosing, + Content = expectedContent + }; + + // Act + var output = tagHelperOutput.GenerateContent(); + + // Assert + Assert.Same(expectedContent, output); + } + [Fact] public void GeneratePostContent_ReturnsPostContent() { @@ -258,7 +304,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers } [Fact] - public void GeneratePostContent_ReturnsNothingIfSelfClosing() + public void GeneratePostContent_ReturnsNothingIfSelfClosingWhenTagNameIsNotNullOrWhitespace() { // Arrange var tagHelperOutput = new TagHelperOutput("p") @@ -287,6 +333,29 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers Assert.Equal("

", output); } + [Theory] + [InlineData(null, true)] + [InlineData("\t", true )] + [InlineData(null, false)] + [InlineData("\t", false)] + public void GeneratePostContent_ReturnsPostContentIfTagNameIsNullOrWhitespace(string tagName, bool selfClosing) + { + // Arrange + var expectedContent = "Hello World"; + + var tagHelperOutput = new TagHelperOutput(tagName) + { + SelfClosing = selfClosing, + PostContent = expectedContent + }; + + // Act + var output = tagHelperOutput.GeneratePostContent(); + + // Assert + Assert.Equal(expectedContent, output); + } + [Fact] public void GenerateEndTag_ReturnsNothingIfSelfClosing() { diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperRunnerTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperRunnerTest.cs index a54d83d53e..d85f0e08f5 100644 --- a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperRunnerTest.cs +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperRunnerTest.cs @@ -62,7 +62,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { // Arrange var runner = new TagHelperRunner(); - var executionContext = new TagHelperExecutionContext("p"); + var executionContext = new TagHelperExecutionContext("p", selfClosing: false); var processOrder = new List(); foreach (var order in tagHelperOrders) @@ -81,12 +81,32 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers Assert.Equal(expectedTagHelperOrders, processOrder); } + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task RunAsync_SetTagHelperOutputSelfClosing(bool selfClosing) + { + // Arrange + var runner = new TagHelperRunner(); + var executionContext = new TagHelperExecutionContext("p", selfClosing); + var tagHelper = new TagHelperContextTouchingTagHelper(); + + executionContext.Add(tagHelper); + executionContext.AddTagHelperAttribute("foo", true); + + // Act + var output = await runner.RunAsync(executionContext); + + // Assert + Assert.Equal(selfClosing, output.SelfClosing); + } + [Fact] public async Task RunAsync_ProcessesAllTagHelpers() { // Arrange var runner = new TagHelperRunner(); - var executionContext = new TagHelperExecutionContext("p"); + var executionContext = new TagHelperExecutionContext("p", selfClosing: false); var executableTagHelper1 = new ExecutableTagHelper(); var executableTagHelper2 = new ExecutableTagHelper(); @@ -105,7 +125,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { // Arrange var runner = new TagHelperRunner(); - var executionContext = new TagHelperExecutionContext("p"); + var executionContext = new TagHelperExecutionContext("p", selfClosing: false); var executableTagHelper = new ExecutableTagHelper(); // Act @@ -125,7 +145,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { // Arrange var runner = new TagHelperRunner(); - var executionContext = new TagHelperExecutionContext("p"); + var executionContext = new TagHelperExecutionContext("p", selfClosing: false); var tagHelper = new TagHelperContextTouchingTagHelper(); // Act diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperScopeManagerTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperScopeManagerTest.cs index 3fc94323c4..a318659d84 100644 --- a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperScopeManagerTest.cs +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperScopeManagerTest.cs @@ -23,11 +23,13 @@ namespace Microsoft.AspNet.Razor.Runtime.Test.TagHelpers var scopeManager = new TagHelperScopeManager(); // Act - var executionContext = scopeManager.Begin("p", - string.Empty, - DefaultExecuteChildContentAsync, - DefaultStartWritingScope, - DefaultEndWritingScope); + var executionContext = scopeManager.Begin( + "p", + selfClosing: false, + uniqueId: string.Empty, + executeChildContentAsync: DefaultExecuteChildContentAsync, + startWritingScope: DefaultStartWritingScope, + endWritingScope: DefaultEndWritingScope); // Assert Assert.Equal("p", executionContext.TagName); @@ -40,38 +42,70 @@ namespace Microsoft.AspNet.Razor.Runtime.Test.TagHelpers var scopeManager = new TagHelperScopeManager(); // Act - var executionContext = scopeManager.Begin("p", - string.Empty, - DefaultExecuteChildContentAsync, - DefaultStartWritingScope, - DefaultEndWritingScope); - executionContext = scopeManager.Begin("div", - string.Empty, - DefaultExecuteChildContentAsync, - DefaultStartWritingScope, - DefaultEndWritingScope); + var executionContext = scopeManager.Begin( + "p", + selfClosing: false, + uniqueId: string.Empty, + executeChildContentAsync: DefaultExecuteChildContentAsync, + startWritingScope: DefaultStartWritingScope, + endWritingScope: DefaultEndWritingScope); + + executionContext = scopeManager.Begin( + "div", + selfClosing: false, + uniqueId: string.Empty, + executeChildContentAsync: DefaultExecuteChildContentAsync, + startWritingScope: DefaultStartWritingScope, + endWritingScope: DefaultEndWritingScope); // Assert Assert.Equal("div", executionContext.TagName); } - [Fact] + [Theory] + [InlineData("true")] + [InlineData("false")] + public void Begin_SetExecutionContextSelfClosing(bool selfClosing) + { + // Arrange + var scopeManager = new TagHelperScopeManager(); + + // Act + var executionContext = scopeManager.Begin( + "p", + selfClosing: selfClosing, + uniqueId: string.Empty, + executeChildContentAsync: DefaultExecuteChildContentAsync, + startWritingScope: DefaultStartWritingScope, + endWritingScope: DefaultEndWritingScope); + + // Assert + Assert.Equal(selfClosing, executionContext.SelfClosing); + } + + [Fact] public void End_ReturnsParentExecutionContext() { // Arrange var scopeManager = new TagHelperScopeManager(); // Act - var executionContext = scopeManager.Begin("p", - string.Empty, - DefaultExecuteChildContentAsync, - DefaultStartWritingScope, - DefaultEndWritingScope); - executionContext = scopeManager.Begin("div", - string.Empty, - DefaultExecuteChildContentAsync, - DefaultStartWritingScope, - DefaultEndWritingScope); + var executionContext = scopeManager.Begin( + "p", + selfClosing: false, + uniqueId: string.Empty, + executeChildContentAsync: DefaultExecuteChildContentAsync, + startWritingScope: DefaultStartWritingScope, + endWritingScope: DefaultEndWritingScope); + + executionContext = scopeManager.Begin( + "div", + selfClosing: false, + uniqueId: string.Empty, + executeChildContentAsync: DefaultExecuteChildContentAsync, + startWritingScope: DefaultStartWritingScope, + endWritingScope: DefaultEndWritingScope); + executionContext = scopeManager.End(); // Assert @@ -85,16 +119,22 @@ namespace Microsoft.AspNet.Razor.Runtime.Test.TagHelpers var scopeManager = new TagHelperScopeManager(); // Act - var executionContext = scopeManager.Begin("p", - string.Empty, - DefaultExecuteChildContentAsync, - DefaultStartWritingScope, - DefaultEndWritingScope); - executionContext = scopeManager.Begin("div", - string.Empty, - DefaultExecuteChildContentAsync, - DefaultStartWritingScope, - DefaultEndWritingScope); + var executionContext = scopeManager.Begin( + "p", + selfClosing: false, + uniqueId: string.Empty, + executeChildContentAsync: DefaultExecuteChildContentAsync, + startWritingScope: DefaultStartWritingScope, + endWritingScope: DefaultEndWritingScope); + + executionContext = scopeManager.Begin( + "div", + selfClosing: false, + uniqueId: string.Empty, + executeChildContentAsync: DefaultExecuteChildContentAsync, + startWritingScope: DefaultStartWritingScope, + endWritingScope: DefaultEndWritingScope); + executionContext = scopeManager.End(); executionContext = scopeManager.End(); diff --git a/test/Microsoft.AspNet.Razor.Test/Framework/BlockTypes.cs b/test/Microsoft.AspNet.Razor.Test/Framework/BlockTypes.cs index b25954eab4..2b3b96717a 100644 --- a/test/Microsoft.AspNet.Razor.Test/Framework/BlockTypes.cs +++ b/test/Microsoft.AspNet.Razor.Test/Framework/BlockTypes.cs @@ -178,26 +178,54 @@ namespace Microsoft.AspNet.Razor.Test.Framework public class MarkupTagHelperBlock : TagHelperBlock { public MarkupTagHelperBlock(string tagName) - : this(tagName, new Dictionary()) + : this(tagName, selfClosing: false, attributes: new Dictionary()) + { + } + + public MarkupTagHelperBlock(string tagName, bool selfClosing) + : this(tagName, selfClosing, new Dictionary()) { } public MarkupTagHelperBlock(string tagName, IDictionary attributes) - : this(tagName, attributes, new SyntaxTreeNode[0]) + : this(tagName, selfClosing: false, attributes: attributes, children: new SyntaxTreeNode[0]) { } public MarkupTagHelperBlock(string tagName, - params SyntaxTreeNode[] children) - : this(tagName, new Dictionary(), children) + bool selfClosing, + IDictionary attributes) + : this(tagName, selfClosing, attributes, new SyntaxTreeNode[0]) + { + } + + public MarkupTagHelperBlock(string tagName, params SyntaxTreeNode[] children) + : this( + tagName, + selfClosing: false, + attributes: new Dictionary(), + children: children) + { + } + + public MarkupTagHelperBlock(string tagName, bool selfClosing, params SyntaxTreeNode[] children) + : this(tagName, selfClosing, new Dictionary(), children) { } public MarkupTagHelperBlock(string tagName, IDictionary attributes, params SyntaxTreeNode[] children) - : base(new TagHelperBlockBuilder(tagName, attributes, children)) + : base(new TagHelperBlockBuilder(tagName, selfClosing: false, attributes: attributes, children: children)) + { + } + + public MarkupTagHelperBlock(string tagName, + bool selfClosing, + IDictionary attributes, + params SyntaxTreeNode[] children) + : base(new TagHelperBlockBuilder(tagName, selfClosing, attributes, children)) { } } diff --git a/test/Microsoft.AspNet.Razor.Test/Framework/ParserTestBase.cs b/test/Microsoft.AspNet.Razor.Test/Framework/ParserTestBase.cs index 33516b6058..dfe5340130 100644 --- a/test/Microsoft.AspNet.Razor.Test/Framework/ParserTestBase.cs +++ b/test/Microsoft.AspNet.Razor.Test/Framework/ParserTestBase.cs @@ -398,6 +398,23 @@ namespace Microsoft.AspNet.Razor.Test.Framework } else { + if (!string.Equals(expected.TagName, actual.TagName, StringComparison.Ordinal)) + { + collector.AddError( + "{0} - FAILED :: TagName mismatch for TagHelperBlock :: ACTUAL: {1}", + expected.TagName, + actual.TagName); + } + + if (expected.SelfClosing != actual.SelfClosing) + { + collector.AddError( + "{0} - FAILED :: SelfClosing for TagHelperBlock {1} :: ACTUAL: {2}", + expected.SelfClosing, + actual.TagName, + actual.SelfClosing); + } + var expectedAttributes = expected.Attributes.GetEnumerator(); var actualAttributes = actual.Attributes.GetEnumerator(); diff --git a/test/Microsoft.AspNet.Razor.Test/Generator/CSharpTagHelperRenderingUnitTest.cs b/test/Microsoft.AspNet.Razor.Test/Generator/CSharpTagHelperRenderingUnitTest.cs index ea9525b913..5d9cfbef3c 100644 --- a/test/Microsoft.AspNet.Razor.Test/Generator/CSharpTagHelperRenderingUnitTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/Generator/CSharpTagHelperRenderingUnitTest.cs @@ -131,12 +131,13 @@ namespace Microsoft.AspNet.Razor.Test.Generator private static TagHelperChunk CreateTagHelperChunk(string tagName, IEnumerable tagHelperDescriptors) { - return new TagHelperChunk + return new TagHelperChunk( + tagName, + selfClosing: false, + attributes: new Dictionary(), + descriptors: tagHelperDescriptors) { - TagName = tagName, - Descriptors = tagHelperDescriptors, Children = new List(), - Attributes = new Dictionary() }; } diff --git a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs index 4ca19e04a5..58a460b966 100644 --- a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs @@ -37,7 +37,8 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "myth", - new Dictionary + selfClosing: true, + attributes: new Dictionary { { "bound", new MarkupBlock() } })), @@ -53,7 +54,8 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "myth", - new Dictionary + selfClosing: true, + attributes: new Dictionary { { "bound", factory.CodeMarkup(" true") } })), @@ -64,7 +66,8 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "myth", - new Dictionary + selfClosing: true, + attributes: new Dictionary { { "bound", factory.CodeMarkup(" ") } })), @@ -80,7 +83,8 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "myth", - new Dictionary + selfClosing: true, + attributes: new Dictionary { { "bound", new MarkupBlock() } })), @@ -99,7 +103,8 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "myth", - new Dictionary + selfClosing: true, + attributes: new Dictionary { { "bound", factory.CodeMarkup(" ") } })), @@ -118,7 +123,8 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "myth", - new Dictionary + selfClosing: true, + attributes: new Dictionary { { "bound", factory.CodeMarkup(string.Empty).With(SpanCodeGenerator.Null) } })), @@ -134,7 +140,8 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "myth", - new Dictionary + selfClosing: true, + attributes: new Dictionary { { "bound", factory.CodeMarkup(string.Empty).With(SpanCodeGenerator.Null) }, { "name", new MarkupBlock() } @@ -151,7 +158,8 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "myth", - new Dictionary + selfClosing: true, + attributes: new Dictionary { { "bound", factory.CodeMarkup(string.Empty).With(SpanCodeGenerator.Null) }, { "name", factory.Markup(" ") } @@ -168,7 +176,8 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "myth", - new Dictionary + selfClosing: true, + attributes: new Dictionary { { "bound", factory.CodeMarkup(string.Empty).With(SpanCodeGenerator.Null) }, { "name", factory.Markup(string.Empty).With(SpanCodeGenerator.Null) } @@ -185,7 +194,8 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "myth", - new Dictionary + selfClosing: true, + attributes: new Dictionary { { "BouND", new MarkupBlock() } })), @@ -201,7 +211,8 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "myth", - new Dictionary + selfClosing: true, + attributes: new Dictionary { { "BOUND", new MarkupBlock() } })), @@ -237,7 +248,8 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "myth", - new Dictionary + selfClosing: true, + attributes: new Dictionary { { "bound", @@ -259,7 +271,8 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "myth", - new Dictionary + selfClosing: true, + attributes: new Dictionary { { "bound", @@ -1990,23 +2003,25 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers "

", new MarkupBlock( new MarkupTagHelperBlock("p", - new Dictionary - { - { "class1", new MarkupBlock() }, - { "class2", factory.Markup("").With(SpanCodeGenerator.Null) }, - { "class3", new MarkupBlock() }, - })) + selfClosing: true, + attributes: new Dictionary + { + { "class1", new MarkupBlock() }, + { "class2", factory.Markup("").With(SpanCodeGenerator.Null) }, + { "class3", new MarkupBlock() }, + })) }, { "

", new MarkupBlock( new MarkupTagHelperBlock("p", - new Dictionary - { - { "class1", new MarkupBlock() }, - { "class2", new MarkupBlock() }, - { "class3", factory.Markup("").With(SpanCodeGenerator.Null) }, - })) + selfClosing: true, + attributes: new Dictionary + { + { "class1", new MarkupBlock() }, + { "class2", new MarkupBlock() }, + { "class3", factory.Markup("").With(SpanCodeGenerator.Null) }, + })) }, }; } @@ -2462,48 +2477,53 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers "", new MarkupBlock( new MarkupTagHelperBlock("person", - new Dictionary - { - { "age", factory.CodeMarkup("12") } - })) + selfClosing: true, + attributes: new Dictionary + { + { "age", factory.CodeMarkup("12") } + })) }, { "", new MarkupBlock( new MarkupTagHelperBlock("person", - new Dictionary - { - { "birthday", factory.CodeMarkup("DateTime.Now") } - })) + selfClosing: true, + attributes: new Dictionary + { + { "birthday", factory.CodeMarkup("DateTime.Now") } + })) }, { "", new MarkupBlock( new MarkupTagHelperBlock("person", - new Dictionary - { - { "name", factory.Markup("John") } - })) + selfClosing: true, + attributes: new Dictionary + { + { "name", factory.Markup("John") } + })) }, { "", new MarkupBlock( new MarkupTagHelperBlock("person", - new Dictionary - { - { "name", new MarkupBlock(factory.Markup("Time:"), dateTimeNow) } - })) + selfClosing: true, + attributes: new Dictionary + { + { "name", new MarkupBlock(factory.Markup("Time:"), dateTimeNow) } + })) }, { "", new MarkupBlock( new MarkupTagHelperBlock("person", - new Dictionary - { - { "age", factory.CodeMarkup("12") }, - { "birthday", factory.CodeMarkup("DateTime.Now") }, - { "name", new MarkupBlock(factory.Markup("Time:"), dateTimeNow) } - })) + selfClosing: true, + attributes: new Dictionary + { + { "age", factory.CodeMarkup("12") }, + { "birthday", factory.CodeMarkup("DateTime.Now") }, + { "name", new MarkupBlock(factory.Markup("Time:"), dateTimeNow) } + })) }, }; } @@ -2668,7 +2688,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers "<

", new MarkupBlock( blockFactory.MarkupTagBlock("<"), - new MarkupTagHelperBlock("p")) + new MarkupTagHelperBlock("p", selfClosing: true)) }, { "< p />", @@ -2679,7 +2699,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers "", new MarkupBlock( blockFactory.MarkupTagBlock("", @@ -2697,7 +2717,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers value: new LocationTagged("foo", 9, 0, 9))), factory.Markup("\"").With(SpanCodeGenerator.Null)), factory.Markup(" ")), - new MarkupTagHelperBlock("p")) + new MarkupTagHelperBlock("p", selfClosing: true)) }, { "/>

>", @@ -3319,11 +3339,12 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers " World

", @@ -3360,37 +3381,45 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers "

", new MarkupBlock( new MarkupTagHelperBlock("p", - new Dictionary - { - { "class", factory.Markup("foo") }, - { "style", factory.Markup("color:red;") } - })) + selfClosing: true, + attributes: new Dictionary + { + { "class", factory.Markup("foo") }, + { "style", factory.Markup("color:red;") } + })) }; yield return new object[] { "

Hello

World

", new MarkupBlock( - new MarkupTagHelperBlock("p", - factory.Markup("Hello "), - new MarkupTagHelperBlock("p", - new Dictionary - { - { "class", factory.Markup("foo") }, - { "style", factory.Markup("color:red;") } - }), - factory.Markup(" World"))) + new MarkupTagHelperBlock( + "p", + selfClosing: false, + children: new SyntaxTreeNode[] { + factory.Markup("Hello "), + new MarkupTagHelperBlock( + "p", + selfClosing: true, + attributes: new Dictionary + { + { "class", factory.Markup("foo") }, + { "style", factory.Markup("color:red;") } + }), + factory.Markup(" World")})) }; yield return new object[] { "Hello

World", new MarkupBlock( factory.Markup("Hello"), new MarkupTagHelperBlock("p", - new Dictionary + selfClosing: true, + attributes: new Dictionary { { "class", factory.Markup("foo") } }), factory.Markup(" "), new MarkupTagHelperBlock("p", - new Dictionary + selfClosing: true, + attributes: new Dictionary { { "style", factory.Markup("color:red;") } }), diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/BasicTagHelpers.CustomAttributeCodeGenerator.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/BasicTagHelpers.CustomAttributeCodeGenerator.cs index 63851c08f8..df0d2e79aa 100644 --- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/BasicTagHelpers.CustomAttributeCodeGenerator.cs +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/BasicTagHelpers.CustomAttributeCodeGenerator.cs @@ -27,9 +27,9 @@ namespace TestOutput Instrumentation.BeginContext(33, 49, true); WriteLiteral("\r\n

\r\n "); Instrumentation.EndContext(); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", false, "test", async() => { WriteLiteral("\r\n "); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", false, "test", async() => { } , StartWritingScope, EndWritingScope); __PTagHelper = CreateTagHelper(); @@ -53,7 +53,7 @@ namespace TestOutput WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag()); __tagHelperExecutionContext = __tagHelperScopeManager.End(); WriteLiteral("\r\n "); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => { } , StartWritingScope, EndWritingScope); __InputTagHelper = CreateTagHelper(); @@ -82,7 +82,7 @@ namespace TestOutput WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag()); __tagHelperExecutionContext = __tagHelperScopeManager.End(); WriteLiteral("\r\n "); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => { } , StartWritingScope, EndWritingScope); __InputTagHelper = CreateTagHelper(); diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/BasicTagHelpers.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/BasicTagHelpers.cs index c6c1de8b40..62d38d533f 100644 --- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/BasicTagHelpers.cs +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/BasicTagHelpers.cs @@ -28,9 +28,9 @@ namespace TestOutput Instrumentation.BeginContext(33, 49, true); WriteLiteral("\r\n
\r\n "); Instrumentation.EndContext(); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", false, "test", async() => { WriteLiteral("\r\n "); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", false, "test", async() => { } , StartWritingScope, EndWritingScope); __PTagHelper = CreateTagHelper(); @@ -54,7 +54,7 @@ namespace TestOutput WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag()); __tagHelperExecutionContext = __tagHelperScopeManager.End(); WriteLiteral("\r\n "); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => { } , StartWritingScope, EndWritingScope); __InputTagHelper = CreateTagHelper(); @@ -83,7 +83,7 @@ namespace TestOutput WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag()); __tagHelperExecutionContext = __tagHelperScopeManager.End(); WriteLiteral("\r\n "); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => { } , StartWritingScope, EndWritingScope); __InputTagHelper = CreateTagHelper(); diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/ComplexTagHelpers.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/ComplexTagHelpers.cs index 666e9cd9e6..75e99f91d8 100644 --- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/ComplexTagHelpers.cs +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/ComplexTagHelpers.cs @@ -40,7 +40,7 @@ namespace TestOutput Instrumentation.BeginContext(84, 55, true); WriteLiteral("
\r\n "); Instrumentation.EndContext(); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", false, "test", async() => { WriteLiteral("\r\n

Set Time:

\r\n"); #line 10 "ComplexTagHelpers.cshtml" @@ -56,9 +56,9 @@ namespace TestOutput #line hidden WriteLiteral(" "); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", false, "test", async() => { WriteLiteral("New Time: "); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => { } , StartWritingScope, EndWritingScope); __InputTagHelper = CreateTagHelper(); @@ -120,9 +120,9 @@ namespace TestOutput #line hidden WriteLiteral(" "); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", false, "test", async() => { WriteLiteral("Current Time: "); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => { } , StartWritingScope, EndWritingScope); __InputTagHelper = CreateTagHelper(); @@ -186,7 +186,7 @@ Write(checkbox); WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag()); __tagHelperExecutionContext = __tagHelperScopeManager.End(); WriteLiteral("\r\n "); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => { } , StartWritingScope, EndWritingScope); __InputTagHelper = CreateTagHelper(); @@ -222,7 +222,7 @@ Write(true ? "checkbox" : "anything"); WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag()); __tagHelperExecutionContext = __tagHelperScopeManager.End(); WriteLiteral("\r\n "); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => { } , StartWritingScope, EndWritingScope); __InputTagHelper = CreateTagHelper(); @@ -314,7 +314,7 @@ Write(DateTime.Now); Instrumentation.BeginContext(672, 10, true); WriteLiteral("\r\n "); Instrumentation.EndContext(); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", false, "test", async() => { WriteLiteral("\r\n"); #line 22 "ComplexTagHelpers.cshtml" @@ -329,7 +329,7 @@ Write(DateTime.Now); #line hidden WriteLiteral("\r\n "); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => { } , StartWritingScope, EndWritingScope); __InputTagHelper = CreateTagHelper(); @@ -392,9 +392,9 @@ __PTagHelper.Age = DateTimeOffset.Now.Year - 1970; Instrumentation.BeginContext(819, 10, true); WriteLiteral("\r\n "); Instrumentation.EndContext(); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", false, "test", async() => { WriteLiteral("\r\n "); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => { } , StartWritingScope, EndWritingScope); __InputTagHelper = CreateTagHelper(); @@ -457,9 +457,9 @@ __PTagHelper.Age = -1970 + DateTimeOffset.Now.Year; Instrumentation.BeginContext(952, 10, true); WriteLiteral("\r\n "); Instrumentation.EndContext(); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", false, "test", async() => { WriteLiteral("\r\n "); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => { } , StartWritingScope, EndWritingScope); __InputTagHelper = CreateTagHelper(); @@ -522,9 +522,9 @@ __PTagHelper.Age = DateTimeOffset.Now.Year - 1970; Instrumentation.BeginContext(1080, 10, true); WriteLiteral("\r\n "); Instrumentation.EndContext(); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", false, "test", async() => { WriteLiteral("\r\n "); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => { } , StartWritingScope, EndWritingScope); __InputTagHelper = CreateTagHelper(); diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/EmptyAttributeTagHelpers.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/EmptyAttributeTagHelpers.cs index 77a073f58f..fdacceb36e 100644 --- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/EmptyAttributeTagHelpers.cs +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/EmptyAttributeTagHelpers.cs @@ -28,7 +28,7 @@ namespace TestOutput Instrumentation.BeginContext(27, 13, true); WriteLiteral("\r\n
\r\n "); Instrumentation.EndContext(); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => { } , StartWritingScope, EndWritingScope); __InputTagHelper = CreateTagHelper(); @@ -66,9 +66,9 @@ __InputTagHelper2.Checked = ; Instrumentation.BeginContext(74, 6, true); WriteLiteral("\r\n "); Instrumentation.EndContext(); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", false, "test", async() => { WriteLiteral("\r\n "); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => { } , StartWritingScope, EndWritingScope); __InputTagHelper = CreateTagHelper(); diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/EscapedTagHelpers.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/EscapedTagHelpers.cs index 3e0498ca5a..346fb9e4b5 100644 --- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/EscapedTagHelpers.cs +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/EscapedTagHelpers.cs @@ -37,7 +37,7 @@ namespace TestOutput Instrumentation.BeginContext(114, 69, true); WriteLiteral(">\r\n \r\n Not a TagHelper: "); Instrumentation.EndContext(); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => { } , StartWritingScope, EndWritingScope); __InputTagHelper = CreateTagHelper(); diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/SingleTagHelper.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/SingleTagHelper.cs index eb4b55fe40..9163fcdad7 100644 --- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/SingleTagHelper.cs +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/SingleTagHelper.cs @@ -26,7 +26,7 @@ namespace TestOutput Instrumentation.BeginContext(33, 2, true); WriteLiteral("\r\n"); Instrumentation.EndContext(); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", false, "test", async() => { WriteLiteral("Body of Tag"); } , StartWritingScope, EndWritingScope); diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/TagHelpersInHelper.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/TagHelpersInHelper.cs index be8e93e2d7..24fb276d2e 100644 --- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/TagHelpersInHelper.cs +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/TagHelpersInHelper.cs @@ -24,9 +24,9 @@ MyHelper(string val) Instrumentation.BeginContext(68, 19, true); WriteLiteralTo(__razor_helper_writer, "
\r\n "); Instrumentation.EndContext(); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("mytaghelper", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("mytaghelper", false, "test", async() => { WriteLiteral("\r\n In None ContentBehavior.\r\n "); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("nestedtaghelper", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("nestedtaghelper", false, "test", async() => { WriteLiteral("Some buffered values with a value of "); #line 8 "TagHelpersInHelper.cshtml" Write(val); @@ -135,10 +135,10 @@ Write(DateTime.Now); Instrumentation.BeginContext(33, 2, true); WriteLiteral("\r\n"); Instrumentation.EndContext(); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("mytaghelper", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("mytaghelper", false, "test", async() => { #line 12 "TagHelpersInHelper.cshtml" Write(MyHelper(item => new Template((__razor_template_writer) => { - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("nestedtaghelper", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("nestedtaghelper", false, "test", async() => { WriteLiteral("Custom Value"); } , StartWritingScope, EndWritingScope); diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/TagHelpersInSection.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/TagHelpersInSection.cs index 958d8317a4..759a8230cb 100644 --- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/TagHelpersInSection.cs +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/TagHelpersInSection.cs @@ -40,9 +40,9 @@ namespace TestOutput Instrumentation.BeginContext(93, 21, true); WriteLiteralTo(__razor_template_writer, "\r\n
\r\n "); Instrumentation.EndContext(); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("mytaghelper", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("mytaghelper", false, "test", async() => { WriteLiteral("\r\n In None ContentBehavior.\r\n "); - __tagHelperExecutionContext = __tagHelperScopeManager.Begin("nestedtaghelper", "test", async() => { + __tagHelperExecutionContext = __tagHelperScopeManager.Begin("nestedtaghelper", false, "test", async() => { WriteLiteral("Some buffered values with "); #line 11 "TagHelpersInSection.cshtml" Write(code);