Add unit tests for ModelExpressionPass
Add unit tests for @inject
This commit is contained in:
parent
b79f8384b0
commit
705369ee51
|
|
@ -1,32 +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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains information for the tag helper attribute code
|
||||
/// generation process.
|
||||
/// </summary>
|
||||
public class GeneratedTagHelperAttributeContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the model expression type.
|
||||
/// </summary>
|
||||
public string ModelExpressionTypeName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name the method to create <c>ModelExpression</c>s.
|
||||
/// </summary>
|
||||
public string CreateModelExpressionMethodName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the <c>IModelExpressionProvider</c>.
|
||||
/// </summary>
|
||||
public string ModelExpressionProviderPropertyName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the property name of the <c>ViewDataDictionary</c>.
|
||||
/// </summary>
|
||||
public string ViewDataPropertyName { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,54 +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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Host.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains necessary information for the view component tag helper code generation process.
|
||||
/// </summary>
|
||||
public class GeneratedViewComponentTagHelperContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Instantiates a new instance of the <see cref="GeneratedViewComponentTagHelperContext"/> with default values.
|
||||
/// </summary>
|
||||
public GeneratedViewComponentTagHelperContext()
|
||||
{
|
||||
ContextualizeMethodName = "Contextualize";
|
||||
InvokeAsyncMethodName = "InvokeAsync";
|
||||
IViewComponentHelperTypeName = "Microsoft.AspNetCore.Mvc.IViewComponentHelper";
|
||||
IViewContextAwareTypeName = "Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware";
|
||||
ViewContextAttributeTypeName = "Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute";
|
||||
ViewContextTypeName = "Microsoft.AspNetCore.Mvc.Rendering.ViewContext";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Contextualize method called by an instance of the IViewContextAware type.
|
||||
/// </summary>
|
||||
public string ContextualizeMethodName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the InvokeAsync method called by an IViewComponentHelper.
|
||||
/// </summary>
|
||||
public string InvokeAsyncMethodName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the IViewComponentHelper type used to invoke view components.
|
||||
/// </summary>
|
||||
public string IViewComponentHelperTypeName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the IViewContextAware type used to contextualize the view context.
|
||||
/// </summary>
|
||||
public string IViewContextAwareTypeName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the ViewContext type for view execution.
|
||||
/// </summary>
|
||||
public string ViewContextTypeName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the ViewContextAttribute type.
|
||||
/// </summary>
|
||||
public string ViewContextAttributeTypeName { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
|||
return builder;
|
||||
}
|
||||
|
||||
private class Pass : IRazorIRPass
|
||||
internal class Pass : IRazorIRPass
|
||||
{
|
||||
public RazorEngine Engine { get; set; }
|
||||
|
||||
|
|
@ -31,18 +31,27 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
|||
var visitor = new Visitor();
|
||||
visitor.Visit(irDocument);
|
||||
|
||||
for (var i = 0; i < visitor.Directives.Count; i++)
|
||||
var properties = new HashSet<string>(StringComparer.Ordinal);
|
||||
|
||||
for (var i = visitor.Directives.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var directive = visitor.Directives[i];
|
||||
var typeName = directive.Tokens.ElementAt(0).Content;;
|
||||
var memberName = directive.Tokens.ElementAt(1).Content;
|
||||
|
||||
var modelType = "dynamic";
|
||||
if (visitor.ModelType.Count > 0)
|
||||
var tokens = directive.Tokens.ToArray();
|
||||
if (tokens.Length < 2)
|
||||
{
|
||||
modelType = visitor.ModelType.Last().Tokens.First().Content;
|
||||
continue;
|
||||
}
|
||||
|
||||
var typeName = tokens[0].Content;
|
||||
var memberName = tokens[1].Content;
|
||||
|
||||
if (!properties.Add(memberName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var modelType = ModelDirective.GetModelType(irDocument);
|
||||
|
||||
typeName = typeName.Replace("<TModel>", "<" + modelType + ">");
|
||||
|
||||
var member = new CSharpStatementIRNode()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// 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.Evolution;
|
||||
|
|
@ -19,6 +20,35 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
|||
return builder;
|
||||
}
|
||||
|
||||
public static string GetModelType(DocumentIRNode document)
|
||||
{
|
||||
if (document == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(document));
|
||||
}
|
||||
|
||||
var visitor = new Visitor();
|
||||
visitor.Visit(document);
|
||||
|
||||
return GetModelType(visitor);
|
||||
}
|
||||
|
||||
private static string GetModelType(Visitor visitor)
|
||||
{
|
||||
for (var i = visitor.ModelDirectives.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var directive = visitor.ModelDirectives[i];
|
||||
|
||||
var tokens = directive.Tokens.ToArray();
|
||||
if (tokens.Length >= 1)
|
||||
{
|
||||
return tokens[0].Content;
|
||||
}
|
||||
}
|
||||
|
||||
return "dynamic";
|
||||
}
|
||||
|
||||
private class Pass : IRazorIRPass
|
||||
{
|
||||
public RazorEngine Engine { get; set; }
|
||||
|
|
@ -31,13 +61,21 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
|||
var visitor = new Visitor();
|
||||
visitor.Visit(irDocument);
|
||||
|
||||
string modelType = "dynamic";
|
||||
if (visitor.Directives.Count == 1)
|
||||
var modelType = GetModelType(visitor);
|
||||
|
||||
var baseType = visitor.Class.BaseType;
|
||||
for (var i = visitor.InheritsDirectives.Count - 1; i >= 0; i--)
|
||||
{
|
||||
modelType = visitor.Directives.Last().Tokens.First().Content;
|
||||
var directive = visitor.InheritsDirectives[i];
|
||||
var tokens = directive.Tokens.ToArray();
|
||||
if (tokens.Length >= 1)
|
||||
{
|
||||
baseType = tokens[0].Content;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
visitor.Class.BaseType = visitor.Class.BaseType.Replace("<TModel>", "<" + modelType + ">");
|
||||
visitor.Class.BaseType = baseType.Replace("<TModel>", "<" + modelType + ">");
|
||||
|
||||
return irDocument;
|
||||
}
|
||||
|
|
@ -47,7 +85,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
|||
{
|
||||
public ClassDeclarationIRNode Class { get; private set; }
|
||||
|
||||
public IList<DirectiveIRNode> Directives { get; } = new List<DirectiveIRNode>();
|
||||
public IList<DirectiveIRNode> InheritsDirectives { get; } = new List<DirectiveIRNode>();
|
||||
|
||||
public IList<DirectiveIRNode> ModelDirectives { get; } = new List<DirectiveIRNode>();
|
||||
|
||||
public override void VisitClass(ClassDeclarationIRNode node)
|
||||
{
|
||||
|
|
@ -63,7 +103,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
|||
{
|
||||
if (node.Descriptor == Directive)
|
||||
{
|
||||
Directives.Add(node);
|
||||
ModelDirectives.Add(node);
|
||||
}
|
||||
else if (node.Descriptor.Name == "inherits")
|
||||
{
|
||||
InheritsDirectives.Add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,9 +38,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
|||
Content = "ModelExpressionProvider.CreateModelExpression(ViewData, __model => ",
|
||||
});
|
||||
|
||||
|
||||
if (node.Children.Count == 1 && node.Children[0] is HtmlContentIRNode)
|
||||
{
|
||||
// A 'simple' expression will look like __model => __model.Foo
|
||||
//
|
||||
// Note that the fact we're looking for HTML here is based on a bug.
|
||||
// https://github.com/aspnet/Razor/issues/963
|
||||
var original = ((HtmlContentIRNode)node.Children[0]);
|
||||
|
||||
builder.Add(new CSharpTokenIRNode()
|
||||
|
|
@ -58,7 +61,32 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
|||
{
|
||||
for (var i = 0; i < node.Children.Count; i++)
|
||||
{
|
||||
builder.Add(node.Children[i]);
|
||||
var nestedExpression = node.Children[i] as CSharpExpressionIRNode;
|
||||
if (nestedExpression != null)
|
||||
{
|
||||
for (var j = 0; j < nestedExpression.Children.Count; j++)
|
||||
{
|
||||
var cSharpToken = nestedExpression.Children[j] as CSharpTokenIRNode;
|
||||
if (cSharpToken != null)
|
||||
{
|
||||
builder.Add(cSharpToken);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Note that the fact we're looking for HTML here is based on a bug.
|
||||
// https://github.com/aspnet/Razor/issues/963
|
||||
var html = node.Children[i] as HtmlContentIRNode;
|
||||
if (html != null)
|
||||
{
|
||||
builder.Add(new CSharpTokenIRNode()
|
||||
{
|
||||
Content = html.Content,
|
||||
Source = html.Source,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -90,5 +90,9 @@
|
|||
{
|
||||
"OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.Directives.UsingChunkMerger : Microsoft.AspNetCore.Mvc.Razor.Directives.IChunkMerger",
|
||||
"Kind": "Removal"
|
||||
},
|
||||
{
|
||||
"OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.GeneratedTagHelperAttributeContext",
|
||||
"Kind": "Removal"
|
||||
}
|
||||
]
|
||||
|
|
@ -90,5 +90,9 @@
|
|||
{
|
||||
"OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.Directives.UsingChunkMerger : Microsoft.AspNetCore.Mvc.Razor.Directives.IChunkMerger",
|
||||
"Kind": "Removal"
|
||||
},
|
||||
{
|
||||
"OldTypeId": "public class Microsoft.AspNetCore.Mvc.Razor.GeneratedTagHelperAttributeContext",
|
||||
"Kind": "Removal"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,174 +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 Microsoft.AspNetCore.Razor.Chunks;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Directives
|
||||
{
|
||||
public class InjectChunkMergerTest
|
||||
{
|
||||
#if OLD_RAZOR
|
||||
[Theory]
|
||||
[InlineData("MyApp.TestHelper<TModel>", "MyApp.TestHelper<Person>")]
|
||||
[InlineData("TestBaseType", "TestBaseType")]
|
||||
public void Visit_UpdatesTModelTokenToMatchModelType(string typeName, string expectedValue)
|
||||
{
|
||||
// Arrange
|
||||
var chunk = new InjectChunk(typeName, "TestHelper");
|
||||
var merger = new InjectChunkMerger("Person");
|
||||
|
||||
// Act
|
||||
merger.VisitChunk(chunk);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedValue, chunk.TypeName);
|
||||
Assert.Equal("TestHelper", chunk.MemberName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Merge_AddsChunkIfChunkWithMatchingPropertyNameWasNotVisitedInChunkTree()
|
||||
{
|
||||
// Arrange
|
||||
var expectedType = "MyApp.MyHelperType";
|
||||
var expectedProperty = "MyHelper";
|
||||
var merger = new InjectChunkMerger("dynamic");
|
||||
var chunkTree = new ChunkTree();
|
||||
var inheritedChunks = new[]
|
||||
{
|
||||
new InjectChunk(expectedType, expectedProperty)
|
||||
};
|
||||
|
||||
// Act
|
||||
merger.MergeInheritedChunks(chunkTree, inheritedChunks);
|
||||
|
||||
// Assert
|
||||
var chunk = Assert.Single(chunkTree.Children);
|
||||
var injectChunk = Assert.IsType<InjectChunk>(chunk);
|
||||
Assert.Equal(expectedType, injectChunk.TypeName);
|
||||
Assert.Equal(expectedProperty, injectChunk.MemberName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Merge_IgnoresChunkIfChunkWithMatchingPropertyNameWasVisitedInChunkTree()
|
||||
{
|
||||
// Arrange
|
||||
var merger = new InjectChunkMerger("dynamic");
|
||||
var chunkTree = new ChunkTree();
|
||||
var inheritedChunks = new[]
|
||||
{
|
||||
new InjectChunk("MyTypeB", "MyProperty")
|
||||
};
|
||||
|
||||
// Act
|
||||
merger.VisitChunk(new InjectChunk("MyTypeA", "MyProperty"));
|
||||
merger.MergeInheritedChunks(chunkTree, inheritedChunks);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(chunkTree.Children);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Merge_MatchesPropertyNameInCaseSensitiveManner()
|
||||
{
|
||||
// Arrange
|
||||
var merger = new InjectChunkMerger("dynamic");
|
||||
var chunkTree = new ChunkTree();
|
||||
var inheritedChunks = new[]
|
||||
{
|
||||
new InjectChunk("MyTypeB", "different-property"),
|
||||
new InjectChunk("MyType", "myproperty"),
|
||||
};
|
||||
|
||||
// Act
|
||||
merger.VisitChunk(new InjectChunk("MyType", "MyProperty"));
|
||||
merger.MergeInheritedChunks(chunkTree, inheritedChunks);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, chunkTree.Children.Count);
|
||||
var injectChunk = Assert.IsType<InjectChunk>(chunkTree.Children[0]);
|
||||
Assert.Equal("MyType", injectChunk.TypeName);
|
||||
Assert.Equal("myproperty", injectChunk.MemberName);
|
||||
|
||||
injectChunk = Assert.IsType<InjectChunk>(chunkTree.Children[1]);
|
||||
Assert.Equal("MyTypeB", injectChunk.TypeName);
|
||||
Assert.Equal("different-property", injectChunk.MemberName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Merge_ResolvesModelNameInTypesWithTModelToken()
|
||||
{
|
||||
// Arrange
|
||||
var merger = new InjectChunkMerger("dynamic");
|
||||
var chunkTree = new ChunkTree();
|
||||
var inheritedChunks = new[]
|
||||
{
|
||||
new InjectChunk("MyHelper<TModel>", "MyProperty")
|
||||
};
|
||||
|
||||
// Act
|
||||
merger.MergeInheritedChunks(chunkTree, inheritedChunks);
|
||||
|
||||
// Assert
|
||||
var chunk = Assert.Single(chunkTree.Children);
|
||||
var injectChunk = Assert.IsType<InjectChunk>(chunk);
|
||||
Assert.Equal("MyHelper<dynamic>", injectChunk.TypeName);
|
||||
Assert.Equal("MyProperty", injectChunk.MemberName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Merge_ReplacesTModelTokensWithModel()
|
||||
{
|
||||
// Arrange
|
||||
var merger = new InjectChunkMerger("MyTestModel2");
|
||||
var chunkTree = new ChunkTree();
|
||||
var inheritedChunks = new[]
|
||||
{
|
||||
new InjectChunk("MyHelper<TModel>", "MyProperty")
|
||||
};
|
||||
|
||||
// Act
|
||||
merger.MergeInheritedChunks(chunkTree, inheritedChunks);
|
||||
|
||||
// Assert
|
||||
var chunk = Assert.Single(chunkTree.Children);
|
||||
var injectChunk = Assert.IsType<InjectChunk>(chunk);
|
||||
Assert.Equal("MyHelper<MyTestModel2>", injectChunk.TypeName);
|
||||
Assert.Equal("MyProperty", injectChunk.MemberName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Merge_UsesTheLastInjectChunkOfAPropertyName()
|
||||
{
|
||||
// Arrange
|
||||
var merger = new InjectChunkMerger("dynamic");
|
||||
var chunkTree = new ChunkTree();
|
||||
var inheritedChunks = new Chunk[]
|
||||
{
|
||||
new LiteralChunk(),
|
||||
new InjectChunk("SomeOtherType", "Property"),
|
||||
new InjectChunk("DifferentPropertyType", "DifferentProperty"),
|
||||
new InjectChunk("SomeType", "Property"),
|
||||
};
|
||||
|
||||
// Act
|
||||
merger.MergeInheritedChunks(chunkTree, inheritedChunks);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(chunkTree.Children,
|
||||
chunk =>
|
||||
{
|
||||
var injectChunk = Assert.IsType<InjectChunk>(chunk);
|
||||
Assert.Equal("SomeType", injectChunk.TypeName);
|
||||
Assert.Equal("Property", injectChunk.MemberName);
|
||||
},
|
||||
chunk =>
|
||||
{
|
||||
var injectChunk = Assert.IsType<InjectChunk>(chunk);
|
||||
Assert.Equal("DifferentPropertyType", injectChunk.TypeName);
|
||||
Assert.Equal("DifferentProperty", injectChunk.MemberName);
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -1,163 +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 Microsoft.AspNetCore.Mvc.Razor.Directives;
|
||||
using Microsoft.AspNetCore.Razor;
|
||||
using Microsoft.AspNetCore.Razor.Chunks;
|
||||
using Microsoft.AspNetCore.Razor.Chunks.Generators;
|
||||
using Microsoft.AspNetCore.Razor.CodeGenerators;
|
||||
using Microsoft.AspNetCore.Razor.Parser.SyntaxTree;
|
||||
using Microsoft.AspNetCore.Razor.Runtime.TagHelpers;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor
|
||||
{
|
||||
public class InjectChunkVisitorTest
|
||||
{
|
||||
#if OLD_RAZOR
|
||||
[Fact]
|
||||
public void Visit_IgnoresNonInjectChunks()
|
||||
{
|
||||
// Arrange
|
||||
var writer = new CSharpCodeWriter();
|
||||
var context = CreateContext();
|
||||
|
||||
var visitor = new InjectChunkVisitor(writer, context, "ActivateAttribute");
|
||||
|
||||
// Act
|
||||
visitor.Accept(new Chunk[]
|
||||
{
|
||||
new LiteralChunk(),
|
||||
new CodeAttributeChunk()
|
||||
});
|
||||
var code = writer.GenerateCode();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(code);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Visit_GeneratesProperties_ForInjectChunks()
|
||||
{
|
||||
// Arrange
|
||||
var expected =
|
||||
@"[ActivateAttribute]
|
||||
public MyType1 MyPropertyName1 { get; private set; }
|
||||
[ActivateAttribute]
|
||||
public MyType2 @MyPropertyName2 { get; private set; }
|
||||
";
|
||||
var writer = new CSharpCodeWriter();
|
||||
var context = CreateContext();
|
||||
|
||||
var visitor = new InjectChunkVisitor(writer, context, "ActivateAttribute");
|
||||
var factory = SpanFactory.CreateCsHtml();
|
||||
var node = (Span)factory.Code("Some code")
|
||||
.As(new InjectParameterGenerator("MyType", "MyPropertyName"));
|
||||
|
||||
// Act
|
||||
visitor.Accept(new Chunk[]
|
||||
{
|
||||
new LiteralChunk(),
|
||||
new InjectChunk("MyType1", "MyPropertyName1") { Association = node },
|
||||
new InjectChunk("MyType2", "@MyPropertyName2") { Association = node }
|
||||
});
|
||||
var code = writer.GenerateCode();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, code);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Visit_WithDesignTimeHost_GeneratesPropertiesAndLinePragmas_ForInjectChunks()
|
||||
{
|
||||
// Arrange
|
||||
var expected = string.Join(Environment.NewLine,
|
||||
"[Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]",
|
||||
"public",
|
||||
@"#line 1 """"",
|
||||
"MyType1 MyPropertyName1",
|
||||
"",
|
||||
"#line default",
|
||||
"#line hidden",
|
||||
"{ get; private set; }",
|
||||
"[Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]",
|
||||
"public",
|
||||
@"#line 1 """"",
|
||||
"MyType2 @MyPropertyName2",
|
||||
"",
|
||||
"#line default",
|
||||
"#line hidden",
|
||||
"{ get; private set; }",
|
||||
"");
|
||||
var writer = new CSharpCodeWriter();
|
||||
var context = CreateContext();
|
||||
context.Host.DesignTimeMode = true;
|
||||
|
||||
var visitor = new InjectChunkVisitor(writer, context, "Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute");
|
||||
var factory = SpanFactory.CreateCsHtml();
|
||||
var node = (Span)factory.Code("Some code")
|
||||
.As(new InjectParameterGenerator("MyType", "MyPropertyName"));
|
||||
|
||||
// Act
|
||||
visitor.Accept(new Chunk[]
|
||||
{
|
||||
new LiteralChunk(),
|
||||
new InjectChunk("MyType1", "MyPropertyName1") { Association = node },
|
||||
new InjectChunk("MyType2", "@MyPropertyName2") { Association = node }
|
||||
});
|
||||
var code = writer.GenerateCode();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, code);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Visit_WithDesignTimeHost_GeneratesPropertiesAndLinePragmas_ForPartialInjectChunks()
|
||||
{
|
||||
// Arrange
|
||||
var expected = @"[Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
|
||||
public
|
||||
#line 1 """"
|
||||
MyType1
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
{ get; private set; }
|
||||
";
|
||||
var writer = new CSharpCodeWriter();
|
||||
var context = CreateContext();
|
||||
context.Host.DesignTimeMode = true;
|
||||
|
||||
var visitor = new InjectChunkVisitor(writer, context, "Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute");
|
||||
var factory = SpanFactory.CreateCsHtml();
|
||||
var node = (Span)factory.Code("Some code")
|
||||
.As(new InjectParameterGenerator("MyType", "MyPropertyName"));
|
||||
|
||||
// Act
|
||||
visitor.Accept(new Chunk[]
|
||||
{
|
||||
new LiteralChunk(),
|
||||
new InjectChunk("MyType1", string.Empty) { Association = node },
|
||||
});
|
||||
var code = writer.GenerateCode();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, code);
|
||||
}
|
||||
|
||||
private static CodeGeneratorContext CreateContext()
|
||||
{
|
||||
var chunkTreeCache = new DefaultChunkTreeCache(new TestFileProvider());
|
||||
return new CodeGeneratorContext(
|
||||
new ChunkGeneratorContext(
|
||||
new MvcRazorHost(chunkTreeCache, new TagHelperDescriptorResolver(designTime: false)),
|
||||
"MyClass",
|
||||
"MyNamespace",
|
||||
string.Empty,
|
||||
shouldGenerateLinePragmas: true),
|
||||
new ErrorSink());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,241 @@
|
|||
// 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;
|
||||
using Microsoft.AspNetCore.Razor.Evolution;
|
||||
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
||||
{
|
||||
public class InjectDirectiveTest
|
||||
{
|
||||
[Fact]
|
||||
public void InjectDirectivePass_Execute_DefinesProperty()
|
||||
{
|
||||
// Arrange
|
||||
var codeDocument = CreateDocument(@"
|
||||
@inject PropertyType PropertyName
|
||||
");
|
||||
|
||||
var engine = CreateEngine();
|
||||
var pass = new InjectDirective.Pass()
|
||||
{
|
||||
Engine = engine,
|
||||
};
|
||||
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
|
||||
// Assert
|
||||
var @class = FindClassNode(irDocument);
|
||||
Assert.NotNull(@class);
|
||||
Assert.Equal(2, @class.Children.Count);
|
||||
|
||||
var statement = Assert.IsType<CSharpStatementIRNode>(@class.Children[1]);
|
||||
Assert.Equal(
|
||||
"[Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]" + Environment.NewLine +
|
||||
"public PropertyType PropertyName { get; private set; }",
|
||||
statement.Content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InjectDirectivePass_Execute_DedupesPropertiesByName()
|
||||
{
|
||||
// Arrange
|
||||
var codeDocument = CreateDocument(@"
|
||||
@inject PropertyType PropertyName
|
||||
@inject PropertyType2 PropertyName
|
||||
");
|
||||
|
||||
var engine = CreateEngine();
|
||||
var pass = new InjectDirective.Pass()
|
||||
{
|
||||
Engine = engine,
|
||||
};
|
||||
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
|
||||
// Assert
|
||||
var @class = FindClassNode(irDocument);
|
||||
Assert.NotNull(@class);
|
||||
Assert.Equal(2, @class.Children.Count);
|
||||
|
||||
var statement = Assert.IsType<CSharpStatementIRNode>(@class.Children[1]);
|
||||
Assert.Equal(
|
||||
"[Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]" + Environment.NewLine +
|
||||
"public PropertyType2 PropertyName { get; private set; }",
|
||||
statement.Content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InjectDirectivePass_Execute_ExpandsTModel_WithDynamic()
|
||||
{
|
||||
// Arrange
|
||||
var codeDocument = CreateDocument(@"
|
||||
@inject PropertyType<TModel> PropertyName
|
||||
");
|
||||
|
||||
var engine = CreateEngine();
|
||||
var pass = new InjectDirective.Pass()
|
||||
{
|
||||
Engine = engine,
|
||||
};
|
||||
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
|
||||
// Assert
|
||||
var @class = FindClassNode(irDocument);
|
||||
Assert.NotNull(@class);
|
||||
Assert.Equal(2, @class.Children.Count);
|
||||
|
||||
var statement = Assert.IsType<CSharpStatementIRNode>(@class.Children[1]);
|
||||
Assert.Equal(
|
||||
"[Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]" + Environment.NewLine +
|
||||
"public PropertyType<dynamic> PropertyName { get; private set; }",
|
||||
statement.Content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InjectDirectivePass_Execute_ExpandsTModel_WithModelTypeFirst()
|
||||
{
|
||||
// Arrange
|
||||
var codeDocument = CreateDocument(@"
|
||||
@model ModelType
|
||||
@inject PropertyType<TModel> PropertyName
|
||||
");
|
||||
|
||||
var engine = CreateEngine();
|
||||
var pass = new InjectDirective.Pass()
|
||||
{
|
||||
Engine = engine,
|
||||
};
|
||||
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
|
||||
// Assert
|
||||
var @class = FindClassNode(irDocument);
|
||||
Assert.NotNull(@class);
|
||||
Assert.Equal(2, @class.Children.Count);
|
||||
|
||||
var statement = Assert.IsType<CSharpStatementIRNode>(@class.Children[1]);
|
||||
Assert.Equal(
|
||||
"[Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]" + Environment.NewLine +
|
||||
"public PropertyType<ModelType> PropertyName { get; private set; }",
|
||||
statement.Content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InjectDirectivePass_Execute_ExpandsTModel_WithModelType()
|
||||
{
|
||||
// Arrange
|
||||
var codeDocument = CreateDocument(@"
|
||||
@inject PropertyType<TModel> PropertyName
|
||||
@model ModelType
|
||||
");
|
||||
|
||||
var engine = CreateEngine();
|
||||
var pass = new InjectDirective.Pass()
|
||||
{
|
||||
Engine = engine,
|
||||
};
|
||||
|
||||
var irDocument = CreateIRDocument(engine, codeDocument);
|
||||
|
||||
// Act
|
||||
pass.Execute(codeDocument, irDocument);
|
||||
|
||||
// Assert
|
||||
var @class = FindClassNode(irDocument);
|
||||
Assert.NotNull(@class);
|
||||
Assert.Equal(2, @class.Children.Count);
|
||||
|
||||
var statement = Assert.IsType<CSharpStatementIRNode>(@class.Children[1]);
|
||||
Assert.Equal(
|
||||
"[Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]" + Environment.NewLine +
|
||||
"public PropertyType<ModelType> PropertyName { get; private set; }",
|
||||
statement.Content);
|
||||
}
|
||||
|
||||
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 ClassDeclarationIRNode FindClassNode(RazorIRNode node)
|
||||
{
|
||||
var visitor = new ClassNodeVisitor();
|
||||
visitor.Visit(node);
|
||||
return visitor.Node;
|
||||
}
|
||||
|
||||
private RazorEngine CreateEngine()
|
||||
{
|
||||
return RazorEngine.Create(b =>
|
||||
{
|
||||
// Notice we're not registering the InjectDirective.Pass here so we can run it on demand.
|
||||
b.AddDirective(InjectDirective.Directive);
|
||||
b.AddDirective(ModelDirective.Directive);
|
||||
});
|
||||
}
|
||||
|
||||
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 IRazorIRPhase)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return codeDocument.GetIRDocument();
|
||||
}
|
||||
|
||||
private string GetCSharpContent(RazorIRNode node)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
for (var i = 0; i < node.Children.Count; i++)
|
||||
{
|
||||
var child = node.Children[i] as CSharpTokenIRNode;
|
||||
builder.Append(child.Content);
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private class ClassNodeVisitor : RazorIRNodeWalker
|
||||
{
|
||||
public ClassDeclarationIRNode Node { get; set; }
|
||||
|
||||
public override void VisitClass(ClassDeclarationIRNode node)
|
||||
{
|
||||
Node = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Host.Internal;
|
||||
using Microsoft.AspNetCore.Razor.Chunks;
|
||||
using Microsoft.AspNetCore.Razor.Parser.SyntaxTree;
|
||||
using Moq;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Host.Internal;
|
||||
using Microsoft.AspNetCore.Razor.Chunks;
|
||||
using Microsoft.AspNetCore.Razor.CodeGenerators;
|
||||
using Xunit;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,258 @@
|
|||
// 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;
|
||||
using ErrorSink = Microsoft.AspNetCore.Razor.Evolution.Legacy.ErrorSink;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Host
|
||||
{
|
||||
public class MvcTagHelperAttributeValueCodeRendererTest
|
||||
{
|
||||
[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
|
||||
var codeDocument = CreateDocument(@"
|
||||
@addTagHelper TestTagHelper, TestAssembly
|
||||
<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<CSharpTokenIRNode>(expression.Children[2]);
|
||||
Assert.Equal("Bar", originalNode.Content);
|
||||
Assert.Equal(new SourceSpan("test.cshtml", 53, 2, 8, 3), originalNode.Source.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ModelExpressionPass_ModelExpressionProperty_ComplexExpression()
|
||||
{
|
||||
// Arrange
|
||||
var codeDocument = CreateDocument(@"
|
||||
@addTagHelper TestTagHelper, TestAssembly
|
||||
<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<CSharpTokenIRNode>(expression.Children[1]);
|
||||
Assert.Equal("Bar", originalNode.Content);
|
||||
Assert.Equal(new SourceSpan("test.cshtml", 54, 2, 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 IRazorIRPhase)
|
||||
{
|
||||
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 CSharpTokenIRNode;
|
||||
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(ErrorSink errorSink)
|
||||
{
|
||||
return TagHelpers;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,61 +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 Microsoft.AspNetCore.Razor;
|
||||
using Microsoft.AspNetCore.Razor.Chunks.Generators;
|
||||
using Microsoft.AspNetCore.Razor.CodeGenerators;
|
||||
using Microsoft.AspNetCore.Razor.Compilation.TagHelpers;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor
|
||||
{
|
||||
public class MvcTagHelperAttributeValueCodeRendererTest
|
||||
{
|
||||
#if OLD_RAZOR
|
||||
[Theory]
|
||||
[InlineData("SomeType", "SomeType", "Provider.SomeMethod(ViewData, __model => __model.MyValue)")]
|
||||
[InlineData("SomeType", "SomeType2", "MyValue")]
|
||||
public void RenderAttributeValue_RendersModelExpressionsCorrectly(
|
||||
string modelExpressionType,
|
||||
string propertyType,
|
||||
string expectedValue)
|
||||
{
|
||||
// Arrange
|
||||
var renderer = new MvcTagHelperAttributeValueCodeRenderer(
|
||||
new GeneratedTagHelperAttributeContext
|
||||
{
|
||||
ModelExpressionTypeName = modelExpressionType,
|
||||
CreateModelExpressionMethodName = "SomeMethod",
|
||||
ModelExpressionProviderPropertyName = "Provider",
|
||||
ViewDataPropertyName = "ViewData"
|
||||
});
|
||||
var attributeDescriptor = new TagHelperAttributeDescriptor
|
||||
{
|
||||
Name = "MyAttribute",
|
||||
PropertyName = "SomeProperty",
|
||||
TypeName = propertyType,
|
||||
};
|
||||
var writer = new CSharpCodeWriter();
|
||||
var generatorContext = new ChunkGeneratorContext(
|
||||
host: null,
|
||||
className: string.Empty,
|
||||
rootNamespace: string.Empty,
|
||||
sourceFile: string.Empty,
|
||||
shouldGenerateLinePragmas: true);
|
||||
var errorSink = new ErrorSink();
|
||||
var context = new CodeGeneratorContext(generatorContext, errorSink);
|
||||
|
||||
// Act
|
||||
renderer.RenderAttributeValue(attributeDescriptor, writer, context,
|
||||
(codeWriter) =>
|
||||
{
|
||||
codeWriter.Write("MyValue");
|
||||
},
|
||||
complexValue: false);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedValue, writer.GenerateCode());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue