|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Linq;
using System.Text;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Xunit;
namespace Microsoft.AspNetCore.Razor.Language.Components;
public class ComponentWhitespacePassTest
{
public ComponentWhitespacePassTest()
{
ProjectEngine = RazorProjectEngine.Create(
RazorConfiguration.Default,
RazorProjectFileSystem.Create(Environment.CurrentDirectory),
b =>
{
if (b.Features.OfType<ComponentWhitespacePass>().Any())
{
b.Features.Remove(b.Features.OfType<ComponentWhitespacePass>().Single());
}
});
Engine = ProjectEngine.Engine;
Pass = new ComponentWhitespacePass()
{
Engine = Engine
};
}
private RazorProjectEngine ProjectEngine { get; }
private RazorEngine Engine { get; }
private ComponentWhitespacePass Pass { get; }
[Fact]
public void Execute_RemovesLeadingAndTrailingWhitespace()
{
// Arrange
var document = CreateDocument(@"
<span>@(""Hello, world"")</span>
");
var documentNode = Lower(document);
// Act
Pass.Execute(document, documentNode);
// Assert
var method = documentNode.FindPrimaryMethod();
Assert.NotNull(method);
var child = Assert.IsType<MarkupElementIntermediateNode>(Assert.Single(method.Children));
Assert.Equal("span", child.TagName);
}
[Fact]
public void Execute_RemovesLeadingAndTrailingWhitespaceInsideElement()
{
// Arrange
var document = CreateDocument(@"
<parent>
<child> Hello, @("" w o r l d "") </child>
</parent>
");
var documentNode = Lower(document);
// Act
Pass.Execute(document, documentNode);
// Assert
var method = documentNode.FindPrimaryMethod();
Assert.NotNull(method);
var parentElement = Assert.IsType<MarkupElementIntermediateNode>(Assert.Single(method.Children));
var childElement = Assert.IsType<MarkupElementIntermediateNode>(Assert.Single(parentElement.Children));
Assert.Equal("child", childElement.TagName);
Assert.Collection(childElement.Children,
node =>
{
var htmlNode = Assert.IsType<HtmlContentIntermediateNode>(node);
Assert.Equal(" Hello, ", GetContent(htmlNode));
},
node =>
{
var csharpExpressionNode = Assert.IsType<CSharpExpressionIntermediateNode>(node);
Assert.Equal(@""" w o r l d """, GetContent(csharpExpressionNode));
});
}
[Fact]
public void Execute_LeavesWhitespaceBetweenSiblingElements()
{
// Arrange
var document = CreateDocument(@" <elem attr=@expr /> <elem attr=@expr /> ");
var documentNode = Lower(document);
// Act
Pass.Execute(document, documentNode);
// Assert
var method = documentNode.FindPrimaryMethod();
Assert.NotNull(method);
Assert.Collection(method.Children,
node => Assert.IsType<MarkupElementIntermediateNode>(node),
node => Assert.IsType<HtmlContentIntermediateNode>(node),
node => Assert.IsType<MarkupElementIntermediateNode>(node));
}
[Fact]
public void Execute_RemovesWhitespacePrecedingAndTrailingCSharpCode()
{
// Arrange
var document = CreateDocument(@"
<parent>
<child>@val1a @val1b</child>
@if(someExpression) { /* Do something */ }
<child>@val2a @val2b</child>
</parent>
");
var documentNode = Lower(document);
// Act
Pass.Execute(document, documentNode);
// Assert
var method = documentNode.FindPrimaryMethod();
Assert.NotNull(method);
var parentElement = Assert.IsType<MarkupElementIntermediateNode>(Assert.Single(method.Children));
Assert.Collection(parentElement.Children,
node =>
{
Assert.Equal("child", Assert.IsType<MarkupElementIntermediateNode>(node).TagName);
Assert.Collection(node.Children,
x => Assert.IsType<CSharpExpressionIntermediateNode>(x),
x => Assert.IsType<HtmlContentIntermediateNode>(x), // We don't remove whitespace before/after C# expressions
x => Assert.IsType<CSharpExpressionIntermediateNode>(x));
},
node => Assert.IsType<CSharpCodeIntermediateNode>(node),
node =>
{
Assert.Equal("child", Assert.IsType<MarkupElementIntermediateNode>(node).TagName);
Assert.Collection(node.Children,
x => Assert.IsType<CSharpExpressionIntermediateNode>(x),
x => Assert.IsType<HtmlContentIntermediateNode>(x), // We don't remove whitespace before/after C# expressions
x => Assert.IsType<CSharpExpressionIntermediateNode>(x));
});
}
private RazorCodeDocument CreateDocument(string content)
{
var source = RazorSourceDocument.Create(content, "test.cshtml");
return ProjectEngine.CreateCodeDocument(source, RazorFileKind.Component);
}
private DocumentIntermediateNode Lower(RazorCodeDocument codeDocument)
{
foreach (var phase in Engine.Phases)
{
if (phase is IRazorCSharpLoweringPhase)
{
break;
}
codeDocument = phase.Execute(codeDocument);
}
return codeDocument.GetRequiredDocumentNode();
}
private static string GetContent(IntermediateNode node)
{
var builder = new StringBuilder();
var tokens = node.Children.OfType<IntermediateToken>();
foreach (var token in tokens)
{
builder.Append(token.Content);
}
return builder.ToString();
}
}
|