Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@@ -0,0 +1,304 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Web.Razor.Editor;
using System.Web.Razor.Generator;
using System.Web.Razor.Parser;
using System.Web.Razor.Parser.SyntaxTree;
using System.Web.Razor.Test.Framework;
using System.Web.Razor.Text;
using Xunit;
namespace System.Web.Razor.Test.Parser.Html
{
public class HtmlAttributeTest : CsHtmlMarkupParserTestBase
{
[Fact]
public void SimpleLiteralAttribute()
{
ParseBlockTest("<a href='Foo' />",
new MarkupBlock(
Factory.Markup("<a"),
new MarkupBlock(new AttributeBlockCodeGenerator(name: "href", prefix: new LocationTagged<string>(" href='", 2, 0, 2), suffix: new LocationTagged<string>("'", 12, 0, 12)),
Factory.Markup(" href='").With(SpanCodeGenerator.Null),
Factory.Markup("Foo").With(new LiteralAttributeCodeGenerator(prefix: new LocationTagged<string>(String.Empty, 9, 0, 9), value: new LocationTagged<string>("Foo", 9, 0, 9))),
Factory.Markup("'").With(SpanCodeGenerator.Null)),
Factory.Markup(" />").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void MultiPartLiteralAttribute()
{
ParseBlockTest("<a href='Foo Bar Baz' />",
new MarkupBlock(
Factory.Markup("<a"),
new MarkupBlock(new AttributeBlockCodeGenerator(name: "href", prefix: new LocationTagged<string>(" href='", 2, 0, 2), suffix: new LocationTagged<string>("'", 20, 0, 20)),
Factory.Markup(" href='").With(SpanCodeGenerator.Null),
Factory.Markup("Foo").With(new LiteralAttributeCodeGenerator(prefix: new LocationTagged<string>(String.Empty, 9, 0, 9), value: new LocationTagged<string>("Foo", 9, 0, 9))),
Factory.Markup(" Bar").With(new LiteralAttributeCodeGenerator(prefix: new LocationTagged<string>(" ", 12, 0, 12), value: new LocationTagged<string>("Bar", 13, 0, 13))),
Factory.Markup(" Baz").With(new LiteralAttributeCodeGenerator(prefix: new LocationTagged<string>(" ", 16, 0, 16), value: new LocationTagged<string>("Baz", 17, 0, 17))),
Factory.Markup("'").With(SpanCodeGenerator.Null)),
Factory.Markup(" />").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void DoubleQuotedLiteralAttribute()
{
ParseBlockTest("<a href=\"Foo Bar Baz\" />",
new MarkupBlock(
Factory.Markup("<a"),
new MarkupBlock(new AttributeBlockCodeGenerator(name: "href", prefix: new LocationTagged<string>(" href=\"", 2, 0, 2), suffix: new LocationTagged<string>("\"", 20, 0, 20)),
Factory.Markup(" href=\"").With(SpanCodeGenerator.Null),
Factory.Markup("Foo").With(new LiteralAttributeCodeGenerator(prefix: new LocationTagged<string>(String.Empty, 9, 0, 9), value: new LocationTagged<string>("Foo", 9, 0, 9))),
Factory.Markup(" Bar").With(new LiteralAttributeCodeGenerator(prefix: new LocationTagged<string>(" ", 12, 0, 12), value: new LocationTagged<string>("Bar", 13, 0, 13))),
Factory.Markup(" Baz").With(new LiteralAttributeCodeGenerator(prefix: new LocationTagged<string>(" ", 16, 0, 16), value: new LocationTagged<string>("Baz", 17, 0, 17))),
Factory.Markup("\"").With(SpanCodeGenerator.Null)),
Factory.Markup(" />").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void UnquotedLiteralAttribute()
{
ParseBlockTest("<a href=Foo Bar Baz />",
new MarkupBlock(
Factory.Markup("<a"),
new MarkupBlock(new AttributeBlockCodeGenerator(name: "href", prefix: new LocationTagged<string>(" href=", 2, 0, 2), suffix: new LocationTagged<string>(String.Empty, 11, 0, 11)),
Factory.Markup(" href=").With(SpanCodeGenerator.Null),
Factory.Markup("Foo").With(new LiteralAttributeCodeGenerator(prefix: new LocationTagged<string>(String.Empty, 8, 0, 8), value: new LocationTagged<string>("Foo", 8, 0, 8)))),
Factory.Markup(" Bar Baz />").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void SimpleExpressionAttribute()
{
ParseBlockTest("<a href='@foo' />",
new MarkupBlock(
Factory.Markup("<a"),
new MarkupBlock(new AttributeBlockCodeGenerator(name: "href", prefix: new LocationTagged<string>(" href='", 2, 0, 2), suffix: new LocationTagged<string>("'", 13, 0, 13)),
Factory.Markup(" href='").With(SpanCodeGenerator.Null),
new MarkupBlock(new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(String.Empty, 9, 0, 9), 9, 0, 9),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))),
Factory.Markup("'").With(SpanCodeGenerator.Null)),
Factory.Markup(" />").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void MultiValueExpressionAttribute()
{
ParseBlockTest("<a href='@foo bar @baz' />",
new MarkupBlock(
Factory.Markup("<a"),
new MarkupBlock(new AttributeBlockCodeGenerator(name: "href", prefix: new LocationTagged<string>(" href='", 2, 0, 2), suffix: new LocationTagged<string>("'", 22, 0, 22)),
Factory.Markup(" href='").With(SpanCodeGenerator.Null),
new MarkupBlock(new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(String.Empty, 9, 0, 9), 9, 0, 9),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))),
Factory.Markup(" bar").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(" ", 13, 0, 13), new LocationTagged<string>("bar", 14, 0, 14))),
new MarkupBlock(new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(" ", 17, 0, 17), 18, 0, 18),
Factory.Markup(" ").With(SpanCodeGenerator.Null),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("baz")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))),
Factory.Markup("'").With(SpanCodeGenerator.Null)),
Factory.Markup(" />").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void VirtualPathAttributesWorkWithConditionalAttributes()
{
ParseBlockTest("<a href='@foo ~/Foo/Bar' />",
new MarkupBlock(
Factory.Markup("<a"),
new MarkupBlock(new AttributeBlockCodeGenerator(name: "href", prefix: new LocationTagged<string>(" href='", 2, 0, 2), suffix: new LocationTagged<string>("'", 23, 0, 23)),
Factory.Markup(" href='").With(SpanCodeGenerator.Null),
new MarkupBlock(new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(String.Empty, 9, 0, 9), 9, 0, 9),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))),
Factory.Markup(" ~/Foo/Bar")
.WithEditorHints(EditorHints.VirtualPath)
.With(new LiteralAttributeCodeGenerator(
new LocationTagged<string>(" ", 13, 0, 13),
new LocationTagged<SpanCodeGenerator>(new ResolveUrlCodeGenerator(), 14, 0, 14))),
Factory.Markup("'").With(SpanCodeGenerator.Null)),
Factory.Markup(" />").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void UnquotedAttributeWithCodeWithSpacesInBlock()
{
ParseBlockTest("<input value=@foo />",
new MarkupBlock(
Factory.Markup("<input"),
new MarkupBlock(new AttributeBlockCodeGenerator(name: "value", prefix: new LocationTagged<string>(" value=", 6, 0, 6), suffix: new LocationTagged<string>(String.Empty, 17, 0, 17)),
Factory.Markup(" value=").With(SpanCodeGenerator.Null),
new MarkupBlock(new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(String.Empty, 13, 0, 13), 13, 0, 13),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)))),
Factory.Markup(" />").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void UnquotedAttributeWithCodeWithSpacesInDocument()
{
ParseDocumentTest("<input value=@foo />",
new MarkupBlock(
Factory.Markup("<input"),
new MarkupBlock(new AttributeBlockCodeGenerator(name: "value", prefix: new LocationTagged<string>(" value=", 6, 0, 6), suffix: new LocationTagged<string>(String.Empty, 17, 0, 17)),
Factory.Markup(" value=").With(SpanCodeGenerator.Null),
new MarkupBlock(new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(String.Empty, 13, 0, 13), 13, 0, 13),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)))),
Factory.Markup(" />")));
}
[Fact]
public void ConditionalAttributeCollapserDoesNotRemoveUrlAttributeValues()
{
// Act
ParserResults results = ParseDocument("<a href='~/Foo/Bar' />");
Block rewritten = new ConditionalAttributeCollapser(new HtmlMarkupParser().BuildSpan).Rewrite(results.Document);
rewritten = new MarkupCollapser(new HtmlMarkupParser().BuildSpan).Rewrite(rewritten);
// Assert
Assert.Equal(0, results.ParserErrors.Count);
EvaluateParseTree(rewritten,
new MarkupBlock(
Factory.Markup("<a"),
new MarkupBlock(new AttributeBlockCodeGenerator(name: "href", prefix: new LocationTagged<string>(" href='", 2, 0, 2), suffix: new LocationTagged<string>("'", 18, 0, 18)),
Factory.Markup(" href='").With(SpanCodeGenerator.Null),
Factory.Markup("~/Foo/Bar")
.WithEditorHints(EditorHints.VirtualPath)
.With(new LiteralAttributeCodeGenerator(
new LocationTagged<string>(String.Empty, 9, 0, 9),
new LocationTagged<SpanCodeGenerator>(new ResolveUrlCodeGenerator(), 9, 0, 9))),
Factory.Markup("'").With(SpanCodeGenerator.Null)),
Factory.Markup(" />")));
}
[Fact]
public void ConditionalAttributesDoNotCreateExtraDataForEntirelyLiteralAttribute()
{
// Arrange
const string code =
#region Big Block o' code
@"<div class=""sidebar"">
<h1>Title</h1>
<p>
As the author, you can <a href=""/Photo/Edit/photoId"">edit</a>
or <a href=""/Photo/Remove/photoId"">remove</a> this photo.
</p>
<dl>
<dt class=""description"">Description</dt>
<dd class=""description"">
The uploader did not provide a description for this photo.
</dd>
<dt class=""uploaded-by"">Uploaded by</dt>
<dd class=""uploaded-by""><a href=""/User/View/user.UserId"">user.DisplayName</a></dd>
<dt class=""upload-date"">Upload date</dt>
<dd class=""upload-date"">photo.UploadDate</dd>
<dt class=""part-of-gallery"">Gallery</dt>
<dd><a href=""/View/gallery.Id"" title=""View gallery.Name gallery"">gallery.Name</a></dd>
<dt class=""tags"">Tags</dt>
<dd class=""tags"">
<ul class=""tags"">
<li>This photo has no tags.</li>
</ul>
<a href=""/Photo/EditTags/photoId"">edit tags</a>
</dd>
</dl>
<p>
<a class=""download"" href=""/Photo/Full/photoId"" title=""Download: (photo.FileTitle + photo.FileExtension)"">Download full photo</a> ((photo.FileSize / 1024) KB)
</p>
</div>
<div class=""main"">
<img class=""large-photo"" alt=""photo.FileTitle"" src=""/Photo/Thumbnail"" />
<h2>Nobody has commented on this photo</h2>
<ol class=""comments"">
<li>
<h3 class=""comment-header"">
<a href=""/User/View/comment.UserId"" title=""View comment.DisplayName's profile"">comment.DisplayName</a> commented at comment.CommentDate:
</h3>
<p class=""comment-body"">comment.CommentText</p>
</li>
</ol>
<form method=""post"" action="""">
<fieldset id=""addComment"">
<legend>Post new comment</legend>
<ol>
<li>
<label for=""newComment"">Comment</label>
<textarea id=""newComment"" name=""newComment"" title=""Your comment"" rows=""6"" cols=""70""></textarea>
</li>
</ol>
<p class=""form-actions"">
<input type=""submit"" title=""Add comment"" value=""Add comment"" />
</p>
</fieldset>
</form>
</div>";
#endregion
// Act
ParserResults results = ParseDocument(code);
Block rewritten = new ConditionalAttributeCollapser(new HtmlMarkupParser().BuildSpan).Rewrite(results.Document);
rewritten = new MarkupCollapser(new HtmlMarkupParser().BuildSpan).Rewrite(rewritten);
// Assert
Assert.Equal(0, results.ParserErrors.Count);
EvaluateParseTree(rewritten, new MarkupBlock(Factory.Markup(code)));
}
[Fact]
public void ConditionalAttributesAreDisabledForDataAttributesInBlock()
{
ParseBlockTest("<span data-foo='@foo'></span>",
new MarkupBlock(
Factory.Markup("<span"),
new MarkupBlock(
Factory.Markup(" data-foo='"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("'")),
Factory.Markup("></span>").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ConditionalAttributesAreDisabledForDataAttributesInDocument()
{
ParseDocumentTest("<span data-foo='@foo'></span>",
new MarkupBlock(
Factory.Markup("<span"),
new MarkupBlock(
Factory.Markup(" data-foo='"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("'")),
Factory.Markup("></span>")));
}
}
}

View File

@@ -0,0 +1,393 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Web.Razor.Editor;
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.Razor.Tokenizer.Symbols;
using Xunit;
using Assert = Microsoft.TestCommon.AssertEx;
namespace System.Web.Razor.Test.Parser.Html
{
public class HtmlBlockTest : CsHtmlMarkupParserTestBase
{
[Fact]
public void ParseBlockMethodThrowsArgNullExceptionOnNullContext()
{
// Arrange
HtmlMarkupParser parser = new HtmlMarkupParser();
// Act and Assert
Assert.Throws<InvalidOperationException>(() => parser.ParseBlock(), RazorResources.Parser_Context_Not_Set);
}
[Fact]
public void ParseBlockHandlesOpenAngleAtEof()
{
ParseDocumentTest(@"@{
<",
new MarkupBlock(
Factory.EmptyHtml(),
new StatementBlock(
Factory.CodeTransition(),
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup("<")))),
new RazorError(
String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, RazorResources.BlockName_Code, "}", "{"),
1, 0, 1));
}
[Fact]
public void ParseBlockHandlesOpenAngleWithProperTagFollowingIt()
{
ParseDocumentTest(@"@{
<
</html>",
new MarkupBlock(
Factory.EmptyHtml(),
new StatementBlock(
Factory.CodeTransition(),
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup("<\r\n")
),
new MarkupBlock(
Factory.Markup(@"</html>").Accepts(AcceptedCharacters.None)
),
Factory.EmptyCSharp().AsStatement()
)
),
designTimeParser: true,
expectedErrors: new[]
{
new RazorError(String.Format(RazorResources.ParseError_UnexpectedEndTag, "html"), 7, 2, 0),
new RazorError(String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, "code", "}", "{"), 1, 0, 1)
});
}
[Fact]
public void TagWithoutCloseAngleDoesNotTerminateBlock()
{
ParseBlockTest(@"<
",
new MarkupBlock(
Factory.Markup("< \r\n ")),
designTimeParser: true,
expectedErrors: new RazorError(String.Format(RazorResources.ParseError_UnfinishedTag, String.Empty), 0, 0, 0));
}
[Fact]
public void ParseBlockAllowsStartAndEndTagsToDifferInCase()
{
SingleSpanBlockTest("<li><p>Foo</P></lI>", BlockType.Markup, SpanKind.Markup, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockReadsToEndOfLineIfFirstCharacterAfterTransitionIsColon()
{
ParseBlockTest(@"@:<li>Foo Bar Baz
bork",
new MarkupBlock(
Factory.MarkupTransition(),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
Factory.Markup("<li>Foo Bar Baz\r\n")
.With(new SingleLineMarkupEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString, AcceptedCharacters.None))
));
}
[Fact]
public void ParseBlockStopsParsingSingleLineBlockAtEOFIfNoEOLReached()
{
ParseBlockTest("@:foo bar",
new MarkupBlock(
Factory.MarkupTransition(),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
Factory.Markup(@"foo bar")
.With(new SingleLineMarkupEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString))
));
}
[Fact]
public void ParseBlockStopsAtMatchingCloseTagToStartTag()
{
SingleSpanBlockTest("<a><b></b></a><c></c>", "<a><b></b></a>", BlockType.Markup, SpanKind.Markup, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockParsesUntilMatchingEndTagIfFirstNonWhitespaceCharacterIsStartTag()
{
SingleSpanBlockTest("<baz><boz><biz></biz></boz></baz>", BlockType.Markup, SpanKind.Markup, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockAllowsUnclosedTagsAsLongAsItCanRecoverToAnExpectedEndTag()
{
SingleSpanBlockTest("<foo><bar><baz></foo>", BlockType.Markup, SpanKind.Markup, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockWithSelfClosingTagJustEmitsTag()
{
SingleSpanBlockTest("<foo />", BlockType.Markup, SpanKind.Markup, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockCanHandleSelfClosingTagsWithinBlock()
{
SingleSpanBlockTest("<foo><bar /></foo>", BlockType.Markup, SpanKind.Markup, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSupportsTagsWithAttributes()
{
ParseBlockTest("<foo bar=\"baz\"><biz><boz zoop=zork/></biz></foo>",
new MarkupBlock(
Factory.Markup("<foo"),
new MarkupBlock(new AttributeBlockCodeGenerator("bar", new LocationTagged<string>(" bar=\"", 4, 0, 4), new LocationTagged<string>("\"", 13, 0, 13)),
Factory.Markup(" bar=\"").With(SpanCodeGenerator.Null),
Factory.Markup("baz").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(String.Empty, 10, 0, 10), new LocationTagged<string>("baz", 10, 0, 10))),
Factory.Markup("\"").With(SpanCodeGenerator.Null)),
Factory.Markup("><biz><boz"),
new MarkupBlock(new AttributeBlockCodeGenerator("zoop", new LocationTagged<string>(" zoop=", 24, 0, 24), new LocationTagged<string>(String.Empty, 34, 0, 34)),
Factory.Markup(" zoop=").With(SpanCodeGenerator.Null),
Factory.Markup("zork").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(String.Empty, 30, 0, 30), new LocationTagged<string>("zork", 30, 0, 30)))),
Factory.Markup("/></biz></foo>").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockAllowsCloseAngleBracketInAttributeValueIfDoubleQuoted()
{
ParseBlockTest("<foo><bar baz=\">\" /></foo>",
new MarkupBlock(
Factory.Markup("<foo><bar"),
new MarkupBlock(new AttributeBlockCodeGenerator("baz", new LocationTagged<string>(" baz=\"", 9, 0, 9), new LocationTagged<string>("\"", 16, 0, 16)),
Factory.Markup(" baz=\"").With(SpanCodeGenerator.Null),
Factory.Markup(">").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(String.Empty, 15, 0, 15), new LocationTagged<string>(">", 15, 0, 15))),
Factory.Markup("\"").With(SpanCodeGenerator.Null)),
Factory.Markup(" /></foo>").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockAllowsCloseAngleBracketInAttributeValueIfSingleQuoted()
{
ParseBlockTest("<foo><bar baz=\'>\' /></foo>",
new MarkupBlock(
Factory.Markup("<foo><bar"),
new MarkupBlock(new AttributeBlockCodeGenerator("baz", new LocationTagged<string>(" baz='", 9, 0, 9), new LocationTagged<string>("'", 16, 0, 16)),
Factory.Markup(" baz='").With(SpanCodeGenerator.Null),
Factory.Markup(">").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(String.Empty, 15, 0, 15), new LocationTagged<string>(">", 15, 0, 15))),
Factory.Markup("'").With(SpanCodeGenerator.Null)),
Factory.Markup(" /></foo>").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockAllowsSlashInAttributeValueIfDoubleQuoted()
{
ParseBlockTest("<foo><bar baz=\"/\"></bar></foo>",
new MarkupBlock(
Factory.Markup("<foo><bar"),
new MarkupBlock(new AttributeBlockCodeGenerator("baz", new LocationTagged<string>(" baz=\"", 9, 0, 9), new LocationTagged<string>("\"", 16, 0, 16)),
Factory.Markup(" baz=\"").With(SpanCodeGenerator.Null),
Factory.Markup("/").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(String.Empty, 15, 0, 15), new LocationTagged<string>("/", 15, 0, 15))),
Factory.Markup("\"").With(SpanCodeGenerator.Null)),
Factory.Markup("></bar></foo>").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockAllowsSlashInAttributeValueIfSingleQuoted()
{
ParseBlockTest("<foo><bar baz=\'/\'></bar></foo>",
new MarkupBlock(
Factory.Markup("<foo><bar"),
new MarkupBlock(new AttributeBlockCodeGenerator("baz", new LocationTagged<string>(" baz='", 9, 0, 9), new LocationTagged<string>("'", 16, 0, 16)),
Factory.Markup(" baz='").With(SpanCodeGenerator.Null),
Factory.Markup("/").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(String.Empty, 15, 0, 15), new LocationTagged<string>("/", 15, 0, 15))),
Factory.Markup("'").With(SpanCodeGenerator.Null)),
Factory.Markup("></bar></foo>").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockTerminatesAtEOF()
{
SingleSpanBlockTest("<foo>", "<foo>", BlockType.Markup, SpanKind.Markup,
new RazorError(String.Format(RazorResources.ParseError_MissingEndTag, "foo"), new SourceLocation(0, 0, 0)));
}
[Fact]
public void ParseBlockSupportsCommentAsBlock()
{
SingleSpanBlockTest("<!-- foo -->", BlockType.Markup, SpanKind.Markup, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSupportsCommentWithinBlock()
{
SingleSpanBlockTest("<foo>bar<!-- zoop -->baz</foo>", BlockType.Markup, SpanKind.Markup, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockProperlyBalancesCommentStartAndEndTags()
{
SingleSpanBlockTest("<!--<foo></bar>-->", BlockType.Markup, SpanKind.Markup, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockTerminatesAtEOFWhenParsingComment()
{
SingleSpanBlockTest("<!--<foo>", "<!--<foo>", BlockType.Markup, SpanKind.Markup);
}
[Fact]
public void ParseBlockOnlyTerminatesCommentOnFullEndSequence()
{
SingleSpanBlockTest("<!--<foo>--</bar>-->", BlockType.Markup, SpanKind.Markup, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockTerminatesCommentAtFirstOccurrenceOfEndSequence()
{
SingleSpanBlockTest("<foo><!--<foo></bar-->--></foo>", BlockType.Markup, SpanKind.Markup, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockTreatsMalformedTagsAsContent()
{
SingleSpanBlockTest(
"<foo></!-- bar --></foo>",
"<foo></!-- bar -->",
BlockType.Markup,
SpanKind.Markup,
AcceptedCharacters.None,
new RazorError(String.Format(RazorResources.ParseError_MissingEndTag, "foo"), 0, 0, 0));
}
[Fact]
public void ParseBlockParsesSGMLDeclarationAsEmptyTag()
{
SingleSpanBlockTest("<foo><!DOCTYPE foo bar baz></foo>", BlockType.Markup, SpanKind.Markup, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockTerminatesSGMLDeclarationAtFirstCloseAngle()
{
SingleSpanBlockTest("<foo><!DOCTYPE foo bar> baz></foo>", BlockType.Markup, SpanKind.Markup, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockParsesXMLProcessingInstructionAsEmptyTag()
{
SingleSpanBlockTest("<foo><?xml foo bar baz?></foo>", BlockType.Markup, SpanKind.Markup, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockTerminatesXMLProcessingInstructionAtQuestionMarkCloseAnglePair()
{
SingleSpanBlockTest("<foo><?xml foo bar?> baz</foo>", BlockType.Markup, SpanKind.Markup, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockDoesNotTerminateXMLProcessingInstructionAtCloseAngleUnlessPreceededByQuestionMark()
{
SingleSpanBlockTest("<foo><?xml foo bar> baz?></foo>", BlockType.Markup, SpanKind.Markup, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSupportsScriptTagsWithLessThanSignsInThem()
{
SingleSpanBlockTest(@"<script>if(foo<bar) { alert(""baz"");)</script>", BlockType.Markup, SpanKind.Markup, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSupportsScriptTagsWithSpacedLessThanSignsInThem()
{
SingleSpanBlockTest(@"<script>if(foo < bar) { alert(""baz"");)</script>", BlockType.Markup, SpanKind.Markup, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockAcceptsEmptyTextTag()
{
ParseBlockTest("<text/>",
new MarkupBlock(
Factory.MarkupTransition("<text/>")
));
}
[Fact]
public void ParseBlockAcceptsTextTagAsOuterTagButDoesNotRender()
{
ParseBlockTest("<text>Foo Bar <foo> Baz</text> zoop",
new MarkupBlock(
Factory.MarkupTransition("<text>"),
Factory.Markup("Foo Bar <foo> Baz"),
Factory.MarkupTransition("</text>"),
Factory.Markup(" ").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockRendersLiteralTextTagIfDoubled()
{
ParseBlockTest("<text><text>Foo Bar <foo> Baz</text></text> zoop",
new MarkupBlock(
Factory.MarkupTransition("<text>"),
Factory.Markup("<text>Foo Bar <foo> Baz</text>"),
Factory.MarkupTransition("</text>"),
Factory.Markup(" ").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockDoesNotConsiderPsuedoTagWithinMarkupBlock()
{
ParseBlockTest("<foo><text><bar></bar></foo>",
new MarkupBlock(
Factory.Markup("<foo><text><bar></bar></foo>").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockStopsParsingMidEmptyTagIfEOFReached()
{
ParseBlockTest("<br/",
new MarkupBlock(
Factory.Markup("<br/")
),
new RazorError(String.Format(RazorResources.ParseError_UnfinishedTag, "br"), SourceLocation.Zero));
}
[Fact]
public void ParseBlockCorrectlyHandlesSingleLineOfMarkupWithEmbeddedStatement()
{
ParseBlockTest("<div>Foo @if(true) {} Bar</div>",
new MarkupBlock(
Factory.Markup("<div>Foo "),
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("if(true) {}").AsStatement()),
Factory.Markup(" Bar</div>").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockIgnoresTagsInContentsOfScriptTag()
{
ParseBlockTest(@"<script>foo<bar baz='@boz'></script>",
new MarkupBlock(
Factory.Markup("<script>foo<bar baz='"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("boz")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: false)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("'></script>")
.Accepts(AcceptedCharacters.None)));
}
}
}

View File

@@ -0,0 +1,239 @@
// 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<InvalidOperationException>(() => parser.ParseDocument(), RazorResources.Parser_Context_Not_Set);
}
[Fact]
public void ParseSectionMethodThrowsArgNullExceptionOnNullContext()
{
// Arrange
HtmlMarkupParser parser = new HtmlMarkupParser();
// Act and Assert
Assert.Throws<InvalidOperationException>(() => 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("<div>Foo @if(true) {} Bar</div>",
new MarkupBlock(
Factory.Markup("<div>Foo "),
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("if(true) {}").AsStatement()),
Factory.Markup(" Bar</div>")));
}
[Fact]
public void ParseDocumentWithinSectionDoesNotCreateDocumentLevelSpan()
{
ParseDocumentTest(@"@section Foo {
<html></html>
}",
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 <html></html>\r\n")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void ParseDocumentParsesWholeContentAsOneSpanIfNoSwapCharacterEncountered()
{
SingleSpanDocumentTest("foo <bar>baz</bar>", 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("<foo>anurse@microsoft.com</foo>", BlockType.Markup, SpanKind.Markup);
}
[Fact]
public void ParseDocumentDoesNotSwitchToCodeOnEmailAddressInAttribute()
{
ParseDocumentTest("<a href=\"mailto:anurse@microsoft.com\">Email me</a>",
new MarkupBlock(
Factory.Markup("<a"),
new MarkupBlock(new AttributeBlockCodeGenerator("href", new LocationTagged<string>(" href=\"", 2, 0, 2), new LocationTagged<string>("\"", 36, 0, 36)),
Factory.Markup(" href=\"").With(SpanCodeGenerator.Null),
Factory.Markup("mailto:anurse@microsoft.com")
.With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(String.Empty, 9, 0, 9), new LocationTagged<string>("mailto:anurse@microsoft.com", 9, 0, 9))),
Factory.Markup("\"").With(SpanCodeGenerator.Null)),
Factory.Markup(">Email me</a>")));
}
[Fact]
public void ParseDocumentDoesNotReturnErrorOnMismatchedTags()
{
SingleSpanDocumentTest("Foo <div><p></p></p> Baz", BlockType.Markup, SpanKind.Markup);
}
[Fact]
public void ParseDocumentReturnsOneMarkupSegmentIfNoCodeBlocksEncountered()
{
SingleSpanDocumentTest("Foo <p>Baz<!--Foo-->Bar<!-F> Qux", BlockType.Markup, SpanKind.Markup);
}
[Fact]
public void ParseDocumentRendersTextPseudoTagAsMarkup()
{
SingleSpanDocumentTest("Foo <text>Foo</text>", BlockType.Markup, SpanKind.Markup);
}
[Fact]
public void ParseDocumentAcceptsEndTagWithNoMatchingStartTag()
{
SingleSpanDocumentTest("Foo </div> Bar", BlockType.Markup, SpanKind.Markup);
}
[Fact]
public void ParseDocumentNoLongerSupportsDollarOpenBraceCombination()
{
ParseDocumentTest("<foo>${bar}</foo>",
new MarkupBlock(
Factory.Markup("<foo>${bar}</foo>")));
}
[Fact]
public void ParseDocumentIgnoresTagsInContentsOfScriptTag()
{
ParseDocumentTest(@"<script>foo<bar baz='@boz'></script>",
new MarkupBlock(
Factory.Markup("<script>foo<bar baz='"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("boz")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: false)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("'></script>")));
}
[Fact]
public void ParseSectionIgnoresTagsInContentsOfScriptTag()
{
ParseDocumentTest(@"@section Foo { <script>foo<bar baz='@boz'></script> }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("Foo"),
Factory.CodeTransition(),
Factory.MetaCode("section Foo {"),
new MarkupBlock(
Factory.Markup(" <script>foo<bar baz='"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("boz")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: false)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("'></script> ")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void ParseBlockCanParse1000NestedElements()
{
string content = Nested1000.ReadAllText();
SingleSpanDocumentTest(content, BlockType.Markup, SpanKind.Markup);
}
}
}

View File

@@ -0,0 +1,89 @@
// 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.SyntaxTree;
using System.Web.Razor.Resources;
using System.Web.Razor.Test.Framework;
using System.Web.Razor.Text;
using Xunit;
namespace System.Web.Razor.Test.Parser.Html
{
public class HtmlErrorTest : CsHtmlMarkupParserTestBase
{
[Fact]
public void ParseBlockAllowsInvalidTagNamesAsLongAsParserCanIdentifyEndTag()
{
SingleSpanBlockTest("<1-foo+bar>foo</1-foo+bar>", BlockType.Markup, SpanKind.Markup, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockThrowsErrorIfStartTextTagContainsTextAfterName()
{
ParseBlockTest("<text foo bar></text>",
new MarkupBlock(
Factory.MarkupTransition("<text").Accepts(AcceptedCharacters.Any),
Factory.Markup(" foo bar>"),
Factory.MarkupTransition("</text>")),
new RazorError(RazorResources.ParseError_TextTagCannotContainAttributes, SourceLocation.Zero));
}
[Fact]
public void ParseBlockThrowsErrorIfEndTextTagContainsTextAfterName()
{
ParseBlockTest("<text></text foo bar>",
new MarkupBlock(
Factory.MarkupTransition("<text>"),
Factory.MarkupTransition("</text").Accepts(AcceptedCharacters.Any),
Factory.Markup(" ")),
new RazorError(RazorResources.ParseError_TextTagCannotContainAttributes, 6, 0, 6));
}
[Fact]
public void ParseBlockThrowsExceptionIfBlockDoesNotStartWithTag()
{
ParseBlockTest("foo bar <baz>",
new MarkupBlock(),
new RazorError(RazorResources.ParseError_MarkupBlock_Must_Start_With_Tag, SourceLocation.Zero));
}
[Fact]
public void ParseBlockStartingWithEndTagProducesRazorErrorThenOutputsMarkupSegmentAndEndsBlock()
{
ParseBlockTest("</foo> bar baz",
new MarkupBlock(
Factory.Markup("</foo> ").Accepts(AcceptedCharacters.None)),
new RazorError(String.Format(RazorResources.ParseError_UnexpectedEndTag, "foo"), SourceLocation.Zero));
}
[Fact]
public void ParseBlockWithUnclosedTopLevelTagThrowsMissingEndTagParserExceptionOnOutermostUnclosedTag()
{
ParseBlockTest("<p><foo></bar>",
new MarkupBlock(
Factory.Markup("<p><foo></bar>").Accepts(AcceptedCharacters.None)),
new RazorError(String.Format(RazorResources.ParseError_MissingEndTag, "p"), new SourceLocation(0, 0, 0)));
}
[Fact]
public void ParseBlockWithUnclosedTagAtEOFThrowsMissingEndTagException()
{
ParseBlockTest("<foo>blah blah blah blah blah",
new MarkupBlock(
Factory.Markup("<foo>blah blah blah blah blah")),
new RazorError(String.Format(RazorResources.ParseError_MissingEndTag, "foo"), new SourceLocation(0, 0, 0)));
}
[Fact]
public void ParseBlockWithUnfinishedTagAtEOFThrowsIncompleteTagException()
{
ParseBlockTest("<foo bar=baz",
new MarkupBlock(
Factory.Markup("<foo"),
new MarkupBlock(new AttributeBlockCodeGenerator("bar", new LocationTagged<string>(" bar=", 4, 0, 4), new LocationTagged<string>(String.Empty, 12, 0, 12)),
Factory.Markup(" bar=").With(SpanCodeGenerator.Null),
Factory.Markup("baz").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(String.Empty, 9, 0, 9), new LocationTagged<string>("baz", 9, 0, 9))))),
new RazorError(String.Format(RazorResources.ParseError_UnfinishedTag, "foo"), new SourceLocation(0, 0, 0)));
}
}
}

View File

@@ -0,0 +1,39 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Web.Razor.Parser;
using System.Web.Razor.Parser.SyntaxTree;
using System.Web.Razor.Test.Framework;
namespace System.Web.Razor.Test.Parser.Html
{
internal class HtmlParserTestUtils
{
public static void RunSingleAtEscapeTest(Action<string, Block> testMethod, AcceptedCharacters lastSpanAcceptedCharacters = AcceptedCharacters.None)
{
var factory = SpanFactory.CreateCsHtml();
testMethod("<foo>@@bar</foo>",
new MarkupBlock(
factory.Markup("<foo>"),
factory.Markup("@").Hidden(),
factory.Markup("@bar</foo>").Accepts(lastSpanAcceptedCharacters)));
}
public static void RunMultiAtEscapeTest(Action<string, Block> testMethod, AcceptedCharacters lastSpanAcceptedCharacters = AcceptedCharacters.None)
{
var factory = SpanFactory.CreateCsHtml();
testMethod("<foo>@@@@@bar</foo>",
new MarkupBlock(
factory.Markup("<foo>"),
factory.Markup("@").Hidden(),
factory.Markup("@"),
factory.Markup("@").Hidden(),
factory.Markup("@"),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("bar")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Markup("</foo>").Accepts(lastSpanAcceptedCharacters)));
}
}
}

View File

@@ -0,0 +1,152 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Web.Razor.Parser.SyntaxTree;
using System.Web.Razor.Resources;
using System.Web.Razor.Test.Framework;
using Xunit;
using Xunit.Extensions;
namespace System.Web.Razor.Test.Parser.Html
{
public class HtmlTagsTest : CsHtmlMarkupParserTestBase
{
public static IEnumerable<string[]> VoidElementNames
{
get
{
yield return new[] { "area" };
yield return new[] { "base" };
yield return new[] { "br" };
yield return new[] { "col" };
yield return new[] { "command" };
yield return new[] { "embed" };
yield return new[] { "hr" };
yield return new[] { "img" };
yield return new[] { "input" };
yield return new[] { "keygen" };
yield return new[] { "link" };
yield return new[] { "meta" };
yield return new[] { "param" };
yield return new[] { "source" };
yield return new[] { "track" };
yield return new[] { "wbr" };
}
}
[Fact]
public void EmptyTagNestsLikeNormalTag()
{
ParseBlockTest("<p></> Bar",
new MarkupBlock(
Factory.Markup("<p></> ").Accepts(AcceptedCharacters.None)),
new RazorError(String.Format(RazorResources.ParseError_MissingEndTag, "p"), 0, 0, 0));
}
[Fact]
public void EmptyTag()
{
ParseBlockTest("<></> Bar",
new MarkupBlock(
Factory.Markup("<></> ").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void CommentTag()
{
ParseBlockTest("<!--Foo--> Bar",
new MarkupBlock(
Factory.Markup("<!--Foo--> ").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void DocTypeTag()
{
ParseBlockTest("<!DOCTYPE html> foo",
new MarkupBlock(
Factory.Markup("<!DOCTYPE html> ").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ProcessingInstructionTag()
{
ParseBlockTest("<?xml version=\"1.0\" ?> foo",
new MarkupBlock(
Factory.Markup("<?xml version=\"1.0\" ?> ").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ElementTags()
{
ParseBlockTest("<p>Foo</p> Bar",
new MarkupBlock(
Factory.Markup("<p>Foo</p> ").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void TextTags()
{
ParseBlockTest("<text>Foo</text>}",
new MarkupBlock(
Factory.MarkupTransition("<text>"),
Factory.Markup("Foo"),
Factory.MarkupTransition("</text>")));
}
[Fact]
public void CDataTag()
{
ParseBlockTest("<![CDATA[Foo]]> Bar",
new MarkupBlock(
Factory.Markup("<![CDATA[Foo]]> ").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ScriptTag()
{
ParseDocumentTest("<script>foo < bar && quantity.toString() !== orderQty.val()</script>",
new MarkupBlock(
Factory.Markup("<script>foo < bar && quantity.toString() !== orderQty.val()</script>")));
}
[Theory]
[PropertyData("VoidElementNames")]
public void VoidElementFollowedByContent(string tagName)
{
ParseBlockTest("<" + tagName + ">foo",
new MarkupBlock(
Factory.Markup("<" + tagName + ">")
.Accepts(AcceptedCharacters.None)));
}
[Theory]
[PropertyData("VoidElementNames")]
public void VoidElementFollowedByOtherTag(string tagName)
{
ParseBlockTest("<" + tagName + "><other>foo",
new MarkupBlock(
Factory.Markup("<" + tagName + ">")
.Accepts(AcceptedCharacters.None)));
}
[Theory]
[PropertyData("VoidElementNames")]
public void VoidElementFollowedByCloseTag(string tagName)
{
ParseBlockTest("<" + tagName + "> </" + tagName + ">foo",
new MarkupBlock(
Factory.Markup("<" + tagName + "> </" + tagName + ">")
.Accepts(AcceptedCharacters.None)));
}
[Theory]
[PropertyData("VoidElementNames")]
public void IncompleteVoidElementEndTag(string tagName)
{
ParseBlockTest("<" + tagName + "></" + tagName,
new MarkupBlock(
Factory.Markup("<" + tagName + "></" + tagName)
.Accepts(AcceptedCharacters.Any)));
}
}
}

View File

@@ -0,0 +1,352 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Web.Razor.Editor;
using System.Web.Razor.Generator;
using System.Web.Razor.Parser;
using System.Web.Razor.Parser.SyntaxTree;
using System.Web.Razor.Test.Framework;
using System.Web.Razor.Text;
using System.Web.Razor.Tokenizer.Symbols;
using Xunit;
namespace System.Web.Razor.Test.Parser.Html
{
public class HtmlToCodeSwitchTest : CsHtmlMarkupParserTestBase
{
[Fact]
public void ParseBlockSwitchesWhenCharacterBeforeSwapIsNonAlphanumeric()
{
ParseBlockTest("<p>foo#@i</p>",
new MarkupBlock(
Factory.Markup("<p>foo#"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("i").AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("</p>").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockSwitchesToCodeWhenSwapCharacterEncounteredMidTag()
{
ParseBlockTest("<foo @bar />",
new MarkupBlock(
Factory.Markup("<foo "),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("bar")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup(" />").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockSwitchesToCodeWhenSwapCharacterEncounteredInAttributeValue()
{
ParseBlockTest("<foo bar=\"@baz\" />",
new MarkupBlock(
Factory.Markup("<foo"),
new MarkupBlock(new AttributeBlockCodeGenerator("bar", new LocationTagged<string>(" bar=\"", 4, 0, 4), new LocationTagged<string>("\"", 14, 0, 14)),
Factory.Markup(" bar=\"").With(SpanCodeGenerator.Null),
new MarkupBlock(new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(String.Empty, 10, 0, 10), 10, 0, 10),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("baz")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))),
Factory.Markup("\"").With(SpanCodeGenerator.Null)),
Factory.Markup(" />").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockSwitchesToCodeWhenSwapCharacterEncounteredInTagContent()
{
ParseBlockTest("<foo>@bar<baz>@boz</baz></foo>",
new MarkupBlock(
Factory.Markup("<foo>"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("bar")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("<baz>"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("boz")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("</baz></foo>").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockParsesCodeWithinSingleLineMarkup()
{
ParseBlockTest(@"@:<li>Foo @Bar Baz
bork",
new MarkupBlock(
Factory.MarkupTransition(),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
Factory.Markup("<li>Foo ").With(new SingleLineMarkupEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString)),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("Bar")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup(" Baz\r\n")
.With(new SingleLineMarkupEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString, AcceptedCharacters.None))));
}
[Fact]
public void ParseBlockSupportsCodeWithinComment()
{
ParseBlockTest("<foo><!-- @foo --></foo>",
new MarkupBlock(
Factory.Markup("<foo><!-- "),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup(" --></foo>").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockSupportsCodeWithinSGMLDeclaration()
{
ParseBlockTest("<foo><!DOCTYPE foo @bar baz></foo>",
new MarkupBlock(
Factory.Markup("<foo><!DOCTYPE foo "),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("bar")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup(" baz></foo>").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockSupportsCodeWithinCDataDeclaration()
{
ParseBlockTest("<foo><![CDATA[ foo @bar baz]]></foo>",
new MarkupBlock(
Factory.Markup("<foo><![CDATA[ foo "),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("bar")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup(" baz]]></foo>").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockSupportsCodeWithinXMLProcessingInstruction()
{
ParseBlockTest("<foo><?xml foo @bar baz?></foo>",
new MarkupBlock(
Factory.Markup("<foo><?xml foo "),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("bar")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup(" baz?></foo>").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockDoesNotSwitchToCodeOnEmailAddressInText()
{
SingleSpanBlockTest("<foo>anurse@microsoft.com</foo>", BlockType.Markup, SpanKind.Markup, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockDoesNotSwitchToCodeOnEmailAddressInAttribute()
{
ParseBlockTest("<a href=\"mailto:anurse@microsoft.com\">Email me</a>",
new MarkupBlock(
Factory.Markup("<a"),
new MarkupBlock(new AttributeBlockCodeGenerator("href", new LocationTagged<string>(" href=\"", 2, 0, 2), new LocationTagged<string>("\"", 36, 0, 36)),
Factory.Markup(" href=\"").With(SpanCodeGenerator.Null),
Factory.Markup("mailto:anurse@microsoft.com")
.With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(String.Empty, 9, 0, 9), new LocationTagged<string>("mailto:anurse@microsoft.com", 9, 0, 9))),
Factory.Markup("\"").With(SpanCodeGenerator.Null)),
Factory.Markup(">Email me</a>").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockGivesWhitespacePreceedingAtToCodeIfThereIsNoMarkupOnThatLine()
{
ParseBlockTest(@" <ul>
@foreach(var p in Products) {
<li>Product: @p.Name</li>
}
</ul>",
new MarkupBlock(
Factory.Markup(" <ul>\r\n"),
new StatementBlock(
Factory.Code(" ").AsStatement(),
Factory.CodeTransition(),
Factory.Code("foreach(var p in Products) {\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" <li>Product: "),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("p.Name")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("</li>\r\n").Accepts(AcceptedCharacters.None)),
Factory.Code(" }\r\n").AsStatement().Accepts(AcceptedCharacters.None)),
Factory.Markup(" </ul>").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseDocumentGivesWhitespacePreceedingAtToCodeIfThereIsNoMarkupOnThatLine()
{
ParseDocumentTest(@" <ul>
@foreach(var p in Products) {
<li>Product: @p.Name</li>
}
</ul>",
new MarkupBlock(
Factory.Markup(" <ul>\r\n"),
new StatementBlock(
Factory.Code(" ").AsStatement(),
Factory.CodeTransition(),
Factory.Code("foreach(var p in Products) {\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" <li>Product: "),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("p.Name")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("</li>\r\n").Accepts(AcceptedCharacters.None)),
Factory.Code(" }\r\n").AsStatement().Accepts(AcceptedCharacters.None)),
Factory.Markup(" </ul>")));
}
[Fact]
public void SectionContextGivesWhitespacePreceedingAtToCodeIfThereIsNoMarkupOnThatLine()
{
ParseDocumentTest(@"@section foo {
<ul>
@foreach(var p in Products) {
<li>Product: @p.Name</li>
}
</ul>
}",
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 <ul>\r\n"),
new StatementBlock(
Factory.Code(" ").AsStatement(),
Factory.CodeTransition(),
Factory.Code("foreach(var p in Products) {\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" <li>Product: "),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("p.Name")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("</li>\r\n").Accepts(AcceptedCharacters.None)),
Factory.Code(" }\r\n").AsStatement().Accepts(AcceptedCharacters.None)),
Factory.Markup(" </ul>\r\n")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void CSharpCodeParserDoesNotAcceptLeadingOrTrailingWhitespaceInDesignMode()
{
ParseBlockTest(@" <ul>
@foreach(var p in Products) {
<li>Product: @p.Name</li>
}
</ul>",
new MarkupBlock(
Factory.Markup(" <ul>\r\n "),
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("foreach(var p in Products) {\r\n ").AsStatement(),
new MarkupBlock(
Factory.Markup("<li>Product: "),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("p.Name").AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("</li>").Accepts(AcceptedCharacters.None)),
Factory.Code("\r\n }").AsStatement().Accepts(AcceptedCharacters.None)),
Factory.Markup("\r\n </ul>").Accepts(AcceptedCharacters.None)),
designTimeParser: true);
}
// Tests for "@@" escape sequence:
[Fact]
public void ParseBlockTreatsTwoAtSignsAsEscapeSequence()
{
HtmlParserTestUtils.RunSingleAtEscapeTest(ParseBlockTest);
}
[Fact]
public void ParseBlockTreatsPairsOfAtSignsAsEscapeSequence()
{
HtmlParserTestUtils.RunMultiAtEscapeTest(ParseBlockTest);
}
[Fact]
public void ParseDocumentTreatsTwoAtSignsAsEscapeSequence()
{
HtmlParserTestUtils.RunSingleAtEscapeTest(ParseDocumentTest, lastSpanAcceptedCharacters: AcceptedCharacters.Any);
}
[Fact]
public void ParseDocumentTreatsPairsOfAtSignsAsEscapeSequence()
{
HtmlParserTestUtils.RunMultiAtEscapeTest(ParseDocumentTest, lastSpanAcceptedCharacters: AcceptedCharacters.Any);
}
[Fact]
public void SectionBodyTreatsTwoAtSignsAsEscapeSequence()
{
ParseDocumentTest("@section Foo { <foo>@@bar</foo> }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("Foo"),
Factory.CodeTransition(),
Factory.MetaCode("section Foo {").AutoCompleteWith(null, atEndOfSpan: true),
new MarkupBlock(
Factory.Markup(" <foo>"),
Factory.Markup("@").Hidden(),
Factory.Markup("@bar</foo> ")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void SectionBodyTreatsPairsOfAtSignsAsEscapeSequence()
{
ParseDocumentTest("@section Foo { <foo>@@@@@bar</foo> }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("Foo"),
Factory.CodeTransition(),
Factory.MetaCode("section Foo {").AutoCompleteWith(null, atEndOfSpan: true),
new MarkupBlock(
Factory.Markup(" <foo>"),
Factory.Markup("@").Hidden(),
Factory.Markup("@"),
Factory.Markup("@").Hidden(),
Factory.Markup("@"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("bar")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("</foo> ")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
}
}

View File

@@ -0,0 +1,272 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Web.Razor.Editor;
using System.Web.Razor.Generator;
using System.Web.Razor.Parser;
using System.Web.Razor.Parser.SyntaxTree;
using System.Web.Razor.Test.Framework;
using System.Web.Razor.Text;
using Xunit;
namespace System.Web.Razor.Test.Parser.Html
{
public class HtmlUrlAttributeTest : CsHtmlMarkupParserTestBase
{
[Fact]
public void SimpleUrlInAttributeInMarkupBlock()
{
ParseBlockTest("<a href='~/Foo/Bar/Baz' />",
new MarkupBlock(
Factory.Markup("<a"),
new MarkupBlock(new AttributeBlockCodeGenerator("href", new LocationTagged<string>(" href='", 2, 0, 2), new LocationTagged<string>("'", 22, 0, 22)),
Factory.Markup(" href='").With(SpanCodeGenerator.Null),
Factory.Markup("~/Foo/Bar/Baz")
.WithEditorHints(EditorHints.VirtualPath)
.With(new LiteralAttributeCodeGenerator(
new LocationTagged<string>(String.Empty, 9, 0, 9),
new LocationTagged<SpanCodeGenerator>(new ResolveUrlCodeGenerator(), 9, 0, 9))),
Factory.Markup("'").With(SpanCodeGenerator.Null)),
Factory.Markup(" />").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void SimpleUrlInAttributeInMarkupDocument()
{
ParseDocumentTest("<a href='~/Foo/Bar/Baz' />",
new MarkupBlock(
Factory.Markup("<a"),
new MarkupBlock(new AttributeBlockCodeGenerator("href", new LocationTagged<string>(" href='", 2, 0, 2), new LocationTagged<string>("'", 22, 0, 22)),
Factory.Markup(" href='").With(SpanCodeGenerator.Null),
Factory.Markup("~/Foo/Bar/Baz")
.WithEditorHints(EditorHints.VirtualPath)
.With(new LiteralAttributeCodeGenerator(
new LocationTagged<string>(String.Empty, 9, 0, 9),
new LocationTagged<SpanCodeGenerator>(new ResolveUrlCodeGenerator(), 9, 0, 9))),
Factory.Markup("'").With(SpanCodeGenerator.Null)),
Factory.Markup(" />")));
}
[Fact]
public void SimpleUrlInAttributeInMarkupSection()
{
ParseDocumentTest("@section Foo { <a href='~/Foo/Bar/Baz' /> }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("Foo"),
Factory.CodeTransition(),
Factory.MetaCode("section Foo {")
.AutoCompleteWith(null, atEndOfSpan: true)
.Accepts(AcceptedCharacters.Any),
new MarkupBlock(
Factory.Markup(" <a"),
new MarkupBlock(new AttributeBlockCodeGenerator("href", new LocationTagged<string>(" href='", 17, 0, 17), new LocationTagged<string>("'", 37, 0, 37)),
Factory.Markup(" href='").With(SpanCodeGenerator.Null),
Factory.Markup("~/Foo/Bar/Baz")
.WithEditorHints(EditorHints.VirtualPath)
.With(new LiteralAttributeCodeGenerator(
new LocationTagged<string>(String.Empty, 24, 0, 24),
new LocationTagged<SpanCodeGenerator>(new ResolveUrlCodeGenerator(), 24, 0, 24))),
Factory.Markup("'").With(SpanCodeGenerator.Null)),
Factory.Markup(" /> ")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void UrlWithExpressionsInAttributeInMarkupBlock()
{
ParseBlockTest("<a href='~/Foo/@id/Baz' />",
new MarkupBlock(
Factory.Markup("<a"),
new MarkupBlock(new AttributeBlockCodeGenerator("href", new LocationTagged<string>(" href='", 2, 0, 2), new LocationTagged<string>("'", 22, 0, 22)),
Factory.Markup(" href='").With(SpanCodeGenerator.Null),
Factory.Markup("~/Foo/")
.WithEditorHints(EditorHints.VirtualPath)
.With(new LiteralAttributeCodeGenerator(
new LocationTagged<string>(String.Empty, 9, 0, 9),
new LocationTagged<SpanCodeGenerator>(new ResolveUrlCodeGenerator(), 9, 0, 9))),
new MarkupBlock(new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(String.Empty, 15, 0, 15), 15, 0, 15),
new ExpressionBlock(
Factory.CodeTransition().Accepts(AcceptedCharacters.None),
Factory.Code("id")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))),
Factory.Markup("/Baz")
.With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(String.Empty, 18, 0, 18), new LocationTagged<string>("/Baz", 18, 0, 18))),
Factory.Markup("'").With(SpanCodeGenerator.Null)),
Factory.Markup(" />").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void UrlWithExpressionsInAttributeInMarkupDocument()
{
ParseDocumentTest("<a href='~/Foo/@id/Baz' />",
new MarkupBlock(
Factory.Markup("<a"),
new MarkupBlock(new AttributeBlockCodeGenerator("href", new LocationTagged<string>(" href='", 2, 0, 2), new LocationTagged<string>("'", 22, 0, 22)),
Factory.Markup(" href='").With(SpanCodeGenerator.Null),
Factory.Markup("~/Foo/")
.WithEditorHints(EditorHints.VirtualPath)
.With(new LiteralAttributeCodeGenerator(
new LocationTagged<string>(String.Empty, 9, 0, 9),
new LocationTagged<SpanCodeGenerator>(new ResolveUrlCodeGenerator(), 9, 0, 9))),
new MarkupBlock(new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(String.Empty, 15, 0, 15), 15, 0, 15),
new ExpressionBlock(
Factory.CodeTransition().Accepts(AcceptedCharacters.None),
Factory.Code("id")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))),
Factory.Markup("/Baz")
.With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(String.Empty, 18, 0, 18), new LocationTagged<string>("/Baz", 18, 0, 18))),
Factory.Markup("'").With(SpanCodeGenerator.Null)),
Factory.Markup(" />")));
}
[Fact]
public void UrlWithExpressionsInAttributeInMarkupSection()
{
ParseDocumentTest("@section Foo { <a href='~/Foo/@id/Baz' /> }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("Foo"),
Factory.CodeTransition(),
Factory.MetaCode("section Foo {")
.AutoCompleteWith(null, atEndOfSpan: true),
new MarkupBlock(
Factory.Markup(" <a"),
new MarkupBlock(new AttributeBlockCodeGenerator("href", new LocationTagged<string>(" href='", 17, 0, 17), new LocationTagged<string>("'", 37, 0, 37)),
Factory.Markup(" href='").With(SpanCodeGenerator.Null),
Factory.Markup("~/Foo/")
.WithEditorHints(EditorHints.VirtualPath)
.With(new LiteralAttributeCodeGenerator(
new LocationTagged<string>(String.Empty, 24, 0, 24),
new LocationTagged<SpanCodeGenerator>(new ResolveUrlCodeGenerator(), 24, 0, 24))),
new MarkupBlock(new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(String.Empty, 30, 0, 30), 30, 0, 30),
new ExpressionBlock(
Factory.CodeTransition().Accepts(AcceptedCharacters.None),
Factory.Code("id")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))),
Factory.Markup("/Baz")
.With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(String.Empty, 33, 0, 33), new LocationTagged<string>("/Baz", 33, 0, 33))),
Factory.Markup("'").With(SpanCodeGenerator.Null)),
Factory.Markup(" /> ")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void UrlWithComplexCharactersInAttributeInMarkupBlock()
{
ParseBlockTest("<a href='~/Foo+Bar:Baz(Biz),Boz' />",
new MarkupBlock(
Factory.Markup("<a"),
new MarkupBlock(new AttributeBlockCodeGenerator("href", new LocationTagged<string>(" href='", 2, 0, 2), new LocationTagged<string>("'", 31, 0, 31)),
Factory.Markup(" href='").With(SpanCodeGenerator.Null),
Factory.Markup("~/Foo+Bar:Baz(Biz),Boz")
.WithEditorHints(EditorHints.VirtualPath)
.With(new LiteralAttributeCodeGenerator(
new LocationTagged<string>(String.Empty, 9, 0, 9),
new LocationTagged<SpanCodeGenerator>(new ResolveUrlCodeGenerator(), 9, 0, 9))),
Factory.Markup("'").With(SpanCodeGenerator.Null)),
Factory.Markup(" />").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void UrlWithComplexCharactersInAttributeInMarkupDocument()
{
ParseDocumentTest("<a href='~/Foo+Bar:Baz(Biz),Boz' />",
new MarkupBlock(
Factory.Markup("<a"),
new MarkupBlock(new AttributeBlockCodeGenerator("href", new LocationTagged<string>(" href='", 2, 0, 2), new LocationTagged<string>("'", 31, 0, 31)),
Factory.Markup(" href='").With(SpanCodeGenerator.Null),
Factory.Markup("~/Foo+Bar:Baz(Biz),Boz")
.WithEditorHints(EditorHints.VirtualPath)
.With(new LiteralAttributeCodeGenerator(
new LocationTagged<string>(String.Empty, 9, 0, 9),
new LocationTagged<SpanCodeGenerator>(new ResolveUrlCodeGenerator(), 9, 0, 9))),
Factory.Markup("'").With(SpanCodeGenerator.Null)),
Factory.Markup(" />")));
}
[Fact]
public void UrlInUnquotedAttributeValueInMarkupBlock()
{
ParseBlockTest("<a href=~/Foo+Bar:Baz(Biz),Boz/@id/Boz />",
new MarkupBlock(
Factory.Markup("<a"),
new MarkupBlock(new AttributeBlockCodeGenerator("href", new LocationTagged<string>(" href=", 2, 0, 2), new LocationTagged<string>(String.Empty, 38, 0, 38)),
Factory.Markup(" href=").With(SpanCodeGenerator.Null),
Factory.Markup("~/Foo+Bar:Baz(Biz),Boz/")
.WithEditorHints(EditorHints.VirtualPath)
.With(new LiteralAttributeCodeGenerator(
new LocationTagged<string>(String.Empty, 8, 0, 8),
new LocationTagged<SpanCodeGenerator>(new ResolveUrlCodeGenerator(), 8, 0, 8))),
new MarkupBlock(new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(String.Empty, 31, 0, 31), 31, 0, 31),
new ExpressionBlock(
Factory.CodeTransition()
.Accepts(AcceptedCharacters.None),
Factory.Code("id")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))),
Factory.Markup("/Boz").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(String.Empty, 34, 0, 34), new LocationTagged<string>("/Boz", 34, 0, 34)))),
Factory.Markup(" />").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void UrlInUnquotedAttributeValueInMarkupDocument()
{
ParseDocumentTest("<a href=~/Foo+Bar:Baz(Biz),Boz/@id/Boz />",
new MarkupBlock(
Factory.Markup("<a"),
new MarkupBlock(new AttributeBlockCodeGenerator("href", new LocationTagged<string>(" href=", 2, 0, 2), new LocationTagged<string>(String.Empty, 38, 0, 38)),
Factory.Markup(" href=").With(SpanCodeGenerator.Null),
Factory.Markup("~/Foo+Bar:Baz(Biz),Boz/")
.WithEditorHints(EditorHints.VirtualPath)
.With(new LiteralAttributeCodeGenerator(
new LocationTagged<string>(String.Empty, 8, 0, 8),
new LocationTagged<SpanCodeGenerator>(new ResolveUrlCodeGenerator(), 8, 0, 8))),
new MarkupBlock(new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(String.Empty, 31, 0, 31), 31, 0, 31),
new ExpressionBlock(
Factory.CodeTransition()
.Accepts(AcceptedCharacters.None),
Factory.Code("id")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))),
Factory.Markup("/Boz").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(String.Empty, 34, 0, 34), new LocationTagged<string>("/Boz", 34, 0, 34)))),
Factory.Markup(" />")));
}
[Fact]
public void UrlInUnquotedAttributeValueInMarkupSection()
{
ParseDocumentTest("@section Foo { <a href=~/Foo+Bar:Baz(Biz),Boz/@id/Boz /> }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("Foo"),
Factory.CodeTransition(),
Factory.MetaCode("section Foo {")
.AutoCompleteWith(null, atEndOfSpan: true),
new MarkupBlock(
Factory.Markup(" <a"),
new MarkupBlock(new AttributeBlockCodeGenerator("href", new LocationTagged<string>(" href=", 17, 0, 17), new LocationTagged<string>(String.Empty, 53, 0, 53)),
Factory.Markup(" href=").With(SpanCodeGenerator.Null),
Factory.Markup("~/Foo+Bar:Baz(Biz),Boz/")
.WithEditorHints(EditorHints.VirtualPath)
.With(new LiteralAttributeCodeGenerator(
new LocationTagged<string>(String.Empty, 23, 0, 23),
new LocationTagged<SpanCodeGenerator>(new ResolveUrlCodeGenerator(), 23, 0, 23))),
new MarkupBlock(new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(String.Empty, 46, 0, 46), 46, 0, 46),
new ExpressionBlock(
Factory.CodeTransition()
.Accepts(AcceptedCharacters.None),
Factory.Code("id")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))),
Factory.Markup("/Boz").With(new LiteralAttributeCodeGenerator(new LocationTagged<string>(String.Empty, 49, 0, 49), new LocationTagged<string>("/Boz", 49, 0, 49)))),
Factory.Markup(" /> ")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
}
}