// 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 = " @
Foo #@item
"; private TemplateBlock TestTemplate() { return new TemplateBlock( new MarkupBlock( Factory.MarkupTransition(), new MarkupTagBlock( Factory.Markup("").Accepts(AcceptedCharacters.None)), Factory.Markup("Foo #"), new ExpressionBlock( Factory.CodeTransition(), Factory.Code("item") .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .Accepts(AcceptedCharacters.NonWhiteSpace) ), new MarkupTagBlock( Factory.Markup("
").Accepts(AcceptedCharacters.None)) ) ); } private const string TestNestedTemplateCode = " @Foo #@Html.Repeat(10, @
@item
)"; private TemplateBlock TestNestedTemplate() { return new TemplateBlock( new MarkupBlock( Factory.MarkupTransition(), new MarkupTagBlock( Factory.Markup("").Accepts(AcceptedCharacters.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("
").Accepts(AcceptedCharacters.None)), Factory.EmptyHtml(), new ExpressionBlock( Factory.CodeTransition(), Factory.Code("item") .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .Accepts(AcceptedCharacters.NonWhiteSpace) ), new MarkupTagBlock( Factory.Markup("
").Accepts(AcceptedCharacters.None)) ) ), Factory.Code(")") .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .Accepts(AcceptedCharacters.NonWhiteSpace) ), new MarkupTagBlock( Factory.Markup("").Accepts(AcceptedCharacters.None)) ) ); } [Fact] public void ParseBlockHandlesSingleLineTemplate() { ParseBlockTest("{ var foo = @: bar" + Environment.NewLine + "; }", new StatementBlock( Factory.MetaCode("{").Accepts(AcceptedCharacters.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(AcceptedCharacters.None) ) ), Factory.Code("; ").AsStatement(), Factory.MetaCode("}").Accepts(AcceptedCharacters.None) )); } [Fact] public void ParseBlockHandlesSingleLineImmediatelyFollowingStatementChar() { ParseBlockTest("{i@: bar" + Environment.NewLine + "}", new StatementBlock( Factory.MetaCode("{").Accepts(AcceptedCharacters.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(AcceptedCharacters.None) ) ), Factory.EmptyCSharp().AsStatement(), Factory.MetaCode("}").Accepts(AcceptedCharacters.None) )); } [Fact] public void ParseBlockHandlesSimpleTemplateInExplicitExpressionParens() { ParseBlockTest("(Html.Repeat(10," + TestTemplateCode + "))", new ExpressionBlock( Factory.MetaCode("(").Accepts(AcceptedCharacters.None), Factory.Code("Html.Repeat(10, ").AsExpression(), TestTemplate(), Factory.Code(")").AsExpression(), Factory.MetaCode(")").Accepts(AcceptedCharacters.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(AcceptedCharacters.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(AcceptedCharacters.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(AcceptedCharacters.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(AcceptedCharacters.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(AcceptedCharacters.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(AcceptedCharacters.None) ), GetNestedTemplateError(74)); } [Fact] public void ParseBlockHandlesSimpleTemplateInStatementWithinStatementBlock() { ParseBlockTest("{ var foo = bar; Html.ExecuteTemplate(foo," + TestTemplateCode + "); }", new StatementBlock( Factory.MetaCode("{").Accepts(AcceptedCharacters.None), Factory.Code(" var foo = bar; Html.ExecuteTemplate(foo, ") .AsStatement() .AutoCompleteWith(autoCompleteString: null), TestTemplate(), Factory.Code("); ").AsStatement(), Factory.MetaCode("}").Accepts(AcceptedCharacters.None) )); } [Fact] public void ParseBlockHandlessTwoTemplatesInStatementWithinStatementBlock() { ParseBlockTest("{ var foo = bar; Html.ExecuteTemplate(foo," + TestTemplateCode + "," + TestTemplateCode + "); }", new StatementBlock( Factory.MetaCode("{").Accepts(AcceptedCharacters.None), Factory.Code(" var foo = bar; Html.ExecuteTemplate(foo, ") .AsStatement() .AutoCompleteWith(autoCompleteString: null), TestTemplate(), Factory.Code(", ").AsStatement(), TestTemplate(), Factory.Code("); ").AsStatement(), Factory.MetaCode("}").Accepts(AcceptedCharacters.None) )); } [Fact] public void ParseBlockProducesErrorButCorrectlyParsesNestedTemplateInStatementWithinStatementBlock() { ParseBlockTest("{ var foo = bar; Html.ExecuteTemplate(foo," + TestNestedTemplateCode + "); }", new StatementBlock( Factory.MetaCode("{").Accepts(AcceptedCharacters.None), Factory.Code(" var foo = bar; Html.ExecuteTemplate(foo, ") .AsStatement() .AutoCompleteWith(autoCompleteString: null), TestNestedTemplate(), Factory.Code("); ").AsStatement(), Factory.MetaCode("}").Accepts(AcceptedCharacters.None) ), GetNestedTemplateError(69)); } [Fact] public void ParseBlock_WithDoubleTransition_DoesNotThrow() { FixupSpans = true; // Arrange var testTemplateWithDoubleTransitionCode = " @Foo #@item
"; var testTemplateWithDoubleTransition = new TemplateBlock( new MarkupBlock( Factory.MarkupTransition(), new MarkupTagBlock( Factory.Markup("(" foo='", 46, 0, 46), new LocationTagged