- Updated all tests and TagHelpers to utilize the new TagHelperOutput.Attributes and TagHelperContext.AllAttribute types.

aspnet/Razor#279
This commit is contained in:
N. Taylor Mullen 2015-04-23 16:02:07 -07:00
parent 05ac641f9a
commit f152ea7004
28 changed files with 956 additions and 388 deletions

View File

@ -288,7 +288,7 @@ namespace Microsoft.AspNet.Mvc.Razor
foreach (var attribute in tagHelperOutput.Attributes) foreach (var attribute in tagHelperOutput.Attributes)
{ {
writer.Write(' '); writer.Write(' ');
writer.Write(attribute.Key); writer.Write(attribute.Name);
writer.Write("=\""); writer.Write("=\"");
WriteTo(writer, HtmlEncoder, attribute.Value, escapeQuotes: true); WriteTo(writer, HtmlEncoder, attribute.Value, escapeQuotes: true);
writer.Write('"'); writer.Write('"');

View File

@ -82,7 +82,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var routePrefixedAttributes = output.FindPrefixedAttributes(RouteAttributePrefix); var routePrefixedAttributes = output.FindPrefixedAttributes(RouteAttributePrefix);
// If "href" is already set, it means the user is attempting to use a normal anchor. // If "href" is already set, it means the user is attempting to use a normal anchor.
if (output.Attributes.ContainsKey(Href)) if (output.Attributes.ContainsName(Href))
{ {
if (Action != null || if (Action != null ||
Controller != null || Controller != null ||
@ -154,7 +154,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// TODO: https://github.com/aspnet/Razor/issues/89 - We will not need this method once #89 is completed. // TODO: https://github.com/aspnet/Razor/issues/89 - We will not need this method once #89 is completed.
private static Dictionary<string, object> GetRouteValues( private static Dictionary<string, object> GetRouteValues(
TagHelperOutput output, TagHelperOutput output,
IEnumerable<KeyValuePair<string, object>> routePrefixedAttributes) IEnumerable<TagHelperAttribute> routePrefixedAttributes)
{ {
Dictionary<string, object> routeValues = null; Dictionary<string, object> routeValues = null;
if (routePrefixedAttributes.Any()) if (routePrefixedAttributes.Any())
@ -165,7 +165,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Remove prefix from keys and convert all values to strings. HtmlString and similar classes are not // Remove prefix from keys and convert all values to strings. HtmlString and similar classes are not
// meaningful to routing. // meaningful to routing.
routeValues = routePrefixedAttributes.ToDictionary( routeValues = routePrefixedAttributes.ToDictionary(
attribute => attribute.Key.Substring(RouteAttributePrefix.Length), attribute => attribute.Name.Substring(RouteAttributePrefix.Length),
attribute => (object)attribute.Value.ToString()); attribute => (object)attribute.Value.ToString());
} }

View File

@ -72,7 +72,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var routePrefixedAttributes = output.FindPrefixedAttributes(RouteAttributePrefix); var routePrefixedAttributes = output.FindPrefixedAttributes(RouteAttributePrefix);
// If "action" is already set, it means the user is attempting to use a normal <form>. // If "action" is already set, it means the user is attempting to use a normal <form>.
if (output.Attributes.ContainsKey(HtmlActionAttributeName)) if (output.Attributes.ContainsName(HtmlActionAttributeName))
{ {
if (Action != null || Controller != null || Route != null || routePrefixedAttributes.Any()) if (Action != null || Controller != null || Route != null || routePrefixedAttributes.Any())
{ {
@ -146,7 +146,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// TODO: https://github.com/aspnet/Razor/issues/89 - We will not need this method once #89 is completed. // TODO: https://github.com/aspnet/Razor/issues/89 - We will not need this method once #89 is completed.
private static Dictionary<string, object> GetRouteValues( private static Dictionary<string, object> GetRouteValues(
TagHelperOutput output, TagHelperOutput output,
IEnumerable<KeyValuePair<string, object>> routePrefixedAttributes) IEnumerable<TagHelperAttribute> routePrefixedAttributes)
{ {
Dictionary<string, object> routeValues = null; Dictionary<string, object> routeValues = null;
if (routePrefixedAttributes.Any()) if (routePrefixedAttributes.Any())
@ -157,7 +157,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Remove prefix from keys and convert all values to strings. HtmlString and similar classes are not // Remove prefix from keys and convert all values to strings. HtmlString and similar classes are not
// meaningful to routing. // meaningful to routing.
routeValues = routePrefixedAttributes.ToDictionary( routeValues = routePrefixedAttributes.ToDictionary(
attribute => attribute.Key.Substring(RouteAttributePrefix.Length), attribute => attribute.Name.Substring(RouteAttributePrefix.Length),
attribute => (object)attribute.Value.ToString()); attribute => (object)attribute.Value.ToString());
} }

View File

@ -155,7 +155,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
// inputType may be more specific than default the generator chooses below. // inputType may be more specific than default the generator chooses below.
if (!output.Attributes.ContainsKey("type")) if (!output.Attributes.ContainsName("type"))
{ {
output.Attributes["type"] = inputType; output.Attributes["type"] = inputType;
} }
@ -218,9 +218,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
// Prepare to move attributes from current element to <input type="checkbox"/> generated just below. // Prepare to move attributes from current element to <input type="checkbox"/> generated just below.
var htmlAttributes = output.Attributes.ToDictionary( var htmlAttributes = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
attribute => attribute.Key,
attribute => (object)attribute.Value); // Construct attributes correctly (first attribute wins).
foreach (var attribute in output.Attributes)
{
if (!htmlAttributes.ContainsKey(attribute.Name))
{
htmlAttributes.Add(attribute.Name, attribute.Value);
}
}
var tagBuilder = Generator.GenerateCheckBox( var tagBuilder = Generator.GenerateCheckBox(
ViewContext, ViewContext,

View File

@ -86,10 +86,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
foreach (var attribute in requiredAttributes) foreach (var attribute in requiredAttributes)
{ {
if (!context.AllAttributes.ContainsKey(attribute) || if (!context.AllAttributes.ContainsName(attribute) ||
context.AllAttributes[attribute] == null || context.AllAttributes[attribute] == null ||
(typeof(string).IsAssignableFrom(context.AllAttributes[attribute].GetType()) && (typeof(string).IsAssignableFrom(context.AllAttributes[attribute].Value.GetType()) &&
string.IsNullOrWhiteSpace(context.AllAttributes[attribute] as string))) string.IsNullOrWhiteSpace(context.AllAttributes[attribute].Value as string)))
{ {
// Missing attribute! // Missing attribute!
missingAttributes.Add(attribute); missingAttributes.Add(attribute);

View File

@ -236,7 +236,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var mode = modeResult.FullMatches.Select(match => match.Mode).Max(); var mode = modeResult.FullMatches.Select(match => match.Mode).Max();
// NOTE: Values in TagHelperOutput.Attributes may already be HTML-encoded. // NOTE: Values in TagHelperOutput.Attributes may already be HTML-encoded.
var attributes = new Dictionary<string, object>(output.Attributes); var attributes = new TagHelperAttributeList(output.Attributes);
var builder = new DefaultTagHelperContent(); var builder = new DefaultTagHelperContent();
@ -261,7 +261,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
output.Content.SetContent(builder); output.Content.SetContent(builder);
} }
private void BuildGlobbedLinkTags(IDictionary<string, object> attributes, TagHelperContent builder) private void BuildGlobbedLinkTags(TagHelperAttributeList attributes, TagHelperContent builder)
{ {
EnsureGlobbingUrlBuilder(); EnsureGlobbingUrlBuilder();
@ -341,7 +341,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
} }
private void BuildLinkTag(IDictionary<string, object> attributes, TagHelperContent builder) private void BuildLinkTag(TagHelperAttributeList attributes, TagHelperContent builder)
{ {
EnsureFileVersionProvider(); EnsureFileVersionProvider();
builder.Append("<link "); builder.Append("<link ");
@ -350,7 +350,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
var attributeValue = attribute.Value; var attributeValue = attribute.Value;
if (FileVersion == true && if (FileVersion == true &&
string.Equals(attribute.Key, HrefAttributeName, StringComparison.OrdinalIgnoreCase)) string.Equals(attribute.Name, HrefAttributeName, StringComparison.OrdinalIgnoreCase))
{ {
// "href" values come from bound attributes and globbing. So anything but a non-null string is // "href" values come from bound attributes and globbing. So anything but a non-null string is
// unexpected but could happen if another helper targeting the same element does something odd. // unexpected but could happen if another helper targeting the same element does something odd.
@ -363,7 +363,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
builder builder
.Append(attribute.Key) .Append(attribute.Name)
.Append("=\"") .Append("=\"")
.Append(HtmlEncoder, ViewContext.Writer.Encoding, attributeValue) .Append(HtmlEncoder, ViewContext.Writer.Encoding, attributeValue)
.Append("\" "); .Append("\" ");

View File

@ -51,7 +51,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
// Nothing to do if this <option/> is already selected. // Nothing to do if this <option/> is already selected.
if (!output.Attributes.ContainsKey("selected")) if (!output.Attributes.ContainsName("selected"))
{ {
// Is this <option/> element a child of a <select/> element the SelectTagHelper targeted? // Is this <option/> element a child of a <select/> element the SelectTagHelper targeted?
object formDataEntry; object formDataEntry;

View File

@ -205,7 +205,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var mode = modeResult.FullMatches.Select(match => match.Mode).Max(); var mode = modeResult.FullMatches.Select(match => match.Mode).Max();
// NOTE: Values in TagHelperOutput.Attributes may already be HTML-encoded. // NOTE: Values in TagHelperOutput.Attributes may already be HTML-encoded.
var attributes = new Dictionary<string, object>(output.Attributes); var attributes = new TagHelperAttributeList(output.Attributes);
var builder = new DefaultTagHelperContent(); var builder = new DefaultTagHelperContent();
var originalContent = await context.GetChildContentAsync(); var originalContent = await context.GetChildContentAsync();
@ -233,7 +233,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
private void BuildGlobbedScriptTags( private void BuildGlobbedScriptTags(
TagHelperContent originalContent, TagHelperContent originalContent,
IDictionary<string, object> attributes, TagHelperAttributeList attributes,
TagHelperContent builder) TagHelperContent builder)
{ {
EnsureGlobbingUrlBuilder(); EnsureGlobbingUrlBuilder();
@ -257,7 +257,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
} }
private void BuildFallbackBlock(IDictionary<string, object> attributes, DefaultTagHelperContent builder) private void BuildFallbackBlock(TagHelperAttributeList attributes, DefaultTagHelperContent builder)
{ {
EnsureGlobbingUrlBuilder(); EnsureGlobbingUrlBuilder();
EnsureFileVersionProvider(); EnsureFileVersionProvider();
@ -272,10 +272,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
.Append("||document.write(\""); .Append("||document.write(\"");
// May have no "src" attribute in the dictionary e.g. if Src and SrcInclude were not bound. // May have no "src" attribute in the dictionary e.g. if Src and SrcInclude were not bound.
if (!attributes.ContainsKey(SrcAttributeName)) if (!attributes.ContainsName(SrcAttributeName))
{ {
// Need this entry to place each fallback source. // Need this entry to place each fallback source.
attributes.Add(SrcAttributeName, null); attributes.Add(new TagHelperAttribute(SrcAttributeName, value: null));
} }
foreach (var src in fallbackSrcs) foreach (var src in fallbackSrcs)
@ -287,9 +287,9 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
foreach (var attribute in attributes) foreach (var attribute in attributes)
{ {
if (!attribute.Key.Equals(SrcAttributeName, StringComparison.OrdinalIgnoreCase)) if (!attribute.Name.Equals(SrcAttributeName, StringComparison.OrdinalIgnoreCase))
{ {
var encodedKey = JavaScriptEncoder.JavaScriptStringEncode(attribute.Key); var encodedKey = JavaScriptEncoder.JavaScriptStringEncode(attribute.Name);
var attributeValue = attribute.Value.ToString(); var attributeValue = attribute.Value.ToString();
var encodedValue = JavaScriptEncoder.JavaScriptStringEncode(attributeValue); var encodedValue = JavaScriptEncoder.JavaScriptStringEncode(attributeValue);
@ -307,7 +307,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// attribute.Key ("src") does not need to be JavaScript-encoded. // attribute.Key ("src") does not need to be JavaScript-encoded.
var encodedValue = JavaScriptEncoder.JavaScriptStringEncode(attributeValue); var encodedValue = JavaScriptEncoder.JavaScriptStringEncode(attributeValue);
AppendAttribute(builder, attribute.Key, encodedValue, escapeQuotes: true); AppendAttribute(builder, attribute.Name, encodedValue, escapeQuotes: true);
} }
} }
@ -342,7 +342,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
private void BuildScriptTag( private void BuildScriptTag(
TagHelperContent content, TagHelperContent content,
IDictionary<string, object> attributes, TagHelperAttributeList attributes,
TagHelperContent builder) TagHelperContent builder)
{ {
EnsureFileVersionProvider(); EnsureFileVersionProvider();
@ -352,7 +352,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
var attributeValue = attribute.Value; var attributeValue = attribute.Value;
if (FileVersion == true && if (FileVersion == true &&
string.Equals(attribute.Key, SrcAttributeName, StringComparison.OrdinalIgnoreCase)) string.Equals(attribute.Name, SrcAttributeName, StringComparison.OrdinalIgnoreCase))
{ {
// "src" values come from bound attributes and globbing. So anything but a non-null string is // "src" values come from bound attributes and globbing. So anything but a non-null string is
// unexpected but could happen if another helper targeting the same element does something odd. // unexpected but could happen if another helper targeting the same element does something odd.
@ -364,7 +364,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
} }
AppendAttribute(builder, attribute.Key, attributeValue, escapeQuotes: false); AppendAttribute(builder, attribute.Name, attributeValue, escapeQuotes: false);
} }
builder.Append(">") builder.Append(">")

View File

@ -31,21 +31,23 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
[NotNull] string attributeName, [NotNull] string attributeName,
[NotNull] TagHelperContext context) [NotNull] TagHelperContext context)
{ {
if (!tagHelperOutput.Attributes.ContainsKey(attributeName)) if (!tagHelperOutput.Attributes.ContainsName(attributeName))
{ {
IEnumerable<IReadOnlyTagHelperAttribute> entries;
// We look for the original attribute so we can restore the exact attribute name the user typed. // We look for the original attribute so we can restore the exact attribute name the user typed.
// Approach also ignores changes made to tagHelperOutput[attributeName]. // Approach also ignores changes made to tagHelperOutput[attributeName].
var entry = context.AllAttributes.FirstOrDefault( if (!context.AllAttributes.TryGetAttributes(attributeName, out entries))
attribute => attribute.Key.Equals(attributeName, StringComparison.OrdinalIgnoreCase));
if (entry.Equals(default(KeyValuePair<string, object>)))
{ {
throw new ArgumentException( throw new ArgumentException(
Resources.FormatTagHelperOutput_AttributeDoesNotExist(attributeName, nameof(TagHelperContext)), Resources.FormatTagHelperOutput_AttributeDoesNotExist(attributeName, nameof(TagHelperContext)),
nameof(attributeName)); nameof(attributeName));
} }
tagHelperOutput.Attributes.Add(entry.Key, entry.Value); foreach (var entry in entries)
{
tagHelperOutput.Attributes.Add(entry.Name, entry.Value);
}
} }
} }
@ -57,7 +59,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// <param name="prefix">A prefix to look for.</param> /// <param name="prefix">A prefix to look for.</param>
/// <returns><see cref="KeyValuePair{string, string}"/>s with <see cref="KeyValuePair{string, string}.Key"/> /// <returns><see cref="KeyValuePair{string, string}"/>s with <see cref="KeyValuePair{string, string}.Key"/>
/// starting with the given <paramref name="prefix"/>.</returns> /// starting with the given <paramref name="prefix"/>.</returns>
public static IEnumerable<KeyValuePair<string, object>> FindPrefixedAttributes( public static IEnumerable<TagHelperAttribute> FindPrefixedAttributes(
[NotNull] this TagHelperOutput tagHelperOutput, [NotNull] this TagHelperOutput tagHelperOutput,
[NotNull] string prefix) [NotNull] string prefix)
{ {
@ -65,7 +67,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// We're only interested in HTML attributes that have the desired prefix. // We're only interested in HTML attributes that have the desired prefix.
var prefixedAttributes = tagHelperOutput.Attributes var prefixedAttributes = tagHelperOutput.Attributes
.Where(attribute => attribute.Key.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) .Where(attribute => attribute.Name.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
.ToArray(); .ToArray();
return prefixedAttributes; return prefixedAttributes;
@ -85,13 +87,22 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
foreach (var attribute in tagBuilder.Attributes) foreach (var attribute in tagBuilder.Attributes)
{ {
if (!tagHelperOutput.Attributes.ContainsKey(attribute.Key)) if (!tagHelperOutput.Attributes.ContainsName(attribute.Key))
{ {
tagHelperOutput.Attributes.Add(attribute.Key, attribute.Value); tagHelperOutput.Attributes.Add(attribute.Key, attribute.Value);
} }
else if (attribute.Key.Equals("class", StringComparison.OrdinalIgnoreCase)) else if (attribute.Key.Equals("class", StringComparison.OrdinalIgnoreCase))
{ {
tagHelperOutput.Attributes["class"] += " " + attribute.Value; TagHelperAttribute classAttribute;
if (tagHelperOutput.Attributes.TryGetAttribute("class", out classAttribute))
{
tagHelperOutput.Attributes["class"] = classAttribute.Value + " " + attribute.Value;
}
else
{
tagHelperOutput.Attributes.Add("class", attribute.Value);
}
} }
} }
} }
@ -104,7 +115,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// <param name="attributes">Attributes to remove.</param> /// <param name="attributes">Attributes to remove.</param>
public static void RemoveRange( public static void RemoveRange(
[NotNull] this TagHelperOutput tagHelperOutput, [NotNull] this TagHelperOutput tagHelperOutput,
[NotNull] IEnumerable<KeyValuePair<string, object>> attributes) [NotNull] IEnumerable<TagHelperAttribute> attributes)
{ {
foreach (var attribute in attributes) foreach (var attribute in attributes)
{ {

View File

@ -7,7 +7,7 @@
<title></title> <title></title>
</head> </head>
<body> <body>
<form action="HtmlEncode[[/MvcTagHelper_Home/ProductSubmit]]" method="get"> <form method="get" action="HtmlEncode[[/MvcTagHelper_Home/ProductSubmit]]">
<div> <div>
<label class="product" for="HtmlEncode[[HomePage]]">HtmlEncode[[HomePage]]</label> <label class="product" for="HtmlEncode[[HomePage]]">HtmlEncode[[HomePage]]</label>
<input size="50" type="HtmlEncode[[url]]" id="HtmlEncode[[HomePage]]" name="HtmlEncode[[HomePage]]" value="HtmlEncode[[http://www.contoso.com/]]" /> <input size="50" type="HtmlEncode[[url]]" id="HtmlEncode[[HomePage]]" name="HtmlEncode[[HomePage]]" value="HtmlEncode[[http://www.contoso.com/]]" />

View File

@ -7,7 +7,7 @@
<title></title> <title></title>
</head> </head>
<body> <body>
<form action="/MvcTagHelper_Home/ProductSubmit" method="get"> <form method="get" action="/MvcTagHelper_Home/ProductSubmit">
<div> <div>
<label class="product" for="HomePage">HomePage</label> <label class="product" for="HomePage">HomePage</label>
<input size="50" type="url" id="HomePage" name="HomePage" value="http://www.contoso.com/" /> <input size="50" type="url" id="HomePage" name="HomePage" value="http://www.contoso.com/" />

View File

@ -747,7 +747,7 @@ namespace Microsoft.AspNet.Mvc.Razor
// parameters: TagName, Attributes, SelfClosing, PreContent, Content, PostContent // parameters: TagName, Attributes, SelfClosing, PreContent, Content, PostContent
GetTagHelperOutput( GetTagHelperOutput(
tagName: "div", tagName: "div",
attributes: new Dictionary<string, object>(), attributes: new TagHelperAttributeList(),
selfClosing: false, selfClosing: false,
preElement: null, preElement: null,
preContent: null, preContent: null,
@ -759,7 +759,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: null, tagName: null,
attributes: new Dictionary<string, object>(), attributes: new TagHelperAttributeList(),
selfClosing: false, selfClosing: false,
preElement: null, preElement: null,
preContent: null, preContent: null,
@ -771,7 +771,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: " ", tagName: " ",
attributes: new Dictionary<string, object>(), attributes: new TagHelperAttributeList(),
selfClosing: false, selfClosing: false,
preElement: null, preElement: null,
preContent: null, preContent: null,
@ -783,7 +783,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: "p", tagName: "p",
attributes: new Dictionary<string, object>() { { "test", "testVal" } }, attributes: new TagHelperAttributeList() { { "test", "testVal" } },
selfClosing: false, selfClosing: false,
preElement: null, preElement: null,
preContent: null, preContent: null,
@ -795,7 +795,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: "p", tagName: "p",
attributes: new Dictionary<string, object>() { { "test", "testVal" }, { "something", " spaced " } }, attributes: new TagHelperAttributeList() { { "test", "testVal" }, { "something", " spaced " } },
selfClosing: false, selfClosing: false,
preElement: null, preElement: null,
preContent: null, preContent: null,
@ -807,7 +807,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: "p", tagName: "p",
attributes: new Dictionary<string, object>() { { "test", "testVal" } }, attributes: new TagHelperAttributeList() { { "test", "testVal" } },
selfClosing: true, selfClosing: true,
preElement: null, preElement: null,
preContent: null, preContent: null,
@ -819,7 +819,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: "p", tagName: "p",
attributes: new Dictionary<string, object>() { { "test", "testVal" }, { "something", " spaced " } }, attributes: new TagHelperAttributeList() { { "test", "testVal" }, { "something", " spaced " } },
selfClosing: true, selfClosing: true,
preElement: null, preElement: null,
preContent: null, preContent: null,
@ -831,7 +831,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: "p", tagName: "p",
attributes: new Dictionary<string, object>(), attributes: new TagHelperAttributeList(),
selfClosing: false, selfClosing: false,
preElement: null, preElement: null,
preContent: "Hello World!", preContent: "Hello World!",
@ -843,7 +843,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: "p", tagName: "p",
attributes: new Dictionary<string, object>(), attributes: new TagHelperAttributeList(),
selfClosing: false, selfClosing: false,
preElement: null, preElement: null,
preContent: null, preContent: null,
@ -855,7 +855,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: "p", tagName: "p",
attributes: new Dictionary<string, object>(), attributes: new TagHelperAttributeList(),
selfClosing: false, selfClosing: false,
preElement: null, preElement: null,
preContent: null, preContent: null,
@ -867,7 +867,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: "p", tagName: "p",
attributes: new Dictionary<string, object>(), attributes: new TagHelperAttributeList(),
selfClosing: false, selfClosing: false,
preElement: null, preElement: null,
preContent: "Hello", preContent: "Hello",
@ -879,7 +879,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: "p", tagName: "p",
attributes: new Dictionary<string, object>(), attributes: new TagHelperAttributeList(),
selfClosing: true, selfClosing: true,
preElement: null, preElement: null,
preContent: "Hello", preContent: "Hello",
@ -891,7 +891,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: "custom", tagName: "custom",
attributes: new Dictionary<string, object>(), attributes: new TagHelperAttributeList(),
selfClosing: false, selfClosing: false,
preElement: null, preElement: null,
preContent: "Hello", preContent: "Hello",
@ -903,7 +903,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: "random", tagName: "random",
attributes: new Dictionary<string, object>(), attributes: new TagHelperAttributeList(),
selfClosing: true, selfClosing: true,
preElement: null, preElement: null,
preContent: "Hello", preContent: "Hello",
@ -915,7 +915,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: "custom", tagName: "custom",
attributes: new Dictionary<string, object>(), attributes: new TagHelperAttributeList(),
selfClosing: false, selfClosing: false,
preElement: "Before", preElement: "Before",
preContent: null, preContent: null,
@ -927,7 +927,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: null, tagName: null,
attributes: new Dictionary<string, object>(), attributes: new TagHelperAttributeList(),
selfClosing: false, selfClosing: false,
preElement: "Before", preElement: "Before",
preContent: null, preContent: null,
@ -939,7 +939,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: null, tagName: null,
attributes: new Dictionary<string, object> { { "test", "testVal" } }, attributes: new TagHelperAttributeList { { "test", "testVal" } },
selfClosing: true, selfClosing: true,
preElement: "Before", preElement: "Before",
preContent: null, preContent: null,
@ -951,7 +951,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: "custom", tagName: "custom",
attributes: new Dictionary<string, object> { { "test", "testVal" } }, attributes: new TagHelperAttributeList { { "test", "testVal" } },
selfClosing: true, selfClosing: true,
preElement: "Before", preElement: "Before",
preContent: null, preContent: null,
@ -963,7 +963,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: "custom", tagName: "custom",
attributes: new Dictionary<string, object>(), attributes: new TagHelperAttributeList(),
selfClosing: true, selfClosing: true,
preElement: "Before", preElement: "Before",
preContent: null, preContent: null,
@ -975,7 +975,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: "custom", tagName: "custom",
attributes: new Dictionary<string, object>(), attributes: new TagHelperAttributeList(),
selfClosing: false, selfClosing: false,
preElement: null, preElement: null,
preContent: null, preContent: null,
@ -987,7 +987,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: null, tagName: null,
attributes: new Dictionary<string, object>(), attributes: new TagHelperAttributeList(),
selfClosing: false, selfClosing: false,
preElement: null, preElement: null,
preContent: null, preContent: null,
@ -999,7 +999,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: null, tagName: null,
attributes: new Dictionary<string, object> { { "test", "testVal" } }, attributes: new TagHelperAttributeList { { "test", "testVal" } },
selfClosing: true, selfClosing: true,
preElement: null, preElement: null,
preContent: null, preContent: null,
@ -1011,7 +1011,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: "custom", tagName: "custom",
attributes: new Dictionary<string, object> { { "test", "testVal" } }, attributes: new TagHelperAttributeList { { "test", "testVal" } },
selfClosing: true, selfClosing: true,
preElement: null, preElement: null,
preContent: null, preContent: null,
@ -1023,7 +1023,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: "custom", tagName: "custom",
attributes: new Dictionary<string, object>(), attributes: new TagHelperAttributeList(),
selfClosing: true, selfClosing: true,
preElement: null, preElement: null,
preContent: null, preContent: null,
@ -1035,7 +1035,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: "custom", tagName: "custom",
attributes: new Dictionary<string, object>(), attributes: new TagHelperAttributeList(),
selfClosing: false, selfClosing: false,
preElement: "Before", preElement: "Before",
preContent: "Hello", preContent: "Hello",
@ -1047,7 +1047,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: "custom", tagName: "custom",
attributes: new Dictionary<string, object> { { "test", "testVal" } }, attributes: new TagHelperAttributeList { { "test", "testVal" } },
selfClosing: false, selfClosing: false,
preElement: "Before", preElement: "Before",
preContent: "Hello", preContent: "Hello",
@ -1059,7 +1059,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: "custom", tagName: "custom",
attributes: new Dictionary<string, object>(), attributes: new TagHelperAttributeList(),
selfClosing: true, selfClosing: true,
preElement: "Before", preElement: "Before",
preContent: "Hello", preContent: "Hello",
@ -1071,7 +1071,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: null, tagName: null,
attributes: new Dictionary<string, object>(), attributes: new TagHelperAttributeList(),
selfClosing: true, selfClosing: true,
preElement: "Before", preElement: "Before",
preContent: "Hello", preContent: "Hello",
@ -1083,7 +1083,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: null, tagName: null,
attributes: new Dictionary<string, object>(), attributes: new TagHelperAttributeList(),
selfClosing: false, selfClosing: false,
preElement: "Before", preElement: "Before",
preContent: "Hello", preContent: "Hello",
@ -1095,7 +1095,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
GetTagHelperOutput( GetTagHelperOutput(
tagName: null, tagName: null,
attributes: new Dictionary<string, object> { { "test", "testVal" } }, attributes: new TagHelperAttributeList { { "test", "testVal" } },
selfClosing: false, selfClosing: false,
preElement: "Before", preElement: "Before",
preContent: "Hello", preContent: "Hello",
@ -1161,7 +1161,7 @@ namespace Microsoft.AspNet.Mvc.Razor
}, },
startTagHelperWritingScope: () => { }, startTagHelperWritingScope: () => { },
endTagHelperWritingScope: () => defaultTagHelperContent); endTagHelperWritingScope: () => defaultTagHelperContent);
tagHelperExecutionContext.Output = new TagHelperOutput("p", new Dictionary<string, object>()); tagHelperExecutionContext.Output = new TagHelperOutput("p", new TagHelperAttributeList());
if (childContentRetrieved) if (childContentRetrieved)
{ {
await tagHelperExecutionContext.GetChildContentAsync(); await tagHelperExecutionContext.GetChildContentAsync();
@ -1193,7 +1193,7 @@ namespace Microsoft.AspNet.Mvc.Razor
executeChildContentAsync: () => { return Task.FromResult(result: true); }, executeChildContentAsync: () => { return Task.FromResult(result: true); },
startTagHelperWritingScope: () => { }, startTagHelperWritingScope: () => { },
endTagHelperWritingScope: () => new DefaultTagHelperContent()); endTagHelperWritingScope: () => new DefaultTagHelperContent());
tagHelperExecutionContext.Output = new TagHelperOutput("p", new Dictionary<string, object>()); tagHelperExecutionContext.Output = new TagHelperOutput("p", new TagHelperAttributeList());
tagHelperExecutionContext.Output.Content.SetContent("Hello World!"); tagHelperExecutionContext.Output.Content.SetContent("Hello World!");
// Act // Act
@ -1238,7 +1238,7 @@ namespace Microsoft.AspNet.Mvc.Razor
private static TagHelperOutput GetTagHelperOutput( private static TagHelperOutput GetTagHelperOutput(
string tagName, string tagName,
IDictionary<string, object> attributes, TagHelperAttributeList attributes,
bool selfClosing, bool selfClosing,
string preElement, string preElement,
string preContent, string preContent,

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Mvc.Rendering;
@ -24,7 +25,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var metadataProvider = new TestModelMetadataProvider(); var metadataProvider = new TestModelMetadataProvider();
var tagHelperContext = new TagHelperContext( var tagHelperContext = new TagHelperContext(
allAttributes: new Dictionary<string, object> allAttributes: new TagHelperAttributeList
{ {
{ "id", "myanchor" }, { "id", "myanchor" },
{ "asp-route-foo", "bar" }, { "asp-route-foo", "bar" },
@ -44,7 +45,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
}); });
var output = new TagHelperOutput( var output = new TagHelperOutput(
expectedTagName, expectedTagName,
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
{ "id", "myanchor" }, { "id", "myanchor" },
{ "asp-route-foo", "bar" }, { "asp-route-foo", "bar" },
@ -74,9 +75,9 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Assert // Assert
Assert.Equal(2, output.Attributes.Count); Assert.Equal(2, output.Attributes.Count);
var attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("id")); var attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("id"));
Assert.Equal("myanchor", attribute.Value); Assert.Equal("myanchor", attribute.Value);
attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("href")); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("href"));
Assert.Equal("home/index", attribute.Value); Assert.Equal("home/index", attribute.Value);
Assert.Equal("Something", output.Content.GetContent()); Assert.Equal("Something", output.Content.GetContent());
Assert.Equal(expectedTagName, output.TagName); Assert.Equal(expectedTagName, output.TagName);
@ -87,7 +88,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
// Arrange // Arrange
var context = new TagHelperContext( var context = new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: "test", uniqueId: "test",
getChildContentAsync: () => getChildContentAsync: () =>
@ -98,7 +100,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
}); });
var output = new TagHelperOutput( var output = new TagHelperOutput(
"a", "a",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
output.Content.SetContent(string.Empty); output.Content.SetContent(string.Empty);
var generator = new Mock<IHtmlGenerator>(MockBehavior.Strict); var generator = new Mock<IHtmlGenerator>(MockBehavior.Strict);
@ -129,7 +131,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
// Arrange // Arrange
var context = new TagHelperContext( var context = new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: "test", uniqueId: "test",
getChildContentAsync: () => getChildContentAsync: () =>
@ -140,7 +143,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
}); });
var output = new TagHelperOutput( var output = new TagHelperOutput(
"a", "a",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
output.Content.SetContent(string.Empty); output.Content.SetContent(string.Empty);
var generator = new Mock<IHtmlGenerator>(); var generator = new Mock<IHtmlGenerator>();
@ -181,7 +184,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var anchorTagHelper = new AnchorTagHelper(); var anchorTagHelper = new AnchorTagHelper();
var output = new TagHelperOutput( var output = new TagHelperOutput(
"a", "a",
attributes: new Dictionary<string, object>() attributes: new TagHelperAttributeList
{ {
{ "href", "http://www.contoso.com" } { "href", "http://www.contoso.com" }
}); });
@ -219,7 +222,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
typeof(AnchorTagHelper).GetProperty(propertyName).SetValue(anchorTagHelper, "Home"); typeof(AnchorTagHelper).GetProperty(propertyName).SetValue(anchorTagHelper, "Home");
var output = new TagHelperOutput( var output = new TagHelperOutput(
"a", "a",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
var expectedErrorMessage = "Cannot determine an 'href' attribute for <a>. An <a> with a specified " + var expectedErrorMessage = "Cannot determine an 'href' attribute for <a>. An <a> with a specified " +
"'asp-route' must not have an 'asp-action' or 'asp-controller' attribute."; "'asp-route' must not have an 'asp-action' or 'asp-controller' attribute.";

View File

@ -255,7 +255,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), It.IsAny<IEntryLink>(), out cacheResult)) cache.Setup(c => c.TryGetValue(It.IsAny<string>(), It.IsAny<IEntryLink>(), out cacheResult))
.Returns(false); .Returns(false);
var tagHelperContext = GetTagHelperContext(id, childContent); var tagHelperContext = GetTagHelperContext(id, childContent);
var tagHelperOutput = new TagHelperOutput("cache", new Dictionary<string, object>()); var tagHelperOutput = new TagHelperOutput("cache", new TagHelperAttributeList());
var cacheTagHelper = new CacheTagHelper var cacheTagHelper = new CacheTagHelper
{ {
ViewContext = GetViewContext(), ViewContext = GetViewContext(),
@ -295,7 +295,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), It.IsAny<IEntryLink>(), out cacheResult)) cache.Setup(c => c.TryGetValue(It.IsAny<string>(), It.IsAny<IEntryLink>(), out cacheResult))
.Returns(false); .Returns(false);
var tagHelperContext = GetTagHelperContext(id, childContent); var tagHelperContext = GetTagHelperContext(id, childContent);
var tagHelperOutput = new TagHelperOutput("cache", new Dictionary<string, object>()); var tagHelperOutput = new TagHelperOutput("cache", new TagHelperAttributeList());
var cacheTagHelper = new CacheTagHelper var cacheTagHelper = new CacheTagHelper
{ {
ViewContext = GetViewContext(), ViewContext = GetViewContext(),
@ -327,7 +327,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var childContent = "original-child-content"; var childContent = "original-child-content";
var cache = new MemoryCache(new MemoryCacheOptions()); var cache = new MemoryCache(new MemoryCacheOptions());
var tagHelperContext1 = GetTagHelperContext(id, childContent); var tagHelperContext1 = GetTagHelperContext(id, childContent);
var tagHelperOutput1 = new TagHelperOutput("cache", new Dictionary<string, object>()); var tagHelperOutput1 = new TagHelperOutput("cache", new TagHelperAttributeList());
var cacheTagHelper1 = new CacheTagHelper var cacheTagHelper1 = new CacheTagHelper
{ {
VaryByQuery = "key1,key2", VaryByQuery = "key1,key2",
@ -348,7 +348,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Arrange - 2 // Arrange - 2
var tagHelperContext2 = GetTagHelperContext(id, "different-content"); var tagHelperContext2 = GetTagHelperContext(id, "different-content");
var tagHelperOutput2 = new TagHelperOutput("cache", new Dictionary<string, object>()); var tagHelperOutput2 = new TagHelperOutput("cache", new TagHelperAttributeList());
var cacheTagHelper2 = new CacheTagHelper var cacheTagHelper2 = new CacheTagHelper
{ {
VaryByQuery = "key1,key2", VaryByQuery = "key1,key2",
@ -376,8 +376,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var childContent1 = "original-child-content"; var childContent1 = "original-child-content";
var cache = new MemoryCache(new MemoryCacheOptions()); var cache = new MemoryCache(new MemoryCacheOptions());
var tagHelperContext1 = GetTagHelperContext(id, childContent1); var tagHelperContext1 = GetTagHelperContext(id, childContent1);
var tagHelperOutput1 = new TagHelperOutput("cache", var tagHelperOutput1 = new TagHelperOutput("cache", new TagHelperAttributeList { { "attr", "value" } });
new Dictionary<string, object> { { "attr", "value" } });
tagHelperOutput1.PreContent.Append("<cache>"); tagHelperOutput1.PreContent.Append("<cache>");
tagHelperOutput1.PostContent.SetContent("</cache>"); tagHelperOutput1.PostContent.SetContent("</cache>");
var cacheTagHelper1 = new CacheTagHelper var cacheTagHelper1 = new CacheTagHelper
@ -400,9 +399,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Arrange - 2 // Arrange - 2
var childContent2 = "different-content"; var childContent2 = "different-content";
var tagHelperContext2 = GetTagHelperContext(id, childContent2); var tagHelperContext2 = GetTagHelperContext(id, childContent2);
var tagHelperOutput2 = new TagHelperOutput( var tagHelperOutput2 = new TagHelperOutput("cache", new TagHelperAttributeList { { "attr", "value" } });
"cache",
new Dictionary<string, object> { { "attr", "value" } });
tagHelperOutput2.PreContent.SetContent("<cache>"); tagHelperOutput2.PreContent.SetContent("<cache>");
tagHelperOutput2.PostContent.SetContent("</cache>"); tagHelperOutput2.PostContent.SetContent("</cache>");
var cacheTagHelper2 = new CacheTagHelper var cacheTagHelper2 = new CacheTagHelper
@ -611,8 +608,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
.Returns(() => currentTime); .Returns(() => currentTime);
var cache = new MemoryCache(new MemoryCacheOptions { Clock = clock.Object }); var cache = new MemoryCache(new MemoryCacheOptions { Clock = clock.Object });
var tagHelperContext1 = GetTagHelperContext(id, childContent1); var tagHelperContext1 = GetTagHelperContext(id, childContent1);
var tagHelperOutput1 = new TagHelperOutput("cache", var tagHelperOutput1 = new TagHelperOutput("cache", new TagHelperAttributeList { { "attr", "value" } });
new Dictionary<string, object> { { "attr", "value" } });
tagHelperOutput1.PreContent.SetContent("<cache>"); tagHelperOutput1.PreContent.SetContent("<cache>");
tagHelperOutput1.PostContent.SetContent("</cache>"); tagHelperOutput1.PostContent.SetContent("</cache>");
var cacheTagHelper1 = new CacheTagHelper var cacheTagHelper1 = new CacheTagHelper
@ -634,8 +630,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Arrange - 2 // Arrange - 2
var childContent2 = "different-content"; var childContent2 = "different-content";
var tagHelperContext2 = GetTagHelperContext(id, childContent2); var tagHelperContext2 = GetTagHelperContext(id, childContent2);
var tagHelperOutput2 = new TagHelperOutput("cache", var tagHelperOutput2 = new TagHelperOutput("cache", new TagHelperAttributeList { { "attr", "value" } });
new Dictionary<string, object> { { "attr", "value" } });
tagHelperOutput2.PreContent.SetContent("<cache>"); tagHelperOutput2.PreContent.SetContent("<cache>");
tagHelperOutput2.PostContent.SetContent("</cache>"); tagHelperOutput2.PostContent.SetContent("</cache>");
var cacheTagHelper2 = new CacheTagHelper var cacheTagHelper2 = new CacheTagHelper
@ -668,8 +663,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
.Returns(() => currentTime); .Returns(() => currentTime);
var cache = new MemoryCache(new MemoryCacheOptions { Clock = clock.Object }); var cache = new MemoryCache(new MemoryCacheOptions { Clock = clock.Object });
var tagHelperContext1 = GetTagHelperContext(id, childContent1); var tagHelperContext1 = GetTagHelperContext(id, childContent1);
var tagHelperOutput1 = new TagHelperOutput("cache", var tagHelperOutput1 = new TagHelperOutput("cache", new TagHelperAttributeList { { "attr", "value" } });
new Dictionary<string, object> { { "attr", "value" } });
tagHelperOutput1.PreContent.SetContent("<cache>"); tagHelperOutput1.PreContent.SetContent("<cache>");
tagHelperOutput1.PostContent.SetContent("</cache>"); tagHelperOutput1.PostContent.SetContent("</cache>");
var cacheTagHelper1 = new CacheTagHelper var cacheTagHelper1 = new CacheTagHelper
@ -692,8 +686,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
currentTime = currentTime.AddMinutes(5).AddSeconds(2); currentTime = currentTime.AddMinutes(5).AddSeconds(2);
var childContent2 = "different-content"; var childContent2 = "different-content";
var tagHelperContext2 = GetTagHelperContext(id, childContent2); var tagHelperContext2 = GetTagHelperContext(id, childContent2);
var tagHelperOutput2 = new TagHelperOutput("cache", var tagHelperOutput2 = new TagHelperOutput("cache", new TagHelperAttributeList { { "attr", "value" } });
new Dictionary<string, object> { { "attr", "value" } });
tagHelperOutput2.PreContent.SetContent("<cache>"); tagHelperOutput2.PreContent.SetContent("<cache>");
tagHelperOutput2.PostContent.SetContent("</cache>"); tagHelperOutput2.PostContent.SetContent("</cache>");
var cacheTagHelper2 = new CacheTagHelper var cacheTagHelper2 = new CacheTagHelper
@ -725,8 +718,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
.Returns(() => currentTime); .Returns(() => currentTime);
var cache = new MemoryCache(new MemoryCacheOptions { Clock = clock.Object }); var cache = new MemoryCache(new MemoryCacheOptions { Clock = clock.Object });
var tagHelperContext1 = GetTagHelperContext(id, childContent1); var tagHelperContext1 = GetTagHelperContext(id, childContent1);
var tagHelperOutput1 = new TagHelperOutput("cache", var tagHelperOutput1 = new TagHelperOutput("cache", new TagHelperAttributeList { { "attr", "value" } });
new Dictionary<string, object> { { "attr", "value" } });
tagHelperOutput1.PreContent.SetContent("<cache>"); tagHelperOutput1.PreContent.SetContent("<cache>");
tagHelperOutput1.PostContent.SetContent("</cache>"); tagHelperOutput1.PostContent.SetContent("</cache>");
var cacheTagHelper1 = new CacheTagHelper var cacheTagHelper1 = new CacheTagHelper
@ -749,8 +741,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
currentTime = currentTime.AddSeconds(35); currentTime = currentTime.AddSeconds(35);
var childContent2 = "different-content"; var childContent2 = "different-content";
var tagHelperContext2 = GetTagHelperContext(id, childContent2); var tagHelperContext2 = GetTagHelperContext(id, childContent2);
var tagHelperOutput2 = new TagHelperOutput("cache", var tagHelperOutput2 = new TagHelperOutput("cache", new TagHelperAttributeList { { "attr", "value" } });
new Dictionary<string, object> { { "attr", "value" } });
tagHelperOutput2.PreContent.SetContent("<cache>"); tagHelperOutput2.PreContent.SetContent("<cache>");
tagHelperOutput2.PostContent.SetContent("</cache>"); tagHelperOutput2.PostContent.SetContent("</cache>");
var cacheTagHelper2 = new CacheTagHelper var cacheTagHelper2 = new CacheTagHelper
@ -780,7 +771,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var tokenSource = new CancellationTokenSource(); var tokenSource = new CancellationTokenSource();
var cache = new MemoryCache(new MemoryCacheOptions()); var cache = new MemoryCache(new MemoryCacheOptions());
var tagHelperContext = new TagHelperContext( var tagHelperContext = new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new TagHelperAttributeList(),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: id, uniqueId: id,
getChildContentAsync: () => getChildContentAsync: () =>
@ -793,8 +784,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
}); });
return Task.FromResult<TagHelperContent>(expectedContent); return Task.FromResult<TagHelperContent>(expectedContent);
}); });
var tagHelperOutput = new TagHelperOutput("cache", var tagHelperOutput = new TagHelperOutput("cache", new TagHelperAttributeList { { "attr", "value" } });
new Dictionary<string, object> { { "attr", "value" } });
tagHelperOutput.PreContent.SetContent("<cache>"); tagHelperOutput.PreContent.SetContent("<cache>");
tagHelperOutput.PostContent.SetContent("</cache>"); tagHelperOutput.PostContent.SetContent("</cache>");
var cacheTagHelper = new CacheTagHelper var cacheTagHelper = new CacheTagHelper
@ -837,7 +827,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
string childContent = "some child content") string childContent = "some child content")
{ {
return new TagHelperContext( return new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new TagHelperAttributeList(),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: id, uniqueId: id,
getChildContentAsync: () => getChildContentAsync: () =>

View File

@ -80,7 +80,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Test
// Arrange // Arrange
var content = "content"; var content = "content";
var context = MakeTagHelperContext( var context = MakeTagHelperContext(
attributes: new Dictionary<string, object> { { "names", namesAttribute } }, attributes: new TagHelperAttributeList { { "names", namesAttribute } },
content: content); content: content);
var output = MakeTagHelperOutput("environment"); var output = MakeTagHelperOutput("environment");
var hostingEnvironment = new Mock<IHostingEnvironment>(); var hostingEnvironment = new Mock<IHostingEnvironment>();
@ -108,7 +108,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Test
// Arrange // Arrange
var content = "content"; var content = "content";
var context = MakeTagHelperContext( var context = MakeTagHelperContext(
attributes: new Dictionary<string, object> { { "names", namesAttribute } }, attributes: new TagHelperAttributeList { { "names", namesAttribute } },
content: content); content: content);
var output = MakeTagHelperOutput("environment"); var output = MakeTagHelperOutput("environment");
var hostingEnvironment = new Mock<IHostingEnvironment>(); var hostingEnvironment = new Mock<IHostingEnvironment>();
@ -129,10 +129,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Test
} }
private TagHelperContext MakeTagHelperContext( private TagHelperContext MakeTagHelperContext(
IDictionary<string, object> attributes = null, TagHelperAttributeList attributes = null,
string content = null) string content = null)
{ {
attributes = attributes ?? new Dictionary<string, object>(); attributes = attributes ?? new TagHelperAttributeList();
return new TagHelperContext( return new TagHelperContext(
attributes, attributes,
@ -146,9 +146,9 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Test
}); });
} }
private TagHelperOutput MakeTagHelperOutput(string tagName, IDictionary<string, object> attributes = null) private TagHelperOutput MakeTagHelperOutput(string tagName, TagHelperAttributeList attributes = null)
{ {
attributes = attributes ?? new Dictionary<string, object>(); attributes = attributes ?? new TagHelperAttributeList();
return new TagHelperOutput(tagName, attributes); return new TagHelperOutput(tagName, attributes);
} }

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
@ -25,7 +26,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var expectedTagName = "not-form"; var expectedTagName = "not-form";
var metadataProvider = new TestModelMetadataProvider(); var metadataProvider = new TestModelMetadataProvider();
var tagHelperContext = new TagHelperContext( var tagHelperContext = new TagHelperContext(
allAttributes: new Dictionary<string, object> allAttributes: new TagHelperAttributeList
{ {
{ "id", "myform" }, { "id", "myform" },
{ "asp-route-foo", "bar" }, { "asp-route-foo", "bar" },
@ -44,7 +45,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
}); });
var output = new TagHelperOutput( var output = new TagHelperOutput(
expectedTagName, expectedTagName,
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
{ "id", "myform" }, { "id", "myform" },
{ "asp-route-foo", "bar" }, { "asp-route-foo", "bar" },
@ -74,11 +75,11 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Assert // Assert
Assert.Equal(3, output.Attributes.Count); Assert.Equal(3, output.Attributes.Count);
var attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("id")); var attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("id"));
Assert.Equal("myform", attribute.Value); Assert.Equal("myform", attribute.Value);
attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("method")); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("method"));
Assert.Equal("post", attribute.Value); Assert.Equal("post", attribute.Value);
attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("action")); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("action"));
Assert.Equal("home/index", attribute.Value); Assert.Equal("home/index", attribute.Value);
Assert.Empty(output.PreContent.GetContent()); Assert.Empty(output.PreContent.GetContent());
Assert.True(output.Content.IsEmpty); Assert.True(output.Content.IsEmpty);
@ -97,7 +98,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Arrange // Arrange
var viewContext = CreateViewContext(); var viewContext = CreateViewContext();
var context = new TagHelperContext( var context = new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: "test", uniqueId: "test",
getChildContentAsync: () => getChildContentAsync: () =>
@ -108,7 +110,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
}); });
var output = new TagHelperOutput( var output = new TagHelperOutput(
"form", "form",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
var generator = new Mock<IHtmlGenerator>(MockBehavior.Strict); var generator = new Mock<IHtmlGenerator>(MockBehavior.Strict);
generator generator
.Setup(mock => mock.GenerateForm( .Setup(mock => mock.GenerateForm(
@ -148,7 +150,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Arrange // Arrange
var testViewContext = CreateViewContext(); var testViewContext = CreateViewContext();
var context = new TagHelperContext( var context = new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: "test", uniqueId: "test",
getChildContentAsync: () => getChildContentAsync: () =>
@ -157,10 +160,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
return Task.FromResult<TagHelperContent>(tagHelperContent); return Task.FromResult<TagHelperContent>(tagHelperContent);
}); });
var expectedAttribute = new KeyValuePair<string, object>("asp-ROUTEE-NotRoute", "something"); var expectedAttribute = new TagHelperAttribute("asp-ROUTEE-NotRoute", "something");
var output = new TagHelperOutput( var output = new TagHelperOutput(
"form", "form",
attributes: new Dictionary<string, object>() attributes: new TagHelperAttributeList()
{ {
{ "asp-route-val", "hello" }, { "asp-route-val", "hello" },
{ "asp-roUte--Foo", "bar" } { "asp-roUte--Foo", "bar" }
@ -185,9 +188,9 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var routeValueDictionary = (Dictionary<string, object>)routeValues; var routeValueDictionary = (Dictionary<string, object>)routeValues;
Assert.Equal(2, routeValueDictionary.Count); Assert.Equal(2, routeValueDictionary.Count);
var routeValue = Assert.Single(routeValueDictionary, kvp => kvp.Key.Equals("val")); var routeValue = Assert.Single(routeValueDictionary, attr => attr.Key.Equals("val"));
Assert.Equal("hello", routeValue.Value); Assert.Equal("hello", routeValue.Value);
routeValue = Assert.Single(routeValueDictionary, kvp => kvp.Key.Equals("-Foo")); routeValue = Assert.Single(routeValueDictionary, attr => attr.Key.Equals("-Foo"));
Assert.Equal("bar", routeValue.Value); Assert.Equal("bar", routeValue.Value);
}) })
.Returns(new TagBuilder("form", new CommonTestEncoder())) .Returns(new TagBuilder("form", new CommonTestEncoder()))
@ -219,7 +222,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Arrange // Arrange
var viewContext = CreateViewContext(); var viewContext = CreateViewContext();
var context = new TagHelperContext( var context = new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: "test", uniqueId: "test",
getChildContentAsync: () => getChildContentAsync: () =>
@ -230,7 +234,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
}); });
var output = new TagHelperOutput( var output = new TagHelperOutput(
"form", "form",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
var generator = new Mock<IHtmlGenerator>(MockBehavior.Strict); var generator = new Mock<IHtmlGenerator>(MockBehavior.Strict);
generator generator
.Setup(mock => mock.GenerateForm(viewContext, "Index", "Home", null, null, null)) .Setup(mock => mock.GenerateForm(viewContext, "Index", "Home", null, null, null))
@ -264,7 +268,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Arrange // Arrange
var viewContext = CreateViewContext(); var viewContext = CreateViewContext();
var context = new TagHelperContext( var context = new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: "test", uniqueId: "test",
getChildContentAsync: () => getChildContentAsync: () =>
@ -275,7 +280,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
}); });
var output = new TagHelperOutput( var output = new TagHelperOutput(
"form", "form",
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
{ "asp-route-foo", "bar" } { "asp-route-foo", "bar" }
}); });
@ -333,12 +338,13 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
}; };
var output = new TagHelperOutput("form", var output = new TagHelperOutput("form",
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
{ "aCTiON", "my-action" }, { "aCTiON", "my-action" },
}); });
var context = new TagHelperContext( var context = new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: "test", uniqueId: "test",
getChildContentAsync: () => getChildContentAsync: () =>
@ -356,7 +362,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
Assert.Equal("form", output.TagName); Assert.Equal("form", output.TagName);
Assert.False(output.SelfClosing); Assert.False(output.SelfClosing);
var attribute = Assert.Single(output.Attributes); var attribute = Assert.Single(output.Attributes);
Assert.Equal(new KeyValuePair<string, object>("aCTiON", "my-action"), attribute); Assert.Equal(new TagHelperAttribute("aCTiON", "my-action"), attribute);
Assert.Empty(output.PreContent.GetContent()); Assert.Empty(output.PreContent.GetContent());
Assert.True(output.Content.IsEmpty); Assert.True(output.Content.IsEmpty);
Assert.Equal(expectedPostContent, output.PostContent.GetContent()); Assert.Equal(expectedPostContent, output.PostContent.GetContent());
@ -372,7 +378,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var formTagHelper = new FormTagHelper(); var formTagHelper = new FormTagHelper();
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
"form", "form",
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
{ "action", "my-action" }, { "action", "my-action" },
}); });
@ -409,7 +415,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
typeof(FormTagHelper).GetProperty(propertyName).SetValue(formTagHelper, "Home"); typeof(FormTagHelper).GetProperty(propertyName).SetValue(formTagHelper, "Home");
var output = new TagHelperOutput( var output = new TagHelperOutput(
"form", "form",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
var expectedErrorMessage = "Cannot determine an 'action' attribute for <form>. A <form> with a specified " + var expectedErrorMessage = "Cannot determine an 'action' attribute for <form>. A <form> with a specified " +
"'asp-route' must not have an 'asp-action' or 'asp-controller' attribute."; "'asp-route' must not have an 'asp-action' or 'asp-controller' attribute.";

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
@ -18,6 +19,96 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
public class InputTagHelperTest public class InputTagHelperTest
{ {
public static TheoryData MultiAttributeCheckBoxData
{
get
{
// outputAttributes, expectedAttributeString
return new TheoryData<TagHelperAttributeList, string>
{
{
new TagHelperAttributeList
{
{ "hello", "world" },
{ "hello", "world2" }
},
"hello=\"HtmlEncode[[world]]\""
},
{
new TagHelperAttributeList
{
{ "hello", "world" },
{ "hello", "world2" },
{ "hello", "world3" }
},
"hello=\"HtmlEncode[[world]]\""
},
{
new TagHelperAttributeList
{
{ "HelLO", "world" },
{ "HELLO", "world2" }
},
"HelLO=\"HtmlEncode[[world]]\""
},
{
new TagHelperAttributeList
{
{ "Hello", "world" },
{ "HELLO", "world2" },
{ "hello", "world3" }
},
"Hello=\"HtmlEncode[[world]]\""
},
{
new TagHelperAttributeList
{
{ "HeLlO", "world" },
{ "hello", "world2" }
},
"HeLlO=\"HtmlEncode[[world]]\""
},
};
}
}
[Theory]
[MemberData(nameof(MultiAttributeCheckBoxData))]
public async Task CheckBoxHandlesMultipleAttributesSameNameCorrectly(
TagHelperAttributeList outputAttributes,
string expectedAttributeString)
{
// Arrange
var originalContent = "original content";
var originalTagName = "not-input";
var expectedContent = $"{originalContent}<input {expectedAttributeString} id=\"HtmlEncode[[IsACar]]\" " +
"name=\"HtmlEncode[[IsACar]]\" type=\"HtmlEncode[[checkbox]]\" value=\"HtmlEncode[[true]]\" />" +
"<input name=\"HtmlEncode[[IsACar]]\" type=\"HtmlEncode[[hidden]]\" value=\"HtmlEncode[[false]]\" />";
var context = new TagHelperContext(
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(),
uniqueId: "test",
getChildContentAsync: () => Task.FromResult<TagHelperContent>(result: null));
var output = new TagHelperOutput(originalTagName, outputAttributes)
{
SelfClosing = true,
};
output.Content.SetContent(originalContent);
var htmlGenerator = new TestableHtmlGenerator(new EmptyModelMetadataProvider());
var tagHelper = GetTagHelper(htmlGenerator, model: false, propertyName: nameof(Model.IsACar));
// Act
await tagHelper.ProcessAsync(context, output);
// Assert
Assert.Empty(output.Attributes); // Moved to Content and cleared
Assert.Equal(expectedContent, output.Content.GetContent());
Assert.True(output.SelfClosing);
Assert.Null(output.TagName); // Cleared
}
// Top-level container (List<Model> or Model instance), immediate container type (Model or NestModel), // Top-level container (List<Model> or Model instance), immediate container type (Model or NestModel),
// model accessor, expression path / id, expected value. // model accessor, expression path / id, expected value.
public static TheoryData<object, Type, object, NameAndId, string> TestDataSet public static TheoryData<object, Type, object, NameAndId, string> TestDataSet
@ -84,7 +175,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
string expectedValue) string expectedValue)
{ {
// Arrange // Arrange
var expectedAttributes = new Dictionary<string, object> var expectedAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control" }, { "class", "form-control" },
{ "type", "text" }, { "type", "text" },
@ -99,7 +190,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var expectedTagName = "not-input"; var expectedTagName = "not-input";
var context = new TagHelperContext( var context = new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: "test", uniqueId: "test",
getChildContentAsync: () => getChildContentAsync: () =>
@ -108,7 +200,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
return Task.FromResult<TagHelperContent>(tagHelperContent); return Task.FromResult<TagHelperContent>(tagHelperContent);
}); });
var originalAttributes = new Dictionary<string, object> var originalAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control" }, { "class", "form-control" },
}; };
@ -160,7 +252,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var expectedPostContent = "original post-content"; var expectedPostContent = "original post-content";
var context = new TagHelperContext( var context = new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: "test", uniqueId: "test",
getChildContentAsync: () => getChildContentAsync: () =>
@ -169,7 +262,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
return Task.FromResult<TagHelperContent>(tagHelperContent); return Task.FromResult<TagHelperContent>(tagHelperContent);
}); });
var originalAttributes = new Dictionary<string, object> var originalAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control" }, { "class", "form-control" },
}; };
@ -236,7 +329,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
string model) string model)
{ {
// Arrange // Arrange
var contextAttributes = new Dictionary<string, object> var contextAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control" }, { "class", "form-control" },
}; };
@ -245,7 +338,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
contextAttributes["type"] = inputTypeName; // Support restoration of type attribute, if any. contextAttributes["type"] = inputTypeName; // Support restoration of type attribute, if any.
} }
var expectedAttributes = new Dictionary<string, object> var expectedAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control hidden-control" }, { "class", "form-control hidden-control" },
{ "type", inputTypeName ?? "hidden" }, // Generator restores type attribute; adds "hidden" if none. { "type", inputTypeName ?? "hidden" }, // Generator restores type attribute; adds "hidden" if none.
@ -265,7 +358,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
return Task.FromResult<TagHelperContent>(tagHelperContent); return Task.FromResult<TagHelperContent>(tagHelperContent);
}); });
var originalAttributes = new Dictionary<string, object> var originalAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control" }, { "class", "form-control" },
}; };
@ -335,7 +428,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
string model) string model)
{ {
// Arrange // Arrange
var contextAttributes = new Dictionary<string, object> var contextAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control" }, { "class", "form-control" },
}; };
@ -344,7 +437,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
contextAttributes["type"] = inputTypeName; // Support restoration of type attribute, if any. contextAttributes["type"] = inputTypeName; // Support restoration of type attribute, if any.
} }
var expectedAttributes = new Dictionary<string, object> var expectedAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control password-control" }, { "class", "form-control password-control" },
{ "type", inputTypeName ?? "password" }, // Generator restores type attribute; adds "password" if none. { "type", inputTypeName ?? "password" }, // Generator restores type attribute; adds "password" if none.
@ -364,7 +457,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
return Task.FromResult<TagHelperContent>(tagHelperContent); return Task.FromResult<TagHelperContent>(tagHelperContent);
}); });
var originalAttributes = new Dictionary<string, object> var originalAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control" }, { "class", "form-control" },
}; };
@ -429,7 +522,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
// Arrange // Arrange
var value = "match"; // Real generator would use this for comparison with For.Metadata.Model. var value = "match"; // Real generator would use this for comparison with For.Metadata.Model.
var contextAttributes = new Dictionary<string, object> var contextAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control" }, { "class", "form-control" },
{ "value", value }, { "value", value },
@ -439,7 +532,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
contextAttributes["type"] = inputTypeName; // Support restoration of type attribute, if any. contextAttributes["type"] = inputTypeName; // Support restoration of type attribute, if any.
} }
var expectedAttributes = new Dictionary<string, object> var expectedAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control radio-control" }, { "class", "form-control radio-control" },
{ "type", inputTypeName ?? "radio" }, // Generator restores type attribute; adds "radio" if none. { "type", inputTypeName ?? "radio" }, // Generator restores type attribute; adds "radio" if none.
@ -460,7 +553,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
return Task.FromResult<TagHelperContent>(tagHelperContent); return Task.FromResult<TagHelperContent>(tagHelperContent);
}); });
var originalAttributes = new Dictionary<string, object> var originalAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control" }, { "class", "form-control" },
}; };
@ -536,7 +629,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
string model) string model)
{ {
// Arrange // Arrange
var contextAttributes = new Dictionary<string, object> var contextAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control" }, { "class", "form-control" },
}; };
@ -545,7 +638,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
contextAttributes["type"] = inputTypeName; // Support restoration of type attribute, if any. contextAttributes["type"] = inputTypeName; // Support restoration of type attribute, if any.
} }
var expectedAttributes = new Dictionary<string, object> var expectedAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control text-control" }, { "class", "form-control text-control" },
{ "type", inputTypeName ?? "text" }, // Generator restores type attribute; adds "text" if none. { "type", inputTypeName ?? "text" }, // Generator restores type attribute; adds "text" if none.
@ -565,7 +658,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
return Task.FromResult<TagHelperContent>(tagHelperContent); return Task.FromResult<TagHelperContent>(tagHelperContent);
}); });
var originalAttributes = new Dictionary<string, object> var originalAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control" }, { "class", "form-control" },
}; };
@ -668,19 +761,20 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
string expectedType) string expectedType)
{ {
// Arrange // Arrange
var expectedAttributes = new Dictionary<string, object> var expectedAttributes = new TagHelperAttributeList
{ {
{ "type", expectedType }, // Calculated; not passed to HtmlGenerator. { "type", expectedType }, // Calculated; not passed to HtmlGenerator.
}; };
var expectedTagName = "not-input"; var expectedTagName = "not-input";
var context = new TagHelperContext( var context = new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: "test", uniqueId: "test",
getChildContentAsync: () => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: () => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));
var output = new TagHelperOutput(expectedTagName, attributes: new Dictionary<string, object>()) var output = new TagHelperOutput(expectedTagName, attributes: new TagHelperAttributeList())
{ {
SelfClosing = true, SelfClosing = true,
}; };
@ -748,19 +842,20 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
string expectedType) string expectedType)
{ {
// Arrange // Arrange
var expectedAttributes = new Dictionary<string, object> var expectedAttributes = new TagHelperAttributeList
{ {
{ "type", expectedType }, // Calculated; not passed to HtmlGenerator. { "type", expectedType }, // Calculated; not passed to HtmlGenerator.
}; };
var expectedTagName = "not-input"; var expectedTagName = "not-input";
var context = new TagHelperContext( var context = new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: "test", uniqueId: "test",
getChildContentAsync: () => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: () => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));
var output = new TagHelperOutput(expectedTagName, attributes: new Dictionary<string, object>()) var output = new TagHelperOutput(expectedTagName, attributes: new TagHelperAttributeList())
{ {
SelfClosing = true, SelfClosing = true,
}; };

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Razor.Runtime.TagHelpers; using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Xunit; using Xunit;
@ -19,7 +20,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
{ {
ModeAttributes.Create("mode0", new [] { "first-attr" }) ModeAttributes.Create("mode0", new [] { "first-attr" })
}; };
var attributes = new Dictionary<string, object> var attributes = new TagHelperAttributeList
{ {
["first-attr"] = "value", ["first-attr"] = "value",
["not-in-any-mode"] = "value" ["not-in-any-mode"] = "value"
@ -47,7 +48,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
{ {
ModeAttributes.Create("mode0", new [] { "first-attr", "second-attr" }) ModeAttributes.Create("mode0", new [] { "first-attr", "second-attr" })
}; };
var attributes = new Dictionary<string, object> var attributes = new TagHelperAttributeList
{ {
["first-attr"] = "value", ["first-attr"] = "value",
["second-attr"] = "value", ["second-attr"] = "value",
@ -82,7 +83,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
ModeAttributes.Create("mode2", new [] { "first-attr", "second-attr", "third-attr" }), ModeAttributes.Create("mode2", new [] { "first-attr", "second-attr", "third-attr" }),
ModeAttributes.Create("mode3", new [] { "fourth-attr" }) ModeAttributes.Create("mode3", new [] { "fourth-attr" })
}; };
var attributes = new Dictionary<string, object> var attributes = new TagHelperAttributeList
{ {
["second-attr"] = "value", ["second-attr"] = "value",
["third-attr"] = "value", ["third-attr"] = "value",
@ -119,10 +120,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
} }
private static TagHelperContext MakeTagHelperContext( private static TagHelperContext MakeTagHelperContext(
IDictionary<string, object> attributes = null, TagHelperAttributeList attributes = null,
string content = null) string content = null)
{ {
attributes = attributes ?? new Dictionary<string, object>(); attributes = attributes ?? new TagHelperAttributeList();
return new TagHelperContext( return new TagHelperContext(
attributes, attributes,

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Mvc.Rendering;
@ -164,7 +165,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
// Arrange // Arrange
var expectedTagName = "not-label"; var expectedTagName = "not-label";
var expectedAttributes = new Dictionary<string, object> var expectedAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control" }, { "class", "form-control" },
{ "for", tagHelperOutputContent.ExpectedId } { "for", tagHelperOutputContent.ExpectedId }
@ -186,7 +187,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var expectedPostContent = "original post-content"; var expectedPostContent = "original post-content";
var tagHelperContext = new TagHelperContext( var tagHelperContext = new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: "test", uniqueId: "test",
getChildContentAsync: () => getChildContentAsync: () =>
@ -195,7 +197,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
tagHelperContent.SetContent(tagHelperOutputContent.OriginalChildContent); tagHelperContent.SetContent(tagHelperOutputContent.OriginalChildContent);
return Task.FromResult<TagHelperContent>(tagHelperContent); return Task.FromResult<TagHelperContent>(tagHelperContent);
}); });
var htmlAttributes = new Dictionary<string, object> var htmlAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control" }, { "class", "form-control" },
}; };

View File

@ -28,14 +28,118 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
public class LinkTagHelperTest public class LinkTagHelperTest
{ {
public static TheoryData MultiAttributeSameNameData
{
get
{
// outputAttributes, expectedAttributeString
return new TheoryData<TagHelperAttributeList, string>
{
{
new TagHelperAttributeList
{
{ "hello", "world" },
{ "hello", "world2" }
},
"hello=\"HtmlEncode[[world]]\" hello=\"HtmlEncode[[world2]]\""
},
{
new TagHelperAttributeList
{
{ "hello", "world" },
{ "hello", "world2" },
{ "hello", "world3" }
},
"hello=\"HtmlEncode[[world]]\" hello=\"HtmlEncode[[world2]]\" hello=\"HtmlEncode[[world3]]\""
},
{
new TagHelperAttributeList
{
{ "HelLO", "world" },
{ "HELLO", "world2" }
},
"HelLO=\"HtmlEncode[[world]]\" HELLO=\"HtmlEncode[[world2]]\""
},
{
new TagHelperAttributeList
{
{ "Hello", "world" },
{ "HELLO", "world2" },
{ "hello", "world3" }
},
"Hello=\"HtmlEncode[[world]]\" HELLO=\"HtmlEncode[[world2]]\" hello=\"HtmlEncode[[world3]]\""
},
{
new TagHelperAttributeList
{
{ "HeLlO", "world" },
{ "hello", "world2" }
},
"HeLlO=\"HtmlEncode[[world]]\" hello=\"HtmlEncode[[world2]]\""
},
};
}
}
[Theory]
[MemberData(nameof(MultiAttributeSameNameData))]
public void HandlesMultipleAttributesSameNameCorrectly(
TagHelperAttributeList outputAttributes,
string expectedAttributeString)
{
// Arrange
var allAttributes = new TagHelperAttributeList(
outputAttributes.Concat(
new TagHelperAttributeList
{
{ "rel", new HtmlString("stylesheet") },
{ "href", "test.css" },
{ "asp-fallback-href", "test.css" },
{ "asp-fallback-test-class", "hidden" },
{ "asp-fallback-test-property", "visibility" },
{ "asp-fallback-test-value", "hidden" },
}));
var context = MakeTagHelperContext(allAttributes);
var combinedOutputAttributes = new TagHelperAttributeList(
outputAttributes.Concat(
new[]
{
new TagHelperAttribute("rel", new HtmlString("stylesheet"))
}));
var output = MakeTagHelperOutput("link", combinedOutputAttributes);
var logger = new Mock<ILogger<LinkTagHelper>>();
var hostingEnvironment = MakeHostingEnvironment();
var viewContext = MakeViewContext();
var helper = new LinkTagHelper
{
HtmlEncoder = new CommonTestEncoder(),
JavaScriptEncoder = new CommonTestEncoder(),
Logger = logger.Object,
HostingEnvironment = hostingEnvironment,
ViewContext = viewContext,
FallbackHref = "test.css",
FallbackTestClass = "hidden",
FallbackTestProperty = "visibility",
FallbackTestValue = "hidden",
Href = "test.css",
Cache = MakeCache(),
};
// Act
helper.Process(context, output);
// Assert
Assert.StartsWith("<link " + expectedAttributeString + " rel=\"stylesheet\"", output.Content.GetContent());
}
public static TheoryData RunsWhenRequiredAttributesArePresent_Data public static TheoryData RunsWhenRequiredAttributesArePresent_Data
{ {
get get
{ {
return new TheoryData<IDictionary<string, object>, Action<LinkTagHelper>> return new TheoryData<TagHelperAttributeList, Action<LinkTagHelper>>
{ {
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-href-include"] = "*.css" ["asp-href-include"] = "*.css"
}, },
@ -45,7 +149,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-href-include"] = "*.css", ["asp-href-include"] = "*.css",
["asp-href-exclude"] = "*.min.css" ["asp-href-exclude"] = "*.min.css"
@ -57,7 +161,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-fallback-href"] = "test.css", ["asp-fallback-href"] = "test.css",
["asp-fallback-test-class"] = "hidden", ["asp-fallback-test-class"] = "hidden",
@ -73,7 +177,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-fallback-href-include"] = "*.css", ["asp-fallback-href-include"] = "*.css",
["asp-fallback-test-class"] = "hidden", ["asp-fallback-test-class"] = "hidden",
@ -90,7 +194,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
}, },
// File Version // File Version
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-file-version"] = "true" ["asp-file-version"] = "true"
}, },
@ -100,7 +204,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-href-include"] = "*.css", ["asp-href-include"] = "*.css",
["asp-file-version"] = "true" ["asp-file-version"] = "true"
@ -112,7 +216,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-href-include"] = "*.css", ["asp-href-include"] = "*.css",
["asp-href-exclude"] = "*.min.css", ["asp-href-exclude"] = "*.min.css",
@ -126,7 +230,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-fallback-href"] = "test.css", ["asp-fallback-href"] = "test.css",
["asp-fallback-test-class"] = "hidden", ["asp-fallback-test-class"] = "hidden",
@ -144,7 +248,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-fallback-href-include"] = "*.css", ["asp-fallback-href-include"] = "*.css",
["asp-fallback-test-class"] = "hidden", ["asp-fallback-test-class"] = "hidden",
@ -168,7 +272,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
[Theory] [Theory]
[MemberData(nameof(RunsWhenRequiredAttributesArePresent_Data))] [MemberData(nameof(RunsWhenRequiredAttributesArePresent_Data))]
public void RunsWhenRequiredAttributesArePresent( public void RunsWhenRequiredAttributesArePresent(
IDictionary<string, object> attributes, TagHelperAttributeList attributes,
Action<LinkTagHelper> setProperties) Action<LinkTagHelper> setProperties)
{ {
// Arrange // Arrange
@ -202,21 +306,21 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
// Arrange // Arrange
var context = MakeTagHelperContext( var context = MakeTagHelperContext(
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
["rel"] = new HtmlString("stylesheet"), { "rel", new HtmlString("stylesheet") },
["data-extra"] = new HtmlString("something"), { "data-extra", new HtmlString("something") },
["href"] = "test.css", { "href", "test.css" },
["asp-fallback-href"] = "test.css", { "asp-fallback-href", "test.css" },
["asp-fallback-test-class"] = "hidden", { "asp-fallback-test-class", "hidden" },
["asp-fallback-test-property"] = "visibility", { "asp-fallback-test-property", "visibility" },
["asp-fallback-test-value"] = "hidden" { "asp-fallback-test-value", "hidden" },
}); });
var output = MakeTagHelperOutput("link", var output = MakeTagHelperOutput("link",
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
["rel"] = new HtmlString("stylesheet"), { "rel", new HtmlString("stylesheet") },
["data-extra"] = new HtmlString("something"), { "data-extra", new HtmlString("something") },
}); });
var logger = new Mock<ILogger<LinkTagHelper>>(); var logger = new Mock<ILogger<LinkTagHelper>>();
var hostingEnvironment = MakeHostingEnvironment(); var hostingEnvironment = MakeHostingEnvironment();
@ -248,10 +352,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
get get
{ {
return new TheoryData<IDictionary<string, object>, Action<LinkTagHelper>> return new TheoryData<TagHelperAttributeList, Action<LinkTagHelper>>
{ {
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
// This is commented out on purpose: ["asp-href-include"] = "*.css", // This is commented out on purpose: ["asp-href-include"] = "*.css",
["asp-href-exclude"] = "*.min.css" ["asp-href-exclude"] = "*.min.css"
@ -263,7 +367,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
// This is commented out on purpose: ["asp-fallback-href"] = "test.css", // This is commented out on purpose: ["asp-fallback-href"] = "test.css",
["asp-fallback-test-class"] = "hidden", ["asp-fallback-test-class"] = "hidden",
@ -279,7 +383,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-fallback-href"] = "test.css", ["asp-fallback-href"] = "test.css",
["asp-fallback-test-class"] = "hidden", ["asp-fallback-test-class"] = "hidden",
@ -295,7 +399,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
// This is commented out on purpose: ["asp-fallback-href-include"] = "test.css", // This is commented out on purpose: ["asp-fallback-href-include"] = "test.css",
["asp-fallback-href-exclude"] = "**/*.min.css", ["asp-fallback-href-exclude"] = "**/*.min.css",
@ -319,7 +423,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
[Theory] [Theory]
[MemberData(nameof(DoesNotRunWhenARequiredAttributeIsMissing_Data))] [MemberData(nameof(DoesNotRunWhenARequiredAttributeIsMissing_Data))]
public void DoesNotRunWhenARequiredAttributeIsMissing( public void DoesNotRunWhenARequiredAttributeIsMissing(
IDictionary<string, object> attributes, TagHelperAttributeList attributes,
Action<LinkTagHelper> setProperties) Action<LinkTagHelper> setProperties)
{ {
// Arrange // Arrange
@ -375,15 +479,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
// Arrange // Arrange
var context = MakeTagHelperContext( var context = MakeTagHelperContext(
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
["rel"] = new HtmlString("stylesheet"), { "rel", new HtmlString("stylesheet") },
["href"] = "/css/site.css", { "href", "/css/site.css" },
["asp-href-include"] = "**/*.css" { "asp-href-include", "**/*.css" },
}); });
var output = MakeTagHelperOutput("link", attributes: new Dictionary<string, object> var output = MakeTagHelperOutput("link", attributes: new TagHelperAttributeList
{ {
["rel"] = new HtmlString("stylesheet"), { "rel", new HtmlString("stylesheet") },
}); });
var logger = new Mock<ILogger<LinkTagHelper>>(); var logger = new Mock<ILogger<LinkTagHelper>>();
var hostingEnvironment = MakeHostingEnvironment(); var hostingEnvironment = MakeHostingEnvironment();
@ -418,13 +522,13 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
// Arrange // Arrange
var context = MakeTagHelperContext( var context = MakeTagHelperContext(
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
["rel"] = "stylesheet", ["rel"] = "stylesheet",
["href"] = "/css/site.css", ["href"] = "/css/site.css",
["asp-href-include"] = "**/*.css" ["asp-href-include"] = "**/*.css"
}); });
var output = MakeTagHelperOutput("link", attributes: new Dictionary<string, object> var output = MakeTagHelperOutput("link", attributes: new TagHelperAttributeList
{ {
["rel"] = "stylesheet", ["rel"] = "stylesheet",
}); });
@ -461,15 +565,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
// Arrange // Arrange
var context = MakeTagHelperContext( var context = MakeTagHelperContext(
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
["rel"] = new HtmlString("stylesheet"), { "rel", new HtmlString("stylesheet") },
["href"] = "/css/site.css", { "href", "/css/site.css" },
["asp-file-version"] = "true" { "asp-file-version", "true" }
}); });
var output = MakeTagHelperOutput("link", attributes: new Dictionary<string, object> var output = MakeTagHelperOutput("link", attributes: new TagHelperAttributeList
{ {
["rel"] = new HtmlString("stylesheet"), { "rel", new HtmlString("stylesheet") },
}); });
var logger = new Mock<ILogger<LinkTagHelper>>(); var logger = new Mock<ILogger<LinkTagHelper>>();
var hostingEnvironment = MakeHostingEnvironment(); var hostingEnvironment = MakeHostingEnvironment();
@ -500,15 +604,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
// Arrange // Arrange
var context = MakeTagHelperContext( var context = MakeTagHelperContext(
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
["rel"] = new HtmlString("stylesheet"), { "rel", new HtmlString("stylesheet") },
["href"] = "/bar/css/site.css", { "href", "/bar/css/site.css" },
["asp-file-version"] = "true" { "asp-file-version", "true" },
}); });
var output = MakeTagHelperOutput("link", attributes: new Dictionary<string, object> var output = MakeTagHelperOutput("link", attributes: new TagHelperAttributeList
{ {
["rel"] = new HtmlString("stylesheet"), { "rel", new HtmlString("stylesheet") },
}); });
var logger = new Mock<ILogger<LinkTagHelper>>(); var logger = new Mock<ILogger<LinkTagHelper>>();
var hostingEnvironment = MakeHostingEnvironment(); var hostingEnvironment = MakeHostingEnvironment();
@ -539,16 +643,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
// Arrange // Arrange
var context = MakeTagHelperContext( var context = MakeTagHelperContext(
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
["rel"] = new HtmlString("stylesheet"), { "rel", new HtmlString("stylesheet") },
["href"] = "/css/site.css", { "href", "/css/site.css" },
["asp-href-include"] = "**/*.css", { "asp-href-include", "**/*.css" },
["asp-file-version"] = "true" { "asp-file-version", "true" },
}); });
var output = MakeTagHelperOutput("link", attributes: new Dictionary<string, object> var output = MakeTagHelperOutput("link", attributes: new TagHelperAttributeList
{ {
["rel"] = new HtmlString("stylesheet"), { "rel", new HtmlString("stylesheet") },
}); });
var logger = new Mock<ILogger<LinkTagHelper>>(); var logger = new Mock<ILogger<LinkTagHelper>>();
var hostingEnvironment = MakeHostingEnvironment(); var hostingEnvironment = MakeHostingEnvironment();
@ -600,10 +704,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
private static TagHelperContext MakeTagHelperContext( private static TagHelperContext MakeTagHelperContext(
IDictionary<string, object> attributes = null, TagHelperAttributeList attributes = null,
string content = null) string content = null)
{ {
attributes = attributes ?? new Dictionary<string, object>(); attributes = attributes ?? new TagHelperAttributeList();
return new TagHelperContext( return new TagHelperContext(
attributes, attributes,
@ -617,9 +721,9 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
}); });
} }
private static TagHelperOutput MakeTagHelperOutput(string tagName, IDictionary<string, object> attributes = null) private static TagHelperOutput MakeTagHelperOutput(string tagName, TagHelperAttributeList attributes = null)
{ {
attributes = attributes ?? new Dictionary<string, object>(); attributes = attributes ?? new TagHelperAttributeList();
return new TagHelperOutput(tagName, attributes); return new TagHelperOutput(tagName, attributes);
} }

View File

@ -26,7 +26,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
null, null, null, null, null, null, null, null,
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" } { "label", "my-label" }
}, },
@ -36,7 +36,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
null, string.Empty, "value", null, null, string.Empty, "value", null,
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "value", "value" }, { "selected", "" } { "label", "my-label" }, { "value", "value" }, { "selected", "" }
}, },
@ -46,7 +46,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
null, "selected", "value", null, null, "selected", "value", null,
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "value", "value" }, { "selected", "selected" } { "label", "my-label" }, { "value", "value" }, { "selected", "selected" }
}, },
@ -56,7 +56,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
null, null, "value", Enumerable.Empty<string>(), null, null, "value", Enumerable.Empty<string>(),
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "value", "value" } { "label", "my-label" }, { "value", "value" }
}, },
@ -66,7 +66,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
null, null, "value", new [] { string.Empty, }, null, null, "value", new [] { string.Empty, },
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "value", "value" } { "label", "my-label" }, { "value", "value" }
}, },
@ -76,7 +76,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
null, string.Empty, "value", new [] { string.Empty, }, null, string.Empty, "value", new [] { string.Empty, },
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "value", "value" }, { "selected", "" } { "label", "my-label" }, { "value", "value" }, { "selected", "" }
}, },
@ -86,7 +86,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
null, null, "value", new [] { "value", }, null, null, "value", new [] { "value", },
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "value", "value" }, { "selected", "selected" } { "label", "my-label" }, { "value", "value" }, { "selected", "selected" }
}, },
@ -96,7 +96,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
null, null, "value", new [] { string.Empty, "value", }, null, null, "value", new [] { string.Empty, "value", },
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "value", "value" }, { "selected", "selected" } { "label", "my-label" }, { "value", "value" }, { "selected", "selected" }
}, },
@ -106,7 +106,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
string.Empty, null, null, null, string.Empty, null, null, null,
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" } { "label", "my-label" }
}, },
@ -116,7 +116,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
string.Empty, string.Empty, null, null, string.Empty, string.Empty, null, null,
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "selected", "" } { "label", "my-label" }, { "selected", "" }
}, },
@ -126,7 +126,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
string.Empty, "selected", null, null, string.Empty, "selected", null, null,
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "selected", "selected" } { "label", "my-label" }, { "selected", "selected" }
}, },
@ -136,7 +136,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
string.Empty, null, null, Enumerable.Empty<string>(), string.Empty, null, null, Enumerable.Empty<string>(),
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" } { "label", "my-label" }
}, },
@ -146,7 +146,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
string.Empty, null, null, new [] { string.Empty, }, string.Empty, null, null, new [] { string.Empty, },
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "selected", "selected" } { "label", "my-label" }, { "selected", "selected" }
}, },
@ -156,7 +156,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
string.Empty, string.Empty, null, new [] { string.Empty, }, string.Empty, string.Empty, null, new [] { string.Empty, },
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "selected", "" } { "label", "my-label" }, { "selected", "" }
}, },
@ -166,7 +166,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
string.Empty, null, null, new [] { "text", }, string.Empty, null, null, new [] { "text", },
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" } { "label", "my-label" }
}, },
@ -176,7 +176,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
string.Empty, null, null, new [] { string.Empty, "text", }, string.Empty, null, null, new [] { string.Empty, "text", },
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "selected", "selected" } { "label", "my-label" }, { "selected", "selected" }
}, },
@ -186,7 +186,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
"text", null, null, null, "text", null, null, null,
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" } { "label", "my-label" }
}, },
@ -196,7 +196,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
"text", string.Empty, null, null, "text", string.Empty, null, null,
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "selected", "" } { "label", "my-label" }, { "selected", "" }
}, },
@ -206,7 +206,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
"text", "selected", null, null, "text", "selected", null, null,
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "selected", "selected" } { "label", "my-label" }, { "selected", "selected" }
}, },
@ -216,7 +216,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
"text", null, null, Enumerable.Empty<string>(), "text", null, null, Enumerable.Empty<string>(),
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" } { "label", "my-label" }
}, },
@ -226,7 +226,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
"text", null, null, new [] { string.Empty, }, "text", null, null, new [] { string.Empty, },
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" } { "label", "my-label" }
}, },
@ -236,7 +236,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
"HtmlEncode[[text]]", null, null, new [] { "text", }, "HtmlEncode[[text]]", null, null, new [] { "text", },
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "selected", "selected" } { "label", "my-label" }, { "selected", "selected" }
}, },
@ -246,7 +246,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
"text", string.Empty, null, new [] { "text", }, "text", string.Empty, null, new [] { "text", },
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "selected", "" } { "label", "my-label" }, { "selected", "" }
}, },
@ -256,7 +256,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
"HtmlEncode[[text]]", null, null, new [] { string.Empty, "text", }, "HtmlEncode[[text]]", null, null, new [] { string.Empty, "text", },
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "selected", "selected" } { "label", "my-label" }, { "selected", "selected" }
}, },
@ -266,7 +266,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
"text", string.Empty, "value", null, "text", string.Empty, "value", null,
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "value", "value" }, { "selected", "" } { "label", "my-label" }, { "value", "value" }, { "selected", "" }
}, },
@ -276,7 +276,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
"text", "selected", "value", null, "text", "selected", "value", null,
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "value", "value" }, { "selected", "selected" } { "label", "my-label" }, { "value", "value" }, { "selected", "selected" }
}, },
@ -286,7 +286,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
"text", null, "value", Enumerable.Empty<string>(), "text", null, "value", Enumerable.Empty<string>(),
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "value", "value" } { "label", "my-label" }, { "value", "value" }
}, },
@ -296,7 +296,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
"text", null, "value", new [] { string.Empty, }, "text", null, "value", new [] { string.Empty, },
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "value", "value" } { "label", "my-label" }, { "value", "value" }
}, },
@ -306,7 +306,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
"text", string.Empty, "value", new [] { string.Empty, }, "text", string.Empty, "value", new [] { string.Empty, },
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "value", "value" }, { "selected", "" } { "label", "my-label" }, { "value", "value" }, { "selected", "" }
}, },
@ -316,7 +316,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
"text", null, "value", new [] { "text", }, "text", null, "value", new [] { "text", },
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "value", "value" } { "label", "my-label" }, { "value", "value" }
}, },
@ -326,7 +326,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
"text", null, "value", new [] { "value", }, "text", null, "value", new [] { "value", },
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "value", "value" }, { "selected", "selected" } { "label", "my-label" }, { "value", "value" }, { "selected", "selected" }
}, },
@ -336,7 +336,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
"text", null, "value", new [] { string.Empty, "value", }, "text", null, "value", new [] { string.Empty, "value", },
GetTagHelperOutput( GetTagHelperOutput(
"not-option", "not-option",
new Dictionary<string, object> new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "value", "value" }, { "selected", "selected" } { "label", "my-label" }, { "value", "value" }, { "selected", "selected" }
}, },
@ -379,7 +379,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
TagHelperOutput expectedTagHelperOutput) TagHelperOutput expectedTagHelperOutput)
{ {
// Arrange // Arrange
var originalAttributes = new Dictionary<string, object> var originalAttributes = new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "label", "my-label" },
}; };
@ -388,7 +388,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
originalAttributes.Add("selected", selected); originalAttributes.Add("selected", selected);
} }
var contextAttributes = new Dictionary<string, object>(originalAttributes); var contextAttributes = new TagHelperAttributeList(originalAttributes);
if (value != null) if (value != null)
{ {
contextAttributes.Add("value", value); contextAttributes.Add("value", value);
@ -449,14 +449,14 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
TagHelperOutput ignored) TagHelperOutput ignored)
{ {
// Arrange // Arrange
var originalAttributes = new Dictionary<string, object> var originalAttributes = new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "label", "my-label" },
{ "selected", selected }, { "selected", selected },
}; };
var originalTagName = "not-option"; var originalTagName = "not-option";
var contextAttributes = new Dictionary<string, object> var contextAttributes = new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "label", "my-label" },
{ "selected", selected }, { "selected", selected },
@ -510,14 +510,14 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
TagHelperOutput ignoredOutput) TagHelperOutput ignoredOutput)
{ {
// Arrange // Arrange
var originalAttributes = new Dictionary<string, object> var originalAttributes = new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "label", "my-label" },
{ "selected", selected }, { "selected", selected },
}; };
var originalTagName = "not-option"; var originalTagName = "not-option";
var contextAttributes = new Dictionary<string, object> var contextAttributes = new TagHelperAttributeList
{ {
{ "label", "my-label" }, { "label", "my-label" },
{ "selected", selected }, { "selected", selected },
@ -554,7 +554,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
private static TagHelperOutput GetTagHelperOutput( private static TagHelperOutput GetTagHelperOutput(
string tagName, IDictionary<string, object> attributes, string content) string tagName, TagHelperAttributeList attributes, string content)
{ {
var tagHelperOutput = new TagHelperOutput(tagName, attributes); var tagHelperOutput = new TagHelperOutput(tagName, attributes);
tagHelperOutput.Content.SetContent(content); tagHelperOutput.Content.SetContent(content);

View File

@ -28,14 +28,64 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
public class ScriptTagHelperTest public class ScriptTagHelperTest
{ {
[Theory]
[MemberData(nameof(LinkTagHelperTest.MultiAttributeSameNameData), MemberType = typeof(LinkTagHelperTest))]
public async Task HandlesMultipleAttributesSameNameCorrectly(
TagHelperAttributeList outputAttributes,
string expectedAttributeString)
{
// Arrange
var allAttributes = new TagHelperAttributeList(
outputAttributes.Concat(
new TagHelperAttributeList
{
["data-extra"] = "something",
["src"] = "/blank.js",
["asp-fallback-src"] = "http://www.example.com/blank.js",
["asp-fallback-test"] = "isavailable()",
}));
var tagHelperContext = MakeTagHelperContext(allAttributes);
var viewContext = MakeViewContext();
var combinedOutputAttributes = new TagHelperAttributeList(
outputAttributes.Concat(
new[]
{
new TagHelperAttribute("data-extra", new HtmlString("something"))
}));
var output = MakeTagHelperOutput("script", combinedOutputAttributes);
var hostingEnvironment = MakeHostingEnvironment();
var helper = new ScriptTagHelper
{
HtmlEncoder = new CommonTestEncoder(),
JavaScriptEncoder = new CommonTestEncoder(),
ViewContext = viewContext,
HostingEnvironment = hostingEnvironment,
FallbackSrc = "~/blank.js",
FallbackTestExpression = "http://www.example.com/blank.js",
Src = "/blank.js",
Cache = MakeCache(),
Logger = CreateLogger()
};
// Act
await helper.ProcessAsync(tagHelperContext, output);
// Assert
Assert.StartsWith(
"<script " + expectedAttributeString + " data-extra=\"something\" " +
"src=\"HtmlEncode[[/blank.js]]\"",
output.Content.GetContent());
}
public static TheoryData RunsWhenRequiredAttributesArePresent_Data public static TheoryData RunsWhenRequiredAttributesArePresent_Data
{ {
get get
{ {
return new TheoryData<IDictionary<string, object>, Action<ScriptTagHelper>> return new TheoryData<TagHelperAttributeList, Action<ScriptTagHelper>>
{ {
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-src-include"] = "*.js" ["asp-src-include"] = "*.js"
}, },
@ -45,7 +95,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-src-include"] = "*.js", ["asp-src-include"] = "*.js",
["asp-src-exclude"] = "*.min.js" ["asp-src-exclude"] = "*.min.js"
@ -57,7 +107,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-fallback-src"] = "test.js", ["asp-fallback-src"] = "test.js",
["asp-fallback-test"] = "isavailable()" ["asp-fallback-test"] = "isavailable()"
@ -69,7 +119,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-fallback-src-include"] = "*.js", ["asp-fallback-src-include"] = "*.js",
["asp-fallback-test"] = "isavailable()" ["asp-fallback-test"] = "isavailable()"
@ -81,7 +131,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-fallback-src"] = "test.js", ["asp-fallback-src"] = "test.js",
["asp-fallback-src-include"] = "*.js", ["asp-fallback-src-include"] = "*.js",
@ -95,7 +145,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-fallback-src-include"] = "*.js", ["asp-fallback-src-include"] = "*.js",
["asp-fallback-src-exclude"] = "*.min.js", ["asp-fallback-src-exclude"] = "*.min.js",
@ -110,7 +160,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
}, },
// File Version // File Version
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-file-version"] = "true" ["asp-file-version"] = "true"
}, },
@ -120,7 +170,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-src-include"] = "*.js", ["asp-src-include"] = "*.js",
["asp-file-version"] = "true" ["asp-file-version"] = "true"
@ -132,7 +182,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-src-include"] = "*.js", ["asp-src-include"] = "*.js",
["asp-src-exclude"] = "*.min.js", ["asp-src-exclude"] = "*.min.js",
@ -146,7 +196,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-fallback-src"] = "test.js", ["asp-fallback-src"] = "test.js",
["asp-fallback-test"] = "isavailable()", ["asp-fallback-test"] = "isavailable()",
@ -160,7 +210,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-fallback-src-include"] = "*.js", ["asp-fallback-src-include"] = "*.js",
["asp-fallback-test"] = "isavailable()", ["asp-fallback-test"] = "isavailable()",
@ -174,7 +224,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-fallback-src"] = "test.js", ["asp-fallback-src"] = "test.js",
["asp-fallback-src-include"] = "*.js", ["asp-fallback-src-include"] = "*.js",
@ -190,7 +240,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-fallback-src-include"] = "*.js", ["asp-fallback-src-include"] = "*.js",
["asp-fallback-src-exclude"] = "*.min.js", ["asp-fallback-src-exclude"] = "*.min.js",
@ -212,7 +262,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
[Theory] [Theory]
[MemberData(nameof(RunsWhenRequiredAttributesArePresent_Data))] [MemberData(nameof(RunsWhenRequiredAttributesArePresent_Data))]
public async Task RunsWhenRequiredAttributesArePresent( public async Task RunsWhenRequiredAttributesArePresent(
IDictionary<string, object> attributes, TagHelperAttributeList attributes,
Action<ScriptTagHelper> setProperties) Action<ScriptTagHelper> setProperties)
{ {
// Arrange // Arrange
@ -245,10 +295,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
get get
{ {
return new TheoryData<IDictionary<string, object>, Action<ScriptTagHelper>> return new TheoryData<TagHelperAttributeList, Action<ScriptTagHelper>>
{ {
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
// This is commented out on purpose: ["asp-src-include"] = "*.js", // This is commented out on purpose: ["asp-src-include"] = "*.js",
["asp-src-exclude"] = "*.min.js" ["asp-src-exclude"] = "*.min.js"
@ -260,7 +310,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
// This is commented out on purpose: ["asp-fallback-src"] = "test.js", // This is commented out on purpose: ["asp-fallback-src"] = "test.js",
["asp-fallback-test"] = "isavailable()", ["asp-fallback-test"] = "isavailable()",
@ -272,7 +322,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
["asp-fallback-src"] = "test.js", ["asp-fallback-src"] = "test.js",
// This is commented out on purpose: ["asp-fallback-test"] = "isavailable()" // This is commented out on purpose: ["asp-fallback-test"] = "isavailable()"
@ -284,7 +334,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
}, },
{ {
new Dictionary<string, object> new TagHelperAttributeList
{ {
// This is commented out on purpose: ["asp-fallback-src-include"] = "test.js", // This is commented out on purpose: ["asp-fallback-src-include"] = "test.js",
["asp-fallback-src-exclude"] = "**/*.min.js", ["asp-fallback-src-exclude"] = "**/*.min.js",
@ -304,7 +354,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
[Theory] [Theory]
[MemberData(nameof(DoesNotRunWhenARequiredAttributeIsMissing_Data))] [MemberData(nameof(DoesNotRunWhenARequiredAttributeIsMissing_Data))]
public void DoesNotRunWhenARequiredAttributeIsMissing( public void DoesNotRunWhenARequiredAttributeIsMissing(
IDictionary<string, object> attributes, TagHelperAttributeList attributes,
Action<ScriptTagHelper> setProperties) Action<ScriptTagHelper> setProperties)
{ {
// Arrange // Arrange
@ -333,7 +383,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
[Theory] [Theory]
[MemberData(nameof(DoesNotRunWhenARequiredAttributeIsMissing_Data))] [MemberData(nameof(DoesNotRunWhenARequiredAttributeIsMissing_Data))]
public async Task LogsWhenARequiredAttributeIsMissing( public async Task LogsWhenARequiredAttributeIsMissing(
IDictionary<string, object> attributes, TagHelperAttributeList attributes,
Action<ScriptTagHelper> setProperties) Action<ScriptTagHelper> setProperties)
{ {
// Arrange // Arrange
@ -431,7 +481,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
// Arrange // Arrange
var tagHelperContext = MakeTagHelperContext( var tagHelperContext = MakeTagHelperContext(
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
["data-extra"] = "something", ["data-extra"] = "something",
["src"] = "/blank.js", ["src"] = "/blank.js",
@ -443,7 +493,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var viewContext = MakeViewContext(); var viewContext = MakeViewContext();
var output = MakeTagHelperOutput("src", var output = MakeTagHelperOutput("src",
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
["data-extra"] = "something", ["data-extra"] = "something",
["data-more"] = "else", ["data-more"] = "else",
@ -480,12 +530,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
// Arrange // Arrange
var context = MakeTagHelperContext( var context = MakeTagHelperContext(
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
["src"] = "/js/site.js", ["src"] = "/js/site.js",
["asp-src-include"] = "**/*.js" ["asp-src-include"] = "**/*.js"
}); });
var output = MakeTagHelperOutput("script", attributes: new Dictionary<string, object>()); var output = MakeTagHelperOutput("script", attributes: new TagHelperAttributeList());
var logger = new Mock<ILogger<ScriptTagHelper>>(); var logger = new Mock<ILogger<ScriptTagHelper>>();
var hostingEnvironment = MakeHostingEnvironment(); var hostingEnvironment = MakeHostingEnvironment();
var viewContext = MakeViewContext(); var viewContext = MakeViewContext();
@ -517,12 +567,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
// Arrange // Arrange
var context = MakeTagHelperContext( var context = MakeTagHelperContext(
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
["src"] = "/js/site.js", ["src"] = "/js/site.js",
["asp-src-include"] = "**/*.js" ["asp-src-include"] = "**/*.js"
}); });
var output = MakeTagHelperOutput("script", attributes: new Dictionary<string, object>()); var output = MakeTagHelperOutput("script", attributes: new TagHelperAttributeList());
var logger = new Mock<ILogger<ScriptTagHelper>>(); var logger = new Mock<ILogger<ScriptTagHelper>>();
var hostingEnvironment = MakeHostingEnvironment(); var hostingEnvironment = MakeHostingEnvironment();
var viewContext = MakeViewContext(); var viewContext = MakeViewContext();
@ -555,12 +605,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
// Arrange // Arrange
var context = MakeTagHelperContext( var context = MakeTagHelperContext(
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
["src"] = "/js/site.js", ["src"] = "/js/site.js",
["asp-file-version"] = "true" ["asp-file-version"] = "true"
}); });
var output = MakeTagHelperOutput("script", attributes: new Dictionary<string, object>()); var output = MakeTagHelperOutput("script", attributes: new TagHelperAttributeList());
var logger = new Mock<ILogger<ScriptTagHelper>>(); var logger = new Mock<ILogger<ScriptTagHelper>>();
var hostingEnvironment = MakeHostingEnvironment(); var hostingEnvironment = MakeHostingEnvironment();
@ -592,12 +642,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
// Arrange // Arrange
var context = MakeTagHelperContext( var context = MakeTagHelperContext(
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
["src"] = "/bar/js/site.js", ["src"] = "/bar/js/site.js",
["asp-file-version"] = "true" ["asp-file-version"] = "true"
}); });
var output = MakeTagHelperOutput("script", attributes: new Dictionary<string, object>()); var output = MakeTagHelperOutput("script", attributes: new TagHelperAttributeList());
var logger = new Mock<ILogger<ScriptTagHelper>>(); var logger = new Mock<ILogger<ScriptTagHelper>>();
var hostingEnvironment = MakeHostingEnvironment(); var hostingEnvironment = MakeHostingEnvironment();
@ -629,14 +679,14 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
// Arrange // Arrange
var context = MakeTagHelperContext( var context = MakeTagHelperContext(
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
["src"] = "/js/site.js", ["src"] = "/js/site.js",
["asp-fallback-src-include"] = "fallback.js", ["asp-fallback-src-include"] = "fallback.js",
["asp-fallback-test"] = "isavailable()", ["asp-fallback-test"] = "isavailable()",
["asp-file-version"] = "true" ["asp-file-version"] = "true"
}); });
var output = MakeTagHelperOutput("script", attributes: new Dictionary<string, object>()); var output = MakeTagHelperOutput("script", attributes: new TagHelperAttributeList());
var logger = new Mock<ILogger<ScriptTagHelper>>(); var logger = new Mock<ILogger<ScriptTagHelper>>();
var hostingEnvironment = MakeHostingEnvironment(); var hostingEnvironment = MakeHostingEnvironment();
@ -672,13 +722,13 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
// Arrange // Arrange
var context = MakeTagHelperContext( var context = MakeTagHelperContext(
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
["src"] = "/js/site.js", ["src"] = "/js/site.js",
["asp-src-include"] = "*.js", ["asp-src-include"] = "*.js",
["asp-file-version"] = "true" ["asp-file-version"] = "true"
}); });
var output = MakeTagHelperOutput("script", attributes: new Dictionary<string, object>()); var output = MakeTagHelperOutput("script", attributes: new TagHelperAttributeList());
var logger = new Mock<ILogger<ScriptTagHelper>>(); var logger = new Mock<ILogger<ScriptTagHelper>>();
var hostingEnvironment = MakeHostingEnvironment(); var hostingEnvironment = MakeHostingEnvironment();
var viewContext = MakeViewContext(); var viewContext = MakeViewContext();
@ -709,10 +759,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
private TagHelperContext MakeTagHelperContext( private TagHelperContext MakeTagHelperContext(
IDictionary<string, object> attributes = null, TagHelperAttributeList attributes = null,
string content = null) string content = null)
{ {
attributes = attributes ?? new Dictionary<string, object>(); attributes = attributes ?? new TagHelperAttributeList();
return new TagHelperContext( return new TagHelperContext(
attributes, attributes,
@ -746,9 +796,9 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
return viewContext; return viewContext;
} }
private TagHelperOutput MakeTagHelperOutput(string tagName, IDictionary<string, object> attributes = null) private TagHelperOutput MakeTagHelperOutput(string tagName, TagHelperAttributeList attributes = null)
{ {
attributes = attributes ?? new Dictionary<string, object>(); attributes = attributes ?? new TagHelperAttributeList();
return new TagHelperOutput(tagName, attributes); return new TagHelperOutput(tagName, attributes);
} }

View File

@ -171,13 +171,13 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
string ignored) string ignored)
{ {
// Arrange // Arrange
var originalAttributes = new Dictionary<string, object> var originalAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control" }, { "class", "form-control" },
}; };
var originalPostContent = "original content"; var originalPostContent = "original content";
var expectedAttributes = new Dictionary<string, object>(originalAttributes) var expectedAttributes = new TagHelperAttributeList(originalAttributes)
{ {
{ "id", nameAndId.Id }, { "id", nameAndId.Id },
{ "name", nameAndId.Name }, { "name", nameAndId.Name },
@ -198,7 +198,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var modelExpression = new ModelExpression(nameAndId.Name, modelExplorer); var modelExpression = new ModelExpression(nameAndId.Name, modelExplorer);
var tagHelperContext = new TagHelperContext( var tagHelperContext = new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: "test", uniqueId: "test",
getChildContentAsync: () => getChildContentAsync: () =>
@ -257,13 +258,13 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
string expectedOptions) string expectedOptions)
{ {
// Arrange // Arrange
var originalAttributes = new Dictionary<string, object> var originalAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control" }, { "class", "form-control" },
}; };
var originalPostContent = "original content"; var originalPostContent = "original content";
var expectedAttributes = new Dictionary<string, object>(originalAttributes) var expectedAttributes = new TagHelperAttributeList(originalAttributes)
{ {
{ "id", nameAndId.Id }, { "id", nameAndId.Id },
{ "name", nameAndId.Name }, { "name", nameAndId.Name },
@ -285,7 +286,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var modelExpression = new ModelExpression(nameAndId.Name, modelExplorer); var modelExpression = new ModelExpression(nameAndId.Name, modelExplorer);
var tagHelperContext = new TagHelperContext( var tagHelperContext = new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: "test", uniqueId: "test",
getChildContentAsync: () => getChildContentAsync: () =>
@ -358,13 +360,13 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
string expectedOptions) string expectedOptions)
{ {
// Arrange // Arrange
var originalAttributes = new Dictionary<string, object> var originalAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control" }, { "class", "form-control" },
}; };
var originalPostContent = "original content"; var originalPostContent = "original content";
var expectedAttributes = new Dictionary<string, object>(originalAttributes) var expectedAttributes = new TagHelperAttributeList(originalAttributes)
{ {
{ "id", nameAndId.Id }, { "id", nameAndId.Id },
{ "name", nameAndId.Name }, { "name", nameAndId.Name },
@ -386,7 +388,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var modelExpression = new ModelExpression(name: string.Empty, modelExplorer: modelExplorer); var modelExpression = new ModelExpression(name: string.Empty, modelExplorer: modelExplorer);
var tagHelperContext = new TagHelperContext( var tagHelperContext = new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: "test", uniqueId: "test",
getChildContentAsync: () => getChildContentAsync: () =>
@ -459,12 +462,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
IEnumerable<SelectListItem> expectedItems) IEnumerable<SelectListItem> expectedItems)
{ {
// Arrange // Arrange
var contextAttributes = new Dictionary<string, object> var contextAttributes = new TagHelperAttributeList
{ {
// Provided for completeness. Select tag helper does not confirm AllAttributes set is consistent. // Provided for completeness. Select tag helper does not confirm AllAttributes set is consistent.
{ attributeName, attributeValue }, { attributeName, attributeValue },
}; };
var originalAttributes = new Dictionary<string, object> var originalAttributes = new TagHelperAttributeList
{ {
{ attributeName, attributeValue }, { attributeName, attributeValue },
}; };
@ -545,8 +548,9 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
bool allowMultiple) bool allowMultiple)
{ {
// Arrange // Arrange
var contextAttributes = new Dictionary<string, object>(); var contextAttributes = new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
var originalAttributes = new Dictionary<string, object>(); Enumerable.Empty<IReadOnlyTagHelperAttribute>());
var originalAttributes = new TagHelperAttributeList();
var propertyName = "Property1"; var propertyName = "Property1";
var tagName = "select"; var tagName = "select";

View File

@ -8,12 +8,111 @@ using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Razor.Runtime.TagHelpers; using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Microsoft.AspNet.Testing; using Microsoft.AspNet.Testing;
using Microsoft.Framework.WebEncoders.Testing; using Microsoft.Framework.WebEncoders.Testing;
using Microsoft.Internal.Web.Utils;
using Xunit; using Xunit;
namespace Microsoft.AspNet.Mvc.TagHelpers namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
public class TagHelperOutputExtensionsTest public class TagHelperOutputExtensionsTest
{ {
public static TheoryData CopyHtmlAttributeData_MultipleAttributesSameName
{
get
{
// attributeNameToCopy, allAttributes, expectedAttributes
return new TheoryData<string, TagHelperAttributeList, IEnumerable<TagHelperAttribute>>
{
{
"hello",
new TagHelperAttributeList
{
{ "hello", "world" },
{ "hello", "world2" }
},
new[]
{
new TagHelperAttribute("hello", "world"),
new TagHelperAttribute("hello", "world2"),
}
},
{
"HELLO",
new TagHelperAttributeList
{
{ "hello", "world" },
{ "hello", "world2" }
},
new[]
{
new TagHelperAttribute("hello", "world"),
new TagHelperAttribute("hello", "world2"),
}
},
{
"hello",
new TagHelperAttributeList
{
{ "HelLO", "world" },
{ "HELLO", "world2" }
},
new[]
{
new TagHelperAttribute("HelLO", "world"),
new TagHelperAttribute("HELLO", "world2"),
}
},
{
"hello",
new TagHelperAttributeList
{
{ "hello", "world" },
{ "HELLO", "world2" }
},
new[]
{
new TagHelperAttribute("hello", "world"),
new TagHelperAttribute("HELLO", "world2"),
}
},
{
"HELLO",
new TagHelperAttributeList
{
{ "HeLlO", "world" },
{ "heLLo", "world2" }
},
new[]
{
new TagHelperAttribute("HeLlO", "world"),
new TagHelperAttribute("heLLo", "world2"),
}
},
};
}
}
[Theory]
[MemberData(nameof(CopyHtmlAttributeData_MultipleAttributesSameName))]
public void CopyHtmlAttribute_CopiesAllOriginalAttributes(
string attributeNameToCopy,
TagHelperAttributeList allAttributes,
IEnumerable<TagHelperAttribute> expectedAttributes)
{
// Arrange
var output = new TagHelperOutput("p", attributes: new TagHelperAttributeList());
var context = new TagHelperContext(
allAttributes,
items: new Dictionary<object, object>(),
uniqueId: "test",
getChildContentAsync: () => Task.FromResult<TagHelperContent>(result: null));
// Act
output.CopyHtmlAttribute(attributeNameToCopy, context);
// Assert
Assert.Equal(expectedAttributes, output.Attributes, CaseSensitiveTagHelperAttributeComparer.Default);
}
[Theory] [Theory]
[InlineData("hello", "world")] [InlineData("hello", "world")]
[InlineData("HeLlO", "wOrLd")] [InlineData("HeLlO", "wOrLd")]
@ -22,9 +121,9 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Arrange // Arrange
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
"p", "p",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
var tagHelperContext = new TagHelperContext( var tagHelperContext = new TagHelperContext(
allAttributes: new Dictionary<string, object>(StringComparer.Ordinal) allAttributes: new TagHelperAttributeList
{ {
{ attributeName, attributeValue } { attributeName, attributeValue }
}, },
@ -36,7 +135,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
tagHelperContent.Append("Something"); tagHelperContent.Append("Something");
return Task.FromResult<TagHelperContent>(tagHelperContent); return Task.FromResult<TagHelperContent>(tagHelperContent);
}); });
var expectedAttribute = new KeyValuePair<string, object>(attributeName, attributeValue); var expectedAttribute = new TagHelperAttribute(attributeName, attributeValue);
// Act // Act
tagHelperOutput.CopyHtmlAttribute("hello", tagHelperContext); tagHelperOutput.CopyHtmlAttribute("hello", tagHelperContext);
@ -53,13 +152,13 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var attributeName = "hello"; var attributeName = "hello";
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
"p", "p",
attributes: new Dictionary<string, object>() attributes: new TagHelperAttributeList()
{ {
{ attributeName, "world2" } { attributeName, "world2" }
}); });
var expectedAttribute = new KeyValuePair<string, object>(attributeName, "world2"); var expectedAttribute = new TagHelperAttribute(attributeName, "world2");
var tagHelperContext = new TagHelperContext( var tagHelperContext = new TagHelperContext(
allAttributes: new Dictionary<string, object>(StringComparer.Ordinal) allAttributes: new TagHelperAttributeList
{ {
{ attributeName, "world" } { attributeName, "world" }
}, },
@ -87,9 +186,9 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var invalidAttributeName = "hello2"; var invalidAttributeName = "hello2";
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
"p", "p",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
var tagHelperContext = new TagHelperContext( var tagHelperContext = new TagHelperContext(
allAttributes: new Dictionary<string, object>(StringComparer.Ordinal) allAttributes: new TagHelperAttributeList
{ {
{ "hello", "world" } { "hello", "world" }
}, },
@ -115,12 +214,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Arrange // Arrange
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
"p", "p",
attributes: new Dictionary<string, object>() attributes: new TagHelperAttributeList()
{ {
{ "route-Hello", "World" }, { "route-Hello", "World" },
{ "Route-I", "Am" } { "Route-I", "Am" }
}); });
var expectedAttribute = new KeyValuePair<string, object>("type", "btn"); var expectedAttribute = new TagHelperAttribute("type", "btn");
tagHelperOutput.Attributes.Add(expectedAttribute); tagHelperOutput.Attributes.Add(expectedAttribute);
var attributes = tagHelperOutput.FindPrefixedAttributes("route-"); var attributes = tagHelperOutput.FindPrefixedAttributes("route-");
@ -138,7 +237,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Arrange // Arrange
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
"p", "p",
attributes: new Dictionary<string, object>() attributes: new TagHelperAttributeList()
{ {
{ "routeHello", "World" }, { "routeHello", "World" },
{ "Routee-I", "Am" } { "Routee-I", "Am" }
@ -149,20 +248,178 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Assert // Assert
Assert.Empty(attributes); Assert.Empty(attributes);
var attribute = Assert.Single(tagHelperOutput.Attributes, kvp => kvp.Key.Equals("routeHello")); var attribute = Assert.Single(tagHelperOutput.Attributes, attr => attr.Name.Equals("routeHello"));
Assert.Equal(attribute.Value, "World"); Assert.Equal(attribute.Value, "World");
attribute = Assert.Single(tagHelperOutput.Attributes, kvp => kvp.Key.Equals("Routee-I")); attribute = Assert.Single(tagHelperOutput.Attributes, attr => attr.Name.Equals("Routee-I"));
Assert.Equal(attribute.Value, "Am"); Assert.Equal(attribute.Value, "Am");
} }
public static TheoryData MultipleAttributeSameNameData
{
get
{
// tagBuilderAttributes, outputAttributes, expectedAttributes
return new TheoryData<Dictionary<string, string>, TagHelperAttributeList, TagHelperAttributeList>
{
{
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "class", "btn" }
},
new TagHelperAttributeList
{
{ "class", "btn2" },
{ "class", "btn3" }
},
new TagHelperAttributeList
{
{ "class", "btn2 btn" }
}
},
{
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "ClAsS", "btn" }
},
new TagHelperAttributeList
{
{ "class", "btn2" },
{ "class", "btn3" }
},
new TagHelperAttributeList
{
{ "class", "btn2 btn" }
}
},
{
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "class", "btn" }
},
new TagHelperAttributeList
{
{ "clASS", "btn2" },
{ "class", "btn3" }
},
new TagHelperAttributeList
{
{ "class", "btn2 btn" }
}
},
{
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "class", "btn" }
},
new TagHelperAttributeList
{
{ "clASS", "btn2" },
{ "CLass", "btn3" }
},
new TagHelperAttributeList
{
{ "class", "btn2 btn" }
}
},
{
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "CLASS", "btn" }
},
new TagHelperAttributeList
{
{ "clASS", "btn2" },
{ "CLass", "btn3" }
},
new TagHelperAttributeList
{
{ "class", "btn2 btn" }
}
},
{
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "CLASS", "btn" }
},
new TagHelperAttributeList
{
{ "before", "before value" },
{ "clASS", "btn2" },
{ "mid", "mid value" },
{ "CLass", "btn3" },
{ "after", "after value" },
},
new TagHelperAttributeList
{
{ "before", "before value" },
{ "class", "btn2 btn" },
{ "mid", "mid value" },
{ "after", "after value" },
}
},
{
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "A", "A Value" },
{ "CLASS", "btn" },
{ "B", "B Value" },
},
new TagHelperAttributeList
{
{ "before", "before value" },
{ "clASS", "btn2" },
{ "mid", "mid value" },
{ "CLass", "btn3" },
{ "after", "after value" },
},
new TagHelperAttributeList
{
{ "before", "before value" },
{ "class", "btn2 btn" },
{ "mid", "mid value" },
{ "after", "after value" },
{ "A", "A Value" },
{ "B", "B Value" },
}
}
};
}
}
[Theory]
[MemberData(nameof(MultipleAttributeSameNameData))]
public void MergeAttributes_ClearsDuplicateClassNameAttributes(
Dictionary<string, string> tagBuilderAttributes,
TagHelperAttributeList outputAttributes,
TagHelperAttributeList expectedAttributes)
{
// Arrange
var tagHelperOutput = new TagHelperOutput("p", outputAttributes);
var tagBuilder = new TagBuilder("p", new CommonTestEncoder());
foreach (var attr in tagBuilderAttributes)
{
tagBuilder.Attributes.Add(attr.Key, attr.Value);
}
// Act
tagHelperOutput.MergeAttributes(tagBuilder);
// Assert
Assert.Equal(
expectedAttributes,
tagHelperOutput.Attributes,
CaseSensitiveTagHelperAttributeComparer.Default);
}
[Fact] [Fact]
public void MergeAttributes_DoesNotReplace_TagHelperOutputAttributeValues() public void MergeAttributes_DoesNotReplace_TagHelperOutputAttributeValues()
{ {
// Arrange // Arrange
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
"p", "p",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
var expectedAttribute = new KeyValuePair<string, object>("type", "btn"); var expectedAttribute = new TagHelperAttribute("type", "btn");
tagHelperOutput.Attributes.Add(expectedAttribute); tagHelperOutput.Attributes.Add(expectedAttribute);
var tagBuilder = new TagBuilder("p", new CommonTestEncoder()); var tagBuilder = new TagBuilder("p", new CommonTestEncoder());
@ -182,13 +439,13 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Arrange // Arrange
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
"p", "p",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
tagHelperOutput.Attributes.Add("class", "Hello"); tagHelperOutput.Attributes.Add("class", "Hello");
var tagBuilder = new TagBuilder("p", new CommonTestEncoder()); var tagBuilder = new TagBuilder("p", new CommonTestEncoder());
tagBuilder.Attributes.Add("class", "btn"); tagBuilder.Attributes.Add("class", "btn");
var expectedAttribute = new KeyValuePair<string, object>("class", "Hello btn"); var expectedAttribute = new TagHelperAttribute("class", "Hello btn");
// Act // Act
tagHelperOutput.MergeAttributes(tagBuilder); tagHelperOutput.MergeAttributes(tagBuilder);
@ -208,7 +465,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Arrange // Arrange
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
"p", "p",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
tagHelperOutput.Attributes.Add(originalName, "Hello"); tagHelperOutput.Attributes.Add(originalName, "Hello");
var tagBuilder = new TagBuilder("p", new CommonTestEncoder()); var tagBuilder = new TagBuilder("p", new CommonTestEncoder());
@ -219,7 +476,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Assert // Assert
var attribute = Assert.Single(tagHelperOutput.Attributes); var attribute = Assert.Single(tagHelperOutput.Attributes);
Assert.Equal(new KeyValuePair<string, object>(originalName, "Hello btn"), attribute); Assert.Equal(new TagHelperAttribute(originalName, "Hello btn"), attribute);
} }
[Fact] [Fact]
@ -228,10 +485,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Arrange // Arrange
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
"p", "p",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
var tagBuilder = new TagBuilder("p", new CommonTestEncoder()); var tagBuilder = new TagBuilder("p", new CommonTestEncoder());
var expectedAttribute = new KeyValuePair<string, object>("visible", "val < 3"); var expectedAttribute = new TagHelperAttribute("visible", "val < 3");
tagBuilder.Attributes.Add("visible", "val < 3"); tagBuilder.Attributes.Add("visible", "val < 3");
// Act // Act
@ -248,11 +505,11 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Arrange // Arrange
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
"p", "p",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
var tagBuilder = new TagBuilder("p", new CommonTestEncoder()); var tagBuilder = new TagBuilder("p", new CommonTestEncoder());
var expectedAttribute1 = new KeyValuePair<string, object>("class", "btn"); var expectedAttribute1 = new TagHelperAttribute("class", "btn");
var expectedAttribute2 = new KeyValuePair<string, object>("class2", "btn"); var expectedAttribute2 = new TagHelperAttribute("class2", "btn");
tagBuilder.Attributes.Add("class", "btn"); tagBuilder.Attributes.Add("class", "btn");
tagBuilder.Attributes.Add("class2", "btn"); tagBuilder.Attributes.Add("class2", "btn");
@ -261,9 +518,9 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Assert // Assert
Assert.Equal(2, tagHelperOutput.Attributes.Count); Assert.Equal(2, tagHelperOutput.Attributes.Count);
var attribute = Assert.Single(tagHelperOutput.Attributes, kvp => kvp.Key.Equals("class")); var attribute = Assert.Single(tagHelperOutput.Attributes, attr => attr.Name.Equals("class"));
Assert.Equal(expectedAttribute1.Value, attribute.Value); Assert.Equal(expectedAttribute1.Value, attribute.Value);
attribute = Assert.Single(tagHelperOutput.Attributes, kvp => kvp.Key.Equals("class2")); attribute = Assert.Single(tagHelperOutput.Attributes, attr => attr.Name.Equals("class2"));
Assert.Equal(expectedAttribute2.Value, attribute.Value); Assert.Equal(expectedAttribute2.Value, attribute.Value);
} }
@ -273,8 +530,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Arrange // Arrange
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
"p", "p",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
var expectedAttribute = new KeyValuePair<string, object>("class", "btn"); var expectedAttribute = new TagHelperAttribute("class", "btn");
tagHelperOutput.Attributes.Add(expectedAttribute); tagHelperOutput.Attributes.Add(expectedAttribute);
var tagBuilder = new TagBuilder("p", new CommonTestEncoder()); var tagBuilder = new TagBuilder("p", new CommonTestEncoder());
@ -293,12 +550,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Arrange // Arrange
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
"p", "p",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
var expectedOutputAttribute = new KeyValuePair<string, object>("class", "btn"); var expectedOutputAttribute = new TagHelperAttribute("class", "btn");
tagHelperOutput.Attributes.Add(expectedOutputAttribute); tagHelperOutput.Attributes.Add(expectedOutputAttribute);
var tagBuilder = new TagBuilder("p", new CommonTestEncoder()); var tagBuilder = new TagBuilder("p", new CommonTestEncoder());
var expectedBuilderAttribute = new KeyValuePair<string, object>("for", "hello"); var expectedBuilderAttribute = new TagHelperAttribute("for", "hello");
tagBuilder.Attributes.Add("for", "hello"); tagBuilder.Attributes.Add("for", "hello");
// Act // Act
@ -306,10 +563,40 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Assert // Assert
Assert.Equal(tagHelperOutput.Attributes.Count, 2); Assert.Equal(tagHelperOutput.Attributes.Count, 2);
var attribute = Assert.Single(tagHelperOutput.Attributes, kvp => kvp.Key.Equals("class")); var attribute = Assert.Single(tagHelperOutput.Attributes, attr => attr.Name.Equals("class"));
Assert.Equal(expectedOutputAttribute.Value, attribute.Value); Assert.Equal(expectedOutputAttribute.Value, attribute.Value);
attribute = Assert.Single(tagHelperOutput.Attributes, kvp => kvp.Key.Equals("for")); attribute = Assert.Single(tagHelperOutput.Attributes, attr => attr.Name.Equals("for"));
Assert.Equal(expectedBuilderAttribute.Value, attribute.Value); Assert.Equal(expectedBuilderAttribute.Value, attribute.Value);
} }
private class CaseSensitiveTagHelperAttributeComparer : IEqualityComparer<IReadOnlyTagHelperAttribute>
{
public readonly static CaseSensitiveTagHelperAttributeComparer Default =
new CaseSensitiveTagHelperAttributeComparer();
private CaseSensitiveTagHelperAttributeComparer()
{
}
public bool Equals(
IReadOnlyTagHelperAttribute attributeX,
IReadOnlyTagHelperAttribute attributeY)
{
return
attributeX == attributeY ||
// Normal comparer doesn't care about the Name case, in tests we do.
string.Equals(attributeX.Name, attributeY.Name, StringComparison.Ordinal) &&
Equals(attributeX.Value, attributeY.Value);
}
public int GetHashCode(IReadOnlyTagHelperAttribute attribute)
{
return HashCodeCombiner
.Start()
.Add(attribute.Name, StringComparer.Ordinal)
.Add(attribute.Value)
.CombinedHash;
}
}
} }
} }

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Mvc.Rendering;
@ -88,7 +89,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
string expectedContent) string expectedContent)
{ {
// Arrange // Arrange
var expectedAttributes = new Dictionary<string, object> var expectedAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control" }, { "class", "form-control" },
{ "id", nameAndId.Id }, { "id", nameAndId.Id },
@ -113,7 +114,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
}; };
var tagHelperContext = new TagHelperContext( var tagHelperContext = new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: "test", uniqueId: "test",
getChildContentAsync: () => getChildContentAsync: () =>
@ -122,7 +124,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
return Task.FromResult<TagHelperContent>(tagHelperContent); return Task.FromResult<TagHelperContent>(tagHelperContent);
}); });
var htmlAttributes = new Dictionary<string, object> var htmlAttributes = new TagHelperAttributeList
{ {
{ "class", "form-control" }, { "class", "form-control" },
}; };

View File

@ -3,6 +3,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
@ -34,7 +35,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var expectedPostContent = "original post-content"; var expectedPostContent = "original post-content";
var tagHelperContext = new TagHelperContext( var tagHelperContext = new TagHelperContext(
allAttributes: new Dictionary<string, object> allAttributes: new TagHelperAttributeList
{ {
{ "id", "myvalidationmessage" }, { "id", "myvalidationmessage" },
{ "for", modelExpression }, { "for", modelExpression },
@ -49,7 +50,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
}); });
var output = new TagHelperOutput( var output = new TagHelperOutput(
expectedTagName, expectedTagName,
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
{ "id", "myvalidationmessage" } { "id", "myvalidationmessage" }
}); });
@ -68,13 +69,13 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Assert // Assert
Assert.Equal(4, output.Attributes.Count); Assert.Equal(4, output.Attributes.Count);
var attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("id")); var attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("id"));
Assert.Equal("myvalidationmessage", attribute.Value); Assert.Equal("myvalidationmessage", attribute.Value);
attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("class")); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("class"));
Assert.Equal("field-validation-valid", attribute.Value); Assert.Equal("field-validation-valid", attribute.Value);
attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("data-valmsg-for")); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("data-valmsg-for"));
Assert.Equal("Name", attribute.Value); Assert.Equal("Name", attribute.Value);
attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("data-valmsg-replace")); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("data-valmsg-replace"));
Assert.Equal("true", attribute.Value); Assert.Equal("true", attribute.Value);
Assert.Equal(expectedPreContent, output.PreContent.GetContent()); Assert.Equal(expectedPreContent, output.PreContent.GetContent());
Assert.Equal(expectedContent, output.Content.GetContent()); Assert.Equal(expectedContent, output.Content.GetContent());
@ -94,7 +95,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var expectedContent = "original content"; var expectedContent = "original content";
var expectedPostContent = "original post-content"; var expectedPostContent = "original post-content";
var context = new TagHelperContext( var context = new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: "test", uniqueId: "test",
getChildContentAsync: () => getChildContentAsync: () =>
@ -105,7 +107,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
}); });
var output = new TagHelperOutput( var output = new TagHelperOutput(
"span", "span",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
output.PreContent.SetContent(expectedPreContent); output.PreContent.SetContent(expectedPreContent);
output.Content.SetContent(expectedContent); output.Content.SetContent(expectedContent);
output.PostContent.SetContent(expectedPostContent); output.PostContent.SetContent(expectedPostContent);
@ -145,11 +147,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
}; };
var output = new TagHelperOutput( var output = new TagHelperOutput(
"span", "span",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
output.Content.SetContent(outputContent); output.Content.SetContent(outputContent);
var context = new TagHelperContext( var context = new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: "test", uniqueId: "test",
getChildContentAsync: () => getChildContentAsync: () =>
@ -184,9 +187,9 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Assert // Assert
Assert.Equal("span", output.TagName); Assert.Equal("span", output.TagName);
Assert.Equal(2, output.Attributes.Count); Assert.Equal(2, output.Attributes.Count);
var attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("data-foo")); var attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("data-foo"));
Assert.Equal("bar", attribute.Value); Assert.Equal("bar", attribute.Value);
attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("data-hello")); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("data-hello"));
Assert.Equal("world", attribute.Value); Assert.Equal("world", attribute.Value);
Assert.Equal(expectedOutputContent, output.Content.GetContent()); Assert.Equal(expectedOutputContent, output.Content.GetContent());
} }
@ -204,10 +207,11 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
}; };
var output = new TagHelperOutput( var output = new TagHelperOutput(
"span", "span",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
var context = new TagHelperContext( var context = new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: "test", uniqueId: "test",
getChildContentAsync: () => getChildContentAsync: () =>
@ -242,9 +246,9 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Assert // Assert
Assert.Equal("span", output.TagName); Assert.Equal("span", output.TagName);
Assert.Equal(2, output.Attributes.Count); Assert.Equal(2, output.Attributes.Count);
var attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("data-foo")); var attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("data-foo"));
Assert.Equal("bar", attribute.Value); Assert.Equal("bar", attribute.Value);
attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("data-hello")); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("data-hello"));
Assert.Equal("world", attribute.Value); Assert.Equal("world", attribute.Value);
Assert.Equal(expectedOutputContent, output.Content.GetContent()); Assert.Equal(expectedOutputContent, output.Content.GetContent());
} }
@ -259,7 +263,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var expectedPostContent = "original post-content"; var expectedPostContent = "original post-content";
var output = new TagHelperOutput( var output = new TagHelperOutput(
"span", "span",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
output.PreContent.SetContent(expectedPreContent); output.PreContent.SetContent(expectedPreContent);
output.Content.SetContent(expectedContent); output.Content.SetContent(expectedContent);
output.PostContent.SetContent(expectedPostContent); output.PostContent.SetContent(expectedPostContent);

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
@ -44,7 +45,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var expectedPreContent = "original pre-content"; var expectedPreContent = "original pre-content";
var expectedContent = "original content"; var expectedContent = "original content";
var tagHelperContext = new TagHelperContext( var tagHelperContext = new TagHelperContext(
allAttributes: new Dictionary<string, object>(), allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: "test", uniqueId: "test",
getChildContentAsync: () => getChildContentAsync: () =>
@ -55,7 +57,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
}); });
var output = new TagHelperOutput( var output = new TagHelperOutput(
expectedTagName, expectedTagName,
attributes: new Dictionary<string, object> attributes: new TagHelperAttributeList
{ {
{ "class", "form-control" } { "class", "form-control" }
}); });
@ -74,9 +76,9 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Assert // Assert
Assert.Equal(2, output.Attributes.Count); Assert.Equal(2, output.Attributes.Count);
var attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("class")); var attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("class"));
Assert.Equal("form-control validation-summary-valid", attribute.Value); Assert.Equal("form-control validation-summary-valid", attribute.Value);
attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("data-valmsg-summary")); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("data-valmsg-summary"));
Assert.Equal("true", attribute.Value); Assert.Equal("true", attribute.Value);
Assert.Equal(expectedPreContent, output.PreContent.GetContent()); Assert.Equal(expectedPreContent, output.PreContent.GetContent());
Assert.Equal(expectedContent, output.Content.GetContent()); Assert.Equal(expectedContent, output.Content.GetContent());
@ -102,7 +104,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var expectedPostContent = "original post-content"; var expectedPostContent = "original post-content";
var output = new TagHelperOutput( var output = new TagHelperOutput(
"div", "div",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
output.PreContent.SetContent(expectedPreContent); output.PreContent.SetContent(expectedPreContent);
output.Content.SetContent(expectedContent); output.Content.SetContent(expectedContent);
output.PostContent.SetContent(expectedPostContent); output.PostContent.SetContent(expectedPostContent);
@ -144,7 +146,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var expectedContent = "original content"; var expectedContent = "original content";
var output = new TagHelperOutput( var output = new TagHelperOutput(
"div", "div",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
output.PreContent.SetContent(expectedPreContent); output.PreContent.SetContent(expectedPreContent);
output.Content.SetContent(expectedContent); output.Content.SetContent(expectedContent);
output.PostContent.SetContent("Content of validation summary"); output.PostContent.SetContent("Content of validation summary");
@ -177,11 +179,11 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Assert // Assert
Assert.Equal("div", output.TagName); Assert.Equal("div", output.TagName);
Assert.Equal(3, output.Attributes.Count); Assert.Equal(3, output.Attributes.Count);
var attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("data-foo")); var attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("data-foo"));
Assert.Equal("bar", attribute.Value); Assert.Equal("bar", attribute.Value);
attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("data-hello")); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("data-hello"));
Assert.Equal("world", attribute.Value); Assert.Equal("world", attribute.Value);
attribute = Assert.Single(output.Attributes, kvp => kvp.Key.Equals("anything")); attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("anything"));
Assert.Equal("something", attribute.Value); Assert.Equal("something", attribute.Value);
Assert.Equal(expectedPreContent, output.PreContent.GetContent()); Assert.Equal(expectedPreContent, output.PreContent.GetContent());
Assert.Equal(expectedContent, output.Content.GetContent()); Assert.Equal(expectedContent, output.Content.GetContent());
@ -201,7 +203,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var expectedPostContent = "original post-content"; var expectedPostContent = "original post-content";
var output = new TagHelperOutput( var output = new TagHelperOutput(
"div", "div",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
output.PreContent.SetContent(expectedPreContent); output.PreContent.SetContent(expectedPreContent);
output.Content.SetContent(expectedContent); output.Content.SetContent(expectedContent);
output.PostContent.SetContent(expectedPostContent); output.PostContent.SetContent(expectedPostContent);
@ -236,7 +238,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var expectedContent = "original content"; var expectedContent = "original content";
var output = new TagHelperOutput( var output = new TagHelperOutput(
"div", "div",
attributes: new Dictionary<string, object>()); attributes: new TagHelperAttributeList());
output.PreContent.SetContent(expectedPreContent); output.PreContent.SetContent(expectedPreContent);
output.Content.SetContent(expectedContent); output.Content.SetContent(expectedContent);
output.PostContent.SetContent("Content of validation message"); output.PostContent.SetContent("Content of validation message");

View File

@ -21,8 +21,8 @@ namespace TagHelpersWebSite.TagHelpers
{ {
if (Controller != null && Action != null) if (Controller != null && Action != null)
{ {
var methodParameters = output.Attributes.ToDictionary(attribute => attribute.Key, var methodParameters = output.Attributes.ToDictionary(attribute => attribute.Name,
attribute => (object)attribute.Value); attribute => attribute.Value);
// We remove all attributes from the resulting HTML element because they're supposed to // We remove all attributes from the resulting HTML element because they're supposed to
// be parameters to our final href value. // be parameters to our final href value.