Add tests to validate @tagHelperPrefix inheritance.

- Updated some naming bits that were still using the ViewStart name.
- Updated MvcRazorParserTests to test more cases of the parser, especially with @tagHelperPrefix.

#2110
This commit is contained in:
N. Taylor Mullen 2015-03-16 17:27:52 -07:00
parent f49d52b5fc
commit 2a28e6f4ce
15 changed files with 245 additions and 63 deletions

View File

@ -53,38 +53,62 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
Assert.Equal(expectedContent, responseContent);
}
public static IEnumerable<object[]> TagHelpersAreInheritedFromViewStartPagesData
public static TheoryData TagHelpersAreInheritedFromGlobalImportPagesData
{
get
{
var expected1 =
@"<root>root-content</root>
<nested>nested-content</nested>";
yield return new[] { "NestedViewStartTagHelper", expected1 };
var expected2 =
@"layout:<root>root-content</root>
<nested>nested-content</nested>";
yield return new[] { "ViewWithLayoutAndNestedTagHelper", expected2 };
var expected3 =
@"layout:<root>root-content</root>
page:<root/>
<nested>nested-content</nested>";
yield return new[] { "ViewWithInheritedRemoveTagHelper", expected3 };
// action, expected
return new TheoryData<string, string>
{
{
"NestedGlobalImportTagHelper",
string.Format(
"<root>root-content</root>{0}{0}{0}<nested>nested-content</nested>",
Environment.NewLine)
},
{
"ViewWithLayoutAndNestedTagHelper",
string.Format(
"layout:<root>root-content</root>{0}{0}{0}<nested>nested-content</nested>",
Environment.NewLine)
},
{
"ViewWithInheritedRemoveTagHelper",
string.Format(
"layout:<root>root-content</root>{0}{0}{0}page:<root/>{0}<nested>nested-content</nested>",
Environment.NewLine)
},
{
"ViewWithInheritedTagHelperPrefix",
string.Format(
"layout:<root>root-content</root>{0}{0}{0}page:<root>root-content</root>",
Environment.NewLine)
},
{
"ViewWithOverriddenTagHelperPrefix",
string.Format(
"layout:<root>root-content</root>{0}{0}{0}{0}page:<root>root-content</root>",
Environment.NewLine)
},
{
"ViewWithNestedInheritedTagHelperPrefix",
string.Format(
"layout:<root>root-content</root>{0}{0}{0}page:<root>root-content</root>",
Environment.NewLine)
},
{
"ViewWithNestedOverriddenTagHelperPrefix",
string.Format(
"layout:<root>root-content</root>{0}{0}{0}{0}page:<root>root-content</root>",
Environment.NewLine)
},
};
}
}
[Theory]
[MemberData(nameof(TagHelpersAreInheritedFromViewStartPagesData))]
public async Task TagHelpersAreInheritedFromViewStartPages(string action, string expected)
[MemberData(nameof(TagHelpersAreInheritedFromGlobalImportPagesData))]
public async Task TagHelpersAreInheritedFromGlobalImportPages(string action, string expected)
{
// Arrange
var server = TestHelper.CreateServer(_app, SiteName);
@ -158,7 +182,7 @@ page:<root/>
{ "Age", "1000" },
{ "EmployeeId", "0" },
{ "Email", "a@b.com" },
{ "Salary", "z" },
{ "Salary", "z" },
};
var postContent = new FormUrlEncodedContent(validPostValues);

View File

@ -1,6 +1,7 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Razor.Generator.Compiler;
@ -15,30 +16,132 @@ namespace Microsoft.AspNet.Mvc.Razor
{
public class MvcRazorCodeParserTest
{
[Fact]
public void GetTagHelperDescriptors_ReturnsDescriptorsFromViewStart()
public static TheoryData GlobalImportData
{
get
{
// codeTrees, expectedDirectiveDescriptors
return new TheoryData<CodeTree[], TagHelperDirectiveDescriptor[]>
{
{
new[] { CreateCodeTree(new TagHelperPrefixDirectiveChunk { Prefix = "THP" }) },
new[] { CreateDirectiveDescriptor("THP", TagHelperDirectiveType.TagHelperPrefix) }
},
{
new[] { CreateCodeTree(new AddTagHelperChunk { LookupText = "ATH" }) },
new[] { CreateDirectiveDescriptor("ATH", TagHelperDirectiveType.AddTagHelper) }
},
{
new[]
{
CreateCodeTree(
new AddTagHelperChunk { LookupText = "ATH1" },
new AddTagHelperChunk { LookupText = "ATH2" })
},
new[]
{
CreateDirectiveDescriptor("ATH1", TagHelperDirectiveType.AddTagHelper),
CreateDirectiveDescriptor("ATH2", TagHelperDirectiveType.AddTagHelper)
}
},
{
new[] { CreateCodeTree(new RemoveTagHelperChunk { LookupText = "RTH" }) },
new[] { CreateDirectiveDescriptor("RTH", TagHelperDirectiveType.RemoveTagHelper) }
},
{
new[]
{
CreateCodeTree(
new RemoveTagHelperChunk { LookupText = "RTH1" },
new RemoveTagHelperChunk { LookupText = "RTH2" })
},
new[]
{
CreateDirectiveDescriptor("RTH1", TagHelperDirectiveType.RemoveTagHelper),
CreateDirectiveDescriptor("RTH2", TagHelperDirectiveType.RemoveTagHelper)
}
},
{
new[]
{
CreateCodeTree(new TagHelperPrefixDirectiveChunk { Prefix = "THP1" }),
CreateCodeTree(new TagHelperPrefixDirectiveChunk { Prefix = "THP2" }),
},
new[] { CreateDirectiveDescriptor("THP1", TagHelperDirectiveType.TagHelperPrefix) }
},
{
new[]
{
CreateCodeTree(
new TagHelperPrefixDirectiveChunk { Prefix = "THP" },
new RemoveTagHelperChunk { LookupText = "RTH" },
new AddTagHelperChunk { LookupText = "ATH" })
},
new[]
{
CreateDirectiveDescriptor("RTH", TagHelperDirectiveType.RemoveTagHelper),
CreateDirectiveDescriptor("ATH", TagHelperDirectiveType.AddTagHelper),
CreateDirectiveDescriptor("THP", TagHelperDirectiveType.TagHelperPrefix),
}
},
{
new[]
{
CreateCodeTree(
new LiteralChunk { Text = "Hello world" },
new AddTagHelperChunk { LookupText = "ATH" }),
CreateCodeTree(new RemoveTagHelperChunk { LookupText = "RTH" })
},
new[]
{
CreateDirectiveDescriptor("RTH", TagHelperDirectiveType.RemoveTagHelper),
CreateDirectiveDescriptor("ATH", TagHelperDirectiveType.AddTagHelper),
}
},
{
new[]
{
CreateCodeTree(new TagHelperPrefixDirectiveChunk { Prefix = "THP" }),
CreateCodeTree(
new LiteralChunk { Text = "Hello world" },
new AddTagHelperChunk { LookupText = "ATH" }),
CreateCodeTree(new RemoveTagHelperChunk { LookupText = "RTH" })
},
new[]
{
CreateDirectiveDescriptor("RTH", TagHelperDirectiveType.RemoveTagHelper),
CreateDirectiveDescriptor("ATH", TagHelperDirectiveType.AddTagHelper),
CreateDirectiveDescriptor("THP", TagHelperDirectiveType.TagHelperPrefix),
}
},
{
new[]
{
CreateCodeTree(new TagHelperPrefixDirectiveChunk { Prefix = "THP1" }),
CreateCodeTree(new AddTagHelperChunk { LookupText = "ATH" }),
CreateCodeTree(new RemoveTagHelperChunk { LookupText = "RTH" }),
CreateCodeTree(new TagHelperPrefixDirectiveChunk { Prefix = "THP2" }),
},
new[]
{
CreateDirectiveDescriptor("RTH", TagHelperDirectiveType.RemoveTagHelper),
CreateDirectiveDescriptor("ATH", TagHelperDirectiveType.AddTagHelper),
CreateDirectiveDescriptor("THP1", TagHelperDirectiveType.TagHelperPrefix),
}
},
};
}
}
[Theory]
[MemberData(nameof(GlobalImportData))]
public void GetTagHelperDescriptors_ReturnsExpectedDirectiveDescriptors(
CodeTree[] codeTrees,
TagHelperDirectiveDescriptor[] expectedDirectiveDescriptors)
{
// Arrange
var builder = new BlockBuilder { Type = BlockType.Comment };
var block = new Block(builder);
var codeTrees = new[]
{
new CodeTree
{
Chunks = new Chunk[]
{
new LiteralChunk { Text = "Hello world" },
new AddTagHelperChunk { LookupText = "Add Tag Helper" },
}
},
new CodeTree
{
Chunks = new[]
{
new RemoveTagHelperChunk { LookupText = "Remove Tag Helper" },
}
}
};
IList<TagHelperDirectiveDescriptor> descriptors = null;
var resolver = new Mock<ITagHelperDescriptorResolver>();
@ -50,25 +153,43 @@ namespace Microsoft.AspNet.Mvc.Razor
.Returns(Enumerable.Empty<TagHelperDescriptor>())
.Verifiable();
var baseParser = new RazorParser(new CSharpCodeParser(),
new HtmlMarkupParser(),
resolver.Object);
var parser = new TestableMvcRazorParser(baseParser, codeTrees, new Chunk[0]);
var sink = new ParserErrorSink();
var baseParser = new RazorParser(
new CSharpCodeParser(),
new HtmlMarkupParser(),
tagHelperDescriptorResolver: resolver.Object);
var parser = new TestableMvcRazorParser(baseParser, codeTrees, defaultInheritedChunks: new Chunk[0]);
// Act
var result = parser.GetTagHelperDescriptorsPublic(block, sink).ToArray();
parser.GetTagHelperDescriptorsPublic(block, errorSink: new ParserErrorSink()).ToArray();
// Assert
Assert.NotNull(descriptors);
Assert.Equal(2, descriptors.Count);
Assert.Equal(expectedDirectiveDescriptors.Length, descriptors.Count);
Assert.Equal("Remove Tag Helper", descriptors[0].DirectiveText);
Assert.Equal(SourceLocation.Undefined, descriptors[0].Location);
for (var i = 0; i < expectedDirectiveDescriptors.Length; i++)
{
var expected = expectedDirectiveDescriptors[i];
var actual = descriptors[i];
Assert.Equal("Add Tag Helper", descriptors[1].DirectiveText);
Assert.Equal(TagHelperDirectiveType.AddTagHelper, descriptors[1].DirectiveType);
Assert.Equal(SourceLocation.Undefined, descriptors[1].Location);
Assert.Equal(expected.DirectiveText, actual.DirectiveText, StringComparer.Ordinal);
Assert.Equal(expected.Location, actual.Location);
Assert.Equal(expected.DirectiveType, actual.DirectiveType);
}
}
private static CodeTree CreateCodeTree(params Chunk[] chunks)
{
return new CodeTree
{
Chunks = chunks
};
}
private static TagHelperDirectiveDescriptor CreateDirectiveDescriptor(
string directiveText,
TagHelperDirectiveType directiveType)
{
return new TagHelperDirectiveDescriptor(directiveText, SourceLocation.Undefined, directiveType);
}
private class TestableMvcRazorParser : MvcRazorParser

View File

@ -30,7 +30,7 @@ namespace TagHelpersWebSite.Controllers
return View();
}
public ViewResult NestedViewStartTagHelper()
public ViewResult NestedGlobalImportTagHelper()
{
return View();
}
@ -44,5 +44,29 @@ namespace TagHelpersWebSite.Controllers
{
return View("/Views/RemoveInheritedTagHelpers/ViewWithInheritedRemoveTagHelper.cshtml");
}
public ViewResult ViewWithInheritedTagHelperPrefix()
{
return View("/Views/InheritedTagHelperPrefix/InheritedTagHelperPrefix.cshtml");
}
public ViewResult ViewWithOverriddenTagHelperPrefix()
{
return View("/Views/InheritedTagHelperPrefix/OverriddenTagHelperPrefix.cshtml");
}
public ViewResult ViewWithNestedInheritedTagHelperPrefix()
{
return View(
"/Views/InheritedTagHelperPrefix/NestedInheritedTagHelperPrefix/" +
"NestedInheritedTagHelperPrefix.cshtml");
}
public ViewResult ViewWithNestedOverriddenTagHelperPrefix()
{
return View(
"/Views/InheritedTagHelperPrefix/NestedInheritedTagHelperPrefix/" +
"NestedOverriddenTagHelperPrefix.cshtml");
}
}
}

View File

@ -7,7 +7,7 @@ using Microsoft.AspNet.Razor.TagHelpers;
namespace TagHelpersWebSite.TagHelpers
{
[HtmlElementName("nested")]
public class NestedViewStartTagHelper : TagHelper
public class NestedGlobalImportTagHelper : TagHelper
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{

View File

@ -1 +1 @@
@addTagHelper "TagHelpersWebSite.TagHelpers.NestedViewStartTagHelper, TagHelpersWebSite"
@addTagHelper "TagHelpersWebSite.TagHelpers.NestedGlobalImportTagHelper, TagHelpersWebSite"

View File

@ -0,0 +1 @@
page:<inherited:root></inherited:root>

View File

@ -0,0 +1,3 @@
@tagHelperPrefix "nested-overridden"
page:<nested-overriddenroot></nested-overriddenroot>

View File

@ -0,0 +1,3 @@
@tagHelperPrefix "overridden"
page:<overriddenroot></overriddenroot>

View File

@ -0,0 +1 @@
@tagHelperPrefix "inherited:"

View File

@ -0,0 +1,3 @@
@{
Layout = "~/Views/Shared/_LayoutWithRootTagHelper.cshtml";
}

View File

@ -1,2 +1,2 @@
@removeTagHelper "TagHelpersWebSite.TagHelpers.RootViewStartTagHelper, TagHelpersWebSite"
@addTagHelper "TagHelpersWebSite.TagHelpers.NestedViewStartTagHelper, TagHelpersWebSite"
@addTagHelper "TagHelpersWebSite.TagHelpers.NestedGlobalImportTagHelper, TagHelpersWebSite"

View File

@ -1,5 +1,5 @@
@{
Layout = "~/Views/Shared/_LayoutWithRootTagHelper.cshtml";
}
@addTagHelper "TagHelpersWebSite.TagHelpers.NestedViewStartTagHelper, TagHelpersWebSite"
@addTagHelper "TagHelpersWebSite.TagHelpers.NestedGlobalImportTagHelper, TagHelpersWebSite"
<nested>some-content</nested>