Add `TagHelperOutput.GetChildContentAsync()` overloads including an `HtmlEncoder`
- #643 part 1 - change is viral and requires an update to `RazorPage.StartTagHelperWritingScope()` - memoize `GetChildContentAsync()` per-encoder - update generation tests to match and to test new behaviour - note `HtmlEncoder`s used elsewhere e.g. in other `RazorPage` instances are unaffected Add `NullHtmlEncoder` Nits: - generally clean up affected doc comments and make them more consistent - remove unused `using`s in files I had open
This commit is contained in:
parent
e68c55ab41
commit
37850b5d85
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Razor.TagHelpers;
|
||||
|
||||
|
|
@ -15,9 +16,10 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
{
|
||||
private readonly List<ITagHelper> _tagHelpers;
|
||||
private readonly Func<Task> _executeChildContentAsync;
|
||||
private readonly Action _startTagHelperWritingScope;
|
||||
private readonly Action<HtmlEncoder> _startTagHelperWritingScope;
|
||||
private readonly Func<TagHelperContent> _endTagHelperWritingScope;
|
||||
private TagHelperContent _childContent;
|
||||
private Dictionary<HtmlEncoder, TagHelperContent> _perEncoderChildContent;
|
||||
|
||||
/// <summary>
|
||||
/// Internal for testing purposes only.
|
||||
|
|
@ -28,7 +30,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
items: new Dictionary<object, object>(),
|
||||
uniqueId: string.Empty,
|
||||
executeChildContentAsync: async () => await Task.FromResult(result: true),
|
||||
startTagHelperWritingScope: () => { },
|
||||
startTagHelperWritingScope: _ => { },
|
||||
endTagHelperWritingScope: () => new DefaultTagHelperContent())
|
||||
{
|
||||
}
|
||||
|
|
@ -42,7 +44,10 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
/// <see cref="ITagHelper"/>s</param>
|
||||
/// <param name="uniqueId">An identifier unique to the HTML element this context is for.</param>
|
||||
/// <param name="executeChildContentAsync">A delegate used to execute the child content asynchronously.</param>
|
||||
/// <param name="startTagHelperWritingScope">A delegate used to start a writing scope in a Razor page.</param>
|
||||
/// <param name="startTagHelperWritingScope">
|
||||
/// A delegate used to start a writing scope in a Razor page and optionally override the page's
|
||||
/// <see cref="HtmlEncoder"/> within that scope.
|
||||
/// </param>
|
||||
/// <param name="endTagHelperWritingScope">A delegate used to end a writing scope in a Razor page.</param>
|
||||
public TagHelperExecutionContext(
|
||||
string tagName,
|
||||
|
|
@ -50,7 +55,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
IDictionary<object, object> items,
|
||||
string uniqueId,
|
||||
Func<Task> executeChildContentAsync,
|
||||
Action startTagHelperWritingScope,
|
||||
Action<HtmlEncoder> startTagHelperWritingScope,
|
||||
Func<TagHelperContent> endTagHelperWritingScope)
|
||||
{
|
||||
if (tagName == null)
|
||||
|
|
@ -224,23 +229,57 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute and retrieve the rendered child content asynchronously.
|
||||
/// Executes children asynchronously with the given <paramref name="encoder"/> in scope and returns their
|
||||
/// rendered content.
|
||||
/// </summary>
|
||||
/// <param name="useCachedResult">
|
||||
/// If <c>true</c>, multiple calls with the same <see cref="HtmlEncoder"/> will not cause children to
|
||||
/// re-execute; returns cached content.
|
||||
/// </param>
|
||||
/// <param name="encoder">
|
||||
/// The <see cref="HtmlEncoder"/> to use when the page handles
|
||||
/// non-<see cref="Microsoft.AspNet.Html.IHtmlContent"/> C# expressions. If <c>null</c>, executes children with
|
||||
/// the page's current <see cref="HtmlEncoder"/>.
|
||||
/// </param>
|
||||
/// <returns>A <see cref="Task"/> that on completion returns the rendered child content.</returns>
|
||||
/// <remarks>
|
||||
/// Child content is only executed once. Successive calls to this method or successive executions of the
|
||||
/// returned <see cref="Task{TagHelperContent}"/> return a cached result.
|
||||
/// </remarks>
|
||||
public async Task<TagHelperContent> GetChildContentAsync(bool useCachedResult)
|
||||
public async Task<TagHelperContent> GetChildContentAsync(bool useCachedResult, HtmlEncoder encoder)
|
||||
{
|
||||
if (!useCachedResult || _childContent == null)
|
||||
// Get cached content for this encoder.
|
||||
TagHelperContent childContent;
|
||||
if (encoder == null)
|
||||
{
|
||||
_startTagHelperWritingScope();
|
||||
await _executeChildContentAsync();
|
||||
_childContent = _endTagHelperWritingScope();
|
||||
childContent = _childContent;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_perEncoderChildContent == null)
|
||||
{
|
||||
childContent = null;
|
||||
_perEncoderChildContent = new Dictionary<HtmlEncoder, TagHelperContent>();
|
||||
}
|
||||
else
|
||||
{
|
||||
_perEncoderChildContent.TryGetValue(encoder, out childContent);
|
||||
}
|
||||
}
|
||||
|
||||
return new DefaultTagHelperContent().SetContent(_childContent);
|
||||
if (!useCachedResult || childContent == null)
|
||||
{
|
||||
_startTagHelperWritingScope(encoder);
|
||||
await _executeChildContentAsync();
|
||||
childContent = _endTagHelperWritingScope();
|
||||
|
||||
if (encoder == null)
|
||||
{
|
||||
_childContent = childContent;
|
||||
}
|
||||
else
|
||||
{
|
||||
_perEncoderChildContent[encoder] = childContent;
|
||||
}
|
||||
}
|
||||
|
||||
return new DefaultTagHelperContent().SetContent(childContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Razor.TagHelpers;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Razor.TagHelpers;
|
||||
using Microsoft.Extensions.Internal;
|
||||
|
|
@ -31,7 +32,10 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
/// <param name="tagMode">HTML syntax of the element in the Razor source.</param>
|
||||
/// <param name="uniqueId">An identifier unique to the HTML element this scope is for.</param>
|
||||
/// <param name="executeChildContentAsync">A delegate used to execute the child content asynchronously.</param>
|
||||
/// <param name="startTagHelperWritingScope">A delegate used to start a writing scope in a Razor page.</param>
|
||||
/// <param name="startTagHelperWritingScope">
|
||||
/// A delegate used to start a writing scope in a Razor page and optionally override the page's
|
||||
/// <see cref="HtmlEncoder"/> within that scope.
|
||||
/// </param>
|
||||
/// <param name="endTagHelperWritingScope">A delegate used to end a writing scope in a Razor page.</param>
|
||||
/// <returns>A <see cref="TagHelperExecutionContext"/> to use.</returns>
|
||||
public TagHelperExecutionContext Begin(
|
||||
|
|
@ -39,7 +43,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
TagMode tagMode,
|
||||
string uniqueId,
|
||||
Func<Task> executeChildContentAsync,
|
||||
Action startTagHelperWritingScope,
|
||||
Action<HtmlEncoder> startTagHelperWritingScope,
|
||||
Func<TagHelperContent> endTagHelperWritingScope)
|
||||
{
|
||||
if (tagName == null)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,120 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.Encodings.Web;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.TagHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="HtmlEncoder"/> that does not encode. Should not be used when writing directly to a response
|
||||
/// expected to contain valid HTML.
|
||||
/// </summary>
|
||||
public class NullHtmlEncoder : HtmlEncoder
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a <see cref="NullHtmlEncoder"/> instance.
|
||||
/// </summary>
|
||||
protected NullHtmlEncoder()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="HtmlEncoder"/> instance that does not encode. Should not be used when writing directly to a
|
||||
/// response expected to contain valid HTML.
|
||||
/// </summary>
|
||||
public static new NullHtmlEncoder Default { get; } = new NullHtmlEncoder();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int MaxOutputCharactersPerInputCharacter
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Encode(string value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Encode(TextWriter output, char[] value, int startIndex, int characterCount)
|
||||
{
|
||||
if (output == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(output));
|
||||
}
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
if (characterCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
output.Write(value, startIndex, characterCount);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Encode(TextWriter output, string value, int startIndex, int characterCount)
|
||||
{
|
||||
if (output == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(output));
|
||||
}
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
if (characterCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
output.Write(value.Substring(startIndex, characterCount));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override unsafe int FindFirstCharacterToEncode(char* text, int textLength)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override unsafe bool TryEncodeUnicodeScalar(
|
||||
int unicodeScalar,
|
||||
char* buffer,
|
||||
int bufferLength,
|
||||
out int numberOfCharactersWritten)
|
||||
{
|
||||
if (buffer == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(buffer));
|
||||
}
|
||||
|
||||
numberOfCharactersWritten = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool WillEncode(int unicodeScalar)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers
|
|||
/// </summary>
|
||||
public class TagHelperOutput : IHtmlContent
|
||||
{
|
||||
private readonly Func<bool, Task<TagHelperContent>> _getChildContentAsync;
|
||||
private readonly Func<bool, HtmlEncoder, Task<TagHelperContent>> _getChildContentAsync;
|
||||
private TagHelperContent _preElement;
|
||||
private TagHelperContent _preContent;
|
||||
private TagHelperContent _content;
|
||||
|
|
@ -27,7 +27,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers
|
|||
: this(
|
||||
tagName,
|
||||
new TagHelperAttributeList(),
|
||||
(cachedResult) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()))
|
||||
(useCachedResult, encoder) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -36,12 +36,14 @@ namespace Microsoft.AspNet.Razor.TagHelpers
|
|||
/// </summary>
|
||||
/// <param name="tagName">The HTML element's tag name.</param>
|
||||
/// <param name="attributes">The HTML attributes.</param>
|
||||
/// <param name="getChildContentAsync">A delegate used to execute and retrieve the rendered child content
|
||||
/// asynchronously.</param>
|
||||
/// <param name="getChildContentAsync">
|
||||
/// A delegate used to execute children asynchronously with the given <see cref="HtmlEncoder"/> in scope and
|
||||
/// return their rendered content.
|
||||
/// </param>
|
||||
public TagHelperOutput(
|
||||
string tagName,
|
||||
TagHelperAttributeList attributes,
|
||||
Func<bool, Task<TagHelperContent>> getChildContentAsync)
|
||||
Func<bool, HtmlEncoder, Task<TagHelperContent>> getChildContentAsync)
|
||||
{
|
||||
if (attributes == null)
|
||||
{
|
||||
|
|
@ -206,24 +208,65 @@ namespace Microsoft.AspNet.Razor.TagHelpers
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// A delegate used to execute children asynchronously.
|
||||
/// Executes children asynchronously and returns their rendered content.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="Task"/> that on completion returns content rendered by children.</returns>
|
||||
/// <remarks>This method is memoized.</remarks>
|
||||
/// <remarks>
|
||||
/// This method is memoized. Multiple calls will not cause children to re-execute with the page's original
|
||||
/// <see cref="HtmlEncoder"/>.
|
||||
/// </remarks>
|
||||
public Task<TagHelperContent> GetChildContentAsync()
|
||||
{
|
||||
return GetChildContentAsync(useCachedResult: true);
|
||||
return GetChildContentAsync(useCachedResult: true, encoder: null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A delegate used to execute children asynchronously.
|
||||
/// Executes children asynchronously and returns their rendered content.
|
||||
/// </summary>
|
||||
/// <param name="useCachedResult">If <c>true</c> multiple calls to this method will not cause re-execution
|
||||
/// of child content; cached content will be returned.</param>
|
||||
/// <param name="useCachedResult">
|
||||
/// If <c>true</c>, multiple calls will not cause children to re-execute with the page's original
|
||||
/// <see cref="HtmlEncoder"/>; returns cached content.
|
||||
/// </param>
|
||||
/// <returns>A <see cref="Task"/> that on completion returns content rendered by children.</returns>
|
||||
public Task<TagHelperContent> GetChildContentAsync(bool useCachedResult)
|
||||
{
|
||||
return _getChildContentAsync(useCachedResult);
|
||||
return GetChildContentAsync(useCachedResult, encoder: null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes children asynchronously with the given <paramref name="encoder"/> in scope and returns their
|
||||
/// rendered content.
|
||||
/// </summary>
|
||||
/// <param name="encoder">
|
||||
/// The <see cref="HtmlEncoder"/> to use when the page handles non-<see cref="IHtmlContent"/> C# expressions.
|
||||
/// If <c>null</c>, executes children with the page's current <see cref="HtmlEncoder"/>.
|
||||
/// </param>
|
||||
/// <returns>A <see cref="Task"/> that on completion returns content rendered by children.</returns>
|
||||
/// <remarks>
|
||||
/// This method is memoized. Multiple calls with the same <see cref="HtmlEncoder"/> instance will not cause
|
||||
/// children to re-execute with that encoder in scope.
|
||||
/// </remarks>
|
||||
public Task<TagHelperContent> GetChildContentAsync(HtmlEncoder encoder)
|
||||
{
|
||||
return GetChildContentAsync(useCachedResult: true, encoder: encoder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes children asynchronously with the given <paramref name="encoder"/> in scope and returns their
|
||||
/// rendered content.
|
||||
/// </summary>
|
||||
/// <param name="useCachedResult">
|
||||
/// If <c>true</c>, multiple calls with the same <see cref="HtmlEncoder"/> will not cause children to
|
||||
/// re-execute; returns cached content.
|
||||
/// </param>
|
||||
/// <param name="encoder">
|
||||
/// The <see cref="HtmlEncoder"/> to use when the page handles non-<see cref="IHtmlContent"/> C# expressions.
|
||||
/// If <c>null</c>, executes children with the page's current <see cref="HtmlEncoder"/>.
|
||||
/// </param>
|
||||
/// <returns>A <see cref="Task"/> that on completion returns content rendered by children.</returns>
|
||||
public Task<TagHelperContent> GetChildContentAsync(bool useCachedResult, HtmlEncoder encoder)
|
||||
{
|
||||
return _getChildContentAsync(useCachedResult, encoder);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@
|
|||
"description": "Runtime components for rendering Razor pages.",
|
||||
"version": "4.0.0-*",
|
||||
"compilationOptions": {
|
||||
"warningsAsErrors": true,
|
||||
"keyFile": "../../tools/Key.snk"
|
||||
"allowUnsafe": true,
|
||||
"keyFile": "../../tools/Key.snk",
|
||||
"warningsAsErrors": true
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ using System.Globalization;
|
|||
using System.Linq;
|
||||
using Microsoft.AspNet.Razor.Chunks;
|
||||
using Microsoft.AspNet.Razor.CodeGenerators.Visitors;
|
||||
using Microsoft.AspNet.Razor.TagHelpers;
|
||||
using Microsoft.AspNet.Razor.Compilation.TagHelpers;
|
||||
using Microsoft.AspNet.Razor.TagHelpers;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.CodeGenerators
|
||||
{
|
||||
|
|
@ -659,7 +659,7 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
|
|||
// Scopes are a runtime feature.
|
||||
if (!_designTimeMode)
|
||||
{
|
||||
_writer.WriteMethodInvocation(_tagHelperContext.StartTagHelperWritingScopeMethodName);
|
||||
_writer.WriteMethodInvocation(_tagHelperContext.StartTagHelperWritingScopeMethodName, "null");
|
||||
}
|
||||
|
||||
var visitor = htmlEncodeValues ? _bodyVisitor : _literalBodyVisitor;
|
||||
|
|
@ -668,8 +668,9 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
|
|||
// Scopes are a runtime feature.
|
||||
if (!_designTimeMode)
|
||||
{
|
||||
_writer.WriteStartAssignment(StringValueBufferVariableName)
|
||||
.WriteMethodInvocation(_tagHelperContext.EndTagHelperWritingScopeMethodName);
|
||||
_writer
|
||||
.WriteStartAssignment(StringValueBufferVariableName)
|
||||
.WriteMethodInvocation(_tagHelperContext.EndTagHelperWritingScopeMethodName);
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
|
@ -708,7 +709,7 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
|
|||
StringValueBufferVariableName,
|
||||
_tagHelperContext.TagHelperContentGetContentMethodName,
|
||||
endLine: false,
|
||||
parameters: new string[] { _tagHelperContext.HtmlEncoderPropertyName });
|
||||
parameters: _tagHelperContext.HtmlEncoderPropertyName);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Razor.TagHelpers;
|
||||
using Microsoft.Extensions.WebEncoders.Testing;
|
||||
|
|
@ -43,7 +43,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
items: expectedItems,
|
||||
uniqueId: string.Empty,
|
||||
executeChildContentAsync: async () => await Task.FromResult(result: true),
|
||||
startTagHelperWritingScope: () => { },
|
||||
startTagHelperWritingScope: _ => { },
|
||||
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||
|
||||
// Assert
|
||||
|
|
@ -51,13 +51,47 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
Assert.Same(expectedItems, executionContext.Items);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetChildContentAsync_CachesValue()
|
||||
public static TheoryData<HtmlEncoder> HtmlEncoderData
|
||||
{
|
||||
get
|
||||
{
|
||||
return new TheoryData<HtmlEncoder>
|
||||
{
|
||||
null,
|
||||
HtmlEncoder.Default,
|
||||
NullHtmlEncoder.Default,
|
||||
new HtmlTestEncoder(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static TheoryData<HtmlEncoder> HtmlEncoderDataLessNull
|
||||
{
|
||||
get
|
||||
{
|
||||
var data = new TheoryData<HtmlEncoder>();
|
||||
foreach (var row in HtmlEncoderData)
|
||||
{
|
||||
var encoder = (HtmlEncoder)(row[0]);
|
||||
if (encoder != null)
|
||||
{
|
||||
data.Add(encoder);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(HtmlEncoderData))]
|
||||
public async Task GetChildContentAsync_ReturnsExpectedContent(HtmlEncoder encoder)
|
||||
{
|
||||
// Arrange
|
||||
var defaultTagHelperContent = new DefaultTagHelperContent();
|
||||
var content = string.Empty;
|
||||
var expectedContent = string.Empty;
|
||||
var tagHelperContent = new DefaultTagHelperContent();
|
||||
var executionCount = 0;
|
||||
var content = "Hello from child content";
|
||||
var expectedContent = $"HtmlEncode[[{content}]]";
|
||||
var executionContext = new TagHelperExecutionContext(
|
||||
"p",
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
|
|
@ -65,30 +99,46 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
uniqueId: string.Empty,
|
||||
executeChildContentAsync: () =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(expectedContent))
|
||||
{
|
||||
content = "Hello from child content: " + Guid.NewGuid().ToString();
|
||||
expectedContent = $"HtmlEncode[[{content}]]";
|
||||
}
|
||||
|
||||
defaultTagHelperContent.SetContent(content);
|
||||
executionCount++;
|
||||
tagHelperContent.SetContent(content);
|
||||
|
||||
return Task.FromResult(result: true);
|
||||
},
|
||||
startTagHelperWritingScope: () => { },
|
||||
endTagHelperWritingScope: () => defaultTagHelperContent);
|
||||
startTagHelperWritingScope: _ => { },
|
||||
endTagHelperWritingScope: () => tagHelperContent);
|
||||
|
||||
// Act
|
||||
var content1 = await executionContext.GetChildContentAsync(useCachedResult: true);
|
||||
var content2 = await executionContext.GetChildContentAsync(useCachedResult: true);
|
||||
var actualContent = await executionContext.GetChildContentAsync(useCachedResult: true, encoder: encoder);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedContent, content1.GetContent(new HtmlTestEncoder()));
|
||||
Assert.Equal(expectedContent, content2.GetContent(new HtmlTestEncoder()));
|
||||
Assert.Equal(expectedContent, actualContent.GetContent(new HtmlTestEncoder()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetChildContentAsync_CanExecuteChildrenMoreThanOnce()
|
||||
[Theory]
|
||||
[MemberData(nameof(HtmlEncoderData))]
|
||||
public async Task GetChildContentAsync_StartsWritingScopeWithGivenEncoder(HtmlEncoder encoder)
|
||||
{
|
||||
// Arrange
|
||||
HtmlEncoder passedEncoder = null;
|
||||
var executionContext = new TagHelperExecutionContext(
|
||||
"p",
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
items: new Dictionary<object, object>(),
|
||||
uniqueId: string.Empty,
|
||||
executeChildContentAsync: () => Task.FromResult(result: true),
|
||||
startTagHelperWritingScope: encoderArgument => passedEncoder = encoderArgument,
|
||||
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||
|
||||
// Act
|
||||
await executionContext.GetChildContentAsync(useCachedResult: true, encoder: encoder);
|
||||
|
||||
// Assert
|
||||
Assert.Same(encoder, passedEncoder);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(HtmlEncoderData))]
|
||||
public async Task GetChildContentAsync_CachesValue(HtmlEncoder encoder)
|
||||
{
|
||||
// Arrange
|
||||
var executionCount = 0;
|
||||
|
|
@ -100,15 +150,98 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
executeChildContentAsync: () =>
|
||||
{
|
||||
executionCount++;
|
||||
|
||||
return Task.FromResult(result: true);
|
||||
},
|
||||
startTagHelperWritingScope: () => { },
|
||||
startTagHelperWritingScope: _ => { },
|
||||
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||
|
||||
// Act
|
||||
await executionContext.GetChildContentAsync(useCachedResult: false);
|
||||
await executionContext.GetChildContentAsync(useCachedResult: false);
|
||||
var content1 = await executionContext.GetChildContentAsync(useCachedResult: true, encoder: encoder);
|
||||
var content2 = await executionContext.GetChildContentAsync(useCachedResult: true, encoder: encoder);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, executionCount);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(HtmlEncoderDataLessNull))]
|
||||
public async Task GetChildContentAsync_CachesValuePerEncoder(HtmlEncoder encoder)
|
||||
{
|
||||
// Arrange
|
||||
var executionCount = 0;
|
||||
var executionContext = new TagHelperExecutionContext(
|
||||
"p",
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
items: new Dictionary<object, object>(),
|
||||
uniqueId: string.Empty,
|
||||
executeChildContentAsync: () =>
|
||||
{
|
||||
executionCount++;
|
||||
return Task.FromResult(result: true);
|
||||
},
|
||||
startTagHelperWritingScope: _ => { },
|
||||
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||
|
||||
// Act
|
||||
var content1 = await executionContext.GetChildContentAsync(useCachedResult: true, encoder: null);
|
||||
var content2 = await executionContext.GetChildContentAsync(useCachedResult: true, encoder: encoder);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, executionCount);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(HtmlEncoderData))]
|
||||
public async Task GetChildContentAsync_CachesValuePerEncoderInstance(HtmlEncoder encoder)
|
||||
{
|
||||
// Arrange
|
||||
var executionCount = 0;
|
||||
var executionContext = new TagHelperExecutionContext(
|
||||
"p",
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
items: new Dictionary<object, object>(),
|
||||
uniqueId: string.Empty,
|
||||
executeChildContentAsync: () =>
|
||||
{
|
||||
executionCount++;
|
||||
return Task.FromResult(result: true);
|
||||
},
|
||||
startTagHelperWritingScope: _ => { },
|
||||
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||
|
||||
// HtmlEncoderData includes another HtmlTestEncoder instance but method compares HtmlEncoder instances.
|
||||
var firstEncoder = new HtmlTestEncoder();
|
||||
|
||||
// Act
|
||||
var content1 = await executionContext.GetChildContentAsync(useCachedResult: true, encoder: firstEncoder);
|
||||
var content2 = await executionContext.GetChildContentAsync(useCachedResult: true, encoder: encoder);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, executionCount);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(HtmlEncoderData))]
|
||||
public async Task GetChildContentAsync_CanExecuteChildrenMoreThanOnce(HtmlEncoder encoder)
|
||||
{
|
||||
// Arrange
|
||||
var executionCount = 0;
|
||||
var executionContext = new TagHelperExecutionContext(
|
||||
"p",
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
items: new Dictionary<object, object>(),
|
||||
uniqueId: string.Empty,
|
||||
executeChildContentAsync: () =>
|
||||
{
|
||||
executionCount++;
|
||||
return Task.FromResult(result: true);
|
||||
},
|
||||
startTagHelperWritingScope: _ => { },
|
||||
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||
|
||||
// Act
|
||||
await executionContext.GetChildContentAsync(useCachedResult: false, encoder: encoder);
|
||||
await executionContext.GetChildContentAsync(useCachedResult: false, encoder: encoder);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, executionCount);
|
||||
|
|
@ -120,27 +253,21 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
public async Task GetChildContentAsync_ReturnsNewObjectEveryTimeItIsCalled(bool useCachedResult)
|
||||
{
|
||||
// Arrange
|
||||
var defaultTagHelperContent = new DefaultTagHelperContent();
|
||||
var executionContext = new TagHelperExecutionContext(
|
||||
"p",
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
items: new Dictionary<object, object>(),
|
||||
uniqueId: string.Empty,
|
||||
executeChildContentAsync: () => { return Task.FromResult(result: true); },
|
||||
startTagHelperWritingScope: () => { },
|
||||
endTagHelperWritingScope: () => defaultTagHelperContent);
|
||||
executeChildContentAsync: () => Task.FromResult(result: true),
|
||||
startTagHelperWritingScope: _ => { },
|
||||
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||
|
||||
// Act
|
||||
var content1 = await executionContext.GetChildContentAsync(useCachedResult);
|
||||
content1.Append("Hello");
|
||||
var content2 = await executionContext.GetChildContentAsync(useCachedResult);
|
||||
content2.Append("World!");
|
||||
var content1 = await executionContext.GetChildContentAsync(useCachedResult, encoder: null);
|
||||
var content2 = await executionContext.GetChildContentAsync(useCachedResult, encoder: null);
|
||||
|
||||
// Assert
|
||||
Assert.NotSame(content1, content2);
|
||||
|
||||
var content3 = await executionContext.GetChildContentAsync(useCachedResult);
|
||||
Assert.Empty(content3.GetContent(new HtmlTestEncoder()));
|
||||
}
|
||||
|
||||
public static TheoryData<string, string> DictionaryCaseTestingData
|
||||
|
|
@ -314,7 +441,6 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
Assert.Equal(2, tagHelpers.Length);
|
||||
Assert.Same(tagHelper1, tagHelpers[0]);
|
||||
Assert.Same(tagHelper2, tagHelpers[1]);
|
||||
|
||||
}
|
||||
|
||||
private class PTagHelper : TagHelper
|
||||
|
|
|
|||
|
|
@ -1,698 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
||||
using Microsoft.AspNet.Razor.TagHelpers;
|
||||
using Microsoft.Extensions.WebEncoders.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.Runtime.Test.Runtime.TagHelpers
|
||||
{
|
||||
public class TagHelperOutputTest
|
||||
{
|
||||
public static TheoryData<TagHelperOutput, string> WriteTagHelper_InputData
|
||||
{
|
||||
get
|
||||
{
|
||||
// parameters: TagHelperOutput, expectedOutput
|
||||
return new TheoryData<TagHelperOutput, string>
|
||||
{
|
||||
{
|
||||
// parameters: TagName, Attributes, SelfClosing, PreContent, Content, PostContent
|
||||
GetTagHelperOutput(
|
||||
tagName: "div",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<div>Hello World!</div>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"Hello World!"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: " ",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"Hello World!"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList() { { "test", "testVal" } },
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p test=\"HtmlEncode[[testVal]]\">Hello World!</p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList()
|
||||
{
|
||||
{ "test", "testVal" },
|
||||
{ "something", " spaced " }
|
||||
},
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p test=\"HtmlEncode[[testVal]]\" something=\"HtmlEncode[[ spaced ]]\">Hello World!</p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList()
|
||||
{
|
||||
["test"] = new TagHelperAttribute
|
||||
{
|
||||
Name = "test",
|
||||
Minimized = true
|
||||
},
|
||||
},
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p test>Hello World!</p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList()
|
||||
{
|
||||
["test"] = new TagHelperAttribute
|
||||
{
|
||||
Name = "test",
|
||||
Minimized = true
|
||||
},
|
||||
["test2"] = new TagHelperAttribute
|
||||
{
|
||||
Name = "test2",
|
||||
Minimized = true
|
||||
},
|
||||
},
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p test test2>Hello World!</p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList()
|
||||
{
|
||||
["first"] = "unminimized",
|
||||
["test"] = new TagHelperAttribute
|
||||
{
|
||||
Name = "test",
|
||||
Minimized = true
|
||||
},
|
||||
},
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p first=\"HtmlEncode[[unminimized]]\" test>Hello World!</p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList()
|
||||
{
|
||||
["test"] = new TagHelperAttribute
|
||||
{
|
||||
Name = "test",
|
||||
Minimized = true
|
||||
},
|
||||
["last"] = "unminimized",
|
||||
},
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p test last=\"HtmlEncode[[unminimized]]\">Hello World!</p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList() { { "test", "testVal" } },
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p test=\"HtmlEncode[[testVal]]\" />"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList()
|
||||
{
|
||||
{ "test", "testVal" },
|
||||
{ "something", " spaced " }
|
||||
},
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p test=\"HtmlEncode[[testVal]]\" something=\"HtmlEncode[[ spaced ]]\" />"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList() { { "test", "testVal" } },
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p test=\"HtmlEncode[[testVal]]\">"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList()
|
||||
{
|
||||
{ "test", "testVal" },
|
||||
{ "something", " spaced " }
|
||||
},
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p test=\"HtmlEncode[[testVal]]\" something=\"HtmlEncode[[ spaced ]]\">"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: "Hello World!",
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p>Hello World!</p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p>Hello World!</p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: "Hello World!",
|
||||
postElement: null),
|
||||
"<p>Hello World!</p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: null),
|
||||
"<p>HelloTestWorld!</p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: null,
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: null),
|
||||
"<p />"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: null,
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: null),
|
||||
"<p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: null),
|
||||
"<custom>HelloTestWorld!</custom>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "random",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: null,
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: null),
|
||||
"<random />"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "random",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: null,
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: null),
|
||||
"<random>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: "Before",
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"Before<custom></custom>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: "Before",
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"Before"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: "Before",
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"Before"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: "Before",
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"Before<custom test=\"HtmlEncode[[testVal]]\" />"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: "Before",
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"Before<custom />"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: "Before",
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"Before"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: "Before",
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"Before<custom test=\"HtmlEncode[[testVal]]\">"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: "Before",
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"Before<custom>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: "After"),
|
||||
"<custom></custom>After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: "After"),
|
||||
"After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: "After"),
|
||||
"After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: "After"),
|
||||
"<custom test=\"HtmlEncode[[testVal]]\" />After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: "After"),
|
||||
"<custom />After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: "After"),
|
||||
"After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: "After"),
|
||||
"<custom test=\"HtmlEncode[[testVal]]\">After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: "After"),
|
||||
"<custom>After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: "Before",
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: "After"),
|
||||
"Before<custom>HelloTestWorld!</custom>After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: "Before",
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: "After"),
|
||||
"Before<custom test=\"HtmlEncode[[testVal]]\">HelloTestWorld!</custom>After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: "Before",
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: "After"),
|
||||
"Before<custom />After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: "Before",
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: "After"),
|
||||
"BeforeHelloTestWorld!After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: "Before",
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: "After"),
|
||||
"Before<custom>After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: "Before",
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: "After"),
|
||||
"BeforeHelloTestWorld!After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: "Before",
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: "After"),
|
||||
"BeforeHelloTestWorld!After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: "Before",
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: "After"),
|
||||
"BeforeHelloTestWorld!After"
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(WriteTagHelper_InputData))]
|
||||
public void TagHelperOutput_WritesFormattedTagHelper(TagHelperOutput output, string expected)
|
||||
{
|
||||
// Arrange
|
||||
var writer = new StringWriter();
|
||||
var tagHelperExecutionContext = new TagHelperExecutionContext(
|
||||
tagName: output.TagName,
|
||||
tagMode: output.TagMode,
|
||||
items: new Dictionary<object, object>(),
|
||||
uniqueId: string.Empty,
|
||||
executeChildContentAsync: () => Task.FromResult(result: true),
|
||||
startTagHelperWritingScope: () => { },
|
||||
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||
tagHelperExecutionContext.Output = output;
|
||||
var testEncoder = new HtmlTestEncoder();
|
||||
|
||||
// Act
|
||||
output.WriteTo(writer, testEncoder);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, writer.ToString(), StringComparer.Ordinal);
|
||||
}
|
||||
|
||||
private static TagHelperOutput GetTagHelperOutput(
|
||||
string tagName,
|
||||
TagHelperAttributeList attributes,
|
||||
TagMode tagMode,
|
||||
string preElement,
|
||||
string preContent,
|
||||
string content,
|
||||
string postContent,
|
||||
string postElement)
|
||||
{
|
||||
var output = new TagHelperOutput(
|
||||
tagName,
|
||||
attributes,
|
||||
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()))
|
||||
{
|
||||
TagMode = tagMode
|
||||
};
|
||||
|
||||
if (preElement != null)
|
||||
{
|
||||
output.PreElement.AppendHtml(preElement);
|
||||
}
|
||||
|
||||
if (preContent != null)
|
||||
{
|
||||
output.PreContent.AppendHtml(preContent);
|
||||
}
|
||||
|
||||
if (content != null)
|
||||
{
|
||||
output.Content.AppendHtml(content);
|
||||
}
|
||||
|
||||
if (postContent != null)
|
||||
{
|
||||
output.PostContent.AppendHtml(postContent);
|
||||
}
|
||||
|
||||
if (postElement != null)
|
||||
{
|
||||
output.PostElement.AppendHtml(postElement);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -167,7 +167,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
Assert.Equal(tagMode, executionContext.TagMode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void End_ReturnsParentExecutionContext()
|
||||
{
|
||||
// Arrange
|
||||
|
|
@ -228,7 +228,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
tagMode,
|
||||
uniqueId: string.Empty,
|
||||
executeChildContentAsync: async () => await Task.FromResult(result: true),
|
||||
startTagHelperWritingScope: () => { },
|
||||
startTagHelperWritingScope: _ => { },
|
||||
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,158 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.TagHelpers
|
||||
{
|
||||
public class NullHtmlEncoderTest
|
||||
{
|
||||
[Fact]
|
||||
public void MaxOutputCharactersPerInputCharacter_Returns1()
|
||||
{
|
||||
// Arrange
|
||||
var encoder = NullHtmlEncoder.Default;
|
||||
|
||||
// Act
|
||||
var result = encoder.MaxOutputCharactersPerInputCharacter;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData("abcd")]
|
||||
[InlineData("<<''\"\">>")]
|
||||
public void Encode_String_DoesNotEncode(string value)
|
||||
{
|
||||
// Arrange
|
||||
var encoder = NullHtmlEncoder.Default;
|
||||
|
||||
// Act
|
||||
var result = encoder.Encode(value);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(value, result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData("abcd")]
|
||||
[InlineData("<<''\"\">>")]
|
||||
public void Encode_StringToTextWriter_DoesNotEncode(string value)
|
||||
{
|
||||
// Arrange
|
||||
var encoder = NullHtmlEncoder.Default;
|
||||
|
||||
// Act
|
||||
string result;
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
encoder.Encode(writer, value);
|
||||
result = writer.ToString();
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.Equal(value, result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", 0, 0, "")]
|
||||
[InlineData("abcd", 0, 0, "")]
|
||||
[InlineData("<<''\"\">>", 0, 0, "")]
|
||||
[InlineData("abcd", 0, 1, "a")]
|
||||
[InlineData("<<''\"\">>", 0, 1, "<")]
|
||||
[InlineData("abcd", 0, 4, "abcd")]
|
||||
[InlineData("<<''\"\">>", 0, 8, "<<''\"\">>")]
|
||||
[InlineData("abcd", 2, 0, "")]
|
||||
[InlineData("<<''\"\">>", 2, 0, "")]
|
||||
[InlineData("abcd", 2, 2, "cd")]
|
||||
[InlineData("<<''\"\">>", 2, 2, "''")]
|
||||
[InlineData("abcd", 3, 0, "")]
|
||||
[InlineData("<<''\"\">>", 7, 0, "")]
|
||||
[InlineData("abcd", 3, 1, "d")]
|
||||
[InlineData("<<''\"\">>", 7, 1, ">")]
|
||||
public void Encode_StringToTextWriter_DoesNotEncodeSubstring(
|
||||
string value,
|
||||
int startIndex,
|
||||
int characterCount,
|
||||
string expectedResult)
|
||||
{
|
||||
// Arrange
|
||||
var encoder = NullHtmlEncoder.Default;
|
||||
|
||||
// Act
|
||||
string result;
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
encoder.Encode(writer, value, startIndex, characterCount);
|
||||
result = writer.ToString();
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedResult, result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", 0, 0, "")]
|
||||
[InlineData("abcd", 0, 0, "")]
|
||||
[InlineData("<<''\"\">>", 0, 0, "")]
|
||||
[InlineData("abcd", 0, 1, "a")]
|
||||
[InlineData("<<''\"\">>", 0, 1, "<")]
|
||||
[InlineData("abcd", 0, 4, "abcd")]
|
||||
[InlineData("<<''\"\">>", 0, 8, "<<''\"\">>")]
|
||||
[InlineData("abcd", 2, 0, "")]
|
||||
[InlineData("<<''\"\">>", 2, 0, "")]
|
||||
[InlineData("abcd", 2, 2, "cd")]
|
||||
[InlineData("<<''\"\">>", 2, 2, "''")]
|
||||
[InlineData("abcd", 3, 0, "")]
|
||||
[InlineData("<<''\"\">>", 7, 0, "")]
|
||||
[InlineData("abcd", 3, 1, "d")]
|
||||
[InlineData("<<''\"\">>", 7, 1, ">")]
|
||||
public void Encode_CharsToTextWriter_DoesNotEncodeSubstring(
|
||||
string value,
|
||||
int startIndex,
|
||||
int characterCount,
|
||||
string expectedResult)
|
||||
{
|
||||
// Arrange
|
||||
var encoder = NullHtmlEncoder.Default;
|
||||
var chars = value.ToCharArray();
|
||||
|
||||
// Act
|
||||
string result;
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
encoder.Encode(writer, chars, startIndex, characterCount);
|
||||
result = writer.ToString();
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedResult, result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(int.MaxValue)]
|
||||
[InlineData(int.MinValue)]
|
||||
[InlineData(0)]
|
||||
[InlineData((int)'\n')]
|
||||
[InlineData((int)'\r')]
|
||||
[InlineData((int)'<')]
|
||||
[InlineData((int)'>')]
|
||||
[InlineData((int)'\'')]
|
||||
[InlineData((int)'"')]
|
||||
public void WillEncode_ReturnsFalse(int unicodeScalar)
|
||||
{
|
||||
// Arrange
|
||||
var encoder = NullHtmlEncoder.Default;
|
||||
|
||||
// Act
|
||||
var result = encoder.WillEncode(unicodeScalar);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,12 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
||||
using Microsoft.Extensions.WebEncoders.Testing;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -9,27 +14,148 @@ namespace Microsoft.AspNet.Razor.TagHelpers
|
|||
{
|
||||
public class TagHelperOutputTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task GetChildContentAsync_PassesUseCachedResultAsExpected(bool expectedUseCachedResultValue)
|
||||
[Fact]
|
||||
public async Task GetChildContentAsync_CallsGetChildContentAsync()
|
||||
{
|
||||
// Arrange
|
||||
bool? useCachedResultValue = null;
|
||||
bool? passedUseCacheResult = null;
|
||||
HtmlEncoder passedEncoder = null;
|
||||
var content = new DefaultTagHelperContent();
|
||||
var output = new TagHelperOutput(
|
||||
tagName: "p",
|
||||
tagName: "tag",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
getChildContentAsync: useCachedResult =>
|
||||
getChildContentAsync: (useCachedResult, encoder) =>
|
||||
{
|
||||
useCachedResultValue = useCachedResult;
|
||||
return Task.FromResult<TagHelperContent>(new DefaultTagHelperContent());
|
||||
passedUseCacheResult = useCachedResult;
|
||||
passedEncoder = encoder;
|
||||
return Task.FromResult<TagHelperContent>(content);
|
||||
});
|
||||
|
||||
// Act
|
||||
await output.GetChildContentAsync(expectedUseCachedResultValue);
|
||||
var result = await output.GetChildContentAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedUseCachedResultValue, useCachedResultValue);
|
||||
Assert.True(passedUseCacheResult.HasValue);
|
||||
Assert.True(passedUseCacheResult.Value);
|
||||
Assert.Null(passedEncoder);
|
||||
Assert.Same(content, result);
|
||||
}
|
||||
|
||||
public static TheoryData<HtmlEncoder> HtmlEncoderData
|
||||
{
|
||||
get
|
||||
{
|
||||
return new TheoryData<HtmlEncoder>
|
||||
{
|
||||
null,
|
||||
HtmlEncoder.Default,
|
||||
NullHtmlEncoder.Default,
|
||||
new HtmlTestEncoder(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(HtmlEncoderData))]
|
||||
public async Task GetChildContentAsync_CallsGetChildContentAsync(HtmlEncoder encoder)
|
||||
{
|
||||
// Arrange
|
||||
bool? passedUseCacheResult = null;
|
||||
HtmlEncoder passedEncoder = null;
|
||||
var content = new DefaultTagHelperContent();
|
||||
var output = new TagHelperOutput(
|
||||
tagName: "tag",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
getChildContentAsync: (useCachedResult, encoderArgument) =>
|
||||
{
|
||||
passedUseCacheResult = useCachedResult;
|
||||
passedEncoder = encoderArgument;
|
||||
return Task.FromResult<TagHelperContent>(content);
|
||||
});
|
||||
|
||||
// Act
|
||||
var result = await output.GetChildContentAsync(encoder);
|
||||
|
||||
// Assert
|
||||
Assert.True(passedUseCacheResult.HasValue);
|
||||
Assert.True(passedUseCacheResult.Value);
|
||||
Assert.Same(encoder, passedEncoder);
|
||||
Assert.Same(content, result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public async Task GetChildContentAsync_CallsGetChildContentAsync(bool useCachedResult)
|
||||
{
|
||||
// Arrange
|
||||
bool? passedUseCacheResult = null;
|
||||
HtmlEncoder passedEncoder = null;
|
||||
var content = new DefaultTagHelperContent();
|
||||
var output = new TagHelperOutput(
|
||||
tagName: "tag",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
getChildContentAsync: (useCachedResultArgument, encoder) =>
|
||||
{
|
||||
passedUseCacheResult = useCachedResultArgument;
|
||||
passedEncoder = encoder;
|
||||
return Task.FromResult<TagHelperContent>(content);
|
||||
});
|
||||
|
||||
// Act
|
||||
var result = await output.GetChildContentAsync(useCachedResult);
|
||||
|
||||
// Assert
|
||||
Assert.True(passedUseCacheResult.HasValue);
|
||||
Assert.Equal(useCachedResult, passedUseCacheResult.Value);
|
||||
Assert.Null(passedEncoder);
|
||||
Assert.Same(content, result);
|
||||
}
|
||||
|
||||
public static TheoryData<bool, HtmlEncoder> UseCachedResultAndHtmlEncoderData
|
||||
{
|
||||
get
|
||||
{
|
||||
var data = new TheoryData<bool, HtmlEncoder>();
|
||||
foreach (var useCachedResult in new[] { false, true })
|
||||
{
|
||||
foreach (var encoderEntry in HtmlEncoderData)
|
||||
{
|
||||
var encoder = (HtmlEncoder)(encoderEntry[0]);
|
||||
data.Add(useCachedResult, encoder);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(UseCachedResultAndHtmlEncoderData))]
|
||||
public async Task GetChildContentAsync_CallsGetChildContentAsync(bool useCachedResult, HtmlEncoder encoder)
|
||||
{
|
||||
// Arrange
|
||||
bool? passedUseCacheResult = null;
|
||||
HtmlEncoder passedEncoder = null;
|
||||
var content = new DefaultTagHelperContent();
|
||||
var output = new TagHelperOutput(
|
||||
tagName: "tag",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
getChildContentAsync: (useCachedResultArgument, encoderArgument) =>
|
||||
{
|
||||
passedUseCacheResult = useCachedResultArgument;
|
||||
passedEncoder = encoderArgument;
|
||||
return Task.FromResult<TagHelperContent>(content);
|
||||
});
|
||||
|
||||
// Act
|
||||
var result = await output.GetChildContentAsync(useCachedResult, encoder);
|
||||
|
||||
// Assert
|
||||
Assert.True(passedUseCacheResult.HasValue);
|
||||
Assert.Equal(useCachedResult, passedUseCacheResult.Value);
|
||||
Assert.Same(encoder, passedEncoder);
|
||||
Assert.Same(content, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -175,13 +301,14 @@ namespace Microsoft.AspNet.Razor.TagHelpers
|
|||
public void SuppressOutput_PreventsTagOutput()
|
||||
{
|
||||
// Arrange
|
||||
var tagHelperOutput = new TagHelperOutput("p",
|
||||
var tagHelperOutput = new TagHelperOutput(
|
||||
"p",
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "class", "btn" },
|
||||
{ "something", " spaced " }
|
||||
},
|
||||
(cachedResult) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));
|
||||
(cachedResult, encoder) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));
|
||||
tagHelperOutput.PreContent.Append("Pre Content");
|
||||
tagHelperOutput.Content.Append("Content");
|
||||
tagHelperOutput.PostContent.Append("Post Content");
|
||||
|
|
@ -209,12 +336,13 @@ namespace Microsoft.AspNet.Razor.TagHelpers
|
|||
public void Attributes_IgnoresCase(string originalName, string updateName)
|
||||
{
|
||||
// Arrange
|
||||
var tagHelperOutput = new TagHelperOutput("p",
|
||||
var tagHelperOutput = new TagHelperOutput(
|
||||
"p",
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ originalName, "btn" },
|
||||
},
|
||||
(cachedResult) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));
|
||||
(cachedResult, encoder) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));
|
||||
|
||||
// Act
|
||||
tagHelperOutput.Attributes[updateName] = "super button";
|
||||
|
|
@ -226,5 +354,687 @@ namespace Microsoft.AspNet.Razor.TagHelpers
|
|||
attribute,
|
||||
CaseSensitiveTagHelperAttributeComparer.Default);
|
||||
}
|
||||
|
||||
public static TheoryData<TagHelperOutput, string> WriteTagHelper_InputData
|
||||
{
|
||||
get
|
||||
{
|
||||
// parameters: TagHelperOutput, expectedOutput
|
||||
return new TheoryData<TagHelperOutput, string>
|
||||
{
|
||||
{
|
||||
// parameters: TagName, Attributes, SelfClosing, PreContent, Content, PostContent
|
||||
GetTagHelperOutput(
|
||||
tagName: "div",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<div>Hello World!</div>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"Hello World!"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: " ",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"Hello World!"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList() { { "test", "testVal" } },
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p test=\"HtmlEncode[[testVal]]\">Hello World!</p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList()
|
||||
{
|
||||
{ "test", "testVal" },
|
||||
{ "something", " spaced " }
|
||||
},
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p test=\"HtmlEncode[[testVal]]\" something=\"HtmlEncode[[ spaced ]]\">Hello World!</p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList()
|
||||
{
|
||||
["test"] = new TagHelperAttribute
|
||||
{
|
||||
Name = "test",
|
||||
Minimized = true
|
||||
},
|
||||
},
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p test>Hello World!</p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList()
|
||||
{
|
||||
["test"] = new TagHelperAttribute
|
||||
{
|
||||
Name = "test",
|
||||
Minimized = true
|
||||
},
|
||||
["test2"] = new TagHelperAttribute
|
||||
{
|
||||
Name = "test2",
|
||||
Minimized = true
|
||||
},
|
||||
},
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p test test2>Hello World!</p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList()
|
||||
{
|
||||
["first"] = "unminimized",
|
||||
["test"] = new TagHelperAttribute
|
||||
{
|
||||
Name = "test",
|
||||
Minimized = true
|
||||
},
|
||||
},
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p first=\"HtmlEncode[[unminimized]]\" test>Hello World!</p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList()
|
||||
{
|
||||
["test"] = new TagHelperAttribute
|
||||
{
|
||||
Name = "test",
|
||||
Minimized = true
|
||||
},
|
||||
["last"] = "unminimized",
|
||||
},
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p test last=\"HtmlEncode[[unminimized]]\">Hello World!</p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList() { { "test", "testVal" } },
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p test=\"HtmlEncode[[testVal]]\" />"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList()
|
||||
{
|
||||
{ "test", "testVal" },
|
||||
{ "something", " spaced " }
|
||||
},
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p test=\"HtmlEncode[[testVal]]\" something=\"HtmlEncode[[ spaced ]]\" />"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList() { { "test", "testVal" } },
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p test=\"HtmlEncode[[testVal]]\">"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList()
|
||||
{
|
||||
{ "test", "testVal" },
|
||||
{ "something", " spaced " }
|
||||
},
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p test=\"HtmlEncode[[testVal]]\" something=\"HtmlEncode[[ spaced ]]\">"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: "Hello World!",
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p>Hello World!</p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: "Hello World!",
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"<p>Hello World!</p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: "Hello World!",
|
||||
postElement: null),
|
||||
"<p>Hello World!</p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: null),
|
||||
"<p>HelloTestWorld!</p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: null,
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: null),
|
||||
"<p />"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "p",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: null,
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: null),
|
||||
"<p>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: null),
|
||||
"<custom>HelloTestWorld!</custom>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "random",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: null,
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: null),
|
||||
"<random />"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "random",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: null,
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: null),
|
||||
"<random>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: "Before",
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"Before<custom></custom>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: "Before",
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"Before"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: "Before",
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"Before"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: "Before",
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"Before<custom test=\"HtmlEncode[[testVal]]\" />"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: "Before",
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"Before<custom />"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: "Before",
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"Before"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: "Before",
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"Before<custom test=\"HtmlEncode[[testVal]]\">"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: "Before",
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: null),
|
||||
"Before<custom>"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: "After"),
|
||||
"<custom></custom>After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: "After"),
|
||||
"After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: "After"),
|
||||
"After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: "After"),
|
||||
"<custom test=\"HtmlEncode[[testVal]]\" />After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: "After"),
|
||||
"<custom />After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: "After"),
|
||||
"After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: "After"),
|
||||
"<custom test=\"HtmlEncode[[testVal]]\">After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: null,
|
||||
preContent: null,
|
||||
content: null,
|
||||
postContent: null,
|
||||
postElement: "After"),
|
||||
"<custom>After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: "Before",
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: "After"),
|
||||
"Before<custom>HelloTestWorld!</custom>After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: "Before",
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: "After"),
|
||||
"Before<custom test=\"HtmlEncode[[testVal]]\">HelloTestWorld!</custom>After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: "Before",
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: "After"),
|
||||
"Before<custom />After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.SelfClosing,
|
||||
preElement: "Before",
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: "After"),
|
||||
"BeforeHelloTestWorld!After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: "custom",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: "Before",
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: "After"),
|
||||
"Before<custom>After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagOnly,
|
||||
preElement: "Before",
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: "After"),
|
||||
"BeforeHelloTestWorld!After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList(),
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: "Before",
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: "After"),
|
||||
"BeforeHelloTestWorld!After"
|
||||
},
|
||||
{
|
||||
GetTagHelperOutput(
|
||||
tagName: string.Empty,
|
||||
attributes: new TagHelperAttributeList { { "test", "testVal" } },
|
||||
tagMode: TagMode.StartTagAndEndTag,
|
||||
preElement: "Before",
|
||||
preContent: "Hello",
|
||||
content: "Test",
|
||||
postContent: "World!",
|
||||
postElement: "After"),
|
||||
"BeforeHelloTestWorld!After"
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(WriteTagHelper_InputData))]
|
||||
public void WriteTo_WritesFormattedTagHelper(TagHelperOutput output, string expected)
|
||||
{
|
||||
// Arrange
|
||||
var writer = new StringWriter();
|
||||
var tagHelperExecutionContext = new TagHelperExecutionContext(
|
||||
tagName: output.TagName,
|
||||
tagMode: output.TagMode,
|
||||
items: new Dictionary<object, object>(),
|
||||
uniqueId: string.Empty,
|
||||
executeChildContentAsync: () => Task.FromResult(result: true),
|
||||
startTagHelperWritingScope: _ => { },
|
||||
endTagHelperWritingScope: () => new DefaultTagHelperContent());
|
||||
tagHelperExecutionContext.Output = output;
|
||||
var testEncoder = new HtmlTestEncoder();
|
||||
|
||||
// Act
|
||||
output.WriteTo(writer, testEncoder);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, writer.ToString(), StringComparer.Ordinal);
|
||||
}
|
||||
|
||||
private static TagHelperOutput GetTagHelperOutput(
|
||||
string tagName,
|
||||
TagHelperAttributeList attributes,
|
||||
TagMode tagMode,
|
||||
string preElement,
|
||||
string preContent,
|
||||
string content,
|
||||
string postContent,
|
||||
string postElement)
|
||||
{
|
||||
var output = new TagHelperOutput(
|
||||
tagName,
|
||||
attributes,
|
||||
getChildContentAsync: (useCachedContent, encoder) => Task.FromResult<TagHelperContent>(
|
||||
new DefaultTagHelperContent()))
|
||||
{
|
||||
TagMode = tagMode
|
||||
};
|
||||
|
||||
if (preElement != null)
|
||||
{
|
||||
output.PreElement.AppendHtml(preElement);
|
||||
}
|
||||
|
||||
if (preContent != null)
|
||||
{
|
||||
output.PreContent.AppendHtml(preContent);
|
||||
}
|
||||
|
||||
if (content != null)
|
||||
{
|
||||
output.Content.AppendHtml(content);
|
||||
}
|
||||
|
||||
if (postContent != null)
|
||||
{
|
||||
output.PostContent.AppendHtml(postContent);
|
||||
}
|
||||
|
||||
if (postElement != null)
|
||||
{
|
||||
output.PostElement.AppendHtml(postElement);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,5 +16,8 @@
|
|||
<ItemGroup>
|
||||
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<DnxInvisibleFolder Include=".testPublish\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -51,7 +51,7 @@ namespace TestOutput
|
|||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
||||
__TestNamespace_InputTagHelper2 = CreateTagHelper<global::TestNamespace.InputTagHelper2>();
|
||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper2);
|
||||
StartTagHelperWritingScope();
|
||||
StartTagHelperWritingScope(null);
|
||||
WriteLiteral("2000 + ");
|
||||
#line 6 "BasicTagHelpers.cshtml"
|
||||
Write(ViewBag.DefaultInterval);
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ namespace TestOutput
|
|||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
||||
__TestNamespace_InputTagHelper2 = CreateTagHelper<global::TestNamespace.InputTagHelper2>();
|
||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper2);
|
||||
StartTagHelperWritingScope();
|
||||
StartTagHelperWritingScope(null);
|
||||
WriteLiteral("2000 + ");
|
||||
#line 6 "BasicTagHelpers.cshtml"
|
||||
Write(ViewBag.DefaultInterval);
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ namespace TestOutput
|
|||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
||||
__TestNamespace_InputTagHelper2 = CreateTagHelper<global::TestNamespace.InputTagHelper2>();
|
||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper2);
|
||||
StartTagHelperWritingScope();
|
||||
StartTagHelperWritingScope(null);
|
||||
#line 16 "ComplexTagHelpers.cshtml"
|
||||
WriteLiteral(checkbox);
|
||||
|
||||
|
|
@ -163,7 +163,7 @@ namespace TestOutput
|
|||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
||||
__TestNamespace_InputTagHelper2 = CreateTagHelper<global::TestNamespace.InputTagHelper2>();
|
||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper2);
|
||||
StartTagHelperWritingScope();
|
||||
StartTagHelperWritingScope(null);
|
||||
#line 17 "ComplexTagHelpers.cshtml"
|
||||
WriteLiteral(true ? "checkbox" : "anything");
|
||||
|
||||
|
|
@ -188,7 +188,7 @@ namespace TestOutput
|
|||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
||||
__TestNamespace_InputTagHelper2 = CreateTagHelper<global::TestNamespace.InputTagHelper2>();
|
||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper2);
|
||||
StartTagHelperWritingScope();
|
||||
StartTagHelperWritingScope(null);
|
||||
#line 18 "ComplexTagHelpers.cshtml"
|
||||
if(true) {
|
||||
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ WriteTo(__razor_attribute_value_writer, string.Empty);
|
|||
, StartTagHelperWritingScope, EndTagHelperWritingScope);
|
||||
__TestNamespace_InputTagHelper = CreateTagHelper<global::TestNamespace.InputTagHelper>();
|
||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
||||
StartTagHelperWritingScope();
|
||||
StartTagHelperWritingScope(null);
|
||||
WriteLiteral("prefix ");
|
||||
#line 7 "DynamicAttributeTagHelpers.cshtml"
|
||||
WriteLiteral(DateTime.Now);
|
||||
|
|
@ -136,7 +136,7 @@ AddHtmlAttributeValue(" ", 210, DateTime.Now, 211, 14, false);
|
|||
, StartTagHelperWritingScope, EndTagHelperWritingScope);
|
||||
__TestNamespace_InputTagHelper = CreateTagHelper<global::TestNamespace.InputTagHelper>();
|
||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
||||
StartTagHelperWritingScope();
|
||||
StartTagHelperWritingScope(null);
|
||||
#line 9 "DynamicAttributeTagHelpers.cshtml"
|
||||
WriteLiteral(long.MinValue);
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ namespace TestOutput
|
|||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
||||
__TestNamespace_InputTagHelper2 = CreateTagHelper<global::TestNamespace.InputTagHelper2>();
|
||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper2);
|
||||
StartTagHelperWritingScope();
|
||||
StartTagHelperWritingScope(null);
|
||||
#line 6 "EscapedTagHelpers.cshtml"
|
||||
WriteLiteral(DateTime.Now);
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ namespace TestOutput
|
|||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper);
|
||||
__TestNamespace_InputTagHelper2 = CreateTagHelper<global::TestNamespace.InputTagHelper2>();
|
||||
__tagHelperExecutionContext.Add(__TestNamespace_InputTagHelper2);
|
||||
StartTagHelperWritingScope();
|
||||
StartTagHelperWritingScope(null);
|
||||
WriteLiteral("2000 + ");
|
||||
#line 8 "NestedScriptTagTagHelpers.cshtml"
|
||||
Write(ViewBag.DefaultInterval);
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ __TestNamespace_InputTagHelper2.IntDictionaryProperty["salt"] = 37;
|
|||
__TestNamespace_InputTagHelper2.StringDictionaryProperty["paprika"] = "another string";
|
||||
__tagHelperExecutionContext.AddTagHelperAttribute("string-prefix-paprika", __TestNamespace_InputTagHelper2.StringDictionaryProperty["paprika"]);
|
||||
__TestNamespace_InputTagHelper1.StringDictionaryProperty["paprika"] = __TestNamespace_InputTagHelper2.StringDictionaryProperty["paprika"];
|
||||
StartTagHelperWritingScope();
|
||||
StartTagHelperWritingScope(null);
|
||||
WriteLiteral("literate ");
|
||||
#line 21 "PrefixedAttributeTagHelpers.cshtml"
|
||||
WriteLiteral(literate);
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ __TestNamespace_InputTagHelper1.IntDictionaryProperty["salt"] = 37;
|
|||
__TestNamespace_InputTagHelper1.StringDictionaryProperty["paprika"] = "another string";
|
||||
__tagHelperExecutionContext.AddTagHelperAttribute("string-prefix-paprika", __TestNamespace_InputTagHelper1.StringDictionaryProperty["paprika"]);
|
||||
__TestNamespace_InputTagHelper2.StringDictionaryProperty["paprika"] = __TestNamespace_InputTagHelper1.StringDictionaryProperty["paprika"];
|
||||
StartTagHelperWritingScope();
|
||||
StartTagHelperWritingScope(null);
|
||||
WriteLiteral("literate ");
|
||||
#line 21 "PrefixedAttributeTagHelpers.cshtml"
|
||||
WriteLiteral(literate);
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ namespace TestOutput
|
|||
, StartTagHelperWritingScope, EndTagHelperWritingScope);
|
||||
__TestNamespace_MyTagHelper = CreateTagHelper<global::TestNamespace.MyTagHelper>();
|
||||
__tagHelperExecutionContext.Add(__TestNamespace_MyTagHelper);
|
||||
StartTagHelperWritingScope();
|
||||
StartTagHelperWritingScope(null);
|
||||
WriteLiteral("Current Time: ");
|
||||
#line 9 "TagHelpersInSection.cshtml"
|
||||
WriteLiteral(DateTime.Now);
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ __TestNamespace_PTagHelper.Age = 1337;
|
|||
#line default
|
||||
#line hidden
|
||||
__tagHelperExecutionContext.AddTagHelperAttribute("age", __TestNamespace_PTagHelper.Age);
|
||||
StartTagHelperWritingScope();
|
||||
StartTagHelperWritingScope(null);
|
||||
#line 7 "TagHelpersWithWeirdlySpacedAttributes.cshtml"
|
||||
Write(true);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue