aspnetcore/test/Microsoft.AspNetCore.Razor..../Legacy/CSharpTemplateTest.cs

324 lines
16 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;
using Xunit;
namespace Microsoft.AspNetCore.Razor.Language.Legacy
{
public class CSharpTemplateTest : CsHtmlCodeParserTestBase
{
private const string TestTemplateCode = " @<p>Foo #@item</p>";
private TemplateBlock TestTemplate()
{
return new TemplateBlock(
new MarkupBlock(
Factory.MarkupTransition(),
new MarkupTagBlock(
Factory.Markup("<p>").Accepts(AcceptedCharactersInternal.None)),
Factory.Markup("Foo #"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("item")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharactersInternal.NonWhiteSpace)
),
new MarkupTagBlock(
Factory.Markup("</p>").Accepts(AcceptedCharactersInternal.None))
)
);
}
private const string TestNestedTemplateCode = " @<p>Foo #@Html.Repeat(10, @<p>@item</p>)</p>";
private TemplateBlock TestNestedTemplate()
{
return new TemplateBlock(
new MarkupBlock(
Factory.MarkupTransition(),
new MarkupTagBlock(
Factory.Markup("<p>").Accepts(AcceptedCharactersInternal.None)),
Factory.Markup("Foo #"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("Html.Repeat(10, ")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords),
new TemplateBlock(
new MarkupBlock(
Factory.MarkupTransition(),
new MarkupTagBlock(
Factory.Markup("<p>").Accepts(AcceptedCharactersInternal.None)),
Factory.EmptyHtml(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("item")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharactersInternal.NonWhiteSpace)
),
new MarkupTagBlock(
Factory.Markup("</p>").Accepts(AcceptedCharactersInternal.None))
)
),
Factory.Code(")")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharactersInternal.NonWhiteSpace)
),
new MarkupTagBlock(
Factory.Markup("</p>").Accepts(AcceptedCharactersInternal.None))
)
);
}
[Fact]
public void ParseBlockHandlesSingleLineTemplate()
{
ParseBlockTest("{ var foo = @: bar" + Environment.NewLine
+ "; }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharactersInternal.None),
Factory.Code(" var foo = ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new TemplateBlock(
new MarkupBlock(
Factory.MarkupTransition(),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
Factory.Markup(" bar" + Environment.NewLine)
.With(new SpanEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString))
.Accepts(AcceptedCharactersInternal.None)
)
),
Factory.Code("; ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None)
));
}
[Fact]
public void ParseBlockHandlesSingleLineImmediatelyFollowingStatementChar()
{
ParseBlockTest("{i@: bar" + Environment.NewLine
+ "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharactersInternal.None),
Factory.Code("i")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
new TemplateBlock(
new MarkupBlock(
Factory.MarkupTransition(),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
Factory.Markup(" bar" + Environment.NewLine)
.With(new SpanEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString))
.Accepts(AcceptedCharactersInternal.None)
)
),
Factory.EmptyCSharp().AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None)
));
}
[Fact]
public void ParseBlockHandlesSimpleTemplateInExplicitExpressionParens()
{
ParseBlockTest("(Html.Repeat(10," + TestTemplateCode + "))",
new ExpressionBlock(
Factory.MetaCode("(").Accepts(AcceptedCharactersInternal.None),
Factory.Code("Html.Repeat(10, ").AsExpression(),
TestTemplate(),
Factory.Code(")").AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharactersInternal.None)
));
}
[Fact]
public void ParseBlockHandlesSimpleTemplateInImplicitExpressionParens()
{
ParseBlockTest("Html.Repeat(10," + TestTemplateCode + ")",
new ExpressionBlock(
Factory.Code("Html.Repeat(10, ")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords),
TestTemplate(),
Factory.Code(")")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharactersInternal.NonWhiteSpace)
));
}
[Fact]
public void ParseBlockHandlesTwoTemplatesInImplicitExpressionParens()
{
ParseBlockTest("Html.Repeat(10," + TestTemplateCode + "," + TestTemplateCode + ")",
new ExpressionBlock(
Factory.Code("Html.Repeat(10, ")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords),
TestTemplate(),
Factory.Code(", ")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords),
TestTemplate(),
Factory.Code(")")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharactersInternal.NonWhiteSpace)
));
}
[Fact]
public void ParseBlockProducesErrorButCorrectlyParsesNestedTemplateInImplicitExpressionParens()
{
ParseBlockTest("Html.Repeat(10," + TestNestedTemplateCode + ")",
new ExpressionBlock(
Factory.Code("Html.Repeat(10, ")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords),
TestNestedTemplate(),
Factory.Code(")")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharactersInternal.NonWhiteSpace)
),
GetNestedTemplateError(42));
}
[Fact]
public void ParseBlockHandlesSimpleTemplateInStatementWithinCodeBlock()
{
ParseBlockTest("foreach(foo in Bar) { Html.ExecuteTemplate(foo," + TestTemplateCode + "); }",
new StatementBlock(
Factory.Code("foreach(foo in Bar) { Html.ExecuteTemplate(foo, ").AsStatement(),
TestTemplate(),
Factory.Code("); }")
.AsStatement()
.Accepts(AcceptedCharactersInternal.None)
));
}
[Fact]
public void ParseBlockHandlesTwoTemplatesInStatementWithinCodeBlock()
{
ParseBlockTest("foreach(foo in Bar) { Html.ExecuteTemplate(foo," + TestTemplateCode + "," + TestTemplateCode + "); }",
new StatementBlock(
Factory.Code("foreach(foo in Bar) { Html.ExecuteTemplate(foo, ").AsStatement(),
TestTemplate(),
Factory.Code(", ").AsStatement(),
TestTemplate(),
Factory.Code("); }")
.AsStatement()
.Accepts(AcceptedCharactersInternal.None)
));
}
[Fact]
public void ParseBlockProducesErrorButCorrectlyParsesNestedTemplateInStatementWithinCodeBlock()
{
ParseBlockTest("foreach(foo in Bar) { Html.ExecuteTemplate(foo," + TestNestedTemplateCode + "); }",
new StatementBlock(
Factory.Code("foreach(foo in Bar) { Html.ExecuteTemplate(foo, ")
.AsStatement(),
TestNestedTemplate(),
Factory.Code("); }")
.AsStatement()
.Accepts(AcceptedCharactersInternal.None)
),
GetNestedTemplateError(74));
}
[Fact]
public void ParseBlockHandlesSimpleTemplateInStatementWithinStatementBlock()
{
ParseBlockTest("{ var foo = bar; Html.ExecuteTemplate(foo," + TestTemplateCode + "); }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharactersInternal.None),
Factory.Code(" var foo = bar; Html.ExecuteTemplate(foo, ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
TestTemplate(),
Factory.Code("); ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None)
));
}
[Fact]
public void ParseBlockHandlessTwoTemplatesInStatementWithinStatementBlock()
{
ParseBlockTest("{ var foo = bar; Html.ExecuteTemplate(foo," + TestTemplateCode + "," + TestTemplateCode + "); }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharactersInternal.None),
Factory.Code(" var foo = bar; Html.ExecuteTemplate(foo, ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
TestTemplate(),
Factory.Code(", ").AsStatement(),
TestTemplate(),
Factory.Code("); ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None)
));
}
[Fact]
public void ParseBlockProducesErrorButCorrectlyParsesNestedTemplateInStatementWithinStatementBlock()
{
ParseBlockTest("{ var foo = bar; Html.ExecuteTemplate(foo," + TestNestedTemplateCode + "); }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharactersInternal.None),
Factory.Code(" var foo = bar; Html.ExecuteTemplate(foo, ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
TestNestedTemplate(),
Factory.Code("); ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None)
),
GetNestedTemplateError(69));
}
[Fact]
public void ParseBlock_WithDoubleTransition_DoesNotThrow()
{
FixupSpans = true;
// Arrange
var testTemplateWithDoubleTransitionCode = " @<p foo='@@'>Foo #@item</p>";
var testTemplateWithDoubleTransition = new TemplateBlock(
new MarkupBlock(
Factory.MarkupTransition(),
new MarkupTagBlock(
Factory.Markup("<p"),
new MarkupBlock(
new AttributeBlockChunkGenerator("foo", new LocationTagged<string>(" foo='", 46, 0, 46), new LocationTagged<string>("'", 54, 0, 54)),
Factory.Markup(" foo='").With(SpanChunkGenerator.Null),
new MarkupBlock(
Factory.Markup("@").With(new LiteralAttributeChunkGenerator(new LocationTagged<string>(string.Empty, 52, 0, 52), new LocationTagged<string>("@", 52, 0, 52))).Accepts(AcceptedCharactersInternal.None),
Factory.Markup("@").With(SpanChunkGenerator.Null).Accepts(AcceptedCharactersInternal.None)),
Factory.Markup("'").With(SpanChunkGenerator.Null)),
Factory.Markup(">").Accepts(AcceptedCharactersInternal.None)),
Factory.Markup("Foo #"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("item")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharactersInternal.NonWhiteSpace)
),
new MarkupTagBlock(
Factory.Markup("</p>").Accepts(AcceptedCharactersInternal.None))
)
);
var expected = new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharactersInternal.None),
Factory.Code(" var foo = bar; Html.ExecuteTemplate(foo, ")
.AsStatement()
.AutoCompleteWith(autoCompleteString: null),
testTemplateWithDoubleTransition,
Factory.Code("); ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None));
// Act & Assert
ParseBlockTest("{ var foo = bar; Html.ExecuteTemplate(foo," + testTemplateWithDoubleTransitionCode + "); }", expected);
}
private static RazorError GetNestedTemplateError(int characterIndex)
{
return new RazorError(
LegacyResources.ParseError_InlineMarkup_Blocks_Cannot_Be_Nested,
new SourceLocation(characterIndex, 0, characterIndex),
length: 1);
}
}
}