// 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 Xunit; namespace Microsoft.AspNetCore.Razor.Language.Legacy { public class CSharpDirectivesTest : CsHtmlCodeParserTestBase { [Fact] public void DirectiveDescriptor_CanHandleEOFIncompleteNamespaceTokens() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddNamespaceToken()); // Act & Assert ParseCodeBlockTest( "@custom System.", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), new RazorError( LegacyResources.FormatDirectiveExpectsNamespace("custom"), 8, 0, 8, 7)); } [Fact] public void DirectiveDescriptor_CanHandleEOFInvalidNamespaceTokens() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddNamespaceToken()); // Act & Assert ParseCodeBlockTest( "@custom System<", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), new RazorError( LegacyResources.FormatDirectiveExpectsNamespace("custom"), 8, 0, 8, 7)); } [Fact] public void DirectiveDescriptor_CanHandleIncompleteNamespaceTokens() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddNamespaceToken()); // Act & Assert ParseCodeBlockTest( "@custom System." + Environment.NewLine, new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), new RazorError( LegacyResources.FormatDirectiveExpectsNamespace("custom"), 8, 0, 8, 7)); } [Fact] public void DirectiveDescriptor_CanHandleInvalidNamespaceTokens() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddNamespaceToken()); // Act & Assert ParseCodeBlockTest( "@custom System<" + Environment.NewLine, new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), new RazorError( LegacyResources.FormatDirectiveExpectsNamespace("custom"), 8, 0, 8, 7)); } [Fact] public void ExtensibleDirectiveDoesNotErorrIfNotAtStartOfLineBecauseOfWhitespace() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddTypeToken()); // Act & Assert ParseCodeBlockTest(Environment.NewLine + " @custom System.Text.Encoding.ASCIIEncoding", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.Code(Environment.NewLine + " ").AsStatement(), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "System.Text.Encoding.ASCIIEncoding", markup: false).AsDirectiveToken(descriptor.Tokens[0]))); } [Fact] public void BuiltInDirectiveDoesNotErorrIfNotAtStartOfLineBecauseOfWhitespace() { // Act & Assert ParseCodeBlockTest(Environment.NewLine + " @addTagHelper \"*, Foo\"", Enumerable.Empty(), new DirectiveBlock( Factory.Code(Environment.NewLine + " ").AsStatement(), Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("\"*, Foo\"") .AsAddTagHelper("\"*, Foo\""))); } [Fact] public void BuiltInDirectiveErorrsIfNotAtStartOfLine() { // Act & Assert ParseCodeBlockTest("{ @addTagHelper \"*, Foo\"" + Environment.NewLine + "}", Enumerable.Empty(), new StatementBlock( Factory.MetaCode("{").Accepts(AcceptedCharactersInternal.None), Factory.Code(" ") .AsStatement() .AutoCompleteWith(autoCompleteString: null, atEndOfSpan: false), new DirectiveBlock( Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("\"*, Foo\"") .AsAddTagHelper("\"*, Foo\"")), Factory.Code(Environment.NewLine).AsStatement(), Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None)), new RazorError( Resources.FormatDirectiveMustAppearAtStartOfLine("addTagHelper"), new SourceLocation(4, 0, 4), 12)); } [Fact] public void ExtensibleDirectiveErorrsIfNotAtStartOfLine() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddTypeToken()); // Act & Assert ParseCodeBlockTest( "{ @custom System.Text.Encoding.ASCIIEncoding" + Environment.NewLine + "}", new[] { descriptor }, new StatementBlock( Factory.MetaCode("{").Accepts(AcceptedCharactersInternal.None), Factory.Code(" ") .AsStatement() .AutoCompleteWith(autoCompleteString: null, atEndOfSpan: false), new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "System.Text.Encoding.ASCIIEncoding", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKindInternal.Markup, Environment.NewLine, markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), Factory.EmptyCSharp().AsStatement(), Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None)), new RazorError( Resources.FormatDirectiveMustAppearAtStartOfLine("custom"), new SourceLocation(4, 0, 4), 6)); } [Fact] public void DirectiveDescriptor_UnderstandsTypeTokens() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddTypeToken()); // Act & Assert ParseCodeBlockTest( "@custom System.Text.Encoding.ASCIIEncoding", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "System.Text.Encoding.ASCIIEncoding", markup: false).AsDirectiveToken(descriptor.Tokens[0]))); } [Fact] public void DirectiveDescriptor_UnderstandsMemberTokens() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddMemberToken()); // Act & Assert ParseCodeBlockTest( "@custom Some_Member", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "Some_Member", markup: false).AsDirectiveToken(descriptor.Tokens[0]))); } [Fact] public void Parser_ParsesNamespaceDirectiveToken_WithSingleSegment() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddNamespaceToken()); // Act & Assert ParseCodeBlockTest( "@custom BaseNamespace", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "BaseNamespace", markup: false).AsDirectiveToken(descriptor.Tokens[0]))); } [Fact] public void Parser_ParsesNamespaceDirectiveToken_WithMultipleSegments() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddNamespaceToken()); // Act & Assert ParseCodeBlockTest( "@custom BaseNamespace.Foo.Bar", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "BaseNamespace.Foo.Bar", markup: false).AsDirectiveToken(descriptor.Tokens[0]))); } [Fact] public void DirectiveDescriptor_UnderstandsStringTokens() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddStringToken()); // Act & Assert ParseCodeBlockTest( "@custom \"AString\"", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "\"AString\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]))); } [Fact] public void DirectiveDescriptor_StringToken_ParserErrorForUnquotedValue() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddStringToken()); var expectedError = new RazorError( LegacyResources.FormatDirectiveExpectsQuotedStringLiteral("custom"), new SourceLocation(8, 0, 8), length: 7); // Act & Assert ParseCodeBlockTest( "@custom AString", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), expectedError); } [Fact] public void DirectiveDescriptor_StringToken_ParserErrorForNonStringValue() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddStringToken()); var expectedError = new RazorError( LegacyResources.FormatDirectiveExpectsQuotedStringLiteral("custom"), new SourceLocation(8, 0, 8), length: 1); // Act & Assert ParseCodeBlockTest( "@custom {foo?}", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), expectedError); } [Fact] public void DirectiveDescriptor_StringToken_ParserErrorForSingleQuotedValue() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddStringToken()); var expectedError = new RazorError( LegacyResources.FormatDirectiveExpectsQuotedStringLiteral("custom"), new SourceLocation(8, 0, 8), length: 9); // Act & Assert ParseCodeBlockTest( "@custom 'AString'", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), expectedError); } [Fact] public void DirectiveDescriptor_StringToken_ParserErrorForPartialQuotedValue() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddStringToken()); var expectedError = new RazorError( LegacyResources.FormatDirectiveExpectsQuotedStringLiteral("custom"), new SourceLocation(8, 0, 8), length: 7); // Act & Assert ParseCodeBlockTest( "@custom AString\"", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), expectedError); } [Fact] public void DirectiveDescriptor_UnderstandsMultipleTokens() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddTypeToken().AddMemberToken().AddStringToken()); // Act & Assert ParseCodeBlockTest( "@custom System.Text.Encoding.ASCIIEncoding Some_Member \"AString\"", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "System.Text.Encoding.ASCIIEncoding", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "Some_Member", markup: false).AsDirectiveToken(descriptor.Tokens[1]), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "\"AString\"", markup: false).AsDirectiveToken(descriptor.Tokens[2]))); } [Fact] public void DirectiveDescriptor_UnderstandsRazorBlocks() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.RazorBlock, b => b.AddStringToken()); // Act & Assert ParseCodeBlockTest( "@custom \"Header\" {

F{o}o

}", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "\"Header\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.MetaCode("{") .AutoCompleteWith(null, atEndOfSpan: true) .Accepts(AcceptedCharactersInternal.None), new MarkupBlock( Factory.Markup(" "), new MarkupTagBlock( Factory.Markup("

")), Factory.Markup("F", "{", "o", "}", "o"), new MarkupTagBlock( Factory.Markup("

")), Factory.Markup(" ")), Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None))); } [Fact] public void DirectiveDescriptor_UnderstandsCodeBlocks() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.CodeBlock, b => b.AddStringToken()); // Act & Assert ParseCodeBlockTest( "@custom \"Name\" { foo(); bar(); }", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "\"Name\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.MetaCode("{") .AutoCompleteWith(null, atEndOfSpan: true) .Accepts(AcceptedCharactersInternal.None), Factory.Code(" foo(); bar(); ").AsStatement(), Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None))); } [Fact] public void DirectiveDescriptor_AllowsWhiteSpaceAroundTokens() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddTypeToken().AddMemberToken()); // Act & Assert ParseCodeBlockTest( "@custom System.Text.Encoding.ASCIIEncoding Some_Member ", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "System.Text.Encoding.ASCIIEncoding", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "Some_Member", markup: false).AsDirectiveToken(descriptor.Tokens[1]), Factory.Span(SpanKindInternal.Markup, " ", markup: false) .Accepts(AcceptedCharactersInternal.WhiteSpace))); } [Fact] public void DirectiveDescriptor_ErrorsForInvalidMemberTokens() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddMemberToken()); var expectedErorr = new RazorError( LegacyResources.FormatDirectiveExpectsIdentifier("custom"), new SourceLocation(8, 0, 8), length: 1); // Act & Assert ParseCodeBlockTest( "@custom -Some_Member", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), expectedErorr); } [Fact] public void DirectiveDescriptor_NoErrorsSemicolonAfterDirective() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddStringToken()); // Act & Assert ParseCodeBlockTest( "@custom \"hello\" ; ", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "\"hello\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKindInternal.Markup, " ; ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace))); } [Fact] public void DirectiveDescriptor_ErrorsExtraContentAfterDirective() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddStringToken()); var expectedErorr = new RazorError( LegacyResources.FormatUnexpectedDirectiveLiteral("custom", "line break"), new SourceLocation(16, 0, 16), length: 7); // Act & Assert ParseCodeBlockTest( "@custom \"hello\" \"world\"", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "\"hello\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace)), expectedErorr); } [Fact] public void DirectiveDescriptor_ErrorsWhenExtraContentBeforeBlockStart() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.CodeBlock, b => b.AddStringToken()); var expectedErorr = new RazorError( LegacyResources.FormatUnexpectedDirectiveLiteral("custom", "{"), new SourceLocation(16, 0, 16), length: 5); // Act & Assert ParseCodeBlockTest( "@custom \"Hello\" World { foo(); bar(); }", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "\"Hello\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace)), expectedErorr); } [Fact] public void DirectiveDescriptor_ErrorsWhenEOFBeforeDirectiveBlockStart() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.CodeBlock, b => b.AddStringToken()); var expectedErorr = new RazorError( LegacyResources.FormatUnexpectedEOFAfterDirective("custom", "{"), new SourceLocation(15, 0, 15), length: 1); // Act & Assert ParseCodeBlockTest( "@custom \"Hello\"", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "\"Hello\"", markup: false).AsDirectiveToken(descriptor.Tokens[0])), expectedErorr); } [Fact] public void DirectiveDescriptor_ErrorsWhenMissingEndBrace() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.CodeBlock, b => b.AddStringToken()); var expectedErorr = new RazorError( LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF("custom", "}", "{"), new SourceLocation(16, 0, 16), length: 1); // Act & Assert ParseCodeBlockTest( "@custom \"Hello\" {", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "\"Hello\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.MetaCode("{") .AutoCompleteWith("}", atEndOfSpan: true) .Accepts(AcceptedCharactersInternal.None)), expectedErorr); } [Fact] public void TagHelperPrefixDirective_NoValueSucceeds() { ParseBlockTest("@tagHelperPrefix \"\"", new DirectiveBlock( Factory.CodeTransition(), Factory .MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("\"\"") .AsTagHelperPrefixDirective("\"\""))); } [Fact] public void TagHelperPrefixDirective_Succeeds() { ParseBlockTest("@tagHelperPrefix Foo", new DirectiveBlock( Factory.CodeTransition(), Factory .MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("Foo") .AsTagHelperPrefixDirective("Foo"))); } [Fact] public void TagHelperPrefixDirective_WithQuotes_Succeeds() { ParseBlockTest("@tagHelperPrefix \"Foo\"", new DirectiveBlock( Factory.CodeTransition(), Factory .MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("\"Foo\"") .AsTagHelperPrefixDirective("\"Foo\""))); } [Fact] public void TagHelperPrefixDirective_RequiresValue() { ParseBlockTest("@tagHelperPrefix ", new DirectiveBlock( Factory.CodeTransition(), Factory .MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.EmptyCSharp() .AsTagHelperPrefixDirective(string.Empty) .Accepts(AcceptedCharactersInternal.AnyExceptNewline)), new RazorError( LegacyResources.FormatParseError_DirectiveMustHaveValue( SyntaxConstants.CSharp.TagHelperPrefixKeyword), absoluteIndex: 1, lineIndex: 0, columnIndex: 1, length: 15)); } [Fact] public void TagHelperPrefixDirective_StartQuoteRequiresDoubleQuotesAroundValue() { ParseBlockTest("@tagHelperPrefix \"Foo", new DirectiveBlock( Factory.CodeTransition(), Factory .MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("\"Foo") .AsTagHelperPrefixDirective("\"Foo")), new RazorError( LegacyResources.ParseError_Unterminated_String_Literal, absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 1), new RazorError( LegacyResources.FormatParseError_IncompleteQuotesAroundDirective( SyntaxConstants.CSharp.TagHelperPrefixKeyword), absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 4)); } [Fact] public void TagHelperPrefixDirective_EndQuoteRequiresDoubleQuotesAroundValue() { ParseBlockTest("@tagHelperPrefix Foo \"", new DirectiveBlock( Factory.CodeTransition(), Factory .MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("Foo \"") .AsTagHelperPrefixDirective("Foo \"")), new RazorError( LegacyResources.ParseError_Unterminated_String_Literal, absoluteIndex: 23, lineIndex: 0, columnIndex: 23, length: 1), new RazorError( LegacyResources.FormatParseError_IncompleteQuotesAroundDirective( SyntaxConstants.CSharp.TagHelperPrefixKeyword), absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 7)); } [Fact] public void RemoveTagHelperDirective_NoValue_Succeeds() { ParseBlockTest("@removeTagHelper \"\"", new DirectiveBlock( Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("\"\"") .AsRemoveTagHelper("\"\""))); } [Fact] public void RemoveTagHelperDirective_Succeeds() { ParseBlockTest("@removeTagHelper Foo", new DirectiveBlock( Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("Foo") .AsRemoveTagHelper("Foo"))); } [Fact] public void RemoveTagHelperDirective_WithQuotes_Succeeds() { ParseBlockTest("@removeTagHelper \"Foo\"", new DirectiveBlock( Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("\"Foo\"") .AsRemoveTagHelper("\"Foo\""))); } [Fact] public void RemoveTagHelperDirective_SupportsSpaces() { ParseBlockTest("@removeTagHelper Foo, Bar ", new DirectiveBlock( Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("Foo, Bar ") .AsRemoveTagHelper("Foo, Bar") .Accepts(AcceptedCharactersInternal.AnyExceptNewline))); } [Fact] public void RemoveTagHelperDirective_RequiresValue() { ParseBlockTest("@removeTagHelper ", new DirectiveBlock( Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.EmptyCSharp() .AsRemoveTagHelper(string.Empty) .Accepts(AcceptedCharactersInternal.AnyExceptNewline)), new RazorError( LegacyResources.FormatParseError_DirectiveMustHaveValue( SyntaxConstants.CSharp.RemoveTagHelperKeyword), absoluteIndex: 1, lineIndex: 0, columnIndex: 1, length: 15)); } [Fact] public void RemoveTagHelperDirective_StartQuoteRequiresDoubleQuotesAroundValue() { ParseBlockTest("@removeTagHelper \"Foo", new DirectiveBlock( Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("\"Foo") .AsRemoveTagHelper("\"Foo")), new RazorError( LegacyResources.ParseError_Unterminated_String_Literal, absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 1), new RazorError( LegacyResources.FormatParseError_IncompleteQuotesAroundDirective( SyntaxConstants.CSharp.RemoveTagHelperKeyword), absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 4)); } [Fact] public void RemoveTagHelperDirective_EndQuoteRequiresDoubleQuotesAroundValue() { ParseBlockTest("@removeTagHelper Foo\"", new DirectiveBlock( Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("Foo\"") .AsRemoveTagHelper("Foo\"") .Accepts(AcceptedCharactersInternal.AnyExceptNewline)), new RazorError( LegacyResources.ParseError_Unterminated_String_Literal, absoluteIndex: 20, lineIndex: 0, columnIndex: 20, length: 1), new RazorError( LegacyResources.FormatParseError_IncompleteQuotesAroundDirective( SyntaxConstants.CSharp.RemoveTagHelperKeyword), absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 4)); } [Fact] public void AddTagHelperDirective_NoValue_Succeeds() { ParseBlockTest("@addTagHelper \"\"", new DirectiveBlock( Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("\"\"") .AsAddTagHelper("\"\""))); } [Fact] public void AddTagHelperDirective_Succeeds() { ParseBlockTest("@addTagHelper Foo", new DirectiveBlock( Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("Foo") .AsAddTagHelper("Foo"))); } [Fact] public void AddTagHelperDirective_WithQuotes_Succeeds() { ParseBlockTest("@addTagHelper \"Foo\"", new DirectiveBlock( Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("\"Foo\"") .AsAddTagHelper("\"Foo\""))); } [Fact] public void AddTagHelperDirectiveSupportsSpaces() { ParseBlockTest("@addTagHelper Foo, Bar ", new DirectiveBlock( Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("Foo, Bar ") .AsAddTagHelper("Foo, Bar"))); } [Fact] public void AddTagHelperDirectiveRequiresValue() { ParseBlockTest("@addTagHelper ", new DirectiveBlock( Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.EmptyCSharp() .AsAddTagHelper(string.Empty) .Accepts(AcceptedCharactersInternal.AnyExceptNewline)), new RazorError( LegacyResources.FormatParseError_DirectiveMustHaveValue(SyntaxConstants.CSharp.AddTagHelperKeyword), absoluteIndex: 1, lineIndex: 0, columnIndex: 1, length: 12)); } [Fact] public void AddTagHelperDirective_StartQuoteRequiresDoubleQuotesAroundValue() { ParseBlockTest("@addTagHelper \"Foo", new DirectiveBlock( Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("\"Foo") .AsAddTagHelper("\"Foo")), new RazorError( LegacyResources.ParseError_Unterminated_String_Literal, absoluteIndex: 14, lineIndex: 0, columnIndex: 14, length: 1), new RazorError( LegacyResources.FormatParseError_IncompleteQuotesAroundDirective( SyntaxConstants.CSharp.AddTagHelperKeyword), absoluteIndex: 14, lineIndex: 0, columnIndex: 14, length: 4)); } [Fact] public void AddTagHelperDirective_EndQuoteRequiresDoubleQuotesAroundValue() { ParseBlockTest("@addTagHelper Foo\"", new DirectiveBlock( Factory.CodeTransition(), Factory.MetaCode(SyntaxConstants.CSharp.AddTagHelperKeyword + " ") .Accepts(AcceptedCharactersInternal.None), Factory.Code("Foo\"") .AsAddTagHelper("Foo\"") .Accepts(AcceptedCharactersInternal.AnyExceptNewline)), new RazorError( LegacyResources.ParseError_Unterminated_String_Literal, absoluteIndex: 17, lineIndex: 0, columnIndex: 17, length: 1), new RazorError( LegacyResources.FormatParseError_IncompleteQuotesAroundDirective( SyntaxConstants.CSharp.AddTagHelperKeyword), absoluteIndex: 14, lineIndex: 0, columnIndex: 14, length: 4)); } [Fact] public void InheritsDirective() { ParseBlockTest("@inherits System.Web.WebPages.WebPage", new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor), Factory.CodeTransition(), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "System.Web.WebPages.WebPage", markup: false).AsDirectiveToken(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First()))); } [Fact] public void InheritsDirectiveSupportsArrays() { ParseBlockTest("@inherits string[[]][]", new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor), Factory.CodeTransition(), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "string[[]][]", markup: false).AsDirectiveToken(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First()))); } [Fact] public void InheritsDirectiveSupportsNestedGenerics() { ParseBlockTest("@inherits System.Web.Mvc.WebViewPage>", new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor), Factory.CodeTransition(), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "System.Web.Mvc.WebViewPage>", markup: false) .AsDirectiveToken(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First()))); } [Fact] public void InheritsDirectiveSupportsTypeKeywords() { ParseBlockTest("@inherits string", new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.InheritsDirectiveDescriptor), Factory.CodeTransition(), Factory.MetaCode("inherits").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "string", markup: false) .AsDirectiveToken(CSharpCodeParser.InheritsDirectiveDescriptor.Tokens.First()))); } [Fact] public void FunctionsDirective() { ParseBlockTest("@functions { foo(); bar(); }", new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor), Factory.CodeTransition(), Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.Code(" foo(); bar(); ").AsStatement(), Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None))); } [Fact] public void EmptyFunctionsDirective() { ParseBlockTest("@functions { }", new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.FunctionsDirectiveDescriptor), Factory.CodeTransition(), Factory.MetaCode("functions").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), Factory.Code(" ").AsStatement(), Factory.MetaCode("}").Accepts(AcceptedCharactersInternal.None))); } [Fact] public void SectionDirective() { ParseBlockTest("@section Header {

F{o}o

}", new DirectiveBlock(new DirectiveChunkGenerator(CSharpCodeParser.SectionDirectiveDescriptor), Factory.CodeTransition(), Factory.MetaCode("section").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "Header", CSharpSymbolType.Identifier) .AsDirectiveToken(CSharpCodeParser.SectionDirectiveDescriptor.Tokens.First()), Factory.Span(SpanKindInternal.Markup, " ", CSharpSymbolType.WhiteSpace).Accepts(AcceptedCharactersInternal.AllWhiteSpace), Factory.MetaCode("{").AutoCompleteWith(null, atEndOfSpan: true).Accepts(AcceptedCharactersInternal.None), new MarkupBlock( Factory.Markup(" "), new MarkupTagBlock( Factory.Markup("

")), Factory.Markup("F", "{", "o", "}", "o"), new MarkupTagBlock( Factory.Markup("

")), Factory.Markup(" ")), Factory.MetaCode("}") .Accepts(AcceptedCharactersInternal.None))); } [Fact] public void OptionalDirectiveTokens_AreSkipped() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddOptionalStringToken()); // Act & Assert ParseCodeBlockTest( "@custom ", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace))); } [Fact] public void OptionalDirectiveTokens_WithSimpleTokens_AreParsed() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddOptionalStringToken()); // Act & Assert ParseCodeBlockTest( "@custom \"simple-value\"", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "\"simple-value\"", markup: false) .AsDirectiveToken(descriptor.Tokens[0]))); } [Fact] public void OptionalDirectiveTokens_WithBraces_AreParsed() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddOptionalStringToken()); // Act & Assert ParseCodeBlockTest( "@custom \"{formaction}?/{id}?\"", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "\"{formaction}?/{id}?\"", markup: false) .AsDirectiveToken(descriptor.Tokens[0]))); } [Fact] public void OptionalDirectiveTokens_WithMultipleOptionalTokens_AreParsed() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "custom", DirectiveKind.SingleLine, b => b.AddOptionalStringToken().AddOptionalTypeToken()); // Act & Assert ParseCodeBlockTest( "@custom \"{formaction}?/{id}?\" System.String", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("custom").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Markup, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "\"{formaction}?/{id}?\"", markup: false).AsDirectiveToken(descriptor.Tokens[0]), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "System.String", markup: false).AsDirectiveToken(descriptor.Tokens.Last()))); } [Fact] public void OptionalMemberTokens_WithMissingMember_IsParsed() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "TestDirective", DirectiveKind.SingleLine, b => b.AddOptionalMemberToken().AddOptionalStringToken()); // Act & Assert ParseCodeBlockTest( "@TestDirective ", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("TestDirective").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace))); } [Fact] public void OptionalMemberTokens_WithMemberSpecified_IsParsed() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "TestDirective", DirectiveKind.SingleLine, b => b.AddOptionalMemberToken().AddOptionalStringToken()); // Act & Assert ParseCodeBlockTest( "@TestDirective PropertyName", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("TestDirective").Accepts(AcceptedCharactersInternal.None), Factory.Span(SpanKindInternal.Code, " ", markup: false).Accepts(AcceptedCharactersInternal.WhiteSpace), Factory.Span(SpanKindInternal.Code, "PropertyName", markup: false).AsDirectiveToken(descriptor.Tokens[0]))); } [Fact] public void Directives_CanUseReservedWord_Class() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "class", DirectiveKind.SingleLine); // Act & Assert ParseCodeBlockTest( "@class", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("class").Accepts(AcceptedCharactersInternal.None))); } [Fact] public void Directives_CanUseReservedWord_Namespace() { // Arrange var descriptor = DirectiveDescriptor.CreateDirective( "namespace", DirectiveKind.SingleLine); // Act & Assert ParseCodeBlockTest( "@namespace", new[] { descriptor }, new DirectiveBlock( new DirectiveChunkGenerator(descriptor), Factory.CodeTransition(), Factory.MetaCode("namespace").Accepts(AcceptedCharactersInternal.None))); } internal virtual void ParseCodeBlockTest( string document, IEnumerable descriptors, Block expected, params RazorError[] expectedErrors) { var result = ParseCodeBlock(document, descriptors, designTime: false); EvaluateResults(result, expected, expectedErrors.Select(error => RazorDiagnostic.Create(error)).ToList()); } } }