// 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 Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Intermediate; using Xunit; namespace Microsoft.AspNetCore.Blazor.Razor { public class HtmlBlockPassTest { public HtmlBlockPassTest() { Pass = new HtmlBlockPass(); Engine = RazorProjectEngine.Create( BlazorExtensionInitializer.DefaultConfiguration, RazorProjectFileSystem.Create(Environment.CurrentDirectory), b => { BlazorExtensionInitializer.Register(b); if (b.Features.OfType().Any()) { b.Features.Remove(b.Features.OfType().Single()); } }).Engine; Pass.Engine = Engine; } private RazorEngine Engine { get; } private HtmlBlockPass Pass { get; } [Fact] public void Execute_RewritesHtml_Basic() { // Arrange var document = CreateDocument(@" Hello, World! "); var expected = NormalizeContent(@" Hello, World! "); var documentNode = Lower(document); // Act Pass.Execute(document, documentNode); // Assert var block = documentNode.FindDescendantNodes().Single(); Assert.Equal(expected, block.Content, ignoreLineEndingDifferences: true); } [Fact] public void Execute_RewritesHtml_WithComment() { // Arrange var document = CreateDocument(@"StartEnd"); var expected = NormalizeContent(@"StartEnd"); var documentNode = Lower(document); // Act Pass.Execute(document, documentNode); // Assert var block = documentNode.FindDescendantNodes().Single(); Assert.Equal(expected, block.Content, ignoreLineEndingDifferences: true); } [Fact] public void Execute_RewritesHtml_MergesSiblings() { // Arrange var document = CreateDocument(@" @(""Hi"")
@(""Hi"")
"); var expected = NormalizeContent(@"
"); var documentNode = Lower(document); // Act Pass.Execute(document, documentNode); // Assert var block = documentNode.FindDescendantNodes().Single(); Assert.Equal(expected, block.Content, ignoreLineEndingDifferences: true); } [Fact] public void Execute_RewritesHtml_MergesSiblings_LeftEdge() { // Arrange var document = CreateDocument(@"
@(""Hi"")
"); var expected = NormalizeContent(@"
"); var documentNode = Lower(document); // Act Pass.Execute(document, documentNode); // Assert var block = documentNode.FindDescendantNodes().Single(); Assert.Equal(expected, block.Content, ignoreLineEndingDifferences: true); } [Fact] public void Execute_RewritesHtml_CSharpInAttributes() { // Arrange var document = CreateDocument(@"
foo
"); var expected = NormalizeContent("
foo
\n "); var documentNode = Lower(document); // Act Pass.Execute(document, documentNode); // Assert var block = documentNode.FindDescendantNodes().Single(); Assert.Equal(expected, block.Content, ignoreLineEndingDifferences: true); } [Fact] public void Execute_RewritesHtml_CSharpInBody() { // Arrange var document = CreateDocument(@"
@foo
rewriteme
@bar
"); var expected = NormalizeContent("
rewriteme
\n "); var documentNode = Lower(document); // Act Pass.Execute(document, documentNode); // Assert var block = documentNode.FindDescendantNodes().Single(); Assert.Equal(expected, block.Content, ignoreLineEndingDifferences: true); } [Fact] public void Execute_RewritesHtml_EncodesHtmlEntities() { // Arrange var document = CreateDocument(@"
<span>Hi</span>
"); var expected = NormalizeContent(@"
<span>Hi</span>
"); var documentNode = Lower(document); // Act Pass.Execute(document, documentNode); // Assert var block = documentNode.FindDescendantNodes().Single(); Assert.Equal(expected, block.Content, ignoreLineEndingDifferences: true); } [Fact] public void Execute_RewritesHtml_EmptyNonvoid() { // Arrange var document = CreateDocument(@""); var expected = NormalizeContent(@""); var documentNode = Lower(document); // Act Pass.Execute(document, documentNode); // Assert var block = documentNode.FindDescendantNodes().Single(); Assert.Equal(expected, block.Content, ignoreLineEndingDifferences: true); } [Fact] public void Execute_RewritesHtml_Void() { // Arrange var document = CreateDocument(@""); var expected = NormalizeContent(@""); var documentNode = Lower(document); // Act Pass.Execute(document, documentNode); // Assert var block = documentNode.FindDescendantNodes().Single(); Assert.Equal(expected, block.Content, ignoreLineEndingDifferences: true); } [Fact] public void Execute_CannotRewriteHtml_CSharpInCode() { // Arrange var document = CreateDocument(@" @if (some_bool) { @hello } "); var documentNode = Lower(document); // Act Pass.Execute(document, documentNode); // Assert Assert.Empty(documentNode.FindDescendantNodes()); } [Fact] public void Execute_CannotRewriteHtml_Script() { // Arrange var document = CreateDocument(@" @if (some_bool) { } "); var documentNode = Lower(document); // Act Pass.Execute(document, documentNode); // Assert Assert.Empty(documentNode.FindDescendantNodes()); } // The unclosed tag will have errors, so we won't rewrite it or its parent. [Fact] public void Execute_CannotRewriteHtml_Errors() { // Arrange var document = CreateDocument(@" "); var documentNode = Lower(document); // Act Pass.Execute(document, documentNode); // Assert Assert.Empty(documentNode.FindDescendantNodes()); } [Fact] public void Execute_RewritesHtml_MismatchedClosingTag() { // Arrange var document = CreateDocument(@"
rewriteme
"); var expected = NormalizeContent("
rewriteme
\n "); var documentNode = Lower(document); // Act Pass.Execute(document, documentNode); // Assert var block = documentNode.FindDescendantNodes().Single(); Assert.Equal(expected, block.Content, ignoreLineEndingDifferences: true); } private string NormalizeContent(string content) { // Test inputs frequently have leading space for readability. content = content.TrimStart(); // Normalize newlines since we are testing lengths of things. content = content.Replace("\r", ""); content = content.Replace("\n", "\r\n"); return content; } private RazorCodeDocument CreateDocument(string content) { // Normalize newlines since we are testing lengths of things. content = content.Replace("\r", ""); content = content.Replace("\n", "\r\n"); var source = RazorSourceDocument.Create(content, "test.cshtml"); return RazorCodeDocument.Create(source); } private DocumentIntermediateNode Lower(RazorCodeDocument codeDocument) { for (var i = 0; i < Engine.Phases.Count; i++) { var phase = Engine.Phases[i]; if (phase is IRazorCSharpLoweringPhase) { break; } phase.Execute(codeDocument); } var document = codeDocument.GetDocumentIntermediateNode(); Engine.Features.OfType().Single().Execute(codeDocument, document); return document; } private class StaticTagHelperFeature : ITagHelperFeature { public RazorEngine Engine { get; set; } public List TagHelpers { get; set; } public IReadOnlyList GetDescriptors() { return TagHelpers; } } } }