264 lines
8.8 KiB
C#
264 lines
8.8 KiB
C#
// 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.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
|
using Microsoft.AspNetCore.Razor.Evolution;
|
|
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
|
|
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
|
|
using Xunit;
|
|
|
|
namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
|
{
|
|
public class ModelExpressionPassTest
|
|
{
|
|
[Fact]
|
|
public void ModelExpressionPass_NonModelExpressionProperty_Ignored()
|
|
{
|
|
// Arrange
|
|
var codeDocument = CreateDocument(@"
|
|
@addTagHelper TestTagHelper, TestAssembly
|
|
<p foo=""17"">");
|
|
|
|
var tagHelpers = new[]
|
|
{
|
|
new TagHelperDescriptor()
|
|
{
|
|
AssemblyName = "TestAssembly",
|
|
TypeName = "TestTagHelper",
|
|
TagName = "p",
|
|
Attributes = new TagHelperAttributeDescriptor[]
|
|
{
|
|
new TagHelperAttributeDescriptor()
|
|
{
|
|
TypeName = "System.Int32",
|
|
Name = "Foo",
|
|
}
|
|
|
|
}
|
|
}
|
|
};
|
|
|
|
var engine = CreateEngine(tagHelpers);
|
|
var pass = new ModelExpressionPass()
|
|
{
|
|
Engine = engine,
|
|
};
|
|
|
|
var irDocument = CreateIRDocument(engine, codeDocument);
|
|
|
|
// Act
|
|
pass.Execute(codeDocument, irDocument);
|
|
|
|
// Assert
|
|
var tagHelper = FindTagHelperNode(irDocument);
|
|
var setProperty = tagHelper.Children.OfType<SetTagHelperPropertyIRNode>().Single();
|
|
|
|
var child = Assert.IsType<HtmlContentIRNode>(Assert.Single(setProperty.Children));
|
|
Assert.Equal("17", child.Content);
|
|
}
|
|
|
|
[Fact]
|
|
public void ModelExpressionPass_ModelExpressionProperty_SimpleExpression()
|
|
{
|
|
// Arrange
|
|
|
|
// Using \r\n here because we verify line mappings
|
|
var codeDocument = CreateDocument(
|
|
"@addTagHelper TestTagHelper, TestAssembly\r\n<p foo=\"Bar\">");
|
|
|
|
var tagHelpers = new[]
|
|
{
|
|
new TagHelperDescriptor()
|
|
{
|
|
AssemblyName = "TestAssembly",
|
|
TypeName = "TestTagHelper",
|
|
TagName = "p",
|
|
Attributes = new TagHelperAttributeDescriptor[]
|
|
{
|
|
new TagHelperAttributeDescriptor()
|
|
{
|
|
TypeName = typeof(ModelExpression).FullName,
|
|
Name = "Foo",
|
|
}
|
|
|
|
}
|
|
}
|
|
};
|
|
|
|
var engine = CreateEngine(tagHelpers);
|
|
var pass = new ModelExpressionPass()
|
|
{
|
|
Engine = engine,
|
|
};
|
|
|
|
var irDocument = CreateIRDocument(engine, codeDocument);
|
|
|
|
// Act
|
|
pass.Execute(codeDocument, irDocument);
|
|
|
|
// Assert
|
|
var tagHelper = FindTagHelperNode(irDocument);
|
|
var setProperty = tagHelper.Children.OfType<SetTagHelperPropertyIRNode>().Single();
|
|
|
|
var expression = Assert.IsType<CSharpExpressionIRNode>(Assert.Single(setProperty.Children));
|
|
Assert.Equal("ModelExpressionProvider.CreateModelExpression(ViewData, __model => __model.Bar)", GetCSharpContent(expression));
|
|
|
|
var originalNode = Assert.IsType<RazorIRToken>(expression.Children[2]);
|
|
Assert.Equal(RazorIRToken.TokenKind.CSharp, originalNode.Kind);
|
|
Assert.Equal("Bar", originalNode.Content);
|
|
Assert.Equal(new SourceSpan("test.cshtml", 51, 1, 8, 3), originalNode.Source.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void ModelExpressionPass_ModelExpressionProperty_ComplexExpression()
|
|
{
|
|
// Arrange
|
|
|
|
// Using \r\n here because we verify line mappings
|
|
var codeDocument = CreateDocument(
|
|
"@addTagHelper TestTagHelper, TestAssembly\r\n<p foo=\"@Bar\">");
|
|
|
|
var tagHelpers = new[]
|
|
{
|
|
new TagHelperDescriptor()
|
|
{
|
|
AssemblyName = "TestAssembly",
|
|
TypeName = "TestTagHelper",
|
|
TagName = "p",
|
|
Attributes = new TagHelperAttributeDescriptor[]
|
|
{
|
|
new TagHelperAttributeDescriptor()
|
|
{
|
|
TypeName = typeof(ModelExpression).FullName,
|
|
Name = "Foo",
|
|
}
|
|
|
|
}
|
|
}
|
|
};
|
|
|
|
var engine = CreateEngine(tagHelpers);
|
|
var pass = new ModelExpressionPass()
|
|
{
|
|
Engine = engine,
|
|
};
|
|
|
|
var irDocument = CreateIRDocument(engine, codeDocument);
|
|
|
|
// Act
|
|
pass.Execute(codeDocument, irDocument);
|
|
|
|
// Assert
|
|
var tagHelper = FindTagHelperNode(irDocument);
|
|
var setProperty = tagHelper.Children.OfType<SetTagHelperPropertyIRNode>().Single();
|
|
|
|
var expression = Assert.IsType<CSharpExpressionIRNode>(Assert.Single(setProperty.Children));
|
|
Assert.Equal("ModelExpressionProvider.CreateModelExpression(ViewData, __model => Bar)", GetCSharpContent(expression));
|
|
|
|
var originalNode = Assert.IsType<RazorIRToken>(expression.Children[1]);
|
|
Assert.Equal(RazorIRToken.TokenKind.CSharp, originalNode.Kind);
|
|
Assert.Equal("Bar", originalNode.Content);
|
|
Assert.Equal(new SourceSpan("test.cshtml", 52, 1, 9, 3), originalNode.Source.Value);
|
|
}
|
|
|
|
private RazorCodeDocument CreateDocument(string content)
|
|
{
|
|
using (var stream = new MemoryStream())
|
|
{
|
|
var bytes = Encoding.UTF8.GetBytes(content);
|
|
stream.Write(bytes, 0, bytes.Length);
|
|
stream.Seek(0L, SeekOrigin.Begin);
|
|
|
|
var source = RazorSourceDocument.ReadFrom(stream, "test.cshtml");
|
|
return RazorCodeDocument.Create(source);
|
|
}
|
|
}
|
|
|
|
private RazorEngine CreateEngine(params TagHelperDescriptor[] tagHelpers)
|
|
{
|
|
return RazorEngine.Create(b =>
|
|
{
|
|
b.Features.Add(new TagHelperFeature(tagHelpers));
|
|
});
|
|
}
|
|
|
|
private DocumentIRNode CreateIRDocument(RazorEngine engine, RazorCodeDocument codeDocument)
|
|
{
|
|
for (var i = 0; i < engine.Phases.Count; i++)
|
|
{
|
|
var phase = engine.Phases[i];
|
|
phase.Execute(codeDocument);
|
|
|
|
if (phase is IRazorDirectiveClassifierPhase)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return codeDocument.GetIRDocument();
|
|
}
|
|
|
|
private TagHelperIRNode FindTagHelperNode(RazorIRNode node)
|
|
{
|
|
var visitor = new TagHelperNodeVisitor();
|
|
visitor.Visit(node);
|
|
return visitor.Node;
|
|
}
|
|
|
|
private string GetCSharpContent(RazorIRNode node)
|
|
{
|
|
var builder = new StringBuilder();
|
|
for (var i = 0; i < node.Children.Count; i++)
|
|
{
|
|
var child = node.Children[i] as RazorIRToken;
|
|
if (child.Kind == RazorIRToken.TokenKind.CSharp)
|
|
{
|
|
builder.Append(child.Content);
|
|
}
|
|
}
|
|
|
|
return builder.ToString();
|
|
}
|
|
|
|
private class TagHelperNodeVisitor : RazorIRNodeWalker
|
|
{
|
|
public TagHelperIRNode Node { get; set; }
|
|
|
|
public override void VisitTagHelper(TagHelperIRNode node)
|
|
{
|
|
Node = node;
|
|
}
|
|
}
|
|
|
|
private class TagHelperFeature : ITagHelperFeature
|
|
{
|
|
public TagHelperFeature(TagHelperDescriptor[] tagHelpers)
|
|
{
|
|
Resolver = new TagHelperDescriptorResolver(tagHelpers);
|
|
}
|
|
|
|
public RazorEngine Engine { get; set; }
|
|
|
|
public ITagHelperDescriptorResolver Resolver { get; }
|
|
}
|
|
|
|
private class TagHelperDescriptorResolver : ITagHelperDescriptorResolver
|
|
{
|
|
public TagHelperDescriptorResolver(TagHelperDescriptor[] tagHelpers)
|
|
{
|
|
TagHelpers = tagHelpers;
|
|
}
|
|
|
|
public TagHelperDescriptor[] TagHelpers { get; }
|
|
|
|
public IEnumerable<TagHelperDescriptor> Resolve(IList<RazorDiagnostic> errors)
|
|
{
|
|
return TagHelpers;
|
|
}
|
|
}
|
|
}
|
|
} |