198 lines
8.8 KiB
C#
198 lines
8.8 KiB
C#
|
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
|||
|
|
|||
|
using System.Web.Razor.Parser;
|
|||
|
using System.Web.Razor.Parser.SyntaxTree;
|
|||
|
using System.Web.Razor.Resources;
|
|||
|
using System.Web.Razor.Test.Framework;
|
|||
|
using System.Web.Razor.Text;
|
|||
|
using Xunit;
|
|||
|
|
|||
|
namespace System.Web.Razor.Test.Parser.CSharp
|
|||
|
{
|
|||
|
public class CSharpSpecialBlockTest : CsHtmlCodeParserTestBase
|
|||
|
{
|
|||
|
[Fact]
|
|||
|
public void ParseInheritsStatementMarksInheritsSpanAsCanGrowIfMissingTrailingSpace()
|
|||
|
{
|
|||
|
ParseBlockTest("inherits",
|
|||
|
new DirectiveBlock(
|
|||
|
Factory.MetaCode("inherits").Accepts(AcceptedCharacters.Any)
|
|||
|
),
|
|||
|
new RazorError(
|
|||
|
RazorResources.ParseError_InheritsKeyword_Must_Be_Followed_By_TypeName,
|
|||
|
new SourceLocation(8, 0, 8)));
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void InheritsBlockAcceptsMultipleGenericArguments()
|
|||
|
{
|
|||
|
ParseBlockTest("inherits Foo.Bar<Biz<Qux>, string, int>.Baz",
|
|||
|
new DirectiveBlock(
|
|||
|
Factory.MetaCode("inherits ").Accepts(AcceptedCharacters.None),
|
|||
|
Factory.Code("Foo.Bar<Biz<Qux>, string, int>.Baz")
|
|||
|
.AsBaseType("Foo.Bar<Biz<Qux>, string, int>.Baz")
|
|||
|
));
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void InheritsBlockOutputsErrorIfInheritsNotFollowedByTypeButAcceptsEntireLineAsCode()
|
|||
|
{
|
|||
|
ParseBlockTest(@"inherits
|
|||
|
foo",
|
|||
|
new DirectiveBlock(
|
|||
|
Factory.MetaCode("inherits ").Accepts(AcceptedCharacters.None),
|
|||
|
Factory.Code(" \r\n")
|
|||
|
.AsBaseType(String.Empty)
|
|||
|
),
|
|||
|
new RazorError(RazorResources.ParseError_InheritsKeyword_Must_Be_Followed_By_TypeName, 24, 0, 24));
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void NamespaceImportInsideCodeBlockCausesError()
|
|||
|
{
|
|||
|
ParseBlockTest("{ using Foo.Bar.Baz; var foo = bar; }",
|
|||
|
new StatementBlock(
|
|||
|
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
|
|||
|
Factory.Code(" using Foo.Bar.Baz; var foo = bar; ").AsStatement(),
|
|||
|
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
|
|||
|
),
|
|||
|
new RazorError(
|
|||
|
RazorResources.ParseError_NamespaceImportAndTypeAlias_Cannot_Exist_Within_CodeBlock,
|
|||
|
new SourceLocation(2, 0, 2)));
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void TypeAliasInsideCodeBlockIsNotHandledSpecially()
|
|||
|
{
|
|||
|
ParseBlockTest("{ using Foo = Bar.Baz; var foo = bar; }",
|
|||
|
new StatementBlock(
|
|||
|
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
|
|||
|
Factory.Code(" using Foo = Bar.Baz; var foo = bar; ").AsStatement(),
|
|||
|
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
|
|||
|
),
|
|||
|
new RazorError(
|
|||
|
RazorResources.ParseError_NamespaceImportAndTypeAlias_Cannot_Exist_Within_CodeBlock,
|
|||
|
new SourceLocation(2, 0, 2)));
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void Plan9FunctionsKeywordInsideCodeBlockIsNotHandledSpecially()
|
|||
|
{
|
|||
|
ParseBlockTest("{ functions Foo; }",
|
|||
|
new StatementBlock(
|
|||
|
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
|
|||
|
Factory.Code(" functions Foo; ").AsStatement(),
|
|||
|
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
|
|||
|
));
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void NonKeywordStatementInCodeBlockIsHandledCorrectly()
|
|||
|
{
|
|||
|
ParseBlockTest(@"{
|
|||
|
List<dynamic> photos = gallery.Photo.ToList();
|
|||
|
}",
|
|||
|
new StatementBlock(
|
|||
|
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
|
|||
|
Factory.Code("\r\n List<dynamic> photos = gallery.Photo.ToList();\r\n").AsStatement(),
|
|||
|
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
|
|||
|
));
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ParseBlockBalancesBracesOutsideStringsIfFirstCharacterIsBraceAndReturnsSpanOfTypeCode()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
const string code = "foo\"b}ar\" if(condition) { String.Format(\"{0}\"); } ";
|
|||
|
|
|||
|
// Act/Assert
|
|||
|
ParseBlockTest("{" + code + "}",
|
|||
|
new StatementBlock(
|
|||
|
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
|
|||
|
Factory.Code(code).AsStatement(),
|
|||
|
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
|
|||
|
));
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ParseBlockBalancesParensOutsideStringsIfFirstCharacterIsParenAndReturnsSpanOfTypeExpression()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
const string code = "foo\"b)ar\" if(condition) { String.Format(\"{0}\"); } ";
|
|||
|
|
|||
|
// Act/Assert
|
|||
|
ParseBlockTest("(" + code + ")",
|
|||
|
new ExpressionBlock(
|
|||
|
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
|
|||
|
Factory.Code(code).AsExpression(),
|
|||
|
Factory.MetaCode(")").Accepts(AcceptedCharacters.None)
|
|||
|
));
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ParseBlockBalancesBracesAndOutputsContentAsClassLevelCodeSpanIfFirstIdentifierIsFunctionsKeyword()
|
|||
|
{
|
|||
|
const string code = " foo(); \"bar}baz\" ";
|
|||
|
ParseBlockTest("functions {" + code + "} zoop",
|
|||
|
new FunctionsBlock(
|
|||
|
Factory.MetaCode("functions {").Accepts(AcceptedCharacters.None),
|
|||
|
Factory.Code(code).AsFunctionsBody(),
|
|||
|
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
|
|||
|
));
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ParseBlockDoesNoErrorRecoveryForFunctionsBlock()
|
|||
|
{
|
|||
|
ParseBlockTest("functions { { { { { } zoop",
|
|||
|
new FunctionsBlock(
|
|||
|
Factory.MetaCode("functions {").Accepts(AcceptedCharacters.None),
|
|||
|
Factory.Code(" { { { { } zoop").AsFunctionsBody()
|
|||
|
),
|
|||
|
new RazorError(
|
|||
|
String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, "functions", "}", "{"),
|
|||
|
SourceLocation.Zero));
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ParseBlockIgnoresFunctionsUnlessAllLowerCase()
|
|||
|
{
|
|||
|
ParseBlockTest("Functions { foo() }",
|
|||
|
new ExpressionBlock(
|
|||
|
Factory.Code("Functions")
|
|||
|
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
|
|||
|
.Accepts(AcceptedCharacters.NonWhiteSpace)));
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ParseBlockIgnoresSingleSlashAtStart()
|
|||
|
{
|
|||
|
ParseBlockTest("@/ foo",
|
|||
|
new ExpressionBlock(
|
|||
|
Factory.CodeTransition(),
|
|||
|
Factory.EmptyCSharp()
|
|||
|
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
|
|||
|
.Accepts(AcceptedCharacters.NonWhiteSpace)),
|
|||
|
new RazorError(
|
|||
|
String.Format(RazorResources.ParseError_Unexpected_Character_At_Start_Of_CodeBlock_CS, "/"),
|
|||
|
1, 0, 1));
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ParseBlockTerminatesSingleLineCommentAtEndOfLine()
|
|||
|
{
|
|||
|
ParseBlockTest(@"if(!false) {
|
|||
|
// Foo
|
|||
|
<p>A real tag!</p>
|
|||
|
}",
|
|||
|
new StatementBlock(
|
|||
|
Factory.Code("if(!false) {\r\n // Foo\r\n").AsStatement(),
|
|||
|
new MarkupBlock(
|
|||
|
Factory.Markup(" <p>A real tag!</p>\r\n")
|
|||
|
.Accepts(AcceptedCharacters.None)),
|
|||
|
Factory.Code("}").AsStatement()
|
|||
|
));
|
|||
|
}
|
|||
|
}
|
|||
|
}
|