File: Legacy\HtmlDocumentTest.cs
Web Access
Project: src\src\Razor\src\Compiler\Microsoft.AspNetCore.Razor.Language\test\Microsoft.AspNetCore.Razor.Language.UnitTests.csproj (Microsoft.AspNetCore.Razor.Language.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.AspNetCore.Razor.Language.Legacy;
 
public class HtmlDocumentTest() : ParserTestBase(layer: TestProject.Layer.Compiler)
{
    private static readonly TestFile Nested1000 = TestFile.Create("TestFiles/nested-1000.html", typeof(HtmlDocumentTest));
 
    [Fact]
    public void NestedCodeBlockWithMarkupSetsDotAsMarkup()
    {
        ParseDocumentTest("@if (true) { @if(false) { <div>@something.</div> } }");
    }
 
    [Fact]
    public void OutputsEmptyBlockWithEmptyMarkupSpanIfContentIsEmptyString()
    {
        ParseDocumentTest(string.Empty);
    }
 
    [Fact]
    public void OutputsWhitespaceOnlyContentAsSingleWhitespaceMarkupSpan()
    {
        ParseDocumentTest("          ");
    }
 
    [Fact]
    public void AcceptsSwapTokenAtEndOfFileAndOutputsZeroLengthCodeSpan()
    {
        ParseDocumentTest("@");
    }
 
    [Fact]
    public void CorrectlyHandlesOddlySpacedHTMLElements()
    {
        ParseDocumentTest("<div ><p class = 'bar'> Foo </p></div >");
    }
 
    [Fact]
    public void CorrectlyHandlesSingleLineOfMarkupWithEmbeddedStatement()
    {
        ParseDocumentTest("<div>Foo @if(true) {} Bar</div>");
    }
 
    [Fact]
    public void WithinSectionDoesNotCreateDocumentLevelSpan()
    {
        ParseDocumentTest("""
            @section Foo {
                <html></html>
            }
            """,
            [SectionDirective.Directive]);
    }
 
    [Fact]
    public void ParsesWholeContentAsOneSpanIfNoSwapCharacterEncountered()
    {
        ParseDocumentTest("foo baz");
    }
 
    [Fact]
    public void HandsParsingOverToCodeParserWhenAtSignEncounteredAndEmitsOutput()
    {
        ParseDocumentTest("foo @bar baz");
    }
 
    [Fact]
    public void EmitsAtSignAsMarkupIfAtEndOfFile()
    {
        ParseDocumentTest("foo @");
    }
 
    [Fact]
    public void EmitsCodeBlockIfFirstCharacterIsSwapCharacter()
    {
        ParseDocumentTest("@bar");
    }
 
    [Fact]
    public void ParseDocumentDoesNotSwitchToCodeOnEmailAddressInText()
    {
        ParseDocumentTest("example@microsoft.com");
    }
 
    [Fact]
    public void DoesNotSwitchToCodeOnEmailAddressInAttribute()
    {
        ParseDocumentTest("<a href=\"mailto:example@microsoft.com\">Email me</a>");
    }
 
    [Fact]
    public void DoesNotReturnErrorOnMismatchedTags()
    {
        ParseDocumentTest("Foo <div><p></p></p> Baz");
    }
 
    [Fact]
    public void ReturnsOneMarkupSegmentIfNoCodeBlocksEncountered()
    {
        ParseDocumentTest("Foo Baz<!--Foo-->Bar<!--F> Qux");
    }
 
    [Fact]
    public void RendersTextPseudoTagAsMarkup()
    {
        ParseDocumentTest("Foo <text>Foo</text>");
    }
 
    [Fact]
    public void AcceptsEndTagWithNoMatchingStartTag()
    {
        ParseDocumentTest("Foo </div> Bar");
    }
 
    [Fact]
    public void NoLongerSupportsDollarOpenBraceCombination()
    {
        ParseDocumentTest("<foo>${bar}</foo>");
    }
 
    [Fact]
    public void IgnoresTagsInContentsOfScriptTag()
    {
        ParseDocumentTest(@"<script>foo<bar baz='@boz'></script>");
    }
 
    [Fact]
    public void DoesNotRenderExtraNewLineAtTheEndOfVerbatimBlock()
    {
        ParseDocumentTest("@{\r\n}\r\n<html>");
    }
 
    [Fact]
    public void DoesNotRenderExtraWhitespaceAndNewLineAtTheEndOfVerbatimBlock()
    {
        ParseDocumentTest("@{\r\n} \t\r\n<html>");
    }
 
    [Fact]
    public void DoesNotRenderNewlineAfterTextTagInVerbatimBlockIfFollowedByCSharp()
    {
        // ParseDocumentDoesNotRenderExtraNewlineAtTheEndTextTagInVerbatimBlockIfFollowedByCSharp
        ParseDocumentTest("@{<text>Blah</text>\r\n\r\n}<html>");
    }
 
    [Fact]
    public void RendersExtraNewlineAtTheEndTextTagInVerbatimBlockIfFollowedByHtml()
    {
        ParseDocumentTest("@{<text>Blah</text>\r\n<input/>\r\n}<html>");
    }
 
    [Fact]
    public void RendersNewlineAfterTextTagInVerbatimBlockIfFollowedByMarkupTransition()
    {
        // ParseDocumentRendersExtraNewlineAtTheEndTextTagInVerbatimBlockIfFollowedByMarkupTransition
        ParseDocumentTest("@{<text>Blah</text>\r\n@: Bleh\r\n}<html>");
    }
 
    [Fact]
    public void DoesNotIgnoreNewLineAtTheEndOfMarkupBlock()
    {
        ParseDocumentTest("@{\r\n}\r\n<html>\r\n");
    }
 
    [Fact]
    public void DoesNotIgnoreWhitespaceAtTheEndOfVerbatimBlockIfNoNewlinePresent()
    {
        ParseDocumentTest("@{\r\n}   \t<html>\r\n");
    }
 
    [Fact]
    public void HandlesNewLineInNestedBlock()
    {
        ParseDocumentTest("@{\r\n@if(true){\r\n} \r\n}\r\n<html>");
    }
 
    [Fact]
    public void HandlesNewLineAndMarkupInNestedBlock()
    {
        ParseDocumentTest("@{\r\n@if(true){\r\n} <input> }");
    }
 
    [Fact]
    public void HandlesExtraNewLineBeforeMarkupInNestedBlock()
    {
        ParseDocumentTest("@{\r\n@if(true){\r\n} \r\n<input> \r\n}<html>");
    }
 
    [Fact]
    public void ParseSectionIgnoresTagsInContentsOfScriptTag()
    {
        ParseDocumentTest(
            @"@section Foo { <script>foo<bar baz='@boz'></script> }",
            [SectionDirective.Directive]);
    }
 
    [Fact]
    public void ParseBlockCanParse1000NestedElements()
    {
        var content = Nested1000.ReadAllText();
 
        // Assert - does not throw
        ParseDocument(content);
    }
 
    [Fact]
    public void WithDoubleTransitionInAttributeValue_DoesNotThrow()
    {
        var input = "{<span foo='@@' />}";
        ParseDocumentTest(input);
    }
 
    [Fact]
    public void WithDoubleTransitionAtEndOfAttributeValue_DoesNotThrow()
    {
        var input = "{<span foo='abc@@' />}";
        ParseDocumentTest(input);
    }
 
    [Fact]
    public void WithDoubleTransitionAtBeginningOfAttributeValue_DoesNotThrow()
    {
        var input = "{<span foo='@@def' />}";
        ParseDocumentTest(input);
    }
 
    [Fact]
    public void WithDoubleTransitionBetweenAttributeValue_DoesNotThrow()
    {
        var input = "{<span foo='abc @@ def' />}";
        ParseDocumentTest(input);
    }
 
    [Fact]
    public void WithDoubleTransitionWithExpressionBlock_DoesNotThrow()
    {
        var input = "{<span foo='@@@(2+3)' bar='@(2+3)@@@DateTime.Now' baz='@DateTime.Now@@' bat='@DateTime.Now @@' zoo='@@@DateTime.Now' />}";
        ParseDocumentTest(input);
    }
 
    [Fact]
    public void WithDoubleTransitionInEmail_DoesNotThrow()
    {
        var input = "{<span foo='abc@def.com abc@@def.com @@' />}";
        ParseDocumentTest(input);
    }
 
    [Fact]
    public void WithDoubleTransitionInRegex_DoesNotThrow()
    {
        var input = @"{<span foo=""/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@@[a-z0-9]([a-z0-9-]*[a-z0-9])?\.([a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i"" />}";
        ParseDocumentTest(input);
    }
 
    [Fact]
    public void WithUnexpectedTransitionsInAttributeValue_Throws()
    {
        ParseDocumentTest("<span foo='@ @' />");
    }
 
    [Fact]
    public void OpenAngle_01()
    {
        ParseDocumentTest("""
            < @("a").@("b")
            """);
    }
 
    [Fact]
    public void OpenAngle_02()
    {
        ParseDocumentTest("""
            < @("a").@b
            """);
    }
 
    [Fact]
    public void OpenAngle_03()
    {
        ParseDocumentTest("""
            < @("a")x@("b")
            """);
    }
 
    [Fact]
    public void OpenAngle_04()
    {
        ParseDocumentTest("""
            < @("a")x@b
            """);
    }
 
    [Fact]
    public void OpenAngle_05()
    {
        ParseDocumentTest("""
            < @("a").@@("b")
            """);
    }
 
    [Fact]
    public void OpenAngle_06()
    {
        ParseDocumentTest("""
            < @("a").@@b
            """);
    }
 
    [Fact]
    public void OpenAngle_07()
    {
        ParseDocumentTest("""
            < @("a")x@@("b")
            """);
    }
 
    [Fact]
    public void OpenAngle_08()
    {
        ParseDocumentTest("""
            < @("a")x@@b
            """);
    }
 
    [Fact]
    public void OpenAngle_09()
    {
        ParseDocumentTest("""
            < @("a")x@@@("b")
            """);
    }
 
    [Fact]
    public void OpenAngle_10()
    {
        ParseDocumentTest("""
            < @("a")x@@@b
            """);
    }
 
    [Fact]
    public void OpenAngle_11()
    {
        ParseDocumentTest("""
            < @@
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/razor/issues/11327")]
    public void QuoteInAttributeName_01()
    {
        ParseDocumentTest("""
            <div class="test""></div>
            """);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/razor/issues/11327")]
    public void QuoteInAttributeName_02()
    {
        ParseDocumentTest("""
            <div class="test"'></div>
            """);
    }
}