public void ReadHtml(string html, string expected)
        {
            var actual = new List <string>();
            var reader = new HtmlReader(html);

            while (reader.Read(out var token))
            {
                var content = token.RawText.ToString();
                if (token.Type == HtmlTokenType.StartTag || token.Type == HtmlTokenType.EndTag)
                {
                    Assert.True(content.StartsWith('<'));
                    Assert.True(content.EndsWith('>'));
                    content = token.Name.ToString();
                }

                if (token.Attributes.Length > 0)
                {
                    var attributes = new List <string>();
                    foreach (ref var attribute in token.Attributes.Span)
                    {
                        attributes.Add($"{attribute.Name.ToString()}:{attribute.Value.ToString()}[{attribute.RawText.ToString()}]");
                    }
                    content += $"({string.Join(", ", attributes)})";
                }

                actual.Add($"{token.Type}:{content}");
            }

            Assert.Equal(expected, string.Join(", ", actual));
        }
        public void ReadHtmlTextRange(string html, string range)
        {
            var reader = new HtmlReader(html);

            while (reader.Read(out var token))
            {
                if (token.Type == HtmlTokenType.StartTag)
                {
                    Assert.Equal(range, token.Range.ToString());
                }
            }
        }
        public void ReadToEndTag(string html, string expected)
        {
            var reader = new HtmlReader(html);

            Assert.True(reader.Read(out var token));
            Assert.True(reader.ReadToEndTag(token.Name.Span));

            var actual = new StringBuilder();

            while (reader.Read(out token))
            {
                actual.Append(token.RawText);
            }
            Assert.Equal(expected, actual.ToString());
        }