// 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 Microsoft.AspNet.Razor.Generator; using Microsoft.AspNet.Razor.Parser; using Microsoft.AspNet.Razor.Parser.SyntaxTree; using Microsoft.AspNet.Razor.Test.Framework; using Microsoft.AspNet.Razor.Text; using Xunit; namespace Microsoft.AspNet.Razor.Test.Parser.Html { public class HtmlDocumentTest : CsHtmlMarkupParserTestBase { private static readonly TestFile Nested1000 = TestFile.Create("TestFiles/nested-1000.html"); [Fact] public void ParseDocumentMethodThrowsArgNullExceptionOnNullContext() { // Arrange var parser = new HtmlMarkupParser(); // Act and Assert var exception = Assert.Throws(() => parser.ParseDocument()); Assert.Equal(RazorResources.Parser_Context_Not_Set, exception.Message); } [Fact] public void ParseSectionMethodThrowsArgNullExceptionOnNullContext() { // Arrange var parser = new HtmlMarkupParser(); // Act and Assert var exception = Assert.Throws(() => parser.ParseSection(null, true)); Assert.Equal(RazorResources.Parser_Context_Not_Set, exception.Message); } [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 ParseDocumentCorrectlyHandlesOddlySpacedHTMLElements() { ParseDocumentTest("

Foo

", new MarkupBlock( BlockFactory.MarkupTagBlock("
"), BlockFactory.MarkupTagBlock("

"), Factory.Markup(" Foo "), BlockFactory.MarkupTagBlock("

"), BlockFactory.MarkupTagBlock("
"))); } [Fact] public void ParseDocumentCorrectlyHandlesSingleLineOfMarkupWithEmbeddedStatement() { ParseDocumentTest("
Foo @if(true) {} Bar
", new MarkupBlock( BlockFactory.MarkupTagBlock("
"), Factory.Markup("Foo "), new StatementBlock( Factory.CodeTransition(), Factory.Code("if(true) {}").AsStatement()), Factory.Markup(" Bar"), BlockFactory.MarkupTagBlock("
"))); } [Fact] public void ParseDocumentWithinSectionDoesNotCreateDocumentLevelSpan() { ParseDocumentTest("@section Foo {" + Environment.NewLine + " " + Environment.NewLine + "}", new MarkupBlock( Factory.EmptyHtml(), new SectionBlock(new SectionCodeGenerator("Foo"), Factory.CodeTransition(), Factory.MetaCode("section Foo {") .AutoCompleteWith(null, atEndOfSpan: true), new MarkupBlock( Factory.Markup(Environment.NewLine + " "), BlockFactory.MarkupTagBlock(""), BlockFactory.MarkupTagBlock(""), Factory.Markup(Environment.NewLine)), 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( new MarkupTagBlock( 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(">")), Factory.Markup("Email me"), BlockFactory.MarkupTagBlock(""))); } [Fact] public void ParseDocumentDoesNotReturnErrorOnMismatchedTags() { ParseDocumentTest("Foo

Baz", new MarkupBlock( Factory.Markup("Foo "), BlockFactory.MarkupTagBlock("
"), BlockFactory.MarkupTagBlock("

"), BlockFactory.MarkupTagBlock("

"), BlockFactory.MarkupTagBlock("

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