// 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())); } } }