// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. using System.Web.Razor.Generator; 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 System.Web.WebPages.TestUtils; using Xunit; using Assert = Microsoft.TestCommon.AssertEx; namespace System.Web.Razor.Test.Parser.Html { public class HtmlDocumentTest : CsHtmlMarkupParserTestBase { private static readonly TestFile Nested1000 = TestFile.Create("nested-1000.html"); [Fact] public void ParseDocumentMethodThrowsArgNullExceptionOnNullContext() { // Arrange HtmlMarkupParser parser = new HtmlMarkupParser(); // Act and Assert Assert.Throws(() => parser.ParseDocument(), RazorResources.Parser_Context_Not_Set); } [Fact] public void ParseSectionMethodThrowsArgNullExceptionOnNullContext() { // Arrange HtmlMarkupParser parser = new HtmlMarkupParser(); // Act and Assert Assert.Throws(() => parser.ParseSection(null, true), RazorResources.Parser_Context_Not_Set); } [Fact] public void ParseDocumentOutputsEmptyBlockWithEmptyMarkupSpanIfContentIsEmptyString() { ParseDocumentTest(String.Empty, new MarkupBlock(Factory.EmptyHtml())); } [Fact] public void ParseDocumentOutputsWhitespaceOnlyContentAsSingleWhitespaceMarkupSpan() { SingleSpanDocumentTest(" ", BlockType.Markup, SpanKind.Markup); } [Fact] public void ParseDocumentAcceptsSwapTokenAtEndOfFileAndOutputsZeroLengthCodeSpan() { ParseDocumentTest("@", new MarkupBlock( Factory.EmptyHtml(), new ExpressionBlock( Factory.CodeTransition(), Factory.EmptyCSharp() .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .Accepts(AcceptedCharacters.NonWhiteSpace)), Factory.EmptyHtml()), new RazorError(RazorResources.ParseError_Unexpected_EndOfFile_At_Start_Of_CodeBlock, 1, 0, 1)); } [Fact] public void ParseDocumentCorrectlyHandlesSingleLineOfMarkupWithEmbeddedStatement() { ParseDocumentTest("
Foo @if(true) {} Bar
", new MarkupBlock( Factory.Markup("
Foo "), new StatementBlock( Factory.CodeTransition(), Factory.Code("if(true) {}").AsStatement()), Factory.Markup(" Bar
"))); } [Fact] public void ParseDocumentWithinSectionDoesNotCreateDocumentLevelSpan() { ParseDocumentTest(@"@section Foo { }", new MarkupBlock( Factory.EmptyHtml(), new SectionBlock(new SectionCodeGenerator("Foo"), Factory.CodeTransition(), Factory.MetaCode("section Foo {") .AutoCompleteWith(null, atEndOfSpan: true), new MarkupBlock( Factory.Markup("\r\n \r\n")), Factory.MetaCode("}").Accepts(AcceptedCharacters.None)), Factory.EmptyHtml())); } [Fact] public void ParseDocumentParsesWholeContentAsOneSpanIfNoSwapCharacterEncountered() { SingleSpanDocumentTest("foo baz", BlockType.Markup, SpanKind.Markup); } [Fact] public void ParseDocumentHandsParsingOverToCodeParserWhenAtSignEncounteredAndEmitsOutput() { ParseDocumentTest("foo @bar baz", new MarkupBlock( Factory.Markup("foo "), new ExpressionBlock( Factory.CodeTransition(), Factory.Code("bar") .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .Accepts(AcceptedCharacters.NonWhiteSpace)), Factory.Markup(" baz"))); } [Fact] public void ParseDocumentEmitsAtSignAsMarkupIfAtEndOfFile() { ParseDocumentTest("foo @", new MarkupBlock( Factory.Markup("foo "), new ExpressionBlock( Factory.CodeTransition(), Factory.EmptyCSharp() .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .Accepts(AcceptedCharacters.NonWhiteSpace)), Factory.EmptyHtml()), new RazorError(RazorResources.ParseError_Unexpected_EndOfFile_At_Start_Of_CodeBlock, 5, 0, 5)); } [Fact] public void ParseDocumentEmitsCodeBlockIfFirstCharacterIsSwapCharacter() { ParseDocumentTest("@bar", new MarkupBlock( Factory.EmptyHtml(), new ExpressionBlock( Factory.CodeTransition(), Factory.Code("bar") .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .Accepts(AcceptedCharacters.NonWhiteSpace)), Factory.EmptyHtml())); } [Fact] public void ParseDocumentDoesNotSwitchToCodeOnEmailAddressInText() { SingleSpanDocumentTest("anurse@microsoft.com", BlockType.Markup, SpanKind.Markup); } [Fact] public void ParseDocumentDoesNotSwitchToCodeOnEmailAddressInAttribute() { ParseDocumentTest("Email me", new MarkupBlock( Factory.Markup("(" href=\"", 2, 0, 2), new LocationTagged("\"", 36, 0, 36)), Factory.Markup(" href=\"").With(SpanCodeGenerator.Null), Factory.Markup("mailto:anurse@microsoft.com") .With(new LiteralAttributeCodeGenerator(new LocationTagged(String.Empty, 9, 0, 9), new LocationTagged("mailto:anurse@microsoft.com", 9, 0, 9))), Factory.Markup("\"").With(SpanCodeGenerator.Null)), Factory.Markup(">Email me"))); } [Fact] public void ParseDocumentDoesNotReturnErrorOnMismatchedTags() { SingleSpanDocumentTest("Foo

Baz", BlockType.Markup, SpanKind.Markup); } [Fact] public void ParseDocumentReturnsOneMarkupSegmentIfNoCodeBlocksEncountered() { SingleSpanDocumentTest("Foo

BazBar Qux", BlockType.Markup, SpanKind.Markup); } [Fact] public void ParseDocumentRendersTextPseudoTagAsMarkup() { SingleSpanDocumentTest("Foo Foo", BlockType.Markup, SpanKind.Markup); } [Fact] public void ParseDocumentAcceptsEndTagWithNoMatchingStartTag() { SingleSpanDocumentTest("Foo

Bar", BlockType.Markup, SpanKind.Markup); } [Fact] public void ParseDocumentNoLongerSupportsDollarOpenBraceCombination() { ParseDocumentTest("${bar}", new MarkupBlock( Factory.Markup("${bar}"))); } [Fact] public void ParseDocumentIgnoresTagsInContentsOfScriptTag() { ParseDocumentTest(@"", new MarkupBlock( Factory.Markup(""))); } [Fact] public void ParseSectionIgnoresTagsInContentsOfScriptTag() { ParseDocumentTest(@"@section Foo { }", new MarkupBlock( Factory.EmptyHtml(), new SectionBlock(new SectionCodeGenerator("Foo"), Factory.CodeTransition(), Factory.MetaCode("section Foo {"), new MarkupBlock( Factory.Markup(" ")), Factory.MetaCode("}").Accepts(AcceptedCharacters.None)), Factory.EmptyHtml())); } [Fact] public void ParseBlockCanParse1000NestedElements() { string content = Nested1000.ReadAllText(); SingleSpanDocumentTest(content, BlockType.Markup, SpanKind.Markup); } } }