File: Legacy\HtmlMarkupParserTests.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 System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language.Legacy;
using Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Xunit;
 
namespace Microsoft.AspNetCore.Razor.Language.Test.Legacy;
 
public class HtmlMarkupParserTests
{
    private static readonly SyntaxToken doubleHyphenToken = SyntaxFactory.Token(SyntaxKind.DoubleHyphen, "--");
 
    public static IEnumerable<object[]> NonDashTokens
    {
        get
        {
            yield return new[] { SyntaxFactory.Token(SyntaxKind.DoubleHyphen, "--") };
            yield return new[] { SyntaxFactory.Token(SyntaxKind.Text, "asdf") };
            yield return new[] { SyntaxFactory.Token(SyntaxKind.CloseAngle, ">") };
            yield return new[] { SyntaxFactory.Token(SyntaxKind.OpenAngle, "<") };
            yield return new[] { SyntaxFactory.Token(SyntaxKind.Bang, "!") };
        }
    }
 
    [Theory]
    [MemberData(nameof(NonDashTokens))]
    public void IsHyphen_ReturnsFalseForNonDashToken(object token)
    {
        // Arrange
        var convertedToken = (SyntaxToken)token;
 
        // Act & Assert
        Assert.False(HtmlMarkupParser.IsHyphen(convertedToken));
    }
 
    [Fact]
    public void IsHyphen_ReturnsTrueForADashToken()
    {
        // Arrange
        var dashToken = SyntaxFactory.Token(SyntaxKind.Text, "-");
 
        // Act & Assert
        Assert.True(HtmlMarkupParser.IsHyphen(dashToken));
    }
 
    [Fact]
    public void AcceptAllButLastDoubleHypens_ReturnsTheOnlyDoubleHyphenToken()
    {
        // Arrange
        using var sut = CreateTestParserForContent("-->");
 
        // Act
        var token = sut.AcceptAllButLastDoubleHyphens();
 
        // Assert
        Assert.True(doubleHyphenToken.IsEquivalentTo(token));
        Assert.True(sut.At(SyntaxKind.CloseAngle));
        Assert.True(doubleHyphenToken.IsEquivalentTo(sut.PreviousToken));
    }
 
    [Fact]
    public void AcceptAllButLastDoubleHypens_ReturnsTheDoubleHyphenTokenAfterAcceptingTheDash()
    {
        // Arrange
        using var sut = CreateTestParserForContent("--->");
 
        // Act
        var token = sut.AcceptAllButLastDoubleHyphens();
 
        // Assert
        Assert.True(doubleHyphenToken.IsEquivalentTo(token));
        Assert.True(sut.At(SyntaxKind.CloseAngle));
        Assert.NotNull(sut.PreviousToken);
        Assert.True(HtmlMarkupParser.IsHyphen(sut.PreviousToken));
    }
 
    [Fact]
    public void IsHtmlCommentAhead_ReturnsTrueForEmptyCommentTag()
    {
        // Arrange
        using var sut = CreateTestParserForContent("<!---->");
 
        // Act & Assert
        Assert.True(sut.IsHtmlCommentAhead());
    }
 
    [Fact]
    public void IsHtmlCommentAhead_ReturnsTrueForValidCommentTag()
    {
        // Arrange
        using var sut = CreateTestParserForContent("<!-- Some comment content in here -->");
 
        // Act & Assert
        Assert.True(sut.IsHtmlCommentAhead());
    }
 
    [Fact]
    public void IsHtmlCommentAhead_ReturnsTrueForValidCommentTagWithExtraDashesAtClosingTag()
    {
        // Arrange
        using var sut = CreateTestParserForContent("<!-- Some comment content in here ----->");
 
        // Act & Assert
        Assert.True(sut.IsHtmlCommentAhead());
    }
 
    [Fact]
    public void IsHtmlCommentAhead_ReturnsFalseForContentWithBadEndingAndExtraDash()
    {
        // Arrange
        using var sut = CreateTestParserForContent("<!-- Some comment content in here <!--->");
 
        // Act & Assert
        Assert.False(sut.IsHtmlCommentAhead());
    }
 
    [Fact]
    public void IsHtmlCommentAhead_ReturnsTrueForValidCommentTagWithExtraInfoAfter()
    {
        // Arrange
        using var sut = CreateTestParserForContent("<!-- comment --> the first part is a valid comment without the Open angle and bang tokens");
 
        // Act & Assert
        Assert.True(sut.IsHtmlCommentAhead());
    }
 
    [Fact]
    public void IsHtmlCommentAhead_ReturnsFalseForNotClosedComment()
    {
        // Arrange
        using var sut = CreateTestParserForContent("<!-- not closed comment");
 
        // Act & Assert
        Assert.False(sut.IsHtmlCommentAhead());
    }
 
    [Fact]
    public void IsHtmlCommentAhead_ReturnsFalseForCommentWithoutLastClosingAngle()
    {
        // Arrange
        using var sut = CreateTestParserForContent("<!-- not closed comment--");
 
        // Act & Assert
        Assert.False(sut.IsHtmlCommentAhead());
    }
 
    [Fact]
    public void IsHtmlCommentAhead_ReturnsTrueForCommentWithCodeInside()
    {
        // Arrange
        using var sut = CreateTestParserForContent("<!-- not closed @DateTime.Now comment-->");
 
        // Act & Assert
        Assert.True(sut.IsHtmlCommentAhead());
    }
 
    [Fact]
    public void IsCommentContentEndingInvalid_ReturnsFalseForAllowedContent()
    {
        // Arrange
        var expectedToken1 = SyntaxFactory.Token(SyntaxKind.Text, "a");
        using var array = new PooledArrayBuilder<SyntaxToken>();
        array.AddRange(Enumerable.Range('a', 26).Select(item => SyntaxFactory.Token(SyntaxKind.Text, ((char)item).ToString())));
 
        // Act & Assert
        Assert.False(HtmlMarkupParser.IsCommentContentEndingInvalid(in array));
    }
 
    [Fact]
    public void IsCommentContentEndingInvalid_ReturnsTrueForDisallowedContent()
    {
        // Arrange
        using var array = new PooledArrayBuilder<SyntaxToken>();
        array.Add(SyntaxFactory.Token(SyntaxKind.OpenAngle, "<"));
        array.Add(SyntaxFactory.Token(SyntaxKind.Bang, "!"));
        array.Add(SyntaxFactory.Token(SyntaxKind.Text, "-"));
 
        // Act & Assert
        Assert.True(HtmlMarkupParser.IsCommentContentEndingInvalid(in array));
    }
 
    [Fact]
    public void IsCommentContentEndingInvalid_ReturnsFalseForEmptyContent()
    {
        // Arrange
        using var array = new PooledArrayBuilder<SyntaxToken>();
 
        // Act & Assert
        Assert.False(HtmlMarkupParser.IsCommentContentEndingInvalid(in array));
    }
 
    private class TestHtmlMarkupParser : HtmlMarkupParser, IDisposable
    {
        public TestHtmlMarkupParser(ParserContext context)
            : base(context)
        {
            EnsureCurrent();
        }
 
        void IDisposable.Dispose()
        {
            Context.Dispose();
            base.Dispose();
        }
 
        public new SyntaxToken? PreviousToken
        {
            get => base.PreviousToken;
        }
 
        public new bool IsHtmlCommentAhead()
        {
            return base.IsHtmlCommentAhead();
        }
 
        public new SyntaxToken? AcceptAllButLastDoubleHyphens()
        {
            return base.AcceptAllButLastDoubleHyphens();
        }
    }
 
    private static TestHtmlMarkupParser CreateTestParserForContent(string content)
    {
        var source = TestRazorSourceDocument.Create(content);
        var options = RazorParserOptions.Default;
        var context = new ParserContext(source, options);
 
        return new TestHtmlMarkupParser(context);
    }
}